Merge branch 'worktree-agent-a9a8b0dc' into Develop
# Conflicts: # .planning/REQUIREMENTS.md # .planning/ROADMAP.md # .planning/STATE.md # drizzle-pg/meta/0000_snapshot.json # drizzle-pg/meta/_journal.json # src/db/schema.ts # src/db/seed.ts # src/server/middleware/auth.ts # src/server/services/auth.service.ts # src/server/services/category.service.ts # src/server/services/oauth.service.ts # tests/helpers/db.ts
This commit is contained in:
145
.planning/phases/16-multi-user-data-model/16-01-SUMMARY.md
Normal file
145
.planning/phases/16-multi-user-data-model/16-01-SUMMARY.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
phase: 16-multi-user-data-model
|
||||
plan: 01
|
||||
subsystem: database
|
||||
tags: [drizzle, pgTable, multi-user, userId, postgresql, auth-middleware]
|
||||
|
||||
requires:
|
||||
- phase: 14-postgresql-migration
|
||||
provides: PostgreSQL infrastructure and PGlite test setup
|
||||
- phase: 15-external-authentication
|
||||
provides: OIDC auth via Logto, API key and OAuth Bearer auth methods
|
||||
provides:
|
||||
- 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
|
||||
affects: [16-02, 16-03, 16-04, services, routes, mcp-tools, tests]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [userId-on-context, per-user-data-isolation, lazy-uncategorized-creation, upsert-on-first-login]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- drizzle-pg.config.ts
|
||||
- drizzle-pg/0000_thankful_loners.sql
|
||||
modified:
|
||||
- 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
|
||||
|
||||
key-decisions:
|
||||
- "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"
|
||||
|
||||
patterns-established:
|
||||
- "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"
|
||||
|
||||
requirements-completed: [MULTI-01, MULTI-04, MULTI-06]
|
||||
|
||||
duration: 8min
|
||||
completed: 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*
|
||||
Reference in New Issue
Block a user