# S05 Research: [A] Sprint 0 Refactoring Tasks

## Summary

This is straightforward structural cleanup work. The M018 site audit (AUDIT-FINDINGS.md, SITE-AUDIT-REPORT.md) identified 8 Phase 2 risks. S05 scopes to the ones that are (a) low-risk, (b) don't require functional changes, and (c) unblock clean Phase 2 development. No unfamiliar technology — all work uses established patterns already in the codebase.

**Requirements:** No active requirements are owned by this slice. It's pure structural refactoring that reduces debt and risk for future requirement work.

## Recommendation

Scope S05 to **three concrete refactoring tasks**, prioritized by impact on future Phase 2 slices:

1. **Split `public-client.ts` (945 lines) into domain modules** — highest impact, unblocks clean imports for every future frontend slice
2. **Add `React.lazy()` code splitting for heavy/admin pages** — prevents bundle bloat as Phase 2 adds pages
3. **Standardize API response consistency** — normalize the two bare-list endpoints (`/topics`, `/videos`) to paginated `{items, total, offset, limit}` pattern

**Explicitly out of scope** (defer to the milestone that needs them):
- Monolithic CSS split — S02 already established CSS modules for new components. Progressive migration happens naturally. A bulk migration is high-risk, low-reward.
- `models.py` split — 656 lines with 15 models is manageable. Split when a milestone adds 5+ new models.
- Breakpoint standardization — affects visual rendering across all pages, needs browser verification. Better done during a dedicated UI milestone.
- CI/CD pipeline — separate milestone scope, not a refactoring task.
- Dead CSS audit — nice-to-have, not blocking anything.

## Implementation Landscape

### Task 1: Split `public-client.ts`

**Current state:** 945 lines, single file, 16 consumers importing from it. Contains:
- Shared infrastructure: `request<T>()` helper, `ApiError` class, `AUTH_TOKEN_KEY`, base URL config (lines 1-308)
- Search functions: `searchApi`, `fetchSuggestions`, `fetchPopularSearches` (lines 309-405)
- Technique functions: `fetchTechniques`, `fetchTechnique`, `fetchRandomTechnique`, versions (lines 336-378)
- Stats: `fetchStats` (line 385)
- Topics: `fetchTopics`, `fetchSubTopicTechniques` (lines 407-433)
- Creators: `fetchCreators`, `fetchCreator` (lines 435-486)
- Reports: `submitReport`, `fetchReports`, `updateReport` (lines 488-530)
- Pipeline admin: 15+ functions (lines 531-840) — biggest domain group
- Admin techniques: `fetchAdminTechniquePages` (lines 844-914)
- Auth: `authRegister`, `authLogin`, `authGetMe`, `authUpdateProfile` (lines 916-945)

**Natural split:**
```
frontend/src/api/
  client.ts          — request(), ApiError, AUTH_TOKEN_KEY, base URL (shared infra)
  search.ts          — search + suggestions + popular
  techniques.ts      — technique CRUD + versions
  creators.ts        — creator browse + detail
  topics.ts          — topics + subtopics
  stats.ts           — stats endpoint
  reports.ts         — content reports
  admin-pipeline.ts  — pipeline admin (largest group)
  admin-techniques.ts — technique admin
  auth.ts            — auth endpoints
  index.ts           — re-export barrel for backward compat
```

**Key constraint:** The `request<T>()` helper and `ApiError` class must live in a shared `client.ts` that all domain modules import from. The auto-inject Authorization header logic stays in `client.ts`.

**Consumers (16 files):** Each currently uses `from "../api/public-client"`. The barrel `index.ts` re-exports everything, so existing imports work unchanged. New code imports from specific modules.

**Risk:** Low. The barrel file preserves backward compatibility. TypeScript compiler catches any missed re-exports.

### Task 2: React.lazy Code Splitting

**Current state:** All 17 page components are eagerly imported at the top of `App.tsx`. The bundle includes every page regardless of which route the user visits.

**Candidates for lazy loading** (admin/creator pages that most users never visit):
- `AdminPipeline` — heaviest admin page, complex state
- `AdminTechniquePages` — table-heavy
- `AdminReports` — rarely visited
- `CreatorDashboard` — behind auth gate
- `CreatorSettings` — behind auth gate
- `About` — static content, rarely visited

**Keep eagerly loaded** (core public pages, fast navigation expected):
- `Home`, `SearchResults`, `TechniquePage`, `CreatorsBrowse`, `CreatorDetail`, `TopicsBrowse`, `SubTopicPage`
- `Login`, `Register` — small, needed for auth flow

**Pattern:**
```tsx
const AdminPipeline = lazy(() => import("./pages/AdminPipeline"));
// In Routes:
<Route path="/admin/pipeline" element={<Suspense fallback={<div>Loading…</div>}><AdminPipeline /></Suspense>} />
```

**Risk:** Low. React.lazy + Suspense is standard React. Only wrapping infrequently-visited routes.

### Task 3: API Response Consistency

**Current state:** Two endpoints return bare lists instead of the paginated `{items, total, offset, limit}` pattern:
- `GET /api/v1/topics` → returns `list[TopicCategory]`
- `GET /api/v1/videos` → returns `list[SourceVideo]`

All other list endpoints use `{items, total, offset, limit}`.

**Backend changes:**
- `backend/routers/topics.py` `list_topics()` — wrap return in `{"items": topics, "total": len(topics)}`
- `backend/routers/videos.py` — add offset/limit params, wrap return

**Frontend changes:**
- `frontend/src/pages/TopicsBrowse.tsx` — update to read `.items` from response
- Any consumer of `/api/v1/videos` (check `rg "fetchVideos\|/videos"`)

**Risk:** Low but requires coordinated backend + frontend change. The `/topics` endpoint has exactly one frontend consumer (TopicsBrowse). The `/videos` endpoint is only used by admin pages.

## Verification Strategy

- **Task 1:** `npm run build` passes with zero errors. All 16 consumer files import successfully. No `public-client` direct imports remain (only barrel `index.ts` re-exports).
- **Task 2:** `npm run build` produces multiple chunks (check `dist/assets/` for split bundles). Lazy-loaded pages still render (manual spot-check or build output verification).
- **Task 3:** `curl` the normalized endpoints, verify `{items, total}` shape. Frontend build passes. Existing backend tests pass (`pytest backend/tests/`).

## Constraints and Gotchas

1. **Barrel re-exports are critical** — without the `index.ts` barrel, all 16 consumer files would need import path updates. The barrel makes this a non-breaking change.
2. **Auth header injection** lives in the shared `request()` helper — it must stay in the shared `client.ts`, not get duplicated into domain modules.
3. **Pipeline admin is actively running on ub01** — the `/videos` response shape change needs the frontend and backend deployed together. Not a problem with Docker Compose (single `docker compose up -d` deploys both).
4. **TypeScript strictness** — the frontend uses TypeScript. Any missed interface re-export will be caught at build time.
5. **The `/topics` response is consumed by `TopicsBrowse.tsx` which destructures the array directly** — need to update to destructure `.items`.
