> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cfosilvia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Radar frontend structure

# Radar Frontend Structure

**Location**: `app/radar/`

**Purpose**: User interface for viewing AI-generated insights and managing radar schedules.

## User Experience Flow

```
User visits /radar
     ↓
Landing page appears with "Enter Radar" button
     ↓
User clicks Enter → Main interface loads
     ↓
3 Tabs: All | Bookmarked | Alerts
     ↓
"All" & "Bookmarked" show Silvia Feed (scenarios)
"Alerts" shows Radar Feed (scheduled radar results)
     ↓
Sidebar shows active schedules + create new form
     ↓
User creates schedule → Backend processes → Result appears in feed
```

## Page Structure (`page.tsx`)

The main Radar page is a React component with several key sections:

### 1. Landing Screen

* **Shows first** on every visit (no persistence)
* Explains Radar feature with visual examples
* User must click "Enter Radar" to access main interface
* Component: `<RadarLanding />`

### 2. Account Validation

* **Checks if user has connected accounts** (Plaid, SnapTrade, manual, crypto)
* **Blocks access** if no accounts found
* Shows alert with "Connect Account" button
* Opens account connection dialog when clicked

### 3. Filter Tabs

Three filter options at the top:

* **All** - Shows SilviaFeed with all scenarios and radar results
* **Bookmarked** - Shows only bookmarked items from SilviaFeed
* **Alerts** - Shows RadarFeed with scheduled radar results only

### 4. Main Feed (Left/Center)

Two different feed components based on active filter:

**SilviaFeed** (for "All" and "Bookmarked"):

* Displays AI-generated scenarios from the scenarios feature
* Shows radar results mixed with scenario cards
* Supports bookmarking individual items
* Hot loading strategy: loads from DB first, generates if needed
* Component: `<SilviaFeed />`

**RadarFeed** (for "Alerts"):

* Displays only scheduled radar results
* Shows results grouped by radar schedule
* No bookmarking functionality
* Component: `<RadarFeed />`

### 5. Sidebar (Right)

Sticky sidebar containing:

* **Schedule List** - Active/inactive radar schedules with toggle and delete
* **Create Form** - Input for new prompt, frequency selector (Daily/Weekly/Monthly)
* **Day Selection** - For weekly schedules (Mon, Tue, Wed, etc.)
* **Day of Month** - For monthly schedules (1-31)
* **Create Button** - Triggers schedule creation
* Component: `<RadarSidebar />`

## Custom Hooks (`hooks.ts`)

### 1. `useRadarSchedules`

**Purpose**: Manages radar schedule CRUD operations

**What it does**:

* Fetches list of user's schedules from API on mount
* Creates new schedules with prompt and frequency config
* Toggles schedule enabled/disabled status
* Deletes schedules with confirmation dialog
* Tracks loading and creating states
* Sends analytics events for all actions

**Returns**:

```typescript theme={null}
{
  schedules: RadarSchedule[]        // Array of user's schedules
  isLoading: boolean                // Initial load state
  isCreating: boolean               // Creating new schedule
  createSchedule: (prompt, config) => Promise<RadarSchedule | null>
  toggleSchedule: (id, enabled) => Promise<void>
  deleteSchedule: (id) => Promise<boolean>
  loadSchedules: () => Promise<void>
}
```

### 2. `useRadarResults`

**Purpose**: Manages radar execution results and polling

**What it does**:

* Fetches results for all schedules from API
* Polls for status updates every 5 seconds for processing results
* Stores results mapped by scheduleId
* Triggers manual radar execution ("Run Now" button)
* Cleans up polling intervals on unmount
* Updates results when processing completes

**Polling Logic**:

1. When result status is "PROCESSING", starts 5-second interval
2. Checks status endpoint repeatedly
3. When status becomes "COMPLETED" or "FAILED", stops polling
4. Automatically fetches full results after completion

**Returns**:

```typescript theme={null}
{
  results: Record<string, RadarResult>           // Map of scheduleId → result
  resultStatuses: Record<string, ResultStatus>   // Map of scheduleId → status
  triggerNow: (scheduleId) => Promise<void>      // Manual trigger
  clearResultForSchedule: (scheduleId) => void   // Cleanup
  loadResults: () => Promise<void>               // Refresh
}
```

### 3. `useRadarForm`

**Purpose**: Manages the create schedule form state

**What it does**:

* Stores form field values (prompt, frequency, days, time)
* Handles day selection for weekly schedules (toggle on/off)
* Builds schedule config object from form state
* Resets form after successful creation
* Manages form expanded/collapsed state

**Returns**:

