# Presidency Social Reporting Dashboard — Claude Code Instructions

> **Project:** The Presidency of South Africa — Social Media Reporting Dashboard  
> **Client:** The Presidency of South Africa  
> **Agency:** Mind Interactive (Bokang Mabiletsa — bmabiletsa@gmail.com)  
> **Wireframe Reference:** `Dashboard_Wireframe_Mockup.jsx` (in this folder — read it before writing any UI code)

---

## 1. Project Overview

Mind Interactive is a digital agency operating on a **120-hour/month retainer** with The Presidency of South Africa. They produce multimedia content (graphics, videos, motion, strategy, social media management) across LinkedIn, YouTube, TikTok, Twitter/X, Instagram, Facebook, and WhatsApp.

This dashboard serves **two audiences**:

| Role | Who | What they do |
|------|-----|--------------|
| **Admin / Agency Staff** | Mind Interactive team | Create projects, log tasks, track hours, upload files, post comments, manage campaigns |
| **Client Viewer** | The Presidency staff | View reports, see analytics, browse the calendar, download deliverables — read-only |

The system must support **both live API data and manual data entry**, because some social platforms may not grant API access and data will need to be entered by hand.

---

## 2. Wireframe Reference

The file `Dashboard_Wireframe_Mockup.jsx` in this directory is a fully interactive React mockup. **Read it before building any feature.** It contains:

- All component names and data structures
- Mock data for `MONTH_DATA`, `CALENDAR_EVENTS`, `TASK_DETAILS`
- The exact UX flow for the Task Drawer (Files / Links / Comments tabs)
- The Social Calendar grid and list view
- Dashboard KPIs, campaign cards, and hours tracking charts

**All UI must match the wireframe visually and functionally.** Do not invent UI that is not in the wireframe without asking the user first.

---

## 3. Tech Stack

| Layer | Technology |
|-------|-----------|
| Framework | Next.js 14+ (App Router) |
| Language | TypeScript (strict mode) |
| Styling | Tailwind CSS v3 |
| UI Components | shadcn/ui + Lucide React icons |
| Charts | Recharts |
| ORM | Prisma |
| Database | PostgreSQL (Supabase or Railway) |
| Auth | NextAuth.js v5 (credentials + magic link) |
| File Storage | Vercel Blob or Supabase Storage |
| Deployment | Vercel |
| Package Manager | pnpm |

---

## 4. Project Structure

```
/
├── app/
│   ├── (auth)/
│   │   ├── login/page.tsx
│   │   └── layout.tsx
│   ├── (dashboard)/
│   │   ├── layout.tsx              # Sidebar + nav shell (Admin & Client share the shell)
│   │   ├── page.tsx                # Dashboard home
│   │   ├── campaigns/
│   │   │   ├── page.tsx            # Campaign list
│   │   │   └── [id]/page.tsx       # Single campaign + task table
│   │   ├── calendar/page.tsx       # Social content calendar
│   │   ├── hours/page.tsx          # Hours tracking
│   │   ├── analytics/page.tsx      # Analytics (API + manual)
│   │   └── reports/page.tsx        # Reports
│   └── api/
│       ├── auth/[...nextauth]/route.ts
│       ├── campaigns/route.ts
│       ├── tasks/route.ts
│       ├── tasks/[id]/
│       │   ├── files/route.ts
│       │   ├── links/route.ts
│       │   └── comments/route.ts
│       ├── hours/route.ts
│       ├── analytics/
│       │   ├── manual/route.ts
│       │   └── sync/route.ts       # Triggers API fetch from social platforms
│       └── reports/route.ts
├── components/
│   ├── layout/
│   │   ├── Sidebar.tsx
│   │   └── TopBar.tsx
│   ├── dashboard/
│   │   ├── KPICard.tsx
│   │   ├── MonthToggle.tsx
│   │   └── TasksCompletedList.tsx
│   ├── campaigns/
│   │   ├── CampaignCard.tsx
│   │   ├── TaskTable.tsx
│   │   └── TaskDrawer.tsx          # Slide-in panel: Files / Links / Comments tabs
│   ├── calendar/
│   │   ├── CalendarGrid.tsx
│   │   ├── CalendarListView.tsx
│   │   └── MonthSwitcher.tsx
│   ├── analytics/
│   │   ├── PlatformCard.tsx
│   │   ├── ManualEntryForm.tsx     # Manual data entry when API unavailable
│   │   └── ApiSyncButton.tsx
│   └── shared/
│       ├── FileUpload.tsx
│       ├── CommentFeed.tsx
│       ├── ExternalLinkList.tsx
│       └── RoleBadge.tsx
├── lib/
│   ├── auth.ts                     # NextAuth config
│   ├── prisma.ts                   # Prisma client singleton
│   ├── roles.ts                    # RBAC helpers
│   └── social-apis/
│       ├── linkedin.ts
│       ├── youtube.ts
│       ├── tiktok.ts
│       ├── twitter.ts
│       ├── instagram.ts
│       └── facebook.ts
├── prisma/
│   ├── schema.prisma
│   └── seed.ts
├── middleware.ts                   # Auth + role enforcement
└── CLAUDE.md                       # This file
```

