# App Configuration Settings — Design Doc

**Date:** 2026-02-23
**Status:** Approved

## Goal

Create a centralized admin settings page that controls mobile app behavior without requiring app rebuilds. Consolidate the existing feed algorithm settings into this page as a tab.

## Architecture

```
Admin saves → app_settings table → API GET /api/app/config (60s cache) → Mobile AppConfigProvider (5min cache) → Screens
```

- **Admin page:** `/admin/app/app_settings.cgi` — 6-tab Tailwind UI page
- **API endpoint:** `GET /api/app/config` — returns all `app_*` and `feed_*` settings as flat JSON, cached 60s server-side
- **Mobile context:** `AppConfigContext.js` — fetches on app launch, caches 5min, provides `useAppConfig()` hook
- **DB:** Existing `app_settings` table (key/value), no schema changes needed

## Settings Schema

### Tab 1: Content Rules (prefix: `app_`)
| Key | Default | Type | Description |
|-----|---------|------|-------------|
| `app_video_max_duration` | `60` | int (seconds) | Max video length for uploads |
| `app_video_max_loops` | `2` | int | Auto-replay count before pausing |
| `app_caption_max_length` | `2000` | int (chars) | Max post caption length |
| `app_password_min_length` | `6` | int (chars) | Min password length |
| `app_report_reasons` | `["Inappropriate","Harassment","Spam"]` | JSON array | Report menu options |

### Tab 2: Ads & Monetization (prefix: `app_ad_`)
| Key | Default | Type | Description |
|-----|---------|------|-------------|
| `app_ad_interval` | `10` | int | Insert ad every N items in lists |
| `app_ad_zone_feed` | `55` | int | Ad zone ID for feed |
| `app_ad_zone_jobs` | `56` | int | Ad zone ID for jobs |
| `app_ad_zone_members` | `57` | int | Ad zone ID for members |
| `app_ad_zone_shop` | `58` | int | Ad zone ID for shop |

### Tab 3: Feature Flags (prefix: `app_feature_`)
| Key | Default | Type | Description |
|-----|---------|------|-------------|
| `app_feature_marketplace` | `1` | 0/1 | Show/hide marketplace tab |
| `app_feature_nearby` | `1` | 0/1 | Show/hide nearby feature |
| `app_feature_messaging` | `1` | 0/1 | Enable/disable messaging |
| `app_feature_video_posts` | `1` | 0/1 | Allow video uploads |
| `app_feature_registration` | `1` | 0/1 | Allow new registrations |
| `app_feature_jobs` | `1` | 0/1 | Show/hide jobs tab |

### Tab 4: Appearance (prefix: `app_color_`, `app_logo_`, `app_welcome_`)
| Key | Default | Type | Description |
|-----|---------|------|-------------|
| `app_color_primary` | `#0069ed` | hex | Primary button/link color |
| `app_color_accent` | `#c8102e` | hex | Accent/red color |
| `app_color_accent_gold` | `#d4a843` | hex | Gold accent color |
| `app_color_header_bg` | `#000000` | hex | Header background |
| `app_logo_light` | `https://hbcuconnect.com/hbcu-app/assets/HBCUConnect840.png?v=2` | URL | Logo for login screen |
| `app_logo_dark` | `https://hbcuconnect.com/hbcu-app/assets/HBCUConnect540.png?v=2` | URL | Logo for dark headers |
| `app_welcome_title` | `Welcome to the Feed!` | text | Empty feed title |
| `app_welcome_text` | `Follow members and post photos to see content here.` | text | Empty feed subtitle |

### Tab 5: Performance (prefix: `app_`)
| Key | Default | Type | Description |
|-----|---------|------|-------------|
| `app_poll_interval` | `30000` | int (ms) | Notification/badge poll interval |
| `app_nearby_radius_default` | `25` | int (miles) | Default nearby radius |
| `app_nearby_radius_options` | `[5,10,25,50,100]` | JSON array | Radius picker options |
| `app_view_delay_video` | `3000` | int (ms) | Time before video view counts |
| `app_view_delay_photo` | `1000` | int (ms) | Time before photo view counts |

### Tab 6: Feed Algorithm (prefix: `feed_`)
Existing 23 `feed_*` keys — moved from `feed_settings.cgi`. No changes to keys or values.

## Files to Create/Modify

| File | Action | Description |
|------|--------|-------------|
| `admin/app/app_settings.cgi` | CREATE | 6-tab admin settings page |
| `admin/app/index.cgi` | MODIFY | Replace feed_settings link with app_settings link |
| `hbcu-app/api/routes/appConfig.js` | CREATE | GET /api/app/config endpoint |
| `hbcu-app/api/server.js` | MODIFY | Mount new route |
| `hbcu-app/mobile/src/context/AppConfigContext.js` | CREATE | React context + provider + hook |
| `hbcu-app/mobile/src/context/theme.js` | MODIFY | Support config overrides for colors/logos |
| `hbcu-app/mobile/src/utils/adHelpers.js` | MODIFY | Read zones/interval from config |
| `hbcu-app/mobile/src/screens/media/FeedScreen.js` | MODIFY | Use config for MAX_LOOPS, view delays, report reasons, welcome text |
| `hbcu-app/mobile/src/screens/media/CreatePostScreen.js` | MODIFY | Use config for MAX_CAPTION, video duration, video_posts flag |
| `hbcu-app/mobile/src/screens/media/PostDetailScreen.js` | MODIFY | Use config for MAX_LOOPS |
| `hbcu-app/mobile/src/screens/members/NearbyScreen.js` | MODIFY | Use config for radius options/default |
| `hbcu-app/mobile/src/navigation/MainTabs.js` | MODIFY | Use feature flags to show/hide tabs, poll interval from config |
| `hbcu-app/mobile/src/components/NotificationBell.js` | MODIFY | Poll interval from config |
| `hbcu-app/mobile/src/screens/members/MemberSearchScreen.js` | MODIFY | Poll interval from config |
| `hbcu-app/mobile/src/screens/settings/SettingsScreen.js` | MODIFY | Password min length from config |
| `hbcu-app/mobile/App.js` | MODIFY | Wrap with AppConfigProvider |

## Mobile App Config Loading

`AppConfigContext.js` fetches `GET /api/app/config` on mount. The response is a flat object like:
```json
{
  "videoMaxDuration": 60,
  "videoMaxLoops": 2,
  "captionMaxLength": 2000,
  "passwordMinLength": 6,
  "reportReasons": ["Inappropriate", "Harassment", "Spam"],
  "adInterval": 10,
  "adZones": { "feed": 55, "jobs": 56, "members": 57, "shop": 58 },
  "features": { "marketplace": true, "nearby": true, "messaging": true, "videoPosts": true, "registration": true, "jobs": true },
  "colors": { "primary": "#0069ed", "accent": "#c8102e", "accentGold": "#d4a843", "headerBg": "#000000" },
  "logos": { "light": "...", "dark": "..." },
  "welcomeTitle": "Welcome to the Feed!",
  "welcomeText": "Follow members and post photos to see content here.",
  "pollInterval": 30000,
  "nearbyRadiusDefault": 25,
  "nearbyRadiusOptions": [5, 10, 25, 50, 100],
  "viewDelayVideo": 3000,
  "viewDelayPhoto": 1000
}
```

The hook `useAppConfig()` returns this object. All values have hardcoded defaults as fallbacks so the app works even if the API call fails.

## Retiring feed_settings.cgi

- `feed_settings.cgi` stays on disk but is no longer linked from `index.cgi`
- Its functionality is fully replicated in Tab 6 of `app_settings.cgi`
- Can be deleted in a future cleanup pass
