Files
GearBox/.planning/phases/16-multi-user-data-model/16-01-SUMMARY.md
Jean-Luc Makiola a0e5442816 docs(16-01): complete multi-user data model foundation plan
- Add 16-01-SUMMARY.md with schema, middleware, and test changes
- Update STATE.md with phase 16 progress and decisions
- Update ROADMAP.md with plan progress (1/4 complete)
- Mark MULTI-01, MULTI-04, MULTI-06 complete in REQUIREMENTS.md
2026-04-05 10:37:57 +02:00

6.5 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
16-multi-user-data-model 01 database
drizzle
pgTable
multi-user
userId
postgresql
auth-middleware
phase provides
14-postgresql-migration PostgreSQL infrastructure and PGlite test setup
phase provides
15-external-authentication OIDC auth via Logto, API key and OAuth Bearer auth methods
users table with logtoSub for OIDC mapping
userId FK columns on all entity tables (items, categories, threads, setups, apiKeys, oauthTokens)
composite unique constraint on categories(userId, name)
composite primary key on settings(userId, key)
requireAuth middleware resolving userId onto Hono context
getOrCreateUser upsert function for OIDC login
getOrCreateUncategorized lazy category creation
test helper returning { db, userId } with seeded user
16-02
16-03
16-04
services
routes
mcp-tools
tests
added patterns
userId-on-context
per-user-data-isolation
lazy-uncategorized-creation
upsert-on-first-login
created modified
drizzle-pg.config.ts
drizzle-pg/0000_thankful_loners.sql
src/db/schema.ts
src/db/seed.ts
src/server/middleware/auth.ts
src/server/services/auth.service.ts
src/server/services/oauth.service.ts
src/server/services/category.service.ts
src/server/index.ts
tests/helpers/db.ts
All API routes require auth (no GET bypass) so userId is always available for per-user scoping
OAuth service functions converted from sync (.get/.run) to async (await) for pg compatibility
getOrCreateUncategorized placed in category.service.ts since it is category-related
userId resolution: requireAuth sets c.set('userId', ...) for all three auth methods
verifyApiKey/verifyAccessToken return { userId } | null instead of boolean
createTestDb returns { db, userId } -- all tests must destructure
Lazy per-user Uncategorized category creation on first OIDC login
MULTI-01
MULTI-04
MULTI-06
8min 2026-04-05

Phase 16 Plan 01: Multi-User Data Model Foundation Summary

pgTable schema with users table, userId FK on 6 entity tables, composite constraints, and auth middleware resolving userId for all auth methods

Performance

  • Duration: 8 min
  • Started: 2026-04-05T08:31:24Z
  • Completed: 2026-04-05T08:39:00Z
  • Tasks: 3
  • Files modified: 10

Accomplishments

  • Migrated entire schema.ts from sqlite-core to pg-core (pgTable, serial, timestamp, doublePrecision)
  • Added users table with logtoSub unique identifier for OIDC mapping and userId FK to items, categories, threads, setups, apiKeys, oauthTokens
  • Auth middleware now resolves userId for API key, Bearer token, and OIDC session; all routes require auth
  • Test infrastructure returns { db, userId } with seeded user and createSecondTestUser helper

Task Commits

Each task was committed atomically:

  1. Task 1: Migrate schema.ts to pgTable and add users table + userId columns - 91e93a3 (feat)
  2. Task 2: Update auth middleware and auth services to resolve userId - b6d562f (feat)
  3. Task 3: Update test helper to seed user and return { db, userId } - 050478c (feat)

Files Created/Modified

  • src/db/schema.ts - Rewritten from sqlite-core to pg-core; users table, userId columns, composite constraints
  • src/db/seed.ts - Emptied global seed; per-user categories created lazily
  • src/server/middleware/auth.ts - Rewritten to resolve userId for all 3 auth methods
  • src/server/services/auth.service.ts - Rewritten: getOrCreateUser, verifyApiKey returns userId, scoped API key CRUD
  • src/server/services/oauth.service.ts - Rewritten: all functions async, verifyAccessToken returns userId, generateTokens accepts userId
  • src/server/services/category.service.ts - Added getOrCreateUncategorized helper
  • src/server/index.ts - Removed GET bypass; all API routes require auth
  • tests/helpers/db.ts - PGlite-based, seeds user, returns { db, userId }, createSecondTestUser helper
  • drizzle-pg.config.ts - Drizzle config for PostgreSQL dialect
  • drizzle-pg/0000_thankful_loners.sql - Generated migration with full schema

Decisions Made

  • All API routes require auth (removed GET bypass) so userId is always available on context for per-user data scoping
  • OAuth service functions converted from synchronous (.get/.run/.all) to async/await for PostgreSQL compatibility
  • getOrCreateUncategorized placed in category.service.ts since it is category-domain logic
  • Old user/session management functions removed from auth.service.ts (replaced by Logto OIDC)

Deviations from Plan

Auto-fixed Issues

1. [Rule 2 - Missing Critical] Converted all oauth.service.ts functions to async

  • Found during: Task 2 (auth service updates)
  • Issue: All oauth.service functions used synchronous .get()/.run()/.all() calls from bun-sqlite; these do not work with pg/PGlite which is async-only
  • Fix: Rewrote all oauth.service functions to use async/await with array destructuring instead of .get()
  • Files modified: src/server/services/oauth.service.ts
  • Verification: Code compiles correctly with pg-core types
  • Committed in: b6d562f (Task 2 commit)

2. [Rule 3 - Blocking] Created drizzle-pg.config.ts for migration generation

  • Found during: Task 1 (schema migration)
  • Issue: Existing drizzle.config.ts was SQLite-only; needed PostgreSQL config to generate migrations
  • Fix: Created drizzle-pg.config.ts pointing to drizzle-pg/ output directory
  • Files modified: drizzle-pg.config.ts (new)
  • Verification: Migration generated successfully with 12 tables
  • Committed in: 91e93a3 (Task 1 commit)

Total deviations: 2 auto-fixed (1 missing critical, 1 blocking) Impact on plan: Both fixes essential for pg compatibility. No scope creep.

Issues Encountered

None

Known Stubs

None - all data model changes are structural (schema, middleware, test infrastructure). No UI rendering involved.

User Setup Required

None - no external service configuration required.

Next Phase Readiness

  • Schema foundation complete with users table and userId columns on all entity tables
  • Auth middleware resolves userId for all auth methods
  • Test helper ready with seeded user
  • Next: Plan 16-02 updates all service files to accept userId parameter and filter queries
  • Note: createTestDb return type changed from db to { db, userId } -- existing tests will need updating in Plan 16-04

Phase: 16-multi-user-data-model Completed: 2026-04-05