---

## 5. Database Schema

Implement the following Prisma schema exactly. Do not rename models or fields without consulting the user.

```prisma
// prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

enum Role {
  ADMIN          // Mind Interactive staff — full access
  AGENCY_STAFF   // Mind Interactive junior staff — limited write
  CLIENT_VIEWER  // The Presidency — read-only
}

enum DataSource {
  API     // Fetched from social platform API
  MANUAL  // Entered manually by agency staff
}

model User {
  id            String    @id @default(cuid())
  name          String
  email         String    @unique
  emailVerified DateTime?
  image         String?
  role          Role      @default(CLIENT_VIEWER)
  avatarColor   String?   // Hex color for comment avatars
  avatarInitials String?  // e.g. "BN" for Bokang N.
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt

  comments      Comment[]
  sessions      Session[]
  accounts      Account[]
}

model Campaign {
  id          String    @id @default(cuid())
  name        String
  color       String    // Hex color, e.g. "#007749"
  month       String    // "2026-03" format (YYYY-MM)
  status      String    @default("active") // active | completed | archived
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt

  tasks       Task[]
}

model Task {
  id          String    @id @default(cuid())
  title       String
  campaign    Campaign  @relation(fields: [campaignId], references: [id])
  campaignId  String
  category    String    // e.g. "Digital Services", "Motion Graphics"
  platform    String?   // e.g. "LinkedIn", "YouTube"
  scheduledDate DateTime?
  completedAt DateTime?
  status      String    @default("pending") // pending | in_progress | completed
  hours       Float     @default(0)
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt

  files       TaskFile[]
  links       TaskLink[]
  comments    Comment[]
}

model TaskFile {
  id          String    @id @default(cuid())
  task        Task      @relation(fields: [taskId], references: [id], onDelete: Cascade)
  taskId      String
  name        String
  url         String    // Vercel Blob or Supabase Storage URL
  size        Int       // bytes
  mimeType    String
  uploadedAt  DateTime  @default(now())
}

model TaskLink {
  id          String    @id @default(cuid())
  task        Task      @relation(fields: [taskId], references: [id], onDelete: Cascade)
  taskId      String
  label       String    // e.g. "Content Calendar – Canva"
  url         String
  type        String    // "canva" | "gdrive" | "youtube" | "other"
  createdAt   DateTime  @default(now())
}

model Comment {
  id          String    @id @default(cuid())
  task        Task      @relation(fields: [taskId], references: [id], onDelete: Cascade)
  taskId      String
  author      User      @relation(fields: [authorId], references: [id])
  authorId    String
  text        String
  createdAt   DateTime  @default(now())
}

model HoursLog {
  id          String    @id @default(cuid())
  month       String    // "2026-03" format
  hoursUsed   Float
  hoursContract Float   @default(120)
  notes       String?
  loggedAt    DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
}

model AnalyticsEntry {
  id          String     @id @default(cuid())
  platform    String     // "linkedin" | "youtube" | "tiktok" | "twitter" | "instagram" | "facebook"
  metric      String     // "followers" | "impressions" | "engagements" | "views" | "clicks"
  value       Float
  month       String     // "2026-03" format
  source      DataSource @default(MANUAL)
  fetchedAt   DateTime   @default(now())
  updatedAt   DateTime   @updatedAt

  @@unique([platform, metric, month]) // One row per platform+metric+month
}

// NextAuth required models
model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?
  user              User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}
```

---

## 6. Authentication & Role-Based Access Control

### NextAuth Configuration (`lib/auth.ts`)

