# S03: Homepage Cards & Creator Metric Polish

**Goal:** Homepage technique cards show sub-topic tag pills and key moment count. Creator detail pages show technique count by topic category instead of '0 views'.
**Demo:** After this: Homepage technique cards show sub-topic tags and key moment count. Creator pages show technique count by topic instead of '0 views'.

## Tasks
- [x] **T01: Added key_moment_count correlated subquery to technique list API and rendered topic tag pills + moment count on homepage cards** — Two coupled changes: (1) Backend — add `key_moment_count: int = 0` field to `TechniquePageRead` schema and populate it via a correlated COUNT subquery in the `list_techniques` endpoint, matching the existing pattern in `creators.py`. (2) Frontend — add `key_moment_count: number` to the `TechniqueListItem` TypeScript interface, then render `topic_tags` as pill badges and `key_moment_count` as a small inline label in the homepage "Recently Added" cards.

Backend steps:
1. In `backend/schemas.py`, add `key_moment_count: int = 0` to `TechniquePageRead` class
2. In `backend/routers/techniques.py` `list_techniques`, add a correlated subquery: `key_moment_count_sq = select(func.count()).where(KeyMoment.technique_page_id == TechniquePage.id).correlate(TechniquePage).scalar_subquery()` — import KeyMoment from models
3. Add `.add_columns(key_moment_count_sq.label('key_moment_count'))` to the main query
4. Update the result processing loop to set `item.key_moment_count` from the subquery column
5. 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'`
6. Verify: `curl http://ub01:8096/api/v1/techniques?limit=3 | python3 -m json.tool | grep key_moment_count`

Frontend steps:
1. In `frontend/src/api/public-client.ts`, add `key_moment_count: number` to `TechniqueListItem` interface
2. In `frontend/src/pages/Home.tsx`, inside the `recent-card__meta` span:
   - After the category badge, render `topic_tags` as pills: `{t.topic_tags && t.topic_tags.length > 0 && t.topic_tags.map(tag => <span key={tag} className="pill">{tag}</span>)}`
   - After the summary, render key moment count: `{t.key_moment_count > 0 && <span className="recent-card__moments">{t.key_moment_count} moment{t.key_moment_count !== 1 ? 's' : ''}</span>}`
3. In `frontend/src/App.css`, add minimal styles for `.recent-card__moments` (small, muted text)
4. Run `npx tsc --noEmit` and `npm run build` to verify
5. Rebuild web container: `ssh ub01 'cd /vmPool/r/repos/xpltdco/chrysopedia && docker compose build chrysopedia-web-8096 && docker compose up -d chrysopedia-web-8096'`

Note on the subquery approach: The `list_techniques` endpoint currently uses `select(TechniquePage)` and then `.options(selectinload(...))`. Adding `.add_columns()` changes the result shape from scalar `TechniquePage` objects to `Row` tuples of `(TechniquePage, int)`. The loop that processes results needs to unpack accordingly: `for row in result: p = row[0]; count = row[1]`. Check the existing pattern in `routers/creators.py` lines 37-65 for reference.
  - Estimate: 45m
  - Files: backend/schemas.py, backend/routers/techniques.py, frontend/src/api/public-client.ts, frontend/src/pages/Home.tsx, frontend/src/App.css
  - Verify: curl -s http://ub01:8096/api/v1/techniques?limit=3 | python3 -c "import sys,json; items=json.load(sys.stdin)['items']; assert all('key_moment_count' in i for i in items), 'missing key_moment_count'; print('API OK')" && cd frontend && npx tsc --noEmit && npm run build
- [x] **T02: Replaced meaningless '0 views' display with topic-category counts derived from techniques array on creator detail page** — Replace the meaningless '0 views' display on the creator detail page with a compact topic-category breakdown derived from the already-fetched techniques array.

Steps:
1. In `frontend/src/pages/CreatorDetail.tsx`, find the stats span showing `{creator.view_count.toLocaleString()} views` (around line 110)
2. Compute a topic category map from the techniques array: `const topicCounts = techniques.reduce((acc, t) => { const cat = t.topic_category || 'Uncategorized'; acc[cat] = (acc[cat] || 0) + 1; return acc; }, {} as Record<string, number>);`
3. Replace the views span with the category breakdown. Format: pills or dot-separated like "Mixing: 4 · Synthesis: 2". If techniques array is empty, show nothing or a subtle 'No techniques' note.
4. In `frontend/src/App.css`, add minimal styling for the topic breakdown display if needed — the existing `.creator-detail__stats` flex layout should accommodate pills or inline text.
5. Handle edge case: if techniques haven't loaded yet (loading state), don't show stale '0 views' — wait for techniques or show nothing.
6. Run `npx tsc --noEmit` and `npm run build`
7. Rebuild web container on ub01

This task is independent of T01 — all data needed (techniques with topic_category) is already fetched by the existing `fetchTechniques` call.
  - Estimate: 25m
  - Files: frontend/src/pages/CreatorDetail.tsx, frontend/src/App.css
  - Verify: cd frontend && npx tsc --noEmit && npm run build && grep -q 'topic' frontend/src/pages/CreatorDetail.tsx && ! grep -q 'view_count' frontend/src/pages/CreatorDetail.tsx
