# App Ad Serving — Design Document

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

## Overview

Serve banner ads within the HBCU Connect mobile app by reusing the existing zone-based ad server (`ad_server.cgi`). Ads appear every 10th item in scrollable lists across four screens: Feed, Jobs, Members, and Shop. The app loads ads via WebView (the same iframe pattern used on the website), with link clicks opening a full-screen in-app browser modal.

## Decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| Architecture | WebView loading ad_server.cgi | Reuses all existing rotation, tracking, and ad types with zero backend changes |
| Ad frequency | Every 10th item | Unobtrusive, roughly 1 ad per 2 screenfuls |
| Ad zones | New app-specific zones | Separate inventory/reporting from website |
| Primary ad size | 300x250 (Medium Rectangle) | Standard mobile format, good visibility |
| Secondary ad size | 468x60 (Full Banner) | Built-in preset for future use, not active now |
| Click behavior | In-app browser modal | Users stay in app; "Open in Browser" button available, auto-closes modal on use |

## Components

### AdBanner (`hbcu-app/mobile/src/components/AdBanner.js`)

Reusable component that renders a WebView loading `https://hbcuconnect.com/cgi-bin/ads/ad_server.cgi?zone_id={zoneId}`.

**Props:**
- `zoneId` (number, required) — ad zone to load
- `size` (string, default `'medium-rectangle'`) — `'medium-rectangle'` (300x250) or `'full-banner'` (468x60)

**Behavior:**
- Renders WebView at the appropriate dimensions
- Shows subtle "Ad" label
- Shimmer/placeholder while loading
- Intercepts all navigation requests — opens InAppBrowser modal instead of navigating inside the WebView

### InAppBrowser (`hbcu-app/mobile/src/components/InAppBrowser.js`)

Full-screen modal browser for viewing ad destinations.

**UI:**
- Top bar: domain display, close (X) button
- Bottom toolbar: back, forward, "Open in Browser" button
- Loading progress bar

**Behavior:**
- Receives URL, renders full-screen WebView
- Ad server click redirect (302) followed automatically — click tracking works as-is
- "Open in Browser" calls `Linking.openURL()` then immediately closes the modal
- Close (X) returns user to their feed/list

### Ad Helpers (`hbcu-app/mobile/src/utils/adHelpers.js`)

- `insertAds(items, zoneId, interval=10)` — returns new array with ad placeholder objects at every Nth position
- Ad placeholders: `{ _isAd: true, _adKey: unique-string, zoneId: N }`

## Screen Modifications

| Screen | File | Zone | Notes |
|--------|------|------|-------|
| Feed | `screens/media/FeedScreen.js` | App - Feed | Ads between posts in vertical feed |
| Jobs | `screens/jobs/JobListScreen.js` | App - Jobs | Ads between job listings |
| Members | `screens/members/MemberSearchScreen.js` | App - Members | Ads between member cards |
| Shop | `screens/marketplace/CategoryProductsScreen.js` | App - Shop | Full-width ad breaking out of 2-column grid |

Each screen's `FlatList` `renderItem` checks `item._isAd` — if true, renders `<AdBanner>`, otherwise renders the normal item component.

## Database

INSERT 4 new zones into `career_center.banner_zones`:

```sql
INSERT INTO banner_zones (zone_name, zone_description, width, height, ad_types, active)
VALUES
  ('App - Feed', 'HBCU App: between posts in social feed', 300, 250, 'html,image,remote', 1),
  ('App - Jobs', 'HBCU App: between job listings', 300, 250, 'html,image,remote', 1),
  ('App - Members', 'HBCU App: between member cards', 300, 250, 'html,image,remote', 1),
  ('App - Shop', 'HBCU App: between product listings', 300, 250, 'html,image,remote', 1);
```

No backend code changes. Ad assignment is done through existing `ad_management.cgi`.

## Dependencies

- `react-native-webview` — npm package (not currently installed)

## No Backend Changes

The existing `ad_server.cgi` handles:
- Priority-weighted banner rotation
- Impression tracking (deferred to log file, batch-inserted)
- Click tracking via redirect (`?click=N` → 302 to target_url)
- All ad types (HTML, image, remote URL, content ads)
