# Implementation Slices Each slice is a self-contained unit of work. Implement sequentially — each slice builds on the previous. Every slice follows TDD: write tests first, then implement until tests pass. **Reference:** See [PLAN.md](PLAN.md) for full architecture context, color system, layout details, and project structure. **Prompt files:** Each slice has a corresponding prompt in `prompts/` that can be handed to an agent for autonomous execution. --- ## Slice 0: Project Scaffold ✅ **Goal:** Set up the project skeleton so all subsequent slices have a working dev environment. **Deliverables:** - `pyproject.toml` — Python 3.12+, managed with `uv`. Deps: `fastapi`, `uvicorn[standard]`, `pydantic`, `pydantic-settings`, `python-multipart`. Dev deps (via `[dependency-groups]`): `pytest`, `httpx`, `ruff`, `mypy`. Ruff + mypy config sections included. - `backend/app/__init__.py` (empty) - `backend/app/config.py` — `Settings` class via `pydantic-settings` with fields: `admin_token: str`, `data_dir: str = "./data"`, `max_upload_bytes: int = 100_000_000`, `allowed_upload_types: str = "pdf,png,jpg,jpeg,gif,mp4,webm,mp3,wav,ogg,webp"`. Env prefix `HANDIN_`. - `backend/tests/__init__.py` (empty) - `backend/tests/conftest.py` — fixtures: `tmp_data_dir` (creates temp dir with `assets/` subdir), `settings` (overrides `data_dir` and `admin_token`), `db` (initializes SQLite in temp dir), `client` (FastAPI `TestClient`). - `frontend/package.json` — deps: `vue`, `marked`, `vuedraggable`. Dev deps: `vite`, `@vitejs/plugin-vue`, `typescript`, `vue-tsc`, `tailwindcss`, `@tailwindcss/vite`, `@tailwindcss/typography`. Pin exact versions. - `frontend/tsconfig.json`, `frontend/vite.config.ts` (with `@tailwindcss/vite` plugin). - `frontend/src/main.ts`, `frontend/src/App.vue` (minimal), `frontend/src/style.css` (Tailwind directives). - `frontend/index.html` - `.gitignore` — Python, Node, data dir, IDE files. **Verify:** `uv run pytest backend/tests/ -v` runs (0 tests collected, no errors). `cd frontend && npm install && npm run build` succeeds. --- ## Slice 1: Database + Models ✅ **Prompt:** `prompts/slice-1-database-models.md` **Goal:** SQLite persistence layer with schema initialization and Pydantic models. **Tests first (`backend/tests/test_database.py`):** - Test: `init_db` creates tables (`site`, `segments`) in a fresh DB. - Test: calling `init_db` twice is idempotent. - Test: WAL mode is enabled after init. - Test: `get_connection` returns a connection with `busy_timeout` set. **Implement:** - `backend/app/database.py` — `init_db(db_path)` creates schema with `CREATE TABLE IF NOT EXISTS`. Sets `PRAGMA journal_mode=WAL` and `PRAGMA busy_timeout=5000`. `get_connection(db_path)` returns a `sqlite3.Connection` with row factory. - `backend/app/models.py` — `SegmentType(StrEnum)`, `Segment(BaseModel)`, `SegmentCreateRequest`, `SegmentUpdateRequest`, `ReorderRequest`, `SegmentResponse`, `SiteResponse`, `SiteUpdateRequest`. **Verify:** `uv run pytest backend/tests/test_database.py -v` — all pass. `uv run mypy --strict backend/app/models.py backend/app/database.py` — clean. --- ## Slice 2: Segment & Site Service Layer ✅ **Prompt:** `prompts/slice-2-segment-service.md` **Goal:** Business logic + persistence for segments and site metadata. **Tests first (`backend/tests/test_services.py`):** - 12 segment service tests (create, auto-increment sort_order, list empty/ordered, get found/not found, update title/not found, delete found/not found, reorder valid/invalid) - 3 site service tests (default title, update + get, overwrite) **Implement:** - `backend/app/services/segment_service.py` — `create_segment`, `list_segments`, `get_segment`, `update_segment`, `delete_segment`, `reorder_segments`, `_row_to_segment`. - `backend/app/services/site_service.py` — `get_site_title`, `update_site_title`. **Verify:** 15 service tests pass. Zero mypy/ruff errors. --- ## Slice 3: Auth + API Routes + Concurrency **Prompt:** `prompts/slice-3-api-routes.md` **Goal:** Complete the backend — auth dependency, all API route handlers, concurrent write safety. **Covers (from original plan):** Auth (PLAN slice 2), Segment CRUD routes (3), Reorder route (4), Site routes (6), Concurrency tests (7). **Tests first:** - `backend/tests/test_routes.py` — ~19 HTTP-level tests for segments, site, and auth (CRUD, reorder, unauthorized access, not-found cases) - `backend/tests/test_concurrent.py` — 2 concurrency tests (parallel creates, concurrent create + reorder) **Implement:** - `backend/app/auth.py` — `require_admin` dependency. Checks `?token=` query param first, falls back to `Authorization: Bearer` header. - `backend/app/routes/auth.py` — `GET /api/auth/verify` endpoint. - `backend/app/routes/segments.py` — CRUD + reorder at `/api/segments`. Public: GET list, GET by id. Admin: POST, PATCH, DELETE, PUT reorder. - `backend/app/routes/site.py` — GET + PUT at `/api/site`. Public: GET. Admin: PUT. - `backend/app/main.py` — register routers, wire lifespan with `init_db`. **Verify:** All backend tests pass (~40 total). Zero mypy/ruff errors across entire backend. --- ## Slice 4: Asset Service + Docker **Prompt:** `prompts/slice-4-assets-docker.md` **Goal:** File upload/serve/delete and containerized deployment. **Covers (from original plan):** Asset Upload + Serve (5), Docker (13). **Tests first (`backend/tests/test_assets.py`):** - 8 tests: upload valid file, file exists on disk, disallowed type → 415, too large → 413, no auth → 401, delete file, delete not found → 404, serve via StaticFiles. **Implement:** - `backend/app/services/asset_service.py` — `save_asset`, `delete_asset`. - `backend/app/routes/assets.py` — POST upload, DELETE by filename. - Mount `StaticFiles` at `/api/assets` in `main.py`. - `Dockerfile` — multi-stage build (Node → Python). - `docker-compose.yml` — single service, volume mount, env vars. **Verify:** All backend tests pass. `docker compose up --build` serves at localhost:8000. --- ## Slice 5: Frontend Shell + Renderers **Prompt:** `prompts/slice-5-frontend-shell.md` **Goal:** Read-only frontend — app shell, sidebar nav, mobile layout, all segment renderers. **Covers (from original plan):** Frontend Shell + Tailwind Theme (8), Segment Renderers (9). **Deliverables:** - `style.css` — Tailwind v4 with `@theme` block for primary palette. - `types/segment.ts` — TypeScript types matching backend models. - Layout components: `AppShell.vue`, `SidebarNav.vue`, `MobileHeader.vue`. - `composables/useSegments.ts` — fetch segments + site title. - `views/HomePage.vue` — main page rendering. - Segment components: `SegmentRenderer.vue`, `SegmentList.vue`, plus renderers for markdown, PDF, video, audio, iframe, gallery. **Verify:** `npm run build` succeeds. Dev server renders sidebar + segments correctly on desktop and mobile. --- ## Slice 6: Admin UI ✅ **Prompt:** `prompts/slice-6-admin-ui.md` **Goal:** Full admin experience — token entry, inline editing, asset upload, drag-and-drop reorder. **Covers (from original plan):** Admin Token + Toolbar (10), Segment Editor + CRUD (11), Asset Upload + Drag-and-Drop Reorder (12). **Deliverables:** - `composables/useAdmin.ts` — token management via module-level reactive state, auth headers, verify/login/logout, sessionStorage persistence. - `composables/useAssetUpload.ts` — file upload via FormData + native fetch. - `components/admin/TokenPrompt.vue` — subtle lock icon in title bar → inline token input. - `components/admin/AdminToolbar.vue` — thin editing bar below tabs with "Editing" badge + "Add Segment" + "Logout". - `components/admin/SegmentEditor.vue` — inline editor below each segment card, type-aware content editing, custom styled delete confirmation modal. - `components/admin/AssetUploader.vue` — drag-and-drop file upload zone with click-to-browse. - `components/admin/AddSegmentModal.vue` — modal dialog with button-group type selector for creating new segments. - `types/vuedraggable.d.ts` — type declaration for vuedraggable 4.x. - Drag-and-drop reorder via `vuedraggable` in `SegmentList.vue` with grip-dot handles. - Modified `AppShell.vue` — TokenPrompt in header, AdminToolbar below tabs (when authenticated). - Modified `SegmentList.vue` — pencil edit icons, inline editors, draggable reorder (admin), plain rendering (read-only). - Modified `HomePage.vue` — wires all admin mutations (create/PATCH/DELETE/reorder) with auth headers + refresh(). - **New segment type: `link`** — nav-only external links. Renders as `` in SidebarNav/MobileHeader, excluded from content area. Backend `SegmentType` enum and frontend type updated. **Verify:** `npm run build` passes with zero errors. Full admin flow works end-to-end. No admin UI visible without token. --- ## Slice 7: Polish + Final Validation **Prompt:** `prompts/slice-7-polish.md` **Goal:** End-to-end sweep, edge cases, visual polish. **Tasks:** - Run full backend test suite: `uv run pytest backend/tests/ -v`. - Run `uv run ruff check backend/` + `uv run mypy --strict backend/app/`. - Run `npm run lint` + `npm run type-check` in frontend. - Test mobile layout on narrow viewport (sidebar collapses, touch-friendly targets). - Test all segment types render correctly in read-only mode. - Test admin flow end-to-end: enter token, add each segment type, upload assets, reorder, delete, logout. - Test concurrent edits: two browser tabs editing simultaneously. - Verify no admin UI leaks in read-only mode.