# S03: Homepage Stats Scorecard

**Goal:** Homepage shows a stats scorecard with live article count and creator count from the API.
**Demo:** After this: Homepage shows a metric block with article count, creator count in scorecard style matching the dark/cyan design.

## Tasks
- [x] **T01: Added GET /api/v1/stats endpoint returning live technique_count (21) and creator_count (7) from PostgreSQL** — Create a new stats router with a single endpoint that returns technique_count and creator_count. Register it in main.py.

## Steps

1. Create `backend/routers/stats.py` with a `GET /stats` endpoint:
   - Import `APIRouter`, `Depends`, `AsyncSession` from FastAPI/SQLAlchemy
   - Import `get_session` from `database`
   - Import `TechniquePage` and `Creator` from `models`
   - Use `select(func.count()).select_from(TechniquePage)` and same for `Creator`
   - Return a dict `{"technique_count": N, "creator_count": N}`
   - Use `tags=["stats"]` on the router
2. Edit `backend/main.py` to add `from routers import stats` and `app.include_router(stats.router, prefix="/api/v1")` following the existing pattern (after the last `include_router` call around line 88).
3. Rebuild and restart the API container on ub01:
   ```
   ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia && git pull && docker compose build chrysopedia-api && docker compose up -d chrysopedia-api'
   ```
4. Verify: `curl http://ub01:8096/api/v1/stats` returns JSON with both counts > 0.

## Must-Haves

- [ ] Endpoint returns `{"technique_count": int, "creator_count": int}`
- [ ] Both counts are > 0 against the live database
- [ ] Router registered with `/api/v1` prefix

## Verification

- `curl -s http://ub01:8096/api/v1/stats | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['technique_count']>0 and d['creator_count']>0, f'Bad counts: {d}'"` exits 0
- `curl -s -o /dev/null -w '%{http_code}' http://ub01:8096/api/v1/stats` returns 200
  - Estimate: 20m
  - Files: backend/routers/stats.py, backend/main.py
  - Verify: curl -s http://ub01:8096/api/v1/stats | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['technique_count']>0 and d['creator_count']>0"
- [x] **T02: Homepage displays a stats scorecard showing live article and creator counts from /api/v1/stats in cyan-on-dark design** — Wire up the frontend to fetch stats from the new endpoint and render a scorecard section on the homepage matching the dark/cyan design.

## Steps

1. Edit `frontend/src/api/public-client.ts`:
   - Add `StatsResponse` interface: `{ technique_count: number; creator_count: number }`
   - Add `fetchStats()` function: `return request<StatsResponse>(\`${BASE}/stats\`)` — follows the exact pattern of `fetchTopics()` at line 311.
2. Edit `frontend/src/pages/Home.tsx`:
   - Import `fetchStats` and `StatsResponse` (if exported as type) from `public-client`
   - Add state: `const [stats, setStats] = useState<{technique_count: number; creator_count: number} | null>(null)`
   - Add a `useEffect` (with cancellation flag pattern matching existing effects in the file) that calls `fetchStats()` and sets state.
   - Render a `<section className="home-stats">` between the nav-cards section (ends ~line 177) and the random technique button (starts ~line 180). Show two metric items: technique count labeled "Articles" and creator count labeled "Creators". Use `card-stagger` animation class. Only render when stats is non-null.
3. Edit `frontend/src/App.css`:
   - Add `.home-stats` section styles: centered flex row, gap, subtle background using `var(--surface-1)`, border using `var(--border)`.
   - `.home-stats__metric`: large font for the number (use `var(--accent)` cyan color), small label below in `var(--text-secondary)`.
   - Keep it subtle — communicating volume without being boastful per R034.
4. Verify `npm run build` compiles cleanly.
5. Rebuild and restart the web container on ub01:
   ```
   ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia && git pull && docker compose build chrysopedia-web-8096 && docker compose up -d chrysopedia-web-8096'
   ```
6. Verify the homepage at http://ub01:8096 shows the scorecard with real counts.

## Must-Haves

- [ ] `fetchStats()` function in public-client.ts
- [ ] Homepage renders scorecard section with technique count and creator count
- [ ] Scorecard uses existing CSS custom properties (--accent, --surface-1, --border, --text-secondary)
- [ ] `npm run build` succeeds

## Verification

- `cd frontend && npm run build` exits 0
- Homepage at http://ub01:8096 displays scorecard with two metrics showing numbers > 0
  - Estimate: 30m
  - Files: frontend/src/api/public-client.ts, frontend/src/pages/Home.tsx, frontend/src/App.css
  - Verify: cd frontend && npm run build
