# DocuVault — Project Retrospective

*A living document updated after each milestone. Lessons feed forward into future planning.*

---

## Milestone: v0.2 — UI Overhaul and Optimization

**Shipped:** 2026-06-17
**Phases:** 4 (8–11) | **Plans:** 33 | **Duration:** 10 days (2026-06-07 → 2026-06-17)
**Git:** 198 commits, 236 files changed, +39,557 / −6,288 lines

### What Was Built

- Backend monolith decomposition — three router monoliths (934L, 852L, 825L) split into focused sub-packages with zero URL or behavior changes; shared schemas extracted to `api/schemas.py`
- Frontend client decomposition — `client.js` (635L) → 7 domain modules + barrel re-export; 35+ consumer files unchanged
- Admin panel rearchitecture — standalone `/admin/*` route subtree; `AdminLayout.vue`; `AdminSidebar.vue` with 5 nav links; 5 deep-linkable views; `to.matched.some()` auth guard fix; `GET /api/admin/overview` aggregate endpoint
- UX interaction layer — `EmptyState.vue`, skeleton loaders, keyboard shortcuts (`/`, `U`, `N`, `Escape`), `OsDragOverlay.vue`, Pinia toast store + `ToastContainer.vue`, `BreadcrumbBar.vue`, drag-to-move with Teleport dropdowns, `AppIcon.vue` (66 SVG instances centralized)
- Responsive design + visual polish — hamburger sidebar drawer (below `lg`), adaptive document list columns, 36px touch targets, scrollable modals, `@tailwindcss/forms` baseline, consistent Tailwind-only spacing/typography/focus-visible/hover states
- Bundle optimization — all admin routes lazy-loaded; dead code deleted; bundle −81 kB (−30.6%) from baseline

### What Worked

- **Wave parallelization** — executing independent plans in parallel (e.g., CODE-01/02/03/04 in Phase 8 Wave 2) dramatically reduced wall-clock time; the wave structure in PLAN.md made this trivial to execute
- **Barrel re-export pattern** — decomposing `client.js` with a barrel kept all 35+ consumer files unchanged; zero regressions, zero migration cost
- **Foundation-then-wire order** — building `EmptyState.vue`, `BreadcrumbBar.vue`, `AppIcon.vue`, and the toast store as isolated components in Phase 10 Wave 0 before wiring them in Wave 1 kept each step reviewable and testable
- **Teleport for dropdowns** — solving viewport-edge clipping with `Teleport to="body"` + `getBoundingClientRect()` was the right call; future virtual scrolling is now unblocked
- **UAT gap closure plans** — having dedicated plans (10-13, 11-07) for UAT gaps rather than patching in-flight kept the execution clean and the gap closure auditable

### What Was Inefficient

- **Phase 8 progress table not updated** — the ROADMAP progress table showed "4/8 In Progress" for Phase 8 even after completion, discovered at milestone close. Progress table updates should be part of the plan execution checklist.
- **Admin auth guard bug caught late** — the `to.meta.requiresAdmin` → `to.matched.some()` fix is a security-relevant change that wasn't caught until Phase 9. Nested route guards should be explicitly tested in Phase scaffolding.
- **11-07 mobile toolbar gap** — the mobile compact toolbar fix was a UAT gap rather than planned; the RESP-02 success criterion should have been clearer about the 550px threshold from the start.
- **Multiple SUMMARY.md formats** — some phase summaries used `**One-liner:**` and some used `## One-liner`; extracting them required heuristic grep patterns. A consistent frontmatter schema would help.

### Patterns Established

- **Sub-router NO-prefix rule** — `APIRouter()` in sub-packages must carry no `prefix`; the parent `include_router(sub, prefix=...)` propagates. This is now in CLAUDE.md.
- **FastAPI 0.128+ empty-path restriction** — `@router.get("")` on a sub-router with empty include prefix raises `FastAPIError`; root routes must be registered on the parent aggregator directly.
- **`to.matched.some()` for Vue Router 4 meta inheritance** — Vue Router 4 does not propagate `meta` to children automatically; direct `to.meta` checks are a security regression.
- **AdminLayout as route component, not App.vue branch** — router resolves `AdminLayout` as the `/admin` component; its `<router-view>` renders children. `App.vue` needs no layout branching logic.
- **Lazy-load all non-critical routes** — admin views and other non-initial-path routes should always be lazy-loaded by default; synchronous imports for non-critical routes are a bundle regression.

### Key Lessons

1. **Verify test coverage includes nested route behavior.** The `to.matched.some()` fix was a security-relevant change that required a specific negative test (non-admin navigating directly to `/admin/users`). Add nested-route auth tests to the scaffolding checklist for any phase that touches routing.
2. **Write success criteria with explicit thresholds.** "Mobile responsive" in RESP-02 should have said "toolbar fits without horizontal scrolling at 375px and 550px" rather than leaving it implicit. Explicit viewport thresholds eliminate UAT guesswork.
3. **Archive progress table state in the phase summary.** The ROADMAP progress table is read by the milestone close process; phases should update it as part of the "plan complete" ritual, not leave it for the orchestrator to discover at close.
4. **Barrel re-export is the zero-friction decomposition pattern.** When splitting a large module, start with the barrel and establish the public API first. Consumer files never change; the decomposition is invisible to callers.

### Cost Observations

- Model: Claude Sonnet 4.6 throughout
- No haiku or opus usage in v0.2
- Notable: wave parallelization (3–5 independent plans per wave) was the primary efficiency lever; sequential execution of the same work would have taken ~2–3x longer

---

## Cross-Milestone Trends

### Process Evolution

| Milestone | Duration | Phases | Key Process Change |
|-----------|----------|--------|--------------------|
| v0.1 | ~16 days (2026-05-21→2026-06-06) | 11 (1–7.4) | Feature-first; security gates added mid-stream |
| v0.2 | 10 days (2026-06-07→2026-06-17) | 4 (8–11) | Quality-first; wave parallelization; milestone audit before close |

### Cumulative Quality

| Milestone | Tests at close | Notes |
|-----------|---------------|-------|
| v0.1 | 347 | 1 pre-existing failure (missing module) |
| v0.2 | 277 | Reduction reflects dead test file deletion; coverage per line improved |

### Top Lessons (Verified Across Milestones)

1. **Security gates must run before phase advance, not as a post-close checklist.** Both milestones had late-discovered security issues (v0.1: IDOR stubs, v0.2: auth guard). Bake the security agent into the plan execution ritual.
2. **Explicit success criteria with measurable thresholds eliminate UAT gaps.** Vague criteria ("responsive") always produce UAT gap closure plans. Precise criteria ("at 375px and 550px viewport") do not.
3. **Milestone audits before archival are worth the overhead.** The v0.2 audit caught stale artifacts and the esbuild CVE before the milestone was tagged. Running the audit as a prerequisite rather than a post-mortem saves remediation cost.
