Files
GearBox/.planning/RETROSPECTIVE.md
Jean-Luc Makiola f564e8cb54
All checks were successful
CI / ci (push) Successful in 1m7s
CI / e2e (push) Has been skipped
CI / deploy (push) Successful in 7s
docs: archive v1.3 and v2.0 milestones with roadmap, requirements, and retrospective
2026-04-08 23:10:50 +02:00

15 KiB
Raw Blame History

Project Retrospective

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

Milestone: v1.0 — MVP

Shipped: 2026-03-15 Phases: 3 | Plans: 10 | Commits: 53

What Was Built

  • Full gear collection with item CRUD, categories, weight/cost totals, and image uploads
  • Planning threads with candidate comparison and thread resolution into collection
  • Named setups (loadouts) composed from collection items with live totals
  • Dashboard home page with summary cards
  • Onboarding wizard for first-time user experience
  • Service-level and route-level integration tests

What Worked

  • Coarse 3-phase structure kept momentum high — no planning overhead between tiny phases
  • TDD approach for backend (service tests first) caught issues early and made frontend integration smooth
  • Service layer with DI (db as first param) made testing trivial with in-memory SQLite
  • Visual verification checkpoints at end of each phase caught UI issues before moving on
  • Bun + Vite + Hono stack had zero friction — everything worked together cleanly

