Compare commits
4 Commits
570be6fcc1
...
f564e8cb54
| Author | SHA1 | Date | |
|---|---|---|---|
| f564e8cb54 | |||
| cc0bafe754 | |||
| 9054938d88 | |||
| 8b8a8868d1 |
@@ -1,5 +1,47 @@
|
||||
# Milestones
|
||||
|
||||
## v2.0 Platform Foundation (Shipped: 2026-04-08)
|
||||
|
||||
**Phases completed:** 10 phases, 32 plans
|
||||
**Timeline:** 22 days (2026-03-17 to 2026-04-08)
|
||||
**Codebase:** 23,970 LOC TypeScript (17,859 src + 6,111 tests), 210 files changed (+47,370 / -2,244)
|
||||
|
||||
**Key accomplishments:**
|
||||
|
||||
- PostgreSQL migration: 13 pgTable definitions, async services, PGlite test infrastructure, Docker Compose
|
||||
- External OIDC authentication via Logto with three-way auth middleware (browser sessions, API keys, MCP OAuth)
|
||||
- Multi-user data model with userId on all entities, cross-user isolation, and composite constraints
|
||||
- S3 object storage via MinIO replacing local filesystem for all image operations
|
||||
- Global item catalog with search, owner count aggregation, idempotent seeding, and 18-item bikepacking catalog
|
||||
- User profiles with avatar, bio, public setup sharing, and visibility toggle
|
||||
- Reference item model with COALESCE merge pattern for transparent global-to-personal data overlay
|
||||
- Tag system for global item discovery with AND-filtered search
|
||||
- Global FAB with animated mini menu and full-screen catalog search overlay with tag chip filtering
|
||||
- Item and catalog detail pages replacing slide-out panels, with edit mode toggle
|
||||
- Add-from-catalog flow for both collection items and thread candidates
|
||||
- Manual entry fallback with non-functional catalog submission prompt
|
||||
|
||||
**Archive:** `.planning/milestones/v2.0-ROADMAP.md`, `.planning/milestones/v2.0-REQUIREMENTS.md`
|
||||
|
||||
---
|
||||
|
||||
## v1.3 Research & Decision Tools (Shipped: 2026-04-08)
|
||||
|
||||
**Phases completed:** 4 phases, 6 plans
|
||||
**Timeline:** 23 days (2026-03-16 to 2026-04-08)
|
||||
**Codebase:** ~8,300 LOC TypeScript, 52 files changed (+3,106 / -158)
|
||||
|
||||
**Key accomplishments:**
|
||||
|
||||
- Pros/cons text fields on candidates with full-stack support (schema, service, Zod, form, card indicator)
|
||||
- Candidate ranking with sortOrder column, drag-to-reorder UI, and gold/silver/bronze rank badges
|
||||
- Side-by-side comparison table with sticky labels, weight/price delta highlighting, and resolved-thread winner marking
|
||||
- Setup impact preview showing per-candidate weight and cost deltas against a selected setup with replacement detection
|
||||
|
||||
**Archive:** `.planning/milestones/v1.3-ROADMAP.md`, `.planning/milestones/v1.3-REQUIREMENTS.md`
|
||||
|
||||
---
|
||||
|
||||
## v1.2 Collection Power-Ups (Shipped: 2026-03-16)
|
||||
|
||||
**Phases completed:** 3 phases, 6 plans, 11 tasks
|
||||
@@ -7,6 +49,7 @@
|
||||
**Codebase:** 7,310 LOC TypeScript, 66 files changed (+7,243 / -206)
|
||||
|
||||
**Key accomplishments:**
|
||||
|
||||
- Weight unit conversion (g/oz/lb/kg) with segmented toggle wired across all 8 display call sites
|
||||
- Candidate status tracking (researching/ordered/arrived) with clickable StatusBadge popup
|
||||
- Sticky search/filter toolbar with text search and icon-aware CategoryFilterDropdown
|
||||
@@ -25,6 +68,7 @@
|
||||
**Codebase:** 6,134 LOC TypeScript, 65 files changed (+5,049 / -1,109)
|
||||
|
||||
**Key accomplishments:**
|
||||
|
||||
- Fixed threads table and thread creation with categoryId support, modal dialog flow
|
||||
- Overhauled planning tab with educational empty state, pill tabs, and category filter
|
||||
- Fixed image display bug (Zod schemas missing imageFilename — silently stripped by validator)
|
||||
@@ -43,6 +87,7 @@
|
||||
**Codebase:** 5,742 LOC TypeScript, 53 commits, 114 files
|
||||
|
||||
**Key accomplishments:**
|
||||
|
||||
- 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
|
||||
|
||||
@@ -39,22 +39,25 @@ Help people make better gear decisions — discover what others use, compare rea
|
||||
- ✓ Chart hover tooltips with weight and percentage — v1.2
|
||||
- ✓ Candidate status tracking (researching/ordered/arrived) — v1.2
|
||||
- ✓ Planning category filter with Lucide icons — v1.2
|
||||
- ✓ Candidate pros/cons annotation and ranking with drag-to-reorder — v1.3
|
||||
- ✓ Side-by-side candidate comparison table with weight/price deltas — v1.3
|
||||
- ✓ Setup impact preview for candidates (replacement vs addition detection) — v1.3
|
||||
- ✓ PostgreSQL database with async operations, PGlite test infra, Docker Compose — v2.0
|
||||
- ✓ External OIDC auth via Logto with three-way auth middleware — v2.0
|
||||
- ✓ Multi-user data model with userId isolation on all entities — v2.0
|
||||
- ✓ S3 object storage (MinIO) for images replacing local filesystem — v2.0
|
||||
- ✓ Global item catalog with search, owner count, and 18-item seed — v2.0
|
||||
- ✓ User profiles with avatar/bio, public setup sharing — v2.0
|
||||
- ✓ Reference item model with COALESCE merge for global-to-personal overlay — v2.0
|
||||
- ✓ Tag system for catalog discovery with AND-filtered search — v2.0
|
||||
- ✓ Global FAB with catalog search overlay and tag chip filtering — v2.0
|
||||
- ✓ Item and catalog detail pages replacing slide-out panels — v2.0
|
||||
- ✓ Add-from-catalog flow for collection items and thread candidates — v2.0
|
||||
- ✓ Manual entry fallback with catalog submission prompt stub — v2.0
|
||||
|
||||
### Active
|
||||
|
||||
## Current Milestone: v2.0 Platform Foundation
|
||||
|
||||
**Goal:** Transform GearBox from a single-user gear tracker into a multi-user platform where people discover gear, research purchases using crowd-verified data, and share their setups.
|
||||
|
||||
**Target features:**
|
||||
- External auth provider (self-hosted, open-source) for multi-user registration
|
||||
- Migrate from SQLite to Postgres
|
||||
- Multi-user data model (user ownership on all entities, public/private visibility)
|
||||
- Global item database (seeded from manufacturer data, enrichable by users)
|
||||
- Public user profiles with shared setups
|
||||
- Structured item reviews (ratings + predefined fields, not freeform text)
|
||||
- Discovery feed (browse setups, new items, popular gear)
|
||||
- Item detail pages with aggregated specs, owner count, setup appearances
|
||||
No active milestone. v2.0 shipped 2026-04-08. Next milestone TBD.
|
||||
|
||||
### Future
|
||||
|
||||
@@ -78,12 +81,13 @@ Help people make better gear decisions — discover what others use, compare rea
|
||||
|
||||
## Context
|
||||
|
||||
Shipped through v1.4 with 11,333 LOC TypeScript across 90 files. Starting v2.0 platform transformation.
|
||||
Tech stack: React 19, Hono, Drizzle ORM, SQLite (migrating to Postgres), TanStack Router/Query, Tailwind CSS v4, Lucide React, Recharts, framer-motion, all on Bun.
|
||||
Shipped through v2.0 with 23,970 LOC TypeScript across 210+ files. All milestones v1.0-v2.0 complete.
|
||||
Tech stack: React 19, Hono, Drizzle ORM, PostgreSQL, TanStack Router/Query, Tailwind CSS v4, Lucide React, Recharts, framer-motion, all on Bun.
|
||||
Primary use case is bikepacking gear but data model is hobby-agnostic.
|
||||
Existing auth: single-user with cookie sessions + API keys. Will be replaced by external auth provider.
|
||||
Existing features: MCP server (19 tools), E2E tests (Playwright), CSV import/export, item comparison, candidate ranking, setup impact preview.
|
||||
21 test files (service-level, route-level integration, and E2E).
|
||||
Auth: External OIDC via Logto (browser sessions) + API keys (programmatic) + MCP OAuth (Claude).
|
||||
Infrastructure: PostgreSQL, MinIO (S3-compatible image storage), Docker Compose for dev/prod.
|
||||
Features: MCP server (19 tools), global item catalog, user profiles, public setup sharing, catalog-driven gear flow, item/candidate detail pages, candidate ranking/comparison/impact preview.
|
||||
18+ test files (service-level, route-level integration, MCP). E2E tests pending rewrite for OIDC auth (backlog 999.1).
|
||||
|
||||
## Constraints
|
||||
|
||||
@@ -91,7 +95,7 @@ Existing features: MCP server (19 tools), E2E tests (Playwright), CSV import/exp
|
||||
- **Design**: Light, airy, minimalist — white/light backgrounds, lots of whitespace, no visual clutter
|
||||
- **Navigation**: Dashboard-based home page, not sidebar or top-nav tabs
|
||||
- **Auth**: External self-hosted provider — no in-house auth maintenance
|
||||
- **Database**: Postgres for platform deployment
|
||||
- **Database**: PostgreSQL with Drizzle ORM
|
||||
- **UGC**: Structured input only (ratings, predefined fields) — no freeform text until moderation exists
|
||||
- **Scope**: Multi-user platform with public discovery
|
||||
|
||||
@@ -118,12 +122,15 @@ Existing features: MCP server (19 tools), E2E tests (Playwright), CSV import/exp
|
||||
| Hero image area at top of forms | Image-first UX, 4:3 aspect ratio consistent with cards | ✓ Good |
|
||||
| Emoji-to-icon automatic migration | One-time schema rename + data conversion via Drizzle migration | ✓ Good |
|
||||
| ALTER TABLE RENAME COLUMN for SQLite | Simpler than table recreation for column rename | ✓ Good |
|
||||
| Platform pivot at v2.0 | Single-user model proven, now build for multi-user discovery | — Pending |
|
||||
| External auth provider | Avoid in-house auth security burden, self-hosted + open-source | — Pending |
|
||||
| SQLite → Postgres | Multi-user platform needs proper concurrent DB; auth provider needs Postgres anyway | — Pending |
|
||||
| Single-user mode diverges at v2.0 | Platform features irrelevant for solo use; maintain as separate artifact if needed | — Pending |
|
||||
| Structured UGC only (no freeform) | Minimize moderation burden; ratings + predefined fields cover 80% of value | — Pending |
|
||||
| Discovery-first, not social-first | Users come to research gear decisions, not to build social graphs | — Pending |
|
||||
| Platform pivot at v2.0 | Single-user model proven, now build for multi-user discovery | ✓ Good |
|
||||
| External auth provider (Logto) | Avoid in-house auth security burden, self-hosted + open-source | ✓ Good |
|
||||
| SQLite to Postgres | Multi-user platform needs proper concurrent DB; auth provider needs Postgres anyway | ✓ Good |
|
||||
| Single-user mode diverges at v2.0 | Platform features irrelevant for solo use; maintained as separate artifact if needed | ✓ Good |
|
||||
| Structured UGC only (no freeform) | Minimize moderation burden; ratings + predefined fields cover 80% of value | ✓ Good |
|
||||
| Discovery-first, not social-first | Users come to research gear decisions, not to build social graphs | ✓ Good |
|
||||
| COALESCE merge for reference items | Global base + personal overlay without data duplication | ✓ Good |
|
||||
| Catalog-first add flow with manual fallback | Encourages catalog usage while preserving flexibility | ✓ Good |
|
||||
| Detail pages replacing slide-out panels | Better UX for complex data, shareable URLs | ✓ Good |
|
||||
| Weight conversion precision: g=0dp, oz=1dp, lb=2dp, kg=2dp | Matches common usage conventions | ✓ Good |
|
||||
| Unit toggle in TotalsBar (not settings page) | Visible, quick access for frequent switching | ✓ Good |
|
||||
| CategoryFilterDropdown separate from CategoryPicker | Filter vs form concerns are different | ✓ Good |
|
||||
@@ -152,4 +159,4 @@ This document evolves at phase transitions and milestone boundaries.
|
||||
4. Update Context with current state
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-03 after v2.0 milestone start*
|
||||
*Last updated: 2026-04-08 after v2.0 milestone completion*
|
||||
|
||||
@@ -9,43 +9,43 @@ Requirements for this milestone. Each maps to roadmap phases.
|
||||
|
||||
### Database Migration
|
||||
|
||||
- [ ] **DB-01**: Application runs on PostgreSQL instead of SQLite
|
||||
- [ ] **DB-02**: All service functions use async database operations
|
||||
- [ ] **DB-03**: Test infrastructure uses PGlite instead of bun:sqlite in-memory databases
|
||||
- [ ] **DB-04**: Existing SQLite data can be migrated to Postgres via a one-time script
|
||||
- [ ] **DB-05**: Docker Compose provides Postgres for local development
|
||||
- [x] **DB-01**: Application runs on PostgreSQL instead of SQLite
|
||||
- [x] **DB-02**: All service functions use async database operations
|
||||
- [x] **DB-03**: Test infrastructure uses PGlite instead of bun:sqlite in-memory databases
|
||||
- [x] **DB-04**: Existing SQLite data can be migrated to Postgres via a one-time script
|
||||
- [x] **DB-05**: Docker Compose provides Postgres for local development
|
||||
|
||||
### Authentication
|
||||
|
||||
- [ ] **AUTH-01**: User can register an account via external OIDC auth provider
|
||||
- [ ] **AUTH-02**: User can log in via external auth provider and access their data
|
||||
- [ ] **AUTH-03**: API keys remain functional for programmatic access (MCP, scripts)
|
||||
- [ ] **AUTH-04**: Auth provider runs self-hosted alongside the application
|
||||
- [ ] **AUTH-05**: E2E tests authenticate via API keys without depending on the auth provider
|
||||
- [x] **AUTH-01**: User can register an account via external OIDC auth provider
|
||||
- [x] **AUTH-02**: User can log in via external auth provider and access their data
|
||||
- [x] **AUTH-03**: API keys remain functional for programmatic access (MCP, scripts)
|
||||
- [x] **AUTH-04**: Auth provider runs self-hosted alongside the application
|
||||
- [x] **AUTH-05**: E2E tests authenticate via API keys without depending on the auth provider
|
||||
|
||||
### Multi-User Data Model
|
||||
|
||||
- [ ] **MULTI-01**: Every item, category, thread, and setup is owned by a specific user
|
||||
- [ ] **MULTI-02**: User can only see and modify their own data (cross-user isolation)
|
||||
- [ ] **MULTI-03**: Categories use composite unique constraint (userId + name)
|
||||
- [ ] **MULTI-04**: Existing data is assigned to the original user during migration
|
||||
- [ ] **MULTI-05**: MCP tools operate within the authenticated user's scope
|
||||
- [ ] **MULTI-06**: Settings are per-user rather than global
|
||||
- [x] **MULTI-01**: Every item, category, thread, and setup is owned by a specific user
|
||||
- [x] **MULTI-02**: User can only see and modify their own data (cross-user isolation)
|
||||
- [x] **MULTI-03**: Categories use composite unique constraint (userId + name)
|
||||
- [x] **MULTI-04**: Existing data is assigned to the original user during migration
|
||||
- [x] **MULTI-05**: MCP tools operate within the authenticated user's scope
|
||||
- [x] **MULTI-06**: Settings are per-user rather than global
|
||||
|
||||
### Image Storage
|
||||
|
||||
- [ ] **IMG-01**: Images are stored in MinIO (S3-compatible) instead of local filesystem
|
||||
- [ ] **IMG-02**: Existing uploaded images are migrated to MinIO
|
||||
- [ ] **IMG-03**: Image upload and retrieval work through the new storage layer
|
||||
- [ ] **IMG-04**: Docker Compose provides MinIO for local development
|
||||
- [x] **IMG-01**: Images are stored in MinIO (S3-compatible) instead of local filesystem
|
||||
- [x] **IMG-02**: Existing uploaded images are migrated to MinIO
|
||||
- [x] **IMG-03**: Image upload and retrieval work through the new storage layer
|
||||
- [x] **IMG-04**: Docker Compose provides MinIO for local development
|
||||
|
||||
### Global Item Database
|
||||
|
||||
- [ ] **GLOB-01**: A global item catalog exists with brand, model, category, manufacturer specs, and image
|
||||
- [ ] **GLOB-02**: Global catalog is seeded with initial items from manufacturer data
|
||||
- [ ] **GLOB-03**: User can search the global catalog by name or brand
|
||||
- [ ] **GLOB-04**: User can link a personal collection item to a global catalog entry
|
||||
- [ ] **GLOB-05**: Global item pages show basic info and owner count
|
||||
- [x] **GLOB-01**: A global item catalog exists with brand, model, category, manufacturer specs, and image
|
||||
- [x] **GLOB-02**: Global catalog is seeded with initial items from manufacturer data
|
||||
- [x] **GLOB-03**: User can search the global catalog by name or brand
|
||||
- [x] **GLOB-04**: User can link a personal collection item to a global catalog entry
|
||||
- [x] **GLOB-05**: Global item pages show basic info and owner count
|
||||
|
||||
### Catalog-Driven Gear Flow
|
||||
|
||||
@@ -140,37 +140,36 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| DB-01 | Phase 14 | Pending |
|
||||
| DB-02 | Phase 14 | Pending |
|
||||
| DB-03 | Phase 14 | Pending |
|
||||
| DB-04 | Phase 14 | Pending |
|
||||
| DB-05 | Phase 14 | Pending |
|
||||
| AUTH-01 | Phase 15 | Pending |
|
||||
| AUTH-02 | Phase 15 | Pending |
|
||||
| AUTH-03 | Phase 15 | Pending |
|
||||
| AUTH-04 | Phase 15 | Pending |
|
||||
| AUTH-05 | Phase 15 | Pending |
|
||||
| MULTI-01 | Phase 16 | Pending |
|
||||
| MULTI-02 | Phase 16 | Pending |
|
||||
| MULTI-03 | Phase 16 | Pending |
|
||||
| MULTI-04 | Phase 16 | Pending |
|
||||
| MULTI-05 | Phase 16 | Pending |
|
||||
| MULTI-06 | Phase 16 | Pending |
|
||||
| IMG-01 | Phase 17 | Pending |
|
||||
| IMG-02 | Phase 17 | Pending |
|
||||
| IMG-03 | Phase 17 | Pending |
|
||||
| IMG-04 | Phase 17 | Pending |
|
||||
| GLOB-01 | Phase 18 | Pending |
|
||||
| GLOB-02 | Phase 18 | Pending |
|
||||
| GLOB-03 | Phase 18 | Pending |
|
||||
| GLOB-04 | Phase 18 | Pending |
|
||||
| GLOB-05 | Phase 18 | Pending |
|
||||
| DB-01 | Phase 14 | Complete |
|
||||
| DB-02 | Phase 14 | Complete |
|
||||
| DB-03 | Phase 14 | Complete |
|
||||
| DB-04 | Phase 14 | Complete |
|
||||
| DB-05 | Phase 14 | Complete |
|
||||
| AUTH-01 | Phase 15 | Complete |
|
||||
| AUTH-02 | Phase 15 | Complete |
|
||||
| AUTH-03 | Phase 15 | Complete |
|
||||
| AUTH-04 | Phase 15 | Complete |
|
||||
| AUTH-05 | Phase 15 | Complete |
|
||||
| MULTI-01 | Phase 16 | Complete |
|
||||
| MULTI-02 | Phase 16 | Complete |
|
||||
| MULTI-03 | Phase 16 | Complete |
|
||||
| MULTI-04 | Phase 16 | Complete |
|
||||
| MULTI-05 | Phase 16 | Complete |
|
||||
| MULTI-06 | Phase 16 | Complete |
|
||||
| IMG-01 | Phase 17 | Complete |
|
||||
| IMG-02 | Phase 17 | Complete |
|
||||
| IMG-03 | Phase 17 | Complete |
|
||||
| IMG-04 | Phase 17 | Complete |
|
||||
| GLOB-01 | Phase 18 | Complete |
|
||||
| GLOB-02 | Phase 18 | Complete |
|
||||
| GLOB-03 | Phase 18 | Complete |
|
||||
| GLOB-04 | Phase 18 | Complete |
|
||||
| GLOB-05 | Phase 18 | Complete |
|
||||
| PROF-01 | Phase 18 | Complete |
|
||||
| PROF-02 | Phase 18 | Complete |
|
||||
| PROF-03 | Phase 18 | Complete |
|
||||
| PROF-04 | Phase 18 | Complete |
|
||||
| PROF-05 | Phase 18 | Complete |
|
||||
|
||||
| CATFLOW-01 | Phase 20 | Complete |
|
||||
| CATFLOW-02 | Phase 20 | Complete |
|
||||
| CATFLOW-03 | Phase 19, 22 | Complete |
|
||||
@@ -181,9 +180,9 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
| CATFLOW-08 | Phase 23 | Complete |
|
||||
| TAG-01 | Phase 19 | Complete |
|
||||
| TAG-02 | Phase 19 | Complete |
|
||||
| DETAIL-01 | Phase 21 | Pending |
|
||||
| DETAIL-02 | Phase 21 | Pending |
|
||||
| DETAIL-03 | Phase 21 | Pending |
|
||||
| DETAIL-01 | Phase 21 | Complete |
|
||||
| DETAIL-02 | Phase 21 | Complete |
|
||||
| DETAIL-03 | Phase 21 | Complete |
|
||||
| DETAIL-04 | Phase 21 | Complete |
|
||||
| DETAIL-05 | Phase 21 | Complete |
|
||||
|
||||
@@ -194,4 +193,4 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-04-03*
|
||||
*Last updated: 2026-04-03 after roadmap creation*
|
||||
*Last updated: 2026-04-08 — all v2.0 requirements complete*
|
||||
|
||||
@@ -136,6 +136,103 @@
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
---
|
||||
|
||||
## Cross-Milestone Trends
|
||||
|
||||
### Process Evolution
|
||||
@@ -145,6 +242,8 @@
|
||||
| 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
|
||||
|
||||
@@ -153,6 +252,8 @@
|
||||
| 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)
|
||||
|
||||
@@ -162,3 +263,7 @@
|
||||
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
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
- ✅ **v1.0 MVP** — Phases 1-3 (shipped 2026-03-15)
|
||||
- ✅ **v1.1 Fixes & Polish** — Phases 4-6 (shipped 2026-03-15)
|
||||
- ✅ **v1.2 Collection Power-Ups** — Phases 7-9 (shipped 2026-03-16)
|
||||
- 🚧 **v1.3 Research & Decision Tools** — Phases 10-13 (in progress)
|
||||
- 📋 **v2.0 Platform Foundation** <EFBFBD><EFBFBD> Phases 14-23 (planned)
|
||||
- ✅ **v1.3 Research & Decision Tools** — Phases 10-13 (shipped 2026-04-08)
|
||||
- ✅ **v2.0 Platform Foundation** — Phases 14-23 (shipped 2026-04-08)
|
||||
|
||||
## Phases
|
||||
|
||||
@@ -37,215 +37,31 @@
|
||||
|
||||
</details>
|
||||
|
||||
### v1.3 Research & Decision Tools (In Progress)
|
||||
<details>
|
||||
<summary>✅ v1.3 Research & Decision Tools (Phases 10-13) — SHIPPED 2026-04-08</summary>
|
||||
|
||||
**Milestone Goal:** Give users the tools to actually decide between candidates — compare details side-by-side, see how a pick impacts their setup, and rank/annotate their options.
|
||||
- [x] Phase 10: Schema Foundation + Pros/Cons Fields (1/1 plans) — completed 2026-03-16
|
||||
- [x] Phase 11: Candidate Ranking (2/2 plans) — completed 2026-03-16
|
||||
- [x] Phase 12: Comparison View (1/1 plans) — completed 2026-03-17
|
||||
- [x] Phase 13: Setup Impact Preview (2/2 plans) — completed 2026-04-08
|
||||
|
||||
- [x] **Phase 10: Schema Foundation + Pros/Cons Fields** — Migrate schema and deliver pros/cons annotation UI (completed 2026-03-16)
|
||||
- [x] **Phase 11: Candidate Ranking** — Drag-to-reorder priority ranking with rank badges (completed 2026-03-16)
|
||||
- [x] **Phase 12: Comparison View** — Side-by-side tabular comparison with relative deltas (completed 2026-03-17)
|
||||
- [ ] **Phase 13: Setup Impact Preview** — Per-candidate weight and cost delta against a selected setup
|
||||
</details>
|
||||
|
||||
### v2.0 Platform Foundation (Planned)
|
||||
<details>
|
||||
<summary>✅ v2.0 Platform Foundation (Phases 14-23) — SHIPPED 2026-04-08</summary>
|
||||
|
||||
**Milestone Goal:** Transform GearBox from a single-user gear tracker into a multi-user platform where people discover gear, research purchases using crowd-verified data, and share their setups.
|
||||
- [x] Phase 14: PostgreSQL Migration (6/6 plans) — completed 2026-04-05
|
||||
- [x] Phase 15: External Authentication (3/3 plans) — completed 2026-04-05
|
||||
- [x] Phase 16: Multi-User Data Model (4/4 plans) — completed 2026-04-05
|
||||
- [x] Phase 17: Object Storage (3/3 plans) — completed 2026-04-05
|
||||
- [x] Phase 18: Global Items & Public Profiles (5/5 plans) — completed 2026-04-05
|
||||
- [x] Phase 19: Reference Item Model & Tags Schema (3/3 plans) — completed 2026-04-05
|
||||
- [x] Phase 20: FAB & Full-Screen Catalog Search (2/2 plans) — completed 2026-04-06
|
||||
- [x] Phase 21: Item & Catalog Detail Pages (3/3 plans) — completed 2026-04-06
|
||||
- [x] Phase 22: Add-from-Catalog & Thread Integration (2/2 plans) — completed 2026-04-06
|
||||
- [x] Phase 23: Manual Entry Fallback (1/1 plans) — completed 2026-04-06
|
||||
|
||||
- [ ] **Phase 14: PostgreSQL Migration** — Replace SQLite with Postgres, make all operations async, establish new test infrastructure
|
||||
- [ ] **Phase 15: External Authentication** — Integrate self-hosted OIDC auth provider for user registration and login
|
||||
- [ ] **Phase 16: Multi-User Data Model** — Add user ownership to all entities with cross-user data isolation
|
||||
- [ ] **Phase 17: Object Storage** — Move images from local filesystem to MinIO (S3-compatible)
|
||||
- [x] **Phase 18: Global Items & Public Profiles** — Global item catalog, user profiles, and public setup sharing (completed 2026-04-05)
|
||||
- [x] **Phase 19: Reference Item Model & Tags Schema** — Collection items as references to global catalog, tag system for discovery (completed 2026-04-05)
|
||||
- [x] **Phase 20: FAB & Full-Screen Catalog Search** — Global FAB with mini menu, full-screen catalog search with tag filtering (completed 2026-04-06)
|
||||
- [x] **Phase 21: Item & Catalog Detail Pages** — Full detail pages for collection items and catalog entries, replacing slide-out panels (completed 2026-04-06)
|
||||
- [x] **Phase 22: Add-from-Catalog & Thread Integration** — Add catalog items to collection and threads, resolution creates reference items (completed 2026-04-06)
|
||||
- [x] **Phase 23: Manual Entry Fallback** — Manual add for items not in catalog, non-functional submission prompt (completed 2026-04-06)
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 10: Schema Foundation + Pros/Cons Fields
|
||||
**Goal**: Candidates can be annotated with pros and cons, and the database is ready for ranking
|
||||
**Depends on**: Phase 9
|
||||
**Requirements**: RANK-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can open a candidate edit form and see pros and cons text fields
|
||||
2. User can save pros and cons text; the text persists across page refreshes
|
||||
3. CandidateCard shows a visual indicator when a candidate has pros or cons entered
|
||||
4. All existing tests pass after the schema migration (no column drift in test helper)
|
||||
**Plans:** 1/1 plans complete
|
||||
Plans:
|
||||
- [x] 10-01-PLAN.md — Add pros/cons fields through full stack (schema, service, Zod, form, card indicator)
|
||||
|
||||
### Phase 11: Candidate Ranking
|
||||
**Goal**: Users can drag candidates into a priority order that persists and is visually communicated
|
||||
**Depends on**: Phase 10
|
||||
**Requirements**: RANK-01, RANK-02, RANK-04, RANK-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can drag a candidate card to a new position within the thread's candidate list
|
||||
2. The reordered sequence is still intact after navigating away and returning
|
||||
3. The top three candidates display gold, silver, and bronze rank badges respectively
|
||||
4. Drag handles and rank badges are absent on a resolved thread; candidates render in static order
|
||||
**Plans:** 2/2 plans complete
|
||||
Plans:
|
||||
- [ ] 11-01-PLAN.md — Schema migration, reorder service/route, sort_order persistence + tests
|
||||
- [ ] 11-02-PLAN.md — Drag-to-reorder UI, list/grid toggle, rank badges, resolved-thread guard
|
||||
|
||||
### Phase 12: Comparison View
|
||||
**Goal**: Users can view all candidates for a thread side-by-side in a table with relative weight and price deltas
|
||||
**Depends on**: Phase 11
|
||||
**Requirements**: COMP-01, COMP-02, COMP-03, COMP-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can toggle a "Compare" mode on a thread detail page to reveal a tabular view showing weight, price, images, notes, links, status, pros, and cons for every candidate in columns
|
||||
2. The lightest candidate column is highlighted and all other columns show their weight difference relative to it; the cheapest candidate is highlighted similarly for price
|
||||
3. The comparison table scrolls horizontally on a narrow viewport without breaking layout; the attribute label column stays fixed on the left
|
||||
4. A resolved thread shows the comparison table in read-only mode with the winning candidate visually marked
|
||||
**Plans:** 1/1 plans complete
|
||||
Plans:
|
||||
- [ ] 12-01-PLAN.md — ComparisonTable component + compare toggle wiring in thread detail
|
||||
|
||||
### Phase 13: Setup Impact Preview
|
||||
**Goal**: Users can select any setup and see exactly how much weight and cost each candidate would add or subtract
|
||||
**Depends on**: Phase 12
|
||||
**Requirements**: IMPC-01, IMPC-02, IMPC-03, IMPC-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can select a setup from a dropdown in the thread header and each candidate displays a weight delta and cost delta below its name
|
||||
2. When the selected setup contains an item in the same category as the thread, the delta reflects replacing that item (negative delta is possible) rather than pure addition
|
||||
3. When no category match exists in the selected setup, the delta shows a pure addition amount clearly labeled as "add"
|
||||
4. A candidate with no weight recorded shows a "-- (no weight data)" indicator instead of a zero delta
|
||||
**Plans:** 2 plans
|
||||
Plans:
|
||||
- [ ] 13-01-PLAN.md — TDD pure impact delta computation, uiStore state, ThreadWithCandidates type fix, useImpactDeltas hook
|
||||
- [ ] 13-02-PLAN.md — SetupImpactSelector + ImpactDeltaBadge components, wire into thread detail and all candidate views
|
||||
|
||||
### Phase 14: PostgreSQL Migration
|
||||
**Goal**: The application runs entirely on PostgreSQL with async operations, and all existing tests pass against the new database
|
||||
**Depends on**: Phase 13
|
||||
**Requirements**: DB-01, DB-02, DB-03, DB-04, DB-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Application starts and serves all existing features using PostgreSQL as the sole database
|
||||
2. All service-level and route-level tests pass using PGlite in-memory Postgres (no SQLite test infrastructure remains)
|
||||
3. A one-time migration script converts existing SQLite data into the Postgres database without data loss
|
||||
4. Docker Compose brings up Postgres alongside the app with a single command for local development
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 15: External Authentication
|
||||
**Goal**: Users can register and log in via a self-hosted OIDC auth provider, replacing the built-in single-user auth system
|
||||
**Depends on**: Phase 14
|
||||
**Requirements**: AUTH-01, AUTH-02, AUTH-03, AUTH-04, AUTH-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A new user can register an account through the external auth provider and land on their empty GearBox dashboard
|
||||
2. A returning user can log in via the auth provider and see their previously saved data
|
||||
3. API keys continue to work for MCP tools and programmatic access without involving the auth provider
|
||||
4. E2E tests run successfully using API key authentication, with no dependency on the external auth provider being available
|
||||
5. The auth provider runs self-hosted in Docker Compose alongside Postgres and the application
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 16: Multi-User Data Model
|
||||
**Goal**: Every piece of user-created data is owned by a specific user, with complete isolation between users
|
||||
**Depends on**: Phase 15
|
||||
**Requirements**: MULTI-01, MULTI-02, MULTI-03, MULTI-04, MULTI-05, MULTI-06
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User A cannot see or modify items, categories, threads, or setups created by User B
|
||||
2. Two users can each have a category with the same name without conflict
|
||||
3. Existing data from the single-user era is assigned to the original user account after migration
|
||||
4. MCP tools return only data belonging to the authenticated API key's owner
|
||||
5. Each user has independent settings (weight unit, onboarding state) that do not affect other users
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 17: Object Storage
|
||||
**Goal**: Images are stored in and served from MinIO instead of the local filesystem
|
||||
**Depends on**: Phase 16
|
||||
**Requirements**: IMG-01, IMG-02, IMG-03, IMG-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Uploading an image for an item or candidate stores it in MinIO, not on the local filesystem
|
||||
2. All previously uploaded images are accessible after migration to MinIO (no broken images)
|
||||
3. Image URLs work correctly in all views (collection, planning, setups, comparison table)
|
||||
4. Docker Compose includes MinIO for local development with no manual bucket setup required
|
||||
**Plans**: TBD
|
||||
|
||||
### Phase 18: Global Items & Public Profiles
|
||||
**Goal**: Users can discover gear through a global catalog and share their setups publicly via profile pages
|
||||
**Depends on**: Phase 17
|
||||
**Requirements**: GLOB-01, GLOB-02, GLOB-03, GLOB-04, GLOB-05, PROF-01, PROF-02, PROF-03, PROF-04, PROF-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A global item catalog exists with brand, model, category, specs, and images, seeded with initial manufacturer data
|
||||
2. User can search the global catalog by name or brand and link a personal collection item to a global entry
|
||||
3. A global item page shows basic info and how many users own it
|
||||
4. User can edit their profile (display name, avatar, bio) and view their own public profile page
|
||||
5. User can toggle a setup between public and private; public setups are viewable by anyone without logging in and appear on the owner's public profile
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 19: Reference Item Model & Tags Schema
|
||||
**Goal**: Collection items can be references to global catalog entries, and global items support tags for discovery
|
||||
**Depends on**: Phase 18
|
||||
**Requirements**: CATFLOW-03, CATFLOW-04, CATFLOW-05, CATFLOW-06, TAG-01, TAG-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A collection item can reference a global item and displays merged data (global base + personal fields)
|
||||
2. Global items can have multiple tags, searchable via API
|
||||
3. Thread candidates can link to a global item via globalItemId
|
||||
4. Resolving a thread with a catalog-linked candidate creates a reference item with auto-link
|
||||
**Plans:** 3/3 plans complete
|
||||
Plans:
|
||||
- [x] 19-01-PLAN.md — Schema, migration, Zod schemas, types, seed script
|
||||
- [x] 19-02-PLAN.md — Item service COALESCE merge, thread resolution, route cleanup
|
||||
- [x] 19-03-PLAN.md — Global item tag filtering, secondary service merge propagation
|
||||
|
||||
### Phase 20: FAB & Full-Screen Catalog Search
|
||||
**Goal**: Users discover and add gear through a catalog-first search experience with tag filtering
|
||||
**Depends on**: Phase 19
|
||||
**Requirements**: CATFLOW-01, CATFLOW-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. FAB visible on all pages with mini menu showing "Add to Collection" and "Start Thread"
|
||||
2. "New Setup" option appears in FAB on setups page only
|
||||
3. Full-screen catalog search overlay opens from either add option
|
||||
4. Search results display catalog items with name, weight, price, owner count
|
||||
5. Tag chips filter search results
|
||||
**Plans:** 2/2 plans complete
|
||||
Plans:
|
||||
- [x] 20-01-PLAN.md — Tags endpoint, global-items route registration, UIStore extension, useTags hook
|
||||
- [x] 20-02-PLAN.md — FabMenu component, CatalogSearchOverlay component, root layout wiring
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 21: Item & Catalog Detail Pages
|
||||
**Goal**: Collection items and catalog entries have full detail pages, replacing the slide-out panel pattern
|
||||
**Depends on**: Phase 20
|
||||
**Requirements**: DETAIL-01, DETAIL-02, DETAIL-03, DETAIL-04, DETAIL-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Clicking a collection item card navigates to `/items/:id` showing full item details with edit toggle
|
||||
2. Clicking a catalog search result card navigates to `/global-items/:id` showing public catalog details with "Add to Collection" button
|
||||
3. Thread candidates navigate to detail pages instead of opening slide-out panels
|
||||
4. Item slide-out panel and candidate slide-out panel are removed from the root layout
|
||||
5. No visual distinction between reference items and standalone items — same layout, some fields may be empty
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 22: Add-from-Catalog & Thread Integration
|
||||
**Goal**: Users can add catalog items to their collection and to threads directly from search
|
||||
**Depends on**: Phase 21
|
||||
**Requirements**: CATFLOW-03, CATFLOW-05, CATFLOW-06
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can add a catalog item to collection with one confirmation step (category picker + notes)
|
||||
2. User can add catalog items as thread candidates instantly from search
|
||||
3. Resolving a catalog-linked candidate creates a properly linked reference item in collection
|
||||
**Plans:** 2/2 plans complete
|
||||
Plans:
|
||||
- [x] 22-01-PLAN.md -- UIStore + sonner + AddToCollectionModal + overlay/detail page collection wiring
|
||||
- [x] 22-02-PLAN.md -- AddToThreadModal with thread picker + new thread flow + CATFLOW-06 verification
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 23: Manual Entry Fallback
|
||||
**Goal**: Users can still add items not found in the catalog via manual entry
|
||||
**Depends on**: Phase 22
|
||||
**Requirements**: CATFLOW-07, CATFLOW-08
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can fall back to manual entry from catalog search via "Add Manually" link
|
||||
2. Manual entry saves a standalone collection item (no globalItemId)
|
||||
3. "Submit to catalog?" prompt appears after manual save but takes no backend action
|
||||
**Plans:** 1/1 plans complete
|
||||
Plans:
|
||||
- [x] 23-01-PLAN.md -- ManualEntryForm + CatalogSearchOverlay wiring
|
||||
**UI hint**: yes
|
||||
</details>
|
||||
|
||||
## Progress
|
||||
|
||||
@@ -263,17 +79,17 @@ Plans:
|
||||
| 10. Schema Foundation + Pros/Cons Fields | v1.3 | 1/1 | Complete | 2026-03-16 |
|
||||
| 11. Candidate Ranking | v1.3 | 2/2 | Complete | 2026-03-16 |
|
||||
| 12. Comparison View | v1.3 | 1/1 | Complete | 2026-03-17 |
|
||||
| 13. Setup Impact Preview | v1.3 | 0/2 | Not started | - |
|
||||
| 14. PostgreSQL Migration | v2.0 | 0/? | Not started | - |
|
||||
| 15. External Authentication | v2.0 | 0/? | Not started | - |
|
||||
| 16. Multi-User Data Model | v2.0 | 0/? | Not started | - |
|
||||
| 17. Object Storage | v2.0 | 0/? | Not started | - |
|
||||
| 18. Global Items & Public Profiles | v2.0 | 4/5 | Complete | 2026-04-05 |
|
||||
| 19. Reference Item Model & Tags Schema | v2.0 | 3/3 | Complete | 2026-04-05 |
|
||||
| 20. FAB & Full-Screen Catalog Search | v2.0 | 2/2 | Complete | 2026-04-06 |
|
||||
| 21. Item & Catalog Detail Pages | v2.0 | 1/1 | Complete | 2026-04-06 |
|
||||
| 22. Add-from-Catalog & Thread Integration | v2.0 | 2/2 | Complete | 2026-04-06 |
|
||||
| 23. Manual Entry Fallback | v2.0 | 1/1 | Complete | 2026-04-06 |
|
||||
| 13. Setup Impact Preview | v1.3 | 2/2 | Complete | 2026-04-08 |
|
||||
| 14. PostgreSQL Migration | v2.0 | 6/6 | Complete | 2026-04-05 |
|
||||
| 15. External Authentication | v2.0 | 3/3 | Complete | 2026-04-05 |
|
||||
| 16. Multi-User Data Model | v2.0 | 4/4 | Complete | 2026-04-05 |
|
||||
| 17. Object Storage | v2.0 | 3/3 | Complete | 2026-04-05 |
|
||||
| 18. Global Items & Public Profiles | v2.0 | 5/5 | Complete | 2026-04-05 |
|
||||
| 19. Reference Item Model & Tags Schema | v2.0 | 3/3 | Complete | 2026-04-05 |
|
||||
| 20. FAB & Full-Screen Catalog Search | v2.0 | 2/2 | Complete | 2026-04-06 |
|
||||
| 21. Item & Catalog Detail Pages | v2.0 | 3/3 | Complete | 2026-04-06 |
|
||||
| 22. Add-from-Catalog & Thread Integration | v2.0 | 2/2 | Complete | 2026-04-06 |
|
||||
| 23. Manual Entry Fallback | v2.0 | 1/1 | Complete | 2026-04-06 |
|
||||
|
||||
## Backlog
|
||||
|
||||
@@ -284,3 +100,19 @@ Plans:
|
||||
|
||||
Plans:
|
||||
- [ ] TBD (promote with /gsd:review-backlog when ready)
|
||||
|
||||
### Phase 999.2: Revamp Onboarding Flow (BACKLOG)
|
||||
**Goal**: Redesign the onboarding experience to match the current app style and flow. Replace the manual item edit form with the catalog search function. Visual refresh to align with the newer UI patterns.
|
||||
**Requirements**: TBD
|
||||
**Plans**: TBD
|
||||
|
||||
Plans:
|
||||
- [ ] TBD (promote with /gsd:review-backlog when ready)
|
||||
|
||||
### Phase 999.3: Public Access Auth Model (BACKLOG)
|
||||
**Goal**: Rework auth so the app is accessible without logging in. Currently all routes require authentication, but public-facing pages (discovery/browse, shared setups, public profiles) should be viewable by unauthenticated users. Auth only required for write operations and personal data.
|
||||
**Requirements**: TBD
|
||||
**Plans**: TBD
|
||||
|
||||
Plans:
|
||||
- [ ] TBD (promote with /gsd:review-backlog when ready)
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
---
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.3
|
||||
milestone_name: Research & Decision Tools
|
||||
status: verifying
|
||||
stopped_at: Completed 23-01-PLAN.md
|
||||
last_updated: "2026-04-06T16:01:26.505Z"
|
||||
last_activity: 2026-04-06
|
||||
milestone: v2.0
|
||||
milestone_name: Platform Foundation
|
||||
status: complete
|
||||
stopped_at: v1.3 and v2.0 milestones archived
|
||||
last_updated: "2026-04-08"
|
||||
last_activity: 2026-04-08
|
||||
progress:
|
||||
total_phases: 17
|
||||
completed_phases: 16
|
||||
total_plans: 44
|
||||
completed_plans: 42
|
||||
percent: 0
|
||||
total_phases: 23
|
||||
completed_phases: 23
|
||||
total_plans: 55
|
||||
completed_plans: 55
|
||||
percent: 100
|
||||
---
|
||||
|
||||
# Project State
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .planning/PROJECT.md (updated 2026-04-03)
|
||||
See: .planning/PROJECT.md (updated 2026-04-08)
|
||||
|
||||
**Core value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing.
|
||||
**Current focus:** Phase 23 — manual-entry-fallback
|
||||
**Current focus:** Between milestones — v1.3 and v2.0 shipped, next milestone TBD
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 23
|
||||
Plan: Not started
|
||||
Status: Phase complete — ready for verification
|
||||
Last activity: 2026-04-06
|
||||
Phase: N/A (between milestones)
|
||||
Plan: N/A
|
||||
Status: v1.3 and v2.0 complete and archived
|
||||
Last activity: 2026-04-08
|
||||
|
||||
Progress: [----------] 0% (v2.0 milestone)
|
||||
Progress: [##########] 100% (v2.0 milestone)
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
|
||||
- Total plans completed: 0 (v2.0 milestone)
|
||||
- Average duration: --
|
||||
- Total execution time: --
|
||||
- Total plans completed: 55 (all milestones through v2.0)
|
||||
- v1.3: 6 plans across 4 phases (2026-03-16 to 2026-04-08)
|
||||
- v2.0: 32 plans across 10 phases (2026-03-17 to 2026-04-08)
|
||||
|
||||
*Updated after each plan completion*
|
||||
|
||||
@@ -46,43 +46,27 @@ Progress: [----------] 0% (v2.0 milestone)
|
||||
|
||||
### Decisions
|
||||
|
||||
Key decisions made during v2.0 planning:
|
||||
Key decisions resolved during v2.0:
|
||||
|
||||
- Platform pivot: single-user to multi-user with discovery-first approach
|
||||
- External auth provider (self-hosted, open-source) — Logto vs Authentik OPEN decision
|
||||
- SQLite to Postgres migration — required by auth provider and multi-user concurrency
|
||||
- Structured UGC only — ratings and predefined fields, no freeform text until moderation
|
||||
- Separate globalItems table — not a flag on user items table
|
||||
- Single-user SQLite mode diverges at v2.0 boundary
|
||||
- [Phase 18]: Profile data loaded via usePublicProfile(userId) not /auth/me extension
|
||||
- [Phase 20]: Created tags table in schema (was missing, needed for GET /api/tags endpoint)
|
||||
- [Phase 20]: FAB visible on all authenticated routes, not just collection gear tab
|
||||
- [Phase 20]: Add button on catalog search cards is a stub (Phase 21 wires actual flow)
|
||||
- [Phase 21]: Preserved currentThreadId derivation in __root.tsx for CandidateDeleteDialog
|
||||
- [Phase 21]: CollectionView empty state Add button rewired to catalog search overlay
|
||||
- [Phase 21]: ItemForm/CandidateForm decoupled from UIStore with onClose prop pattern
|
||||
- [Phase 23-manual-entry-fallback]: ManualEntryForm uses local state for manualEntryMode, no Zustand UIStore changes
|
||||
- [Phase 23-manual-entry-fallback]: Submit to Catalog? is toast-only stub — no backend action, deferred to future phase
|
||||
- Platform pivot: single-user to multi-user with discovery-first approach — RESOLVED
|
||||
- External auth provider: Logto (self-hosted OIDC) — RESOLVED
|
||||
- SQLite to Postgres migration — COMPLETE
|
||||
- Structured UGC only — ratings and predefined fields, no freeform text until moderation — ACTIVE
|
||||
- Separate globalItems table — not a flag on user items table — RESOLVED
|
||||
- COALESCE merge for reference items (global base + personal overlay) — RESOLVED
|
||||
- Catalog-first add flow with manual fallback — RESOLVED
|
||||
- Detail pages replacing slide-out panels — RESOLVED
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None active.
|
||||
|
||||
### Quick Tasks Completed
|
||||
|
||||
| # | Description | Date | Commit | Directory |
|
||||
|---|-------------|------|--------|-----------|
|
||||
| 260406-j44 | Comprehensive dev seed script for bikepacking gear data | 2026-04-06 | — | [260406-j44-comprehensive-dev-seed-script-for-bikepa](./quick/260406-j44-comprehensive-dev-seed-script-for-bikepa/) |
|
||||
| Phase 21 P03 | 6min | 2 tasks | 10 files |
|
||||
| Phase 23-manual-entry-fallback P01 | 18 | 2 tasks | 2 files |
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
- Auth provider decision (Logto vs Authentik) must be resolved before Phase 15 planning
|
||||
- Phase 14 is a full schema rewrite touching 6 services, 7 routes, 19 MCP tools, all tests
|
||||
None. Both milestones shipped.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-06T15:57:43.957Z
|
||||
Stopped at: Completed 23-01-PLAN.md
|
||||
Last session: 2026-04-08
|
||||
Stopped at: v1.3 and v2.0 milestones archived
|
||||
Resume file: None
|
||||
|
||||
45
.planning/debug/client-w0-undefined-after-login.md
Normal file
45
.planning/debug/client-w0-undefined-after-login.md
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
status: awaiting_human_verify
|
||||
trigger: "Client-side error 'can't access property id, w[0] is undefined' occurs after login"
|
||||
created: 2026-04-08T00:00:00Z
|
||||
updated: 2026-04-08T00:00:00Z
|
||||
---
|
||||
|
||||
## Current Focus
|
||||
|
||||
hypothesis: CONFIRMED — AddToThreadModal.tsx has an unguarded activeThreads[0].id in a useEffect dependency array, which throws when there are no active threads (new user after login)
|
||||
test: Root cause confirmed by code reading
|
||||
expecting: Fix by replacing activeThreads[0].id with activeThreads[0]?.id in the dependency array
|
||||
next_action: Apply fix
|
||||
|
||||
## Symptoms
|
||||
|
||||
expected: After login, app loads normally and shows user's collection
|
||||
actual: Error thrown client-side: "can't access property 'id', w[0] is undefined"
|
||||
errors: "can't access property 'id', w[0] is undefined" — minified variable name, from production/built bundle
|
||||
reproduction: Happens after logging in (OIDC via Logto)
|
||||
started: Unclear when it started, user noticed it now
|
||||
|
||||
## Eliminated
|
||||
|
||||
- hypothesis: Bug is in auth hooks or route guards
|
||||
evidence: useAuth.ts and __root.tsx are clean — auth handles null/undefined safely
|
||||
timestamp: 2026-04-08T00:00:00Z
|
||||
|
||||
- hypothesis: Bug is in categories[0].id access in CreateThreadModal, ManualEntryForm, or AddToCollectionModal
|
||||
evidence: All three guard with `categories && categories.length > 0` before accessing [0].id
|
||||
timestamp: 2026-04-08T00:00:00Z
|
||||
|
||||
## Evidence
|
||||
|
||||
- timestamp: 2026-04-08T00:00:00Z
|
||||
checked: AddToThreadModal.tsx lines 62-68
|
||||
found: useEffect dependency array evaluates `activeThreads[0].id` unconditionally. When activeThreads is empty (new user after login with no threads), this throws TypeError.
|
||||
implication: This is the root cause. The guard `activeThreads.length === 0` inside the effect body does NOT protect the dependency array itself — React evaluates the dep array on every render.
|
||||
|
||||
## Resolution
|
||||
|
||||
root_cause: In AddToThreadModal.tsx, the useEffect dependency array at lines 62-68 directly accesses `activeThreads[0].id` without optional chaining. When a user logs in with no active threads (empty array), React evaluates this expression during render and throws "can't access property 'id', w[0] is undefined".
|
||||
fix: Replace `activeThreads[0].id` with `activeThreads[0]?.id` in the useEffect dependency array
|
||||
verification: Fix applied — changed `activeThreads[0].id` to `activeThreads[0]?.id` in useEffect dependency array. This prevents the TypeError when activeThreads is empty.
|
||||
files_changed: [src/client/components/AddToThreadModal.tsx]
|
||||
70
.planning/debug/oidc-invalid-session.md
Normal file
70
.planning/debug/oidc-invalid-session.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
status: fixing
|
||||
trigger: "GearBox deployed on Coolify throws Invalid session (HTTP 500) from @hono/oidc-auth middleware when accessing GET /login"
|
||||
created: 2026-04-08T00:00:00Z
|
||||
updated: 2026-04-08T00:01:00Z
|
||||
---
|
||||
|
||||
## Current Focus
|
||||
|
||||
hypothesis: CONFIRMED — oidcAuthMiddleware swallows all errors (including OIDC discovery network failures) as "Invalid session". The actual error is most likely Logto OIDC discovery endpoint unreachable from the Docker container.
|
||||
test: deployed OIDC startup check — check Coolify logs after next deploy for "[OIDC]" lines
|
||||
expecting: logs will show either "Discovery endpoint reachable" or "Discovery endpoint unreachable" with the actual network error
|
||||
next_action: await_human_verify — user deploys and checks Coolify logs
|
||||
|
||||
## Symptoms
|
||||
|
||||
expected: User visits /login, gets redirected to Logto for authentication, completes login, and returns with a valid session.
|
||||
actual: GET /login immediately throws HTTP 500 "Invalid session" from @hono/oidc-auth middleware. The error originates at node_modules/@hono/oidc-auth/dist/index.js:330 — the OIDC session validation catches an error, deletes the cookie, and throws.
|
||||
errors: |
|
||||
Error thrown at node_modules/@hono/oidc-auth/dist/index.js:330 in the catch block.
|
||||
The middleware catches ALL errors from OIDC session validation and throws HTTPException 500 "Invalid session".
|
||||
reproduction: Visit the deployed GearBox instance's /login page
|
||||
started: Was an existing issue locally, temporarily fixed (possibly via Logto config/DB changes), but broke again on deploy to Coolify
|
||||
|
||||
## Eliminated
|
||||
|
||||
- hypothesis: Missing/invalid OIDC env vars (OIDC_AUTH_SECRET too short, OIDC_ISSUER missing, etc.)
|
||||
evidence: getOidcAuthEnv() throws with DIFFERENT messages for missing vars (not "Invalid session"). The error at line 330 only runs AFTER getOidcAuthEnv succeeds. .env.coolify-test shows 32-char secret (minimum OK).
|
||||
timestamp: 2026-04-08
|
||||
|
||||
- hypothesis: Stale session cookie from wrong-secret JWT
|
||||
evidence: If verify() fails (wrong secret), the inner try-catch at line 123-127 catches it and returns null — not throw. Only throws at line 129 if cookie decodes OK but rtkexp/ssnexp are undefined. This would require the same secret but different JWT structure.
|
||||
timestamp: 2026-04-08
|
||||
|
||||
- hypothesis: Error is thrown from setOidcAuthEnv before try-catch
|
||||
evidence: getOidcAuthEnv is called at line 293 OUTSIDE the try block. If it threw, the error message would be from setOidcAuthEnv ("Session secret is not provided", etc.), not "Invalid session".
|
||||
timestamp: 2026-04-08
|
||||
|
||||
## Evidence
|
||||
|
||||
- timestamp: 2026-04-08
|
||||
checked: @hono/oidc-auth/dist/index.js lines 292-330 (oidcAuthMiddleware)
|
||||
found: The outer try-catch at line 298-330 wraps ALL of: getAuth(c), and the redirect-building code (generateAuthorizationRequestUrl → getAuthorizationServer → OIDC discovery fetch). Any error from any of these is caught and re-thrown as HTTPException(500, "Invalid session"). The original error is LOST.
|
||||
implication: "Invalid session" is a misleading umbrella for any failure in the login flow.
|
||||
|
||||
- timestamp: 2026-04-08
|
||||
checked: Error stack trace — lines 325-326 are setCookie("continue"...) and c.redirect(url), inside the if(getAuth===null) block
|
||||
found: These lines are context in the error display, NOT where the error occurred. The throw is at line 330 (catch block). The fact that code is within the getAuth===null branch means getAuth returned null (no cookie or expired) and then generateAuthorizationRequestUrl was called — which calls getAuthorizationServer — which does OIDC discovery.
|
||||
implication: The error occurred during OIDC discovery (network call to OIDC_ISSUER/.well-known/openid-configuration).
|
||||
|
||||
- timestamp: 2026-04-08
|
||||
checked: src/server/index.ts app.onError handler
|
||||
found: Custom onError does NOT handle HTTPException specially — it bypasses getResponse() and returns generic JSON. Hono's default handler uses getResponse() for HTTPException. Both log the error, but the logged HTTPException doesn't carry the original network error (the catch in oidcAuthMiddleware doesn't attach original cause).
|
||||
implication: Server logs show "Invalid session" HTTPException but not the original TypeError (network error). This made diagnosis harder.
|
||||
|
||||
- timestamp: 2026-04-08
|
||||
checked: OIDC env vars in .env.coolify-test
|
||||
found: OIDC_ISSUER=https://auth.gearbox-test.jeanlucmakiola.de/oidc, OIDC_AUTH_SECRET=8515017c9c54186230b6d5210b08a94b (32 chars), OIDC_REDIRECT_URI=https://gearbox-test.jeanlucmakiola.de/callback. All look structurally valid.
|
||||
implication: The issue is NOT invalid env var values — it's runtime failure when using them.
|
||||
|
||||
## Resolution
|
||||
|
||||
root_cause: oidcAuthMiddleware swallows all errors as "Invalid session" — the actual error is almost certainly the OIDC discovery fetch failing because Logto (https://auth.gearbox-test.jeanlucmakiola.de) is either not running, not accessible from the Docker container, or the OIDC_ISSUER URL is wrong in Coolify's environment.
|
||||
fix: |
|
||||
1. Added OIDC startup connectivity check in src/server/index.ts that fetches OIDC_ISSUER/.well-known/openid-configuration at startup and logs the real error if it fails.
|
||||
2. Fixed app.onError to properly return HTTPException.getResponse() so the correct status/message is preserved.
|
||||
3. To fully fix: deploy, check Coolify logs for "[OIDC]" lines, and fix whatever the actual cause is (restart Logto, fix Coolify network, correct OIDC_ISSUER URL).
|
||||
verification:
|
||||
files_changed:
|
||||
- src/server/index.ts
|
||||
59
.planning/milestones/v1.3-REQUIREMENTS.md
Normal file
59
.planning/milestones/v1.3-REQUIREMENTS.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Requirements Archive: v1.3 Research & Decision Tools
|
||||
|
||||
**Archived:** 2026-04-08
|
||||
**Status:** SHIPPED
|
||||
|
||||
---
|
||||
|
||||
## v1.3 Requirements
|
||||
|
||||
Requirements for this milestone. Each maps to roadmap phases 10-13.
|
||||
|
||||
### Candidate Ranking
|
||||
|
||||
- [x] **RANK-01**: User can drag a candidate card to a new position within the thread's candidate list
|
||||
- [x] **RANK-02**: The reordered sequence persists after navigating away and returning
|
||||
- [x] **RANK-03**: Database schema supports pros/cons fields and sort ordering for candidates
|
||||
- [x] **RANK-04**: Top three candidates display gold, silver, and bronze rank badges
|
||||
- [x] **RANK-05**: Drag handles and rank badges are absent on resolved threads
|
||||
|
||||
### Comparison
|
||||
|
||||
- [x] **COMP-01**: User can toggle a "Compare" mode to reveal a tabular view of all candidates
|
||||
- [x] **COMP-02**: Lightest candidate is highlighted with weight deltas shown for all others
|
||||
- [x] **COMP-03**: Cheapest candidate is highlighted with price deltas shown for all others
|
||||
- [x] **COMP-04**: Comparison table scrolls horizontally on narrow viewports with fixed label column
|
||||
|
||||
### Setup Impact Preview
|
||||
|
||||
- [x] **IMPC-01**: User can select a setup and see weight/cost deltas on each candidate
|
||||
- [x] **IMPC-02**: Delta reflects replacement when setup has an item in the same category
|
||||
- [x] **IMPC-03**: Pure addition is clearly labeled when no category match exists
|
||||
- [x] **IMPC-04**: Candidates without weight data show a "no weight data" indicator
|
||||
|
||||
## Traceability
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| RANK-01 | Phase 11 | Complete |
|
||||
| RANK-02 | Phase 11 | Complete |
|
||||
| RANK-03 | Phase 10 | Complete |
|
||||
| RANK-04 | Phase 11 | Complete |
|
||||
| RANK-05 | Phase 11 | Complete |
|
||||
| COMP-01 | Phase 12 | Complete |
|
||||
| COMP-02 | Phase 12 | Complete |
|
||||
| COMP-03 | Phase 12 | Complete |
|
||||
| COMP-04 | Phase 12 | Complete |
|
||||
| IMPC-01 | Phase 13 | Complete |
|
||||
| IMPC-02 | Phase 13 | Complete |
|
||||
| IMPC-03 | Phase 13 | Complete |
|
||||
| IMPC-04 | Phase 13 | Complete |
|
||||
|
||||
**Coverage:**
|
||||
- v1.3 requirements: 13 total
|
||||
- Mapped to phases: 13
|
||||
- Unmapped: 0
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-03-16*
|
||||
*Archived: 2026-04-08*
|
||||
62
.planning/milestones/v1.3-ROADMAP.md
Normal file
62
.planning/milestones/v1.3-ROADMAP.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Roadmap Archive: v1.3 Research & Decision Tools
|
||||
|
||||
**Archived:** 2026-04-08
|
||||
**Status:** SHIPPED
|
||||
**Phases:** 10-13 (4 phases, 6 plans)
|
||||
**Timeline:** 2026-03-16 to 2026-04-08
|
||||
|
||||
---
|
||||
|
||||
## Phase 10: Schema Foundation + Pros/Cons Fields
|
||||
**Goal**: Candidates can be annotated with pros and cons, and the database is ready for ranking
|
||||
**Depends on**: Phase 9
|
||||
**Requirements**: RANK-03
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can open a candidate edit form and see pros and cons text fields
|
||||
2. User can save pros and cons text; the text persists across page refreshes
|
||||
3. CandidateCard shows a visual indicator when a candidate has pros or cons entered
|
||||
4. All existing tests pass after the schema migration (no column drift in test helper)
|
||||
**Plans:** 1/1 plans complete
|
||||
Plans:
|
||||
- [x] 10-01-PLAN.md — Add pros/cons fields through full stack (schema, service, Zod, form, card indicator)
|
||||
|
||||
## Phase 11: Candidate Ranking
|
||||
**Goal**: Users can drag candidates into a priority order that persists and is visually communicated
|
||||
**Depends on**: Phase 10
|
||||
**Requirements**: RANK-01, RANK-02, RANK-04, RANK-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can drag a candidate card to a new position within the thread's candidate list
|
||||
2. The reordered sequence is still intact after navigating away and returning
|
||||
3. The top three candidates display gold, silver, and bronze rank badges respectively
|
||||
4. Drag handles and rank badges are absent on a resolved thread; candidates render in static order
|
||||
**Plans:** 2/2 plans complete
|
||||
Plans:
|
||||
- [x] 11-01-PLAN.md — Schema migration, reorder service/route, sort_order persistence + tests
|
||||
- [x] 11-02-PLAN.md — Drag-to-reorder UI, list/grid toggle, rank badges, resolved-thread guard
|
||||
|
||||
## Phase 12: Comparison View
|
||||
**Goal**: Users can view all candidates for a thread side-by-side in a table with relative weight and price deltas
|
||||
**Depends on**: Phase 11
|
||||
**Requirements**: COMP-01, COMP-02, COMP-03, COMP-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can toggle a "Compare" mode on a thread detail page to reveal a tabular view showing weight, price, images, notes, links, status, pros, and cons for every candidate in columns
|
||||
2. The lightest candidate column is highlighted and all other columns show their weight difference relative to it; the cheapest candidate is highlighted similarly for price
|
||||
3. The comparison table scrolls horizontally on a narrow viewport without breaking layout; the attribute label column stays fixed on the left
|
||||
4. A resolved thread shows the comparison table in read-only mode with the winning candidate visually marked
|
||||
**Plans:** 1/1 plans complete
|
||||
Plans:
|
||||
- [x] 12-01-PLAN.md — ComparisonTable component + compare toggle wiring in thread detail
|
||||
|
||||
## Phase 13: Setup Impact Preview
|
||||
**Goal**: Users can select any setup and see exactly how much weight and cost each candidate would add or subtract
|
||||
**Depends on**: Phase 12
|
||||
**Requirements**: IMPC-01, IMPC-02, IMPC-03, IMPC-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can select a setup from a dropdown in the thread header and each candidate displays a weight delta and cost delta below its name
|
||||
2. When the selected setup contains an item in the same category as the thread, the delta reflects replacing that item (negative delta is possible) rather than pure addition
|
||||
3. When no category match exists in the selected setup, the delta shows a pure addition amount clearly labeled as "add"
|
||||
4. A candidate with no weight recorded shows a "-- (no weight data)" indicator instead of a zero delta
|
||||
**Plans:** 2/2 plans complete
|
||||
Plans:
|
||||
- [x] 13-01-PLAN.md — TDD pure impact delta computation, uiStore state, ThreadWithCandidates type fix, useImpactDeltas hook
|
||||
- [x] 13-02-PLAN.md — SetupImpactSelector + ImpactDeltaBadge components, wire into thread detail and all candidate views
|
||||
145
.planning/milestones/v2.0-REQUIREMENTS.md
Normal file
145
.planning/milestones/v2.0-REQUIREMENTS.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Requirements Archive: v2.0 Platform Foundation
|
||||
|
||||
**Archived:** 2026-04-08
|
||||
**Status:** SHIPPED
|
||||
|
||||
---
|
||||
|
||||
# Requirements: GearBox v2.0 Platform Foundation
|
||||
|
||||
**Defined:** 2026-04-03
|
||||
**Core Value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing.
|
||||
|
||||
## v2.0 Requirements
|
||||
|
||||
### Database Migration
|
||||
|
||||
- [x] **DB-01**: Application runs on PostgreSQL instead of SQLite
|
||||
- [x] **DB-02**: All service functions use async database operations
|
||||
- [x] **DB-03**: Test infrastructure uses PGlite instead of bun:sqlite in-memory databases
|
||||
- [x] **DB-04**: Existing SQLite data can be migrated to Postgres via a one-time script
|
||||
- [x] **DB-05**: Docker Compose provides Postgres for local development
|
||||
|
||||
### Authentication
|
||||
|
||||
- [x] **AUTH-01**: User can register an account via external OIDC auth provider
|
||||
- [x] **AUTH-02**: User can log in via external auth provider and access their data
|
||||
- [x] **AUTH-03**: API keys remain functional for programmatic access (MCP, scripts)
|
||||
- [x] **AUTH-04**: Auth provider runs self-hosted alongside the application
|
||||
- [x] **AUTH-05**: E2E tests authenticate via API keys without depending on the auth provider
|
||||
|
||||
### Multi-User Data Model
|
||||
|
||||
- [x] **MULTI-01**: Every item, category, thread, and setup is owned by a specific user
|
||||
- [x] **MULTI-02**: User can only see and modify their own data (cross-user isolation)
|
||||
- [x] **MULTI-03**: Categories use composite unique constraint (userId + name)
|
||||
- [x] **MULTI-04**: Existing data is assigned to the original user during migration
|
||||
- [x] **MULTI-05**: MCP tools operate within the authenticated user's scope
|
||||
- [x] **MULTI-06**: Settings are per-user rather than global
|
||||
|
||||
### Image Storage
|
||||
|
||||
- [x] **IMG-01**: Images are stored in MinIO (S3-compatible) instead of local filesystem
|
||||
- [x] **IMG-02**: Existing uploaded images are migrated to MinIO
|
||||
- [x] **IMG-03**: Image upload and retrieval work through the new storage layer
|
||||
- [x] **IMG-04**: Docker Compose provides MinIO for local development
|
||||
|
||||
### Global Item Database
|
||||
|
||||
- [x] **GLOB-01**: A global item catalog exists with brand, model, category, manufacturer specs, and image
|
||||
- [x] **GLOB-02**: Global catalog is seeded with initial items from manufacturer data
|
||||
- [x] **GLOB-03**: User can search the global catalog by name or brand
|
||||
- [x] **GLOB-04**: User can link a personal collection item to a global catalog entry
|
||||
- [x] **GLOB-05**: Global item pages show basic info and owner count
|
||||
|
||||
### Catalog-Driven Gear Flow
|
||||
|
||||
- [x] **CATFLOW-01**: FAB shows mini menu with "Add to Collection" and "Start Thread" globally, plus "New Setup" on setups page
|
||||
- [x] **CATFLOW-02**: Full-screen catalog search with tag chip filtering
|
||||
- [x] **CATFLOW-03**: User can add a catalog item to collection as a reference item with personal fields
|
||||
- [x] **CATFLOW-04**: Collection items referencing global items display merged data (global base + personal overlay)
|
||||
- [x] **CATFLOW-05**: Thread candidates can be added from catalog with global item link
|
||||
- [x] **CATFLOW-06**: Thread resolution with catalog-linked candidate creates reference item with auto-link
|
||||
- [x] **CATFLOW-07**: Manual entry fallback when item not in catalog
|
||||
- [x] **CATFLOW-08**: Non-functional "Submit to catalog?" prompt shown after manual save
|
||||
|
||||
### Item & Catalog Detail Pages
|
||||
|
||||
- [x] **DETAIL-01**: Clicking a collection item navigates to a full detail page (`/items/:id`)
|
||||
- [x] **DETAIL-02**: Clicking a catalog search result navigates to a public detail page (`/global-items/:id`)
|
||||
- [x] **DETAIL-03**: Item detail page has edit mode toggle for modifying personal fields
|
||||
- [x] **DETAIL-04**: Thread candidates navigate to detail pages instead of opening slide-out panels
|
||||
- [x] **DETAIL-05**: Slide-out panels for items and candidates are removed from the application
|
||||
|
||||
### Tags
|
||||
|
||||
- [x] **TAG-01**: Tags table seeded with curated tag set for outdoor/adventure gear
|
||||
- [x] **TAG-02**: Global items have multiple tags, searchable and filterable via API
|
||||
|
||||
### User Profiles & Sharing
|
||||
|
||||
- [x] **PROF-01**: User has a profile with display name, avatar, and bio
|
||||
- [x] **PROF-02**: User can view their own public profile page
|
||||
- [x] **PROF-03**: User can set a setup as public or private
|
||||
- [x] **PROF-04**: Public setups are viewable by anyone without authentication
|
||||
- [x] **PROF-05**: Public profile page lists the user's public setups
|
||||
|
||||
## Traceability
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| DB-01 | Phase 14 | Complete |
|
||||
| DB-02 | Phase 14 | Complete |
|
||||
| DB-03 | Phase 14 | Complete |
|
||||
| DB-04 | Phase 14 | Complete |
|
||||
| DB-05 | Phase 14 | Complete |
|
||||
| AUTH-01 | Phase 15 | Complete |
|
||||
| AUTH-02 | Phase 15 | Complete |
|
||||
| AUTH-03 | Phase 15 | Complete |
|
||||
| AUTH-04 | Phase 15 | Complete |
|
||||
| AUTH-05 | Phase 15 | Complete |
|
||||
| MULTI-01 | Phase 16 | Complete |
|
||||
| MULTI-02 | Phase 16 | Complete |
|
||||
| MULTI-03 | Phase 16 | Complete |
|
||||
| MULTI-04 | Phase 16 | Complete |
|
||||
| MULTI-05 | Phase 16 | Complete |
|
||||
| MULTI-06 | Phase 16 | Complete |
|
||||
| IMG-01 | Phase 17 | Complete |
|
||||
| IMG-02 | Phase 17 | Complete |
|
||||
| IMG-03 | Phase 17 | Complete |
|
||||
| IMG-04 | Phase 17 | Complete |
|
||||
| GLOB-01 | Phase 18 | Complete |
|
||||
| GLOB-02 | Phase 18 | Complete |
|
||||
| GLOB-03 | Phase 18 | Complete |
|
||||
| GLOB-04 | Phase 18 | Complete |
|
||||
| GLOB-05 | Phase 18 | Complete |
|
||||
| PROF-01 | Phase 18 | Complete |
|
||||
| PROF-02 | Phase 18 | Complete |
|
||||
| PROF-03 | Phase 18 | Complete |
|
||||
| PROF-04 | Phase 18 | Complete |
|
||||
| PROF-05 | Phase 18 | Complete |
|
||||
| CATFLOW-01 | Phase 20 | Complete |
|
||||
| CATFLOW-02 | Phase 20 | Complete |
|
||||
| CATFLOW-03 | Phase 19, 22 | Complete |
|
||||
| CATFLOW-04 | Phase 19 | Complete |
|
||||
| CATFLOW-05 | Phase 19, 22 | Complete |
|
||||
| CATFLOW-06 | Phase 19, 22 | Complete |
|
||||
| CATFLOW-07 | Phase 23 | Complete |
|
||||
| CATFLOW-08 | Phase 23 | Complete |
|
||||
| TAG-01 | Phase 19 | Complete |
|
||||
| TAG-02 | Phase 19 | Complete |
|
||||
| DETAIL-01 | Phase 21 | Complete |
|
||||
| DETAIL-02 | Phase 21 | Complete |
|
||||
| DETAIL-03 | Phase 21 | Complete |
|
||||
| DETAIL-04 | Phase 21 | Complete |
|
||||
| DETAIL-05 | Phase 21 | Complete |
|
||||
|
||||
**Coverage:**
|
||||
- v2.0 requirements: 45 total
|
||||
- Mapped to phases: 45
|
||||
- Complete: 45
|
||||
- Unmapped: 0
|
||||
|
||||
---
|
||||
*Requirements defined: 2026-04-03*
|
||||
*Archived: 2026-04-08*
|
||||
121
.planning/milestones/v2.0-ROADMAP.md
Normal file
121
.planning/milestones/v2.0-ROADMAP.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Roadmap Archive: v2.0 Platform Foundation
|
||||
|
||||
**Archived:** 2026-04-08
|
||||
**Status:** SHIPPED
|
||||
**Phases:** 14-23 (10 phases, 32 plans)
|
||||
**Timeline:** 2026-03-17 to 2026-04-08
|
||||
|
||||
---
|
||||
|
||||
## Phase 14: PostgreSQL Migration
|
||||
**Goal**: The application runs entirely on PostgreSQL with async operations, and all existing tests pass against the new database
|
||||
**Depends on**: Phase 13
|
||||
**Requirements**: DB-01, DB-02, DB-03, DB-04, DB-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Application starts and serves all existing features using PostgreSQL as the sole database
|
||||
2. All service-level and route-level tests pass using PGlite in-memory Postgres (no SQLite test infrastructure remains)
|
||||
3. A one-time migration script converts existing SQLite data into the Postgres database without data loss
|
||||
4. Docker Compose brings up Postgres alongside the app with a single command for local development
|
||||
**Plans:** 6/6 plans complete
|
||||
|
||||
## Phase 15: External Authentication
|
||||
**Goal**: Users can register and log in via a self-hosted OIDC auth provider, replacing the built-in single-user auth system
|
||||
**Depends on**: Phase 14
|
||||
**Requirements**: AUTH-01, AUTH-02, AUTH-03, AUTH-04, AUTH-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A new user can register an account through the external auth provider and land on their empty GearBox dashboard
|
||||
2. A returning user can log in via the auth provider and see their previously saved data
|
||||
3. API keys continue to work for MCP tools and programmatic access without involving the auth provider
|
||||
4. E2E tests run successfully using API key authentication, with no dependency on the external auth provider being available
|
||||
5. The auth provider runs self-hosted in Docker Compose alongside Postgres and the application
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
## Phase 16: Multi-User Data Model
|
||||
**Goal**: Every piece of user-created data is owned by a specific user, with complete isolation between users
|
||||
**Depends on**: Phase 15
|
||||
**Requirements**: MULTI-01, MULTI-02, MULTI-03, MULTI-04, MULTI-05, MULTI-06
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User A cannot see or modify items, categories, threads, or setups created by User B
|
||||
2. Two users can each have a category with the same name without conflict
|
||||
3. Existing data from the single-user era is assigned to the original user account after migration
|
||||
4. MCP tools return only data belonging to the authenticated API key's owner
|
||||
5. Each user has independent settings (weight unit, onboarding state) that do not affect other users
|
||||
**Plans:** 4/4 plans complete
|
||||
|
||||
## Phase 17: Object Storage
|
||||
**Goal**: Images are stored in and served from MinIO instead of the local filesystem
|
||||
**Depends on**: Phase 16
|
||||
**Requirements**: IMG-01, IMG-02, IMG-03, IMG-04
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Uploading an image for an item or candidate stores it in MinIO, not on the local filesystem
|
||||
2. All previously uploaded images are accessible after migration to MinIO (no broken images)
|
||||
3. Image URLs work correctly in all views (collection, planning, setups, comparison table)
|
||||
4. Docker Compose includes MinIO for local development with no manual bucket setup required
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
## Phase 18: Global Items & Public Profiles
|
||||
**Goal**: Users can discover gear through a global catalog and share their setups publicly via profile pages
|
||||
**Depends on**: Phase 17
|
||||
**Requirements**: GLOB-01, GLOB-02, GLOB-03, GLOB-04, GLOB-05, PROF-01, PROF-02, PROF-03, PROF-04, PROF-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A global item catalog exists with brand, model, category, specs, and images, seeded with initial manufacturer data
|
||||
2. User can search the global catalog by name or brand and link a personal collection item to a global entry
|
||||
3. A global item page shows basic info and how many users own it
|
||||
4. User can edit their profile (display name, avatar, bio) and view their own public profile page
|
||||
5. User can toggle a setup between public and private; public setups are viewable by anyone without logging in and appear on the owner's public profile
|
||||
**Plans:** 5/5 plans complete
|
||||
|
||||
## Phase 19: Reference Item Model & Tags Schema
|
||||
**Goal**: Collection items can be references to global catalog entries, and global items support tags for discovery
|
||||
**Depends on**: Phase 18
|
||||
**Requirements**: CATFLOW-03, CATFLOW-04, CATFLOW-05, CATFLOW-06, TAG-01, TAG-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. A collection item can reference a global item and displays merged data (global base + personal fields)
|
||||
2. Global items can have multiple tags, searchable via API
|
||||
3. Thread candidates can link to a global item via globalItemId
|
||||
4. Resolving a thread with a catalog-linked candidate creates a reference item with auto-link
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
## Phase 20: FAB & Full-Screen Catalog Search
|
||||
**Goal**: Users discover and add gear through a catalog-first search experience with tag filtering
|
||||
**Depends on**: Phase 19
|
||||
**Requirements**: CATFLOW-01, CATFLOW-02
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. FAB visible on all pages with mini menu showing "Add to Collection" and "Start Thread"
|
||||
2. "New Setup" option appears in FAB on setups page only
|
||||
3. Full-screen catalog search overlay opens from either add option
|
||||
4. Search results display catalog items with name, weight, price, owner count
|
||||
5. Tag chips filter search results
|
||||
**Plans:** 2/2 plans complete
|
||||
|
||||
## Phase 21: Item & Catalog Detail Pages
|
||||
**Goal**: Collection items and catalog entries have full detail pages, replacing the slide-out panel pattern
|
||||
**Depends on**: Phase 20
|
||||
**Requirements**: DETAIL-01, DETAIL-02, DETAIL-03, DETAIL-04, DETAIL-05
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Clicking a collection item card navigates to `/items/:id` showing full item details with edit toggle
|
||||
2. Clicking a catalog search result card navigates to `/global-items/:id` showing public catalog details with "Add to Collection" button
|
||||
3. Thread candidates navigate to detail pages instead of opening slide-out panels
|
||||
4. Item slide-out panel and candidate slide-out panel are removed from the root layout
|
||||
5. No visual distinction between reference items and standalone items — same layout, some fields may be empty
|
||||
**Plans:** 3/3 plans complete
|
||||
|
||||
## Phase 22: Add-from-Catalog & Thread Integration
|
||||
**Goal**: Users can add catalog items to their collection and to threads directly from search
|
||||
**Depends on**: Phase 21
|
||||
**Requirements**: CATFLOW-03, CATFLOW-05, CATFLOW-06
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can add a catalog item to collection with one confirmation step (category picker + notes)
|
||||
2. User can add catalog items as thread candidates instantly from search
|
||||
3. Resolving a catalog-linked candidate creates a properly linked reference item in collection
|
||||
**Plans:** 2/2 plans complete
|
||||
|
||||
## Phase 23: Manual Entry Fallback
|
||||
**Goal**: Users can still add items not found in the catalog via manual entry
|
||||
**Depends on**: Phase 22
|
||||
**Requirements**: CATFLOW-07, CATFLOW-08
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. User can fall back to manual entry from catalog search via "Add Manually" link
|
||||
2. Manual entry saves a standalone collection item (no globalItemId)
|
||||
3. "Submit to catalog?" prompt appears after manual save but takes no backend action
|
||||
**Plans:** 1/1 plans complete
|
||||
Reference in New Issue
Block a user