- Use **credentials provider** (email + password) for agency staff
- Use **magic link / email provider** as an option for client viewers
- Store role in JWT token
- Extend the session type to include `role` and `userId`

### Middleware (`middleware.ts`)

Enforce the following access rules on every route:

```
/login               → Public
/(dashboard)/*       → Authenticated users only
/campaigns/*  (POST, PATCH, DELETE) → ADMIN or AGENCY_STAFF only
/hours/*      (POST, PATCH)         → ADMIN only
/analytics/manual/*  (POST, PATCH)  → ADMIN or AGENCY_STAFF only
/analytics/sync/*    (POST)         → ADMIN only
/reports/*    (GET)                 → All authenticated roles
```

### UI Role Enforcement

- If `role === 'CLIENT_VIEWER'`:
  - Hide all "Add", "Edit", "Delete" buttons
  - Hide the comment input box (show comments read-only)
  - Hide file upload area (show download links only)
  - Hide the Hours log edit button
  - Show a "Client View" badge in the top-right of the nav
- If `role === 'ADMIN'` or `'AGENCY_STAFF'`:
  - Show all controls
  - Show "Admin" or "Staff" badge

Implement a `useRole()` hook in `lib/roles.ts` that reads from the session and returns `{ isAdmin, isStaff, isClient }`.

---

## 7. Feature Specifications

### 7.1 Dashboard (`/`)

**Reference:** `DashboardView` component in the wireframe.

- Month toggle buttons (current month and previous month) at the top
- **4 KPI cards** per month:
  1. Hours Used (e.g. 102 / 120 hrs) with a circular progress ring
  2. Tasks Completed This Month (count + clickable list below the card)
  3. Active Campaigns count
  4. Total Deliverables count
- **Tasks Completed This Month** section: a scrollable list of task titles with their campaign color dot, clicking a task opens the Task Drawer
- **Bar chart**: Hours breakdown by category (Recharts `BarChart`)
- **Pie chart**: Campaign distribution (Recharts `PieChart`)
- All data must be fetched from the database, filtered by the selected month

### 7.2 Campaigns (`/campaigns`)

**Reference:** `CampaignsView` and `CampaignCard` components in the wireframe.

- List of campaign cards, each showing: campaign name, color badge, month, task count, status
- Clicking a campaign card expands/navigates to show the **Task Table** for that campaign
- Task Table columns: Task name | Category | Platform | Hours | Files | Links | Comments | Status
- Clicking any **task row** opens the **Task Drawer** (slide-in panel from the right)

**Task Drawer** (`TaskDrawer` component):
- Three tabs: **Files**, **Links**, **Comments**
- **Files tab:**
  - Drag-and-drop upload zone + click-to-browse
  - List of uploaded files with: icon (by type), name, size, upload date
  - Download button on each file
  - Delete button (Admin/Staff only)
  - On upload: POST to `/api/tasks/[id]/files`, store in Vercel Blob, save URL to DB
- **Links tab:**
  - "Add Link" form: label + URL + type (Canva / Google Drive / YouTube / Other)
  - Canva links show the Canva logo icon; Google Drive shows Drive icon; etc.
  - Delete button (Admin/Staff only)
- **Comments tab:**
  - Chronological list of comments with: avatar (initials + color), author name, timestamp, text
  - Text input + "Post" button at the bottom (hidden for CLIENT_VIEWER)
  - On post: POST to `/api/tasks/[id]/comments`, re-fetch comments
  - Comments are visible to all roles (read-only for CLIENT_VIEWER)

**Admin/Staff controls (hidden for CLIENT_VIEWER):**
- "Add Campaign" button → modal form
- "Add Task" button inside campaign → inline form
- Edit/Delete on campaign cards and task rows

### 7.3 Social Calendar (`/calendar`)

**Reference:** `CalendarView` component in the wireframe.

- **Month switcher** (tabs or buttons): shows available months (e.g. "March 2026", "April 2026")
- **View toggle**: Grid (month grid) / List (grouped by day)
- **Grid view:**
  - Standard calendar grid, 7 columns (Sun–Sat)
  - Each day cell shows color-coded event chips for tasks scheduled that day
  - Clicking a chip opens the Task Drawer
  - "Today" date is highlighted
- **List view:**
  - Tasks grouped by day, sorted ascending
  - Each item shows: campaign color dot, task name, campaign name, platform icon, hours
  - Clicking opens Task Drawer
