# 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 `` 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.