```typescript theme={null}
{
  newPrompt: string                              // User's prompt input
  frequency: 'DAILY' | 'WEEKLY' | 'MONTHLY'      // Selected frequency
  selectedDays: number[]                         // For weekly (ISO: 1=Mon, 7=Sun)
  dayOfMonth: number                             // For monthly (1-31)
  buildScheduleConfig: () => ScheduleConfig      // Builds config object
  resetForm: () => void                          // Clears all fields
  // ... setters for each field
}
```

## Feed & Simulation System

### How the Feed Works

The Silvia Feed uses a **"hot loading" strategy** that prioritizes showing content immediately while generating fresh insights in the background.

#### Loading Strategy: 3 Phases

**Phase 1: Initial Generation (On Mount)**

```typescript theme={null}
// When user first loads /radar
1. Generate 2-3 brand new posts immediately via simulation API
2. Don't wait for results - continue loading
3. Takes ~5-10 seconds in background
```

**Phase 2: Database Loading (Progressive)**

```typescript theme={null}
// Load existing posts from DB in batches
Batch 1: Load 3 posts (fastest load)
Batch 2: Load 5 posts (when scrolling near bottom)
Batch 3+: Load 5 posts each (continue until no more)
```

**Phase 3: Infinite Scroll**

```typescript theme={null}
// Intersection Observer triggers when user scrolls
- Watches "bottom sentinel" element
- Triggers 100px before reaching bottom
- Loads next batch automatically
- Shows "Loading more..." indicator
```

#### Simulation API (`/api/radar/silvia-simulation`)

**What it does**:

1. Analyzes user's portfolio using internal chat API
2. Generates insights about:
   * Portfolio composition changes
   * Risk exposure shifts
   * Market trends affecting holdings
   * Opportunities or warnings
3. Stores results in `silvia_feed_posts` table
4. Returns immediately (processing happens in background)

**Example generated insights**:

* "Your tech allocation increased to 42% - consider rebalancing"
* "Bitcoin moved 8% today, affecting 15% of your portfolio"
* "Your portfolio volatility is lower than the S\&P 500"

**Parameters**:

```typescript theme={null}
POST /api/radar/silvia-simulation
Body: { count: 2 }  // Generate 2-3 posts
```

#### Post Lifecycle

```
User loads /radar
     ↓
[GENERATION] API generates 2-3 fresh posts (5-10s)
     ↓
[LOADING] Fetch first 3 posts from DB
     ↓
[DISPLAY] Show posts immediately (includes newly generated)
     ↓
[SCROLL] User scrolls → load 5 more
     ↓
[SCROLL] User scrolls → load 5 more
     ↓
[END] No more posts → show "You've reached the end"
```

#### Mixing Scenarios into Feed

Posts and scenarios are **interleaved** for variety:

```typescript theme={null}
// Every 4 posts, insert 1 scenario
Post 1
Post 2
Post 3
Post 4
>>> Scenario 1 (from /scenarios feature)
Post 5
Post 6
Post 7
Post 8
>>> Scenario 2
...
```

**Rules**:

* Only completed scenarios are shown
* Scenarios must have a response (not failed/processing)
* Sorted by most recent first
* Only mixed in "All" filter (not in "Bookmarked")

#### Filtering System

**All Tab**:

* Shows ALL posts (both regular insights and scenarios)
* Mixed feed with 4:1 ratio (4 posts → 1 scenario)
* Infinite scroll loads both types

**Bookmarked Tab**:

* Shows only posts user has bookmarked
* Filter applied at database level
* Still uses same loading pattern (3 → 5 → 5)
* No scenarios mixed in

**Alerts Tab**:

* Switches to RadarFeed component entirely
* Shows only scheduled radar results
* Different data source (DynamoDB, not Supabase)

### Component Details

### `silvia-feed.tsx`

**Purpose**: Main feed showing scenarios and radar results together

**State Management**:

```typescript theme={null}
const [posts, setPosts] = useState([])              // Loaded posts
const [offset, setOffset] = useState(0)             // Pagination offset
const [hasMore, setHasMore] = useState(true)        // More posts available
const [isLoading, setIsLoading] = useState(false)   // Loading indicator
const [loadPatternIndex, setLoadPatternIndex] = useState(0)  // Which batch (3, 5, 5)
```

**Key Functions**:

1. **generateInitialPosts()** - Creates fresh content on mount
   ```typescript theme={null}
   - Runs once per visit (tracked with ref)
   - Generates 2-3 random posts
   - Calls simulation API in background
   - Doesn't block UI loading
   ```

2. **loadMore()** - Fetches posts from database
   ```typescript theme={null}
   - Uses loading pattern: [3, 5, 5]
   - Respects activeFilter (all/bookmarked)
   - Updates offset for next batch
   - Sets hasMore based on response
   ```

3. **Intersection Observer** - Triggers auto-loading
   ```typescript theme={null}
   - Observes bottom sentinel element
   - Starts loading 100px before bottom
   - Only fires when hasMore is true
   - Prevents duplicate loads with ref
   ```