- **Campaign color legend** at the top of the calendar
- Tasks shown on the calendar are those with a `scheduledDate` in that month
- Admin/Staff can drag a task chip to reschedule it (update `scheduledDate` via PATCH)

### 7.4 Hours Tracking (`/hours`)

**Reference:** `HoursView` component in the wireframe.

- Large circular progress gauge: Hours Used vs. 120hr contract
- Monthly hours breakdown table: Category | Hours | % of total
- Cumulative hours line chart (Recharts `LineChart`) across all months
- Admin can edit hours per task inline in the Task Table (accessible from Campaigns view)
- Admin can log a manual hours adjustment via a modal form
- All hours roll up from individual Task.hours values + any manual HoursLog entries

### 7.5 Analytics (`/analytics`)

**Reference:** `AnalyticsView` component in the wireframe.

#### Dual Data Mode (CRITICAL)

Analytics data can come from two sources. The system must support **both simultaneously**:

**API Mode (preferred):**
- Each social platform has an API integration in `lib/social-apis/`
- Admin clicks "Sync Now" → calls `/api/analytics/sync` → fetches latest metrics → saves to `AnalyticsEntry` with `source: API`
- Store access tokens per platform in environment variables (see section 9)
- If an API call fails, show a warning and fall back to the last known value

**Manual Mode (fallback):**
- For each platform, show a "Manual Entry" form with fields for all metrics
- Admin fills in and submits → POST to `/api/analytics/manual` → saves with `source: MANUAL`
- Each `AnalyticsEntry` row has a `source` field indicating whether it's API or manual
- In the UI, show a small badge: `API` (green) or `Manual` (orange) next to each metric

**Platforms and metrics to track:**

| Platform | Metrics |
|----------|---------|
| LinkedIn | Followers, Impressions, Engagements, Clicks |
| YouTube | Subscribers, Views, Watch Time (hrs), Likes |
| TikTok | Followers, Video Views, Likes, Shares |
| Twitter/X | Followers, Impressions, Engagements, Link Clicks |
| Instagram | Followers, Reach, Impressions, Engagements |
| Facebook | Page Likes, Reach, Impressions, Engagements |

**Analytics UI:**
- Platform cards with current follower count and trend arrow (vs. previous month)
- Bar charts per platform showing month-over-month growth
- Engagement rate calculation: (Engagements / Impressions) × 100
- Export to CSV button for each platform's data

### 7.6 Reports (`/reports`)

**Reference:** `ReportsView` component in the wireframe.

- List of generated reports per month
- "Generate Report" button (Admin only) → creates a PDF/XLSX snapshot of:
  - Hours summary
  - Tasks completed
  - Campaign overview
  - Analytics per platform
- Reports are stored as files in Vercel Blob and linked in the DB
- Client Viewer can download reports

---

## 8. API Routes

All API routes must:
1. Verify the user is authenticated (use `auth()` from NextAuth)
2. Check the user's role before any write operation
3. Return consistent JSON: `{ data: ..., error: null }` on success, `{ data: null, error: "message" }` on failure
4. Use Prisma for all DB operations
5. Handle errors with try/catch and return appropriate HTTP status codes

Key routes to implement:

```
GET    /api/campaigns                      → List all campaigns
POST   /api/campaigns                      → Create campaign (ADMIN/STAFF)
GET    /api/campaigns/[id]                 → Single campaign + tasks
PATCH  /api/campaigns/[id]                 → Update campaign (ADMIN/STAFF)
DELETE /api/campaigns/[id]                 → Delete campaign (ADMIN only)

GET    /api/tasks                          → List tasks (with filters: month, campaign, status)
POST   /api/tasks                          → Create task (ADMIN/STAFF)
PATCH  /api/tasks/[id]                     → Update task (ADMIN/STAFF)
DELETE /api/tasks/[id]                     → Delete task (ADMIN only)

POST   /api/tasks/[id]/files               → Upload file (ADMIN/STAFF)
DELETE /api/tasks/[id]/files/[fileId]      → Delete file (ADMIN only)

GET    /api/tasks/[id]/links               → List links
POST   /api/tasks/[id]/links               → Add link (ADMIN/STAFF)
DELETE /api/tasks/[id]/links/[linkId]      → Delete link (ADMIN/STAFF)

GET    /api/tasks/[id]/comments            → List comments
POST   /api/tasks/[id]/comments            → Post comment (ADMIN/STAFF)

GET    /api/hours?month=2026-03            → Hours data for a month
POST   /api/hours                          → Log manual hours adjustment (ADMIN)

GET    /api/analytics?month=2026-03        → All analytics for a month
POST   /api/analytics/manual               → Save manual analytics entry (ADMIN/STAFF)
POST   /api/analytics/sync                 → Trigger API sync for all platforms (ADMIN)

GET    /api/reports                        → List reports
POST   /api/reports/generate               → Generate report PDF (ADMIN)
```

