feat(04-04): implement item CRUD endpoints + fractional rank (LIST-02)

- Add rank.ts: rankForAppend/rankBetween wrapping fractional-indexing (D-13)
- Extend listsRouter: POST /:id/items (fractional rank at active-bottom),
  GET /:id/items (rank ASC, access-gated)
- Add listItemsRouter (mounted /api/list-items): PATCH /:itemId per-field LWW
  (exactly-one-field zod refine D-08/T-04-07), DELETE /:itemId delete-wins (D-09)
- Uncheck recomputes rank to active-bottom in same write (Open Question 2)
- All item handlers: access-gate via checkListAccess (T-04-05)
- Plan 06 SSE seam comments at each mutation handler
- All 48 tests green; typecheck passes
This commit is contained in:
Lucas Berger
2026-06-09 12:55:32 -04:00
parent b1dc9b8048
commit 5e3151416c
3 changed files with 341 additions and 2 deletions
+2 -1
View File
@@ -7,7 +7,7 @@ import { healthRouter } from './routes/health.js'
import { meRouter } from './routes/me.js'
import { eventsRouter } from './routes/events.js'
import { sseRouter } from './routes/sse.js'
import { listsRouter } from './routes/lists.js'
import { listsRouter, listItemsRouter } from './routes/lists.js'
import { oidcAuthMiddleware, processOAuthCallback } from './auth/middleware.js'
import { devAuthBypass } from './auth/devBypass.js'
import { startBrokerPoller } from './broker/poller.js'
@@ -63,6 +63,7 @@ app.route('/api/me', meRouter)
app.route('/api/events', eventsRouter)
app.route('/api/sse', sseRouter)
app.route('/api/lists', listsRouter)
app.route('/api/list-items', listItemsRouter)
// WR-04: background worker startup (cron schedules) moved into the isMainModule()
// guard below. Calling them at top level registered real node-cron schedules whenever