**Data Flow**:

```
Mount → generateInitialPosts() → loadMore() → Display
  ↓                                  ↓
API simulation               Fetch from DB
(background)                 (immediate)
  ↓                                  ↓
Stores in DB                 Shows in UI
  ↓                                  ↓
Next loadMore()              User scrolls
includes new posts           → loadMore()
```

### `radar-feed.tsx`

**Purpose**: Feed showing only scheduled radar results

**Features**:

* Groups results by schedule type
* Shows timestamp and status
* Displays AI-generated insights
* No bookmarking (these are alerts/notifications)

### `radar-sidebar.tsx`

**Purpose**: Schedule management and creation form

**Contains**:

* List of existing schedules with toggle switches
* "Run Now" button per schedule
* Delete button per schedule
* Create new schedule form with:
  * Prompt input textarea
  * Frequency selector (Daily/Weekly/Monthly)
  * Day picker for weekly
  * Day of month for monthly
  * Time picker (defaults to 6:00 UTC)

### `radar-landing.tsx`

**Purpose**: Welcome screen shown on first visit

**Features**:

* Explains what Radar does
* Shows example radar results
* Large "Enter Radar" button
* Appears every time user visits /radar (no persistence)

### `scenario-card.tsx`

**Purpose**: Individual card for displaying a scenario or radar result

**Features**:

* Shows title and summary
* Displays timestamp
* Bookmark button
* Click to expand full analysis
* Shows status badge (completed/processing)

## API Communication (`utils.ts`)

The frontend communicates with the backend via REST API:

```typescript theme={null}
api.schedules.list(userId)              // GET /schedules
api.schedules.create(userId, data)      // POST /schedules
api.schedules.update(userId, id, data)  // PUT /schedules/{id}
api.schedules.delete(userId, id)        // DELETE /schedules/{id}

api.results.list(userId)                // GET /results
api.results.status(scheduleId)          // GET /results/{scheduleId}/status

api.trigger(userId, scheduleId)         // POST /trigger
```

**Headers sent with every request**:

* `X-User-Id: {clerkId}` - User authentication
* `Content-Type: application/json`

## Data Flow Example: Creating a Schedule

```
1. User fills form in sidebar:
   - Prompt: "Check if my tech allocation is too high"
   - Frequency: WEEKLY
   - Days: Monday, Wednesday
   
2. User clicks "Create Schedule"
   ↓
3. useRadarForm.buildScheduleConfig() creates:
   {
     frequency: "WEEKLY",
     timeUtc: "06:00",
     timezone: "America/New_York",
     daysOfWeek: [1, 3]
   }
   ↓
4. useRadarSchedules.createSchedule() calls:
   POST /schedules
   Body: { promptTemplate, scheduleConfig }
   ↓
5. Backend creates schedule in DynamoDB
   ↓
6. Frontend receives schedule object
   ↓
7. Schedule appears in sidebar list immediately
   ↓
8. Backend will execute on next Monday at 6am UTC
```

## Data Flow Example: Viewing Results

```
1. User opens /radar (after entering from landing)
   ↓
2. Page.tsx loads:
   - useRadarSchedules fetches schedules
   - useRadarResults fetches results
   ↓
3. If result status is "PROCESSING":
   - Polling starts (5-second interval)
   - Status badge shows "Processing..."
   ↓
4. When processing completes:
   - Polling detects "COMPLETED" status
   - Full result is fetched
   - Result card appears in feed
   ↓
5. User sees:
   - Summary text
   - Insights section
   - Recommendations
   - Timestamp
```

## State Management

**No global state management** - uses React hooks only:

* `useState` for component-local state (filters, dialogs)
* Custom hooks for data fetching and API calls
* `useEffect` for side effects (loading data, polling)
* `useRef` for polling interval tracking

## Analytics Tracking

PostHog events tracked:

```typescript theme={null}
analytics.scheduleCreationStarted(frequency, promptLength)
analytics.scheduleCreated(scheduleId, frequency)
analytics.scheduleToggled(scheduleId, enabled)
analytics.scheduleDeleted(scheduleId)
analytics.manuallyTriggered(scheduleId)
analytics.scheduleCreationError(error)
```

## Error Handling

* **No accounts**: Shows alert banner with "Connect Account" button
* **API failures**: Logged to console, silent to user (schedules/results remain)
* **Schedule deletion**: Shows browser confirm() dialog before deleting
* **Network errors**: Each hook handles errors independently, doesn't crash app

## Future Enhancements

* WebSocket for real-time result updates (replace polling)
* Push notifications when radar completes
* Schedule templates (pre-built prompts)
* Result history view (paginated)
* Export results to PDF
* Share results via link


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.