---

## 9. Social Media API Integrations

Implement each platform integration in `lib/social-apis/[platform].ts`. Each module must export:
- `fetchMetrics(month: string): Promise<PlatformMetrics>` — fetches current metrics
- A TypeScript interface `PlatformMetrics` for the return type

**Environment variables required:**

```env
# LinkedIn
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
LINKEDIN_ACCESS_TOKEN=
LINKEDIN_ORG_ID=

# YouTube (Google)
YOUTUBE_API_KEY=
YOUTUBE_CHANNEL_ID=

# TikTok
TIKTOK_CLIENT_KEY=
TIKTOK_CLIENT_SECRET=
TIKTOK_ACCESS_TOKEN=

# Twitter / X
TWITTER_API_KEY=
TWITTER_API_SECRET=
TWITTER_ACCESS_TOKEN=
TWITTER_ACCESS_TOKEN_SECRET=
TWITTER_ACCOUNT_ID=

# Instagram (via Meta Graph API)
INSTAGRAM_ACCESS_TOKEN=
INSTAGRAM_BUSINESS_ACCOUNT_ID=

# Facebook (via Meta Graph API)
FACEBOOK_ACCESS_TOKEN=
FACEBOOK_PAGE_ID=

# App
NEXTAUTH_SECRET=
NEXTAUTH_URL=
DATABASE_URL=
BLOB_READ_WRITE_TOKEN=
```

**Fallback behavior:** If any API key is missing or the API call fails, the sync for that platform should fail silently and return `null`. The UI must detect `null` and show the manual entry form for that platform.

---

## 10. Data Import: Excel / CSV Upload

The user may have historical data in Excel files. Implement an import feature:

- Route: POST `/api/import`
- Accept `.xlsx` or `.csv` files
- Parse using `xlsx` npm package
- Map columns to the appropriate model fields
- Upsert data into the DB (don't create duplicates)
- Return a summary: `{ inserted: N, updated: N, skipped: N, errors: [...] }`

Expected import formats (document these in a README):

**Analytics import (CSV):**
```
month,platform,metric,value
2026-03,linkedin,followers,12400
2026-03,linkedin,impressions,88000
```

**Hours import (CSV):**
```
month,category,hours
2026-03,Digital Services,18
2026-03,Motion Graphics,12
```

---

## 11. Sprint Plan

Build in this order. Complete each sprint before starting the next.

| Sprint | Focus | Deliverable |
|--------|-------|-------------|
| 1 | Setup | Next.js project, Tailwind, Prisma, PostgreSQL, NextAuth, Vercel deploy |
| 2 | Auth + RBAC | Login page, session, role middleware, useRole hook |
| 3 | Database | Run migrations, seed with mock data from wireframe |
| 4 | Layout + Nav | Sidebar, top bar, role badge, responsive shell |
| 5 | Campaigns + Tasks | Campaign list, task table, Task Drawer (Files/Links/Comments) |
| 6 | Dashboard | KPIs, month toggle, charts, tasks completed list |
| 7 | Calendar | Month grid, list view, month switcher, event chips |
| 8 | Hours + Analytics | Hours gauge + charts; Analytics cards + dual data mode (API + manual) |
| 9 | Reports + Import | Report generation, Excel/CSV import, final polish |

---

## 12. Testing Requirements

After each sprint, run tests before marking it complete.

### Unit Tests (Vitest)
- `lib/roles.ts` — test isAdmin, isStaff, isClient helpers for all role values
- `lib/social-apis/*.ts` — mock API responses, test `fetchMetrics` parses correctly, test null returned on failure
- API route handlers — mock Prisma, test that ADMIN routes reject CLIENT_VIEWER requests with 403
- Hours calculations — test rollup from task hours + manual adjustments

### Integration Tests (Playwright)
- Login flow for each role (ADMIN, AGENCY_STAFF, CLIENT_VIEWER)
- CLIENT_VIEWER cannot see "Add Campaign" button
- CLIENT_VIEWER cannot see comment input
- ADMIN can create a campaign, add a task, upload a file, post a comment
- Month toggle on dashboard changes all KPI values
- Calendar grid shows correct tasks on correct dates
- Manual analytics entry saves and appears in the UI
- API sync shows "API" badge on successfully synced metrics

### Run Tests
```bash
pnpm test          # Vitest unit tests
pnpm test:e2e      # Playwright integration tests
pnpm type-check    # TypeScript strict check
pnpm lint          # ESLint
```

All tests must pass before deployment.

---

## 13. Deployment (Vercel)

```bash
# Install Vercel CLI
pnpm add -g vercel

# Link to project
vercel link

# Set environment variables (do this in Vercel dashboard, not CLI for secrets)
# Then deploy
vercel --prod
```

**Checklist before go-live:**
- [ ] All environment variables set in Vercel dashboard
- [ ] Database migrations run against production DB (`pnpm prisma migrate deploy`)
- [ ] Production seed data added (at least one ADMIN user for Mind Interactive)
- [ ] All Playwright tests pass against the staging URL
- [ ] POPIA compliance: privacy notice on login page, data retention policy documented

---

## 14. POPIA Compliance Notes

South African POPIA (Protection of Personal Information Act) requirements:

- Display a privacy notice on the login page
- Users can request deletion of their account and data (`DELETE /api/users/[id]`)
- Do not log or store sensitive personal information beyond what is necessary
- Analytics data must be aggregate only — no individual user tracking
- Document data retention policy: analytics data kept for 24 months, then auto-deleted

---

## 15. Color System

The dashboard uses the following brand colors (match the wireframe exactly):

```js
// South African Presidency palette
const COLORS = {
  presidencyGreen:  "#007749",  // Primary green (nav, buttons, active states)
  presidencyGold:   "#FFB81C",  // Accent gold (highlights)
  presidencyBlack:  "#1A1A1A",  // Text
  presidencyGray:   "#F3F4F6",  // Background
  
  // Campaign colors (used for color-coding campaigns in calendar + charts)
  campaign1: "#007749",  // SAIC 2026
  campaign2: "#003580",  // State of the Nation
  campaign3: "#6B21A8",  // Youth Engagement
  campaign4: "#D97706",  // Economic Reform
  campaign5: "#DC2626",  // Infrastructure
}

// Avatar colors (for comment initials)
const AVATAR_COLORS = {
  BN: "#007749",  // Bokang N.
  SM: "#6B21A8",  // Staff Member
  TN: "#003580",  // Team Name
  JC: "#D97706",  // Junior Creator
  MJ: "#DC2626",  // Another staff
}
```

---

## 16. Getting Started

```bash
# Clone / open the project
cd "Presidency Social Reporting Dash"

# Install dependencies
pnpm install

# Set up environment
cp .env.example .env.local
# Fill in DATABASE_URL and NEXTAUTH_SECRET at minimum

# Run database migrations
pnpm prisma migrate dev

# Seed with mock data (from wireframe)
pnpm prisma db seed

# Start dev server
pnpm dev
```

The dev server runs at `http://localhost:3000`.

Seed creates three test users:
- `admin@mindinteractive.co.za` / `admin123` → ADMIN role
- `staff@mindinteractive.co.za` / `staff123` → AGENCY_STAFF role
- `client@presidency.gov.za` / `client123` → CLIENT_VIEWER role

---

## Important Notes for Claude Code

1. **Read `Dashboard_Wireframe_Mockup.jsx` first** before writing any component. Do not guess at layouts or data structures.
2. **Never store credentials in code.** All keys go in `.env.local` (gitignored).
3. **Manual entry is not a second-class feature.** It must be as polished as the API path. Most months will start with manual data.
4. **Role checks must be both client-side (UI hiding) AND server-side (API 403).** Never rely on UI hiding alone.
5. **The client (The Presidency) will see this dashboard.** Keep the UI clean, professional, and branded. No placeholder text, no "TODO" visible in the UI.
6. **When in doubt, ask.** Use `gh issue create` or leave a `// TODO(ask):` comment rather than making assumptions about business logic.