What Was Inefficient

  • Verification plans (XX-03) were mostly rubber-stamp auto-approvals in yolo mode — could skip for v2
  • Some ROADMAP plan checkboxes never got checked off (cosmetic, didn't affect tracking)
  • Performance metrics in STATE.md had stale placeholder data alongside real data

Patterns Established

  • Service functions: (db, params) => result with production db default
  • Route-level integration tests using Hono context variables for db injection
  • Prices in cents everywhere, display conversion in UI only
  • Tab navigation via URL search params for shareability
  • Atomic sync pattern: delete-all + re-insert in transaction

Key Lessons

  1. Coarse granularity (3 phases for an MVP) is the right call for a greenfield app — avoids over-planning
  2. The Vite proxy pattern is required when using TanStack Router plugin — can't do Bun fullstack serving
  3. drizzle-kit needs better-sqlite3 even on Bun — can't use bun:sqlite for migrations
  4. Onboarding state belongs in the database (settings table), not in client-side stores

Cost Observations

  • Model mix: quality profile throughout
  • Sessions: ~10 plan executions across 2 days
  • Notable: Most plans completed in 3-5 minutes, total wall time under 1 hour

Milestone: v1.1 — Fixes & Polish

Shipped: 2026-03-15 Phases: 3 | Plans: 7 | Files changed: 65

What Was Built

  • Fixed threads table and thread creation with categoryId support and modal dialog
  • Overhauled planning tab with educational empty state, pill tabs, and category filter
  • Fixed image display bug (Zod schema missing imageFilename)
  • Redesigned image upload as 4:3 hero preview area with placeholders on all cards
  • Migrated categories from emoji to Lucide icons with 119-icon curated picker
  • Built IconPicker with search, 8 group tabs, and portal popover

What Worked

  • Auto-advance pipeline (discuss → plan → execute) completed both phases end-to-end without manual intervention
  • Wave-based parallel execution in Phase 6 — plans 06-02 and 06-03 ran concurrently with no conflicts
  • Executor auto-fix deviations handled cascading renames gracefully (emoji→icon required touching hooks/routes beyond plan scope)
  • Context discussion upfront captured clear decisions — no ambiguity during execution
  • Verifier caught real issues (Zod schema root cause) and confirmed all must-haves

What Was Inefficient

  • Schema renames cascade through many files (12 in 06-01) — executors had to auto-fix downstream references not in the plan
  • Some ROADMAP.md plan checkboxes remained unchecked despite plans completing (cosmetic tracking drift)
  • Phase 5 executor installed inline SVGs for ImageUpload icons, then Phase 6 added lucide-react anyway — could have coordinated

Patterns Established

  • Portal-based popover pattern: reused from EmojiPicker → IconPicker (click-outside, escape, portal rendering)
  • LucideIcon dynamic lookup component: icons[name] from lucide-react for runtime icon resolution
  • Curated icon data file pattern: static data organized by groups for picker UIs
  • Hero image area: full-width 4:3 preview at top of forms with placeholder/upload/preview states

Key Lessons

  1. Zod validation middleware silently strips unknown fields — always add new schema fields to Zod schemas, not just DB schema
  2. Auto-fix deviations are a feature, not a bug — executors that fix cascading renames save manual replanning
  3. Auto-advance pipeline works well for straightforward phases — interactive discussion ensures decisions are clear before autonomous execution
  4. Parallel Wave 2 execution with no file overlap is safe and efficient

Cost Observations

  • Model mix: opus for execution, sonnet for verification/checking
  • Sessions: 1 continuous auto-advance pipeline for both phases
  • Notable: Full milestone (discuss + plan + execute × 2 phases) completed in a single session

Milestone: v1.2 — Collection Power-Ups

Shipped: 2026-03-16 Phases: 3 | Plans: 6 | Files changed: 66

What Was Built

  • Weight unit conversion (g/oz/lb/kg) with segmented toggle wired across all weight display call sites
  • Candidate status tracking (researching/ordered/arrived) with clickable StatusBadge popup
  • Sticky search/filter toolbar with text search and icon-aware CategoryFilterDropdown
  • Per-setup item classification (base/worn/consumable) with click-to-cycle ClassificationBadge
  • Recharts donut chart with category/classification toggle and hover tooltips
  • Classification-preserving sync that maintains metadata across atomic setup item re-sync

What Worked

  • Coarse 3-phase structure again — 19 requirements compressed into 3 phases with clear dependency ordering
  • TDD red/green commits for schema migrations (status, classification) caught edge cases early
  • Vertical slice pattern (schema → service → tests → API → UI in one plan) kept each deliverable self-contained
  • Click-outside dismiss pattern established in v1.1 was reused cleanly in StatusBadge and CategoryFilterDropdown
  • All 6 plans executed with zero deviations from plan — evidence of mature planning process

What Was Inefficient

  • Some ROADMAP.md plan checkboxes remained unchecked despite summaries existing (persistent cosmetic drift)
  • Recharts v3 Cell component is deprecated for v4 — will need migration eventually
  • Phase 8 bundled search/filter with candidate status (different concerns) — could have been separate phases for cleaner scope

Patterns Established

  • Click-to-cycle badge: for small enums (3 values), direct click cycling is simpler than popup menus
  • Join table metadata preservation: save metadata to Map before atomic sync, restore after re-insert
  • CategoryFilterDropdown: reusable filter dropdown (separate from form-based CategoryPicker)
  • Chart data transformation: group items by key, sum weights, compute percentages, filter zeroes
  • apiPatch helper: PATCH method now available in client API library for partial updates

Key Lessons

  1. Classification belongs on join tables (setupItems), not entity tables (items) — same item has different roles in different contexts
  2. Vertical slice delivery (schema → service → test → API → UI) is the optimal plan structure for feature additions
  3. Search complexity should match data scale — no debounce needed for <1000 items
  4. Recharts composable API (PieChart + Pie + Cell + Tooltip + Label) gives fine-grained chart control with minimal wrapper code

Cost Observations

  • Model mix: quality profile throughout (opus for execution)
  • Sessions: 3 continuous auto-advance sessions (one per phase)
  • Notable: All plans completed with zero deviations, execution faster than v1.0/v1.1

Milestone: v1.3 — Research & Decision Tools

Shipped: 2026-04-08 Phases: 4 | Plans: 6 | Files changed: 52 (+3,106 / -158)

What Was Built

  • Pros/cons text annotation on candidates with visual indicator badges
  • Candidate ranking with sortOrder REAL column, drag-to-reorder via Reorder.Group, and gold/silver/bronze badges
  • Side-by-side comparison table with sticky attribute labels, weight/price delta highlighting, and winner marking
  • Setup impact preview with per-candidate weight/cost deltas, replacement detection, and "no weight data" indicator

What Worked

  • TDD for impact delta computation (Phase 13) — pure function tested in isolation before any UI work
  • Vertical slice pattern continued from v1.2 — each plan delivered end-to-end from schema to UI
  • framer-motion Reorder.Group provided drag-to-reorder with minimal code vs building from scratch
  • candidateViewMode pattern in UIStore cleanly separates grid/list/compare views without route complexity

What Was Inefficient

  • Phase 13 had a 3-week gap between research (2026-03-17) and execution (2026-04-08) — v2.0 work interleaved
  • Comparison table required careful horizontal scroll CSS that took iteration to get right
  • The 11-02 summary extraction failed (garbled output) — plan summaries should always have clean one-liners

Patterns Established

  • candidateViewMode (grid/list/compare): UIStore enum for toggling candidate presentation
  • Impact delta computation as pure function: computeImpactDeltas(candidates, setup) — no side effects
  • SetupImpactSelector: dropdown component for setup selection in thread context
  • ImpactDeltaBadge: reusable delta display component with replace/add/no-data states

Key Lessons

  1. Pure computation functions (no DB, no HTTP) are the fastest to TDD and most reliable to maintain
  2. Drag-to-reorder needs REAL (float) sort_order — integer ranks break on insert between existing items
  3. Comparison tables need both horizontal scroll and fixed first column — mobile-first means testing narrow viewports early
  4. Setup impact preview is most useful when it detects category-match replacement, not just addition

Cost Observations

  • Model mix: quality profile for execution
  • Sessions: Split across v2.0 work — phases 10-12 in one burst, phase 13 after v2.0 infrastructure
  • Notable: Smallest milestone (4 phases, 6 plans) but high user value per plan

Milestone: v2.0 — Platform Foundation

Shipped: 2026-04-08 Phases: 10 | Plans: 32 | Files changed: 210 (+47,370 / -2,244)

What Was Built

  • Full PostgreSQL migration: 13 pgTable definitions, async services, PGlite test infrastructure, Docker Compose
  • External OIDC auth via Logto: three-way middleware (browser sessions, API keys, MCP OAuth)
  • Multi-user data model: userId FK on 6 entity tables, cross-user isolation, composite constraints
  • S3 object storage via MinIO: upload/delete/presigned URL abstraction, image migration script
  • Global item catalog: search, owner count, tags, 18-item bikepacking seed
  • User profiles with public setup sharing and visibility toggle
  • Reference item model with COALESCE merge pattern
  • Full catalog-driven gear flow: FAB, search overlay, add-to-collection/thread modals, manual fallback
  • Item and catalog detail pages replacing all slide-out panels

What Worked

  • Infrastructure phases (14-17) done in one concentrated push — no mixing infra with features
  • COALESCE merge pattern allowed reference items to inherit global data without duplication
  • Three-way auth middleware cleanly separated browser, API key, and MCP OAuth concerns
  • PGlite for tests eliminated external Postgres dependency while keeping real SQL execution
  • Catalog-first add flow with modal confirmation provided good UX without losing flexibility
  • Phase-per-concern kept scope manageable despite 10 phases

What Was Inefficient

  • SQLite to Postgres migration touched every service, route, and test file — massive blast radius
  • E2E tests broke and had to be disabled (backlog 999.1) — OIDC auth incompatible with test auth flow
  • Some phases (14, 18) had many plans (5-6) — could have been split into smaller milestones
  • Auth middleware complexity (OIDC + API keys + OAuth) required multiple fix commits post-merge
  • Phase 18 plan count (5) was at the upper limit — more granular phases would have been cleaner

Patterns Established

  • PGlite test infrastructure: createTestDb() returns async in-memory Postgres
  • Three-way auth: OIDC cookie → API key header → OAuth bearer, resolved to userId
  • COALESCE merge: COALESCE(items.field, globalItems.field) for transparent reference data
  • Global FAB pattern: floating action button with animated mini menu on all authenticated routes
  • Catalog search overlay: full-screen modal with debounced search, tag chip AND-filtering
  • AddToCollectionModal / AddToThreadModal: confirmation step with category picker + personal fields
  • Detail page pattern: /items/:id and /global-items/:id replacing slide-out panels

Key Lessons

  1. Database migration milestones should be their own release — touching every file means high risk of regressions
  2. PGlite is excellent for test infrastructure — real SQL without external dependencies
  3. Auth should be designed for testability from day one — bolting on OIDC broke the E2E test model
  4. COALESCE merge for reference data is elegant but requires careful propagation to all read paths
  5. Catalog-first flow works when the catalog is pre-seeded — empty catalog defeats the purpose
  6. Slide-out panels don't scale — detail pages with edit mode toggle are better for complex data
  7. Three-way auth middleware is maintainable when each method resolves to the same userId shape

Cost Observations

  • Model mix: quality profile throughout
  • Sessions: ~15 execution sessions across 22 days
  • Notable: Largest milestone by far (32 plans, 210 files) — v2.0 was effectively a rewrite of the backend

Process Evolution

Milestone Commits Phases Key Change
v1.0 53 3 Initial build, coarse granularity, TDD backend
v1.1 ~30 3 Auto-advance pipeline, parallel wave execution, auto-fix deviations
v1.2 25 3 Zero-deviation execution, vertical slice pattern, join table metadata
v1.3 ~15 4 Pure function TDD, interleaved with v2.0, drag-to-reorder
v2.0 ~350 10 Full platform rewrite, Postgres + OIDC + multi-user + catalog

Cumulative Quality

Milestone LOC Files Tests
v1.0 5,742 114 Service + route integration
v1.1 6,134 ~130 Service + route integration (updated for icon schema)
v1.2 7,310 ~150 121 tests (service + route + classification)
v1.3 ~8,300 ~160 +impact delta tests
v2.0 23,970 210+ 161+ tests (PGlite, multi-user isolation, MCP)

Top Lessons (Verified Across Milestones)

  1. Coarse phases with TDD backend → smooth frontend integration
  2. Service DI pattern enables fast, reliable testing without mocks
  3. Always update Zod schemas alongside DB schema — middleware silently strips unvalidated fields
  4. Auto-advance pipeline (discuss → plan → execute) works well for clear-scope phases
  5. Vertical slice delivery (schema → service → test → API → UI) is optimal for feature additions
  6. Join table metadata (not entity table) when same entity plays different roles in different contexts
  7. Database migrations are high-risk — isolate them from feature work
  8. Auth testability must be designed upfront — retrofitting breaks E2E tests
  9. COALESCE merge is powerful for reference data but must be propagated to all read paths
  10. Catalog-first flows need pre-seeded data to provide value on day one