- SUMMARY.md for plan 09-01: theme column, personal channels, event-key and subscription tables
6.4 KiB
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 09-user-profile-preferences-new | 01 | schema-and-types |
|
|
|
|
|
|
Phase 9 Plan 01: Schema and Types Foundation Summary
One-liner: Three sequential migrations land theme column, personal-channel ownership, and event-subscription tables; TypeScript types extended to match; session.user.theme exposed via Better Auth additionalFields following Phase 7.1 precedent.
Tasks Completed
| Task | Name | Commit | Files |
|---|---|---|---|
| 1 | Add theme column to user + Better Auth additionalField | 4fc4a3d |
migrations/084_add_user_theme.sql, lib/auth.ts |
| 2 | Add owner_user_id + partial unique index to notification_channels + create event-keys / subscriptions tables | b4f8cca |
migrations/085_personal_notification_channels.sql, migrations/086_notify_event_keys_and_subscriptions.sql, lib/types/pipeline.ts |
What Was Built
migrations/084_add_user_theme.sql
Adds theme TEXT NOT NULL DEFAULT 'system' to the Better Auth "user" table.
ALTER TABLE "user" ADD COLUMN IF NOT EXISTS theme TEXT NOT NULL DEFAULT 'system'- Defensive backfill:
UPDATE "user" SET theme = 'system' WHERE theme IS NULL COMMENT ON COLUMN "user".themedocuments allowed values (light | dark | system)- Mirrors 083_add_user_timezone.sql structure exactly
migrations/085_personal_notification_channels.sql
Extends notification_channels to support personal (per-user) channels alongside existing global rows.
ALTER TABLE notification_channels ADD COLUMN IF NOT EXISTS owner_user_id TEXT REFERENCES "user"(id) ON DELETE CASCADE- Cascade delete: removing a Better Auth user removes their personal channels automatically
- Non-unique index
idx_notification_channels_owneron(owner_user_id, channel_type) WHERE owner_user_id IS NOT NULLfor query performance - Partial unique index
notification_channels_owner_user_id_channel_type_uniqon(owner_user_id, channel_type) WHERE owner_user_id IS NOT NULL— enforces one-personal-channel-per-type-per-user at DB layer; global rows (NULL owner) are exempt COMMENT ON COLUMN notification_channels.owner_user_iddocuments the global vs personal semantics
migrations/086_notify_event_keys_and_subscriptions.sql
Creates two new tables for the notification event taxonomy and per-user subscription matrix.
notify_event_keystable:key TEXT PRIMARY KEY,display_label,description,sort_order,is_active, audit columns. Index on(is_active, sort_order, key). Seeded withticket_assigned_to_merow viaINSERT ... ON CONFLICT (key) DO NOTHING.user_event_subscriptionstable: compositePRIMARY KEY (user_id, event_key, channel_type),enabled BOOLEAN NOT NULL DEFAULT true,updated_at.user_idcascades on user delete. Index on(user_id).- Table comments document the opt-out model (row absence = enabled) and the humanization-layer-only role of event keys.
lib/auth.ts — theme additionalField
Added theme as the fourth additionalFields entry, immediately after timezone:
theme: {
type: "string",
defaultValue: "system",
},
session.user.theme is now exposed via Better Auth in the same way session.user.timezone is (Phase 7.1 precedent). The server-side value becomes available after the next session refresh.
lib/types/pipeline.ts — type extensions
Three changes, no other types touched:
NotificationChannelgainsowner_user_id: string | null(inserted afteris_active)- New exported interface
NotifyEventKeywith fieldskey,display_label,description: string | null,sort_order,is_active,created_at,updated_at - New exported interface
UserEventSubscriptionwith fieldsuser_id,event_key,channel_type: ChannelType,enabled,updated_at
Deviations from Plan
None — plan executed exactly as written.
Threat Flags
No new network endpoints, auth paths, file access patterns, or schema changes at trust boundaries beyond what was declared in the plan's threat model. All six threats documented in plan T-09-01-01 through T-09-01-06 are addressed by the schema choices made here (cascade delete, composite PK, partial unique index, NOT NULL DEFAULT).
Self-Check: PASSED
Files exist:
- migrations/084_add_user_theme.sql: FOUND
- migrations/085_personal_notification_channels.sql: FOUND
- migrations/086_notify_event_keys_and_subscriptions.sql: FOUND
- lib/auth.ts: FOUND (modified)
- lib/types/pipeline.ts: FOUND (modified)
Commits exist:
TypeScript: npx tsc --noEmit --pretty exit 0 — no errors.