---
phase: 03-setups-and-dashboard
plan: 01
type: tdd
wave: 1
depends_on: []
files_modified:
  - src/db/schema.ts
  - src/shared/schemas.ts
  - src/shared/types.ts
  - src/server/services/setup.service.ts
  - src/server/routes/setups.ts
  - src/server/index.ts
  - tests/helpers/db.ts
  - tests/services/setup.service.test.ts
  - tests/routes/setups.test.ts
autonomous: true
requirements:
  - SETP-01
  - SETP-02
  - SETP-03

must_haves:
  truths:
    - "Setup CRUD operations work (create, read, update, delete)"
    - "Items can be added to and removed from a setup via junction table"
    - "Setup totals (weight, cost, item count) are computed correctly via SQL aggregation"
    - "Deleting a setup cascades to setup_items, deleting a collection item cascades from setup_items"
  artifacts:
    - path: "src/db/schema.ts"
      provides: "setups and setupItems table definitions"
      contains: "setupItems"
    - path: "src/shared/schemas.ts"
      provides: "Zod schemas for setup create/update/sync"
      contains: "createSetupSchema"
    - path: "src/shared/types.ts"
      provides: "Setup and SetupWithItems TypeScript types"
      contains: "CreateSetup"
    - path: "src/server/services/setup.service.ts"
      provides: "Setup business logic with DB injection"
      exports: ["getAllSetups", "getSetupWithItems", "createSetup", "updateSetup", "deleteSetup", "syncSetupItems", "removeSetupItem"]
    - path: "src/server/routes/setups.ts"
      provides: "Hono API routes for setups"
      contains: "setupRoutes"
    - path: "tests/services/setup.service.test.ts"
      provides: "Unit tests for setup service"
      min_lines: 50
    - path: "tests/routes/setups.test.ts"
      provides: "Integration tests for setup API routes"
      min_lines: 30
  key_links:
    - from: "src/server/routes/setups.ts"
      to: "src/server/services/setup.service.ts"
      via: "service function calls"
      pattern: "setup\\.service"
    - from: "src/server/index.ts"
      to: "src/server/routes/setups.ts"
      via: "route mounting"
      pattern: "setupRoutes"
    - from: "src/server/services/setup.service.ts"
      to: "src/db/schema.ts"
      via: "drizzle schema imports"
      pattern: "import.*schema"
---

<objective>
Build the complete setup backend: database schema (setups + setup_items junction table), shared Zod schemas/types, service layer with CRUD + item sync + totals aggregation, and Hono API routes. All with TDD.

Purpose: Provides the data layer and API that the frontend (Plan 02) will consume. The many-to-many junction table is the only new DB pattern in this project.
Output: Working API at /api/setups with full test coverage.
</objective>

<execution_context>
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-setups-and-dashboard/03-RESEARCH.md

@src/db/schema.ts
@src/shared/schemas.ts
@src/shared/types.ts
@src/server/index.ts
@tests/helpers/db.ts

<interfaces>
<!-- Existing patterns to follow exactly -->

From src/server/services/thread.service.ts (pattern reference):
```typescript
export function getAllThreads(db: Db = prodDb, includeResolved = false) { ... }
export function getThread(db: Db = prodDb, id: number) { ... }
export function createThread(db: Db = prodDb, data: CreateThread) { ... }
export function deleteThread(db: Db = prodDb, id: number) { ... }
```

From src/server/routes/threads.ts (pattern reference):
```typescript
const threadRoutes = new Hono<{ Variables: { db: Db } }>();
threadRoutes.get("/", (c) => { ... });
threadRoutes.post("/", zValidator("json", createThreadSchema), (c) => { ... });
```

From tests/helpers/db.ts:
```typescript
export function createTestDb() { ... } // Returns in-memory Drizzle instance
```
</interfaces>
</context>

<feature>
  <name>Setup Backend with Junction Table</name>
  <files>
    src/db/schema.ts, src/shared/schemas.ts, src/shared/types.ts,
    src/server/services/setup.service.ts, src/server/routes/setups.ts,
    src/server/index.ts, tests/helpers/db.ts,
    tests/services/setup.service.test.ts, tests/routes/setups.test.ts
  </files>
  <behavior>
    Service layer (setup.service.ts):
    - getAllSetups: returns setups with itemCount, totalWeight (grams), totalCost (cents) via SQL subqueries
    - getSetupWithItems: returns single setup with full item details (joined with categories), null if not found
    - createSetup: creates setup with name, returns created setup
    - updateSetup: updates setup name, returns updated setup, null if not found
    - deleteSetup: deletes setup (cascade deletes setup_items), returns boolean
    - syncSetupItems: delete-all + re-insert in transaction, accepts setupId + itemIds array
    - removeSetupItem: removes single item from setup by setupId + itemId

    API routes (setups.ts):
    - GET /api/setups -> list all setups with aggregated totals
    - GET /api/setups/:id -> single setup with items
    - POST /api/setups -> create setup (validates name via createSetupSchema)
    - PUT /api/setups/:id -> update setup name
    - DELETE /api/setups/:id -> delete setup
    - PUT /api/setups/:id/items -> sync setup items (validates itemIds via syncSetupItemsSchema)
    - DELETE /api/setups/:id/items/:itemId -> remove single item from setup

    Edge cases:
    - Syncing with empty itemIds array clears all items from setup
    - Deleting a collection item cascades removal from all setups
    - getAllSetups returns 0 for weight/cost when setup has no items (COALESCE)
  </behavior>
  <implementation>
    1. Add setups and setupItems tables to src/db/schema.ts (with cascade FKs)
    2. Add Zod schemas (createSetupSchema, updateSetupSchema, syncSetupItemsSchema) to src/shared/schemas.ts
    3. Add types (CreateSetup, UpdateSetup, SyncSetupItems, Setup, SetupItem) to src/shared/types.ts
    4. Add setups and setup_items CREATE TABLE to tests/helpers/db.ts
    5. Implement setup.service.ts following thread.service.ts pattern (db as first param with prod default)
    6. Implement setups.ts routes following threads.ts pattern (Hono with zValidator)
    7. Mount setupRoutes in src/server/index.ts
    8. Use raw SQL in Drizzle sql`` for correlated subqueries in getAllSetups (per Phase 2 decision about table.column refs)
  </implementation>
</feature>

<verification>
```bash
bun test tests/services/setup.service.test.ts && bun test tests/routes/setups.test.ts && bun test
```
All setup service and route tests pass. Full test suite remains green.
</verification>

<success_criteria>
- Setup CRUD API responds correctly at all 7 endpoints
- Junction table correctly links items to setups (many-to-many)
- Totals aggregation returns correct weight/cost/count via SQL
- Cascade delete works both directions (setup deletion, item deletion)
- All existing tests still pass
</success_criteria>

<output>
After completion, create `.planning/phases/03-setups-and-dashboard/03-01-SUMMARY.md`
</output>
