diff --git a/docs/development/database-schema.dbml b/docs/development/database-schema.dbml index 3d2105ac33..aade679fab 100644 --- a/docs/development/database-schema.dbml +++ b/docs/development/database-schema.dbml @@ -1326,7 +1326,7 @@ table push_tokens { last_seen_at "timestamp with time zone" [not null, default: `now()`] indexes { - (user_id, device_id) [name: 'idx_push_tokens_user_device', unique] + device_id [name: 'idx_push_tokens_device', unique] user_id [name: 'idx_push_tokens_user'] last_seen_at [name: 'idx_push_tokens_last_seen'] } diff --git a/packages/database/migrations/0104_topic_usage_push_tokens_tasks_doc_shares.sql b/packages/database/migrations/0104_topic_usage_push_tokens_tasks_doc_shares.sql index 7fe493de33..f6ee1731db 100644 --- a/packages/database/migrations/0104_topic_usage_push_tokens_tasks_doc_shares.sql +++ b/packages/database/migrations/0104_topic_usage_push_tokens_tasks_doc_shares.sql @@ -39,7 +39,7 @@ ALTER TABLE "push_tokens" DROP CONSTRAINT IF EXISTS "push_tokens_user_id_users_i ALTER TABLE "push_tokens" ADD CONSTRAINT "push_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint CREATE UNIQUE INDEX IF NOT EXISTS "document_shares_document_id_unique" ON "document_shares" USING btree ("document_id");--> statement-breakpoint CREATE INDEX IF NOT EXISTS "document_shares_user_id_idx" ON "document_shares" USING btree ("user_id");--> statement-breakpoint -CREATE UNIQUE INDEX IF NOT EXISTS "idx_push_tokens_user_device" ON "push_tokens" USING btree ("user_id","device_id");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "idx_push_tokens_device" ON "push_tokens" USING btree ("device_id");--> statement-breakpoint CREATE INDEX IF NOT EXISTS "idx_push_tokens_user" ON "push_tokens" USING btree ("user_id");--> statement-breakpoint CREATE INDEX IF NOT EXISTS "idx_push_tokens_last_seen" ON "push_tokens" USING btree ("last_seen_at");--> statement-breakpoint CREATE INDEX IF NOT EXISTS "topics_model_idx" ON "topics" USING btree ("model");--> statement-breakpoint diff --git a/packages/database/migrations/meta/0104_snapshot.json b/packages/database/migrations/meta/0104_snapshot.json index 5261644341..40e5cc663c 100644 --- a/packages/database/migrations/meta/0104_snapshot.json +++ b/packages/database/migrations/meta/0104_snapshot.json @@ -6,7 +6,7 @@ }, "dialect": "postgresql", "enums": {}, - "id": "fe7c1962-3f6f-4c00-b2dd-7ce035fecb9f", + "id": "07e041f5-28d5-443a-b5c5-59aa6122ba48", "policies": {}, "prevId": "e8bb3ce2-fead-4b3d-810e-307c98e891b7", "roles": {}, @@ -10001,15 +10001,9 @@ } }, "indexes": { - "idx_push_tokens_user_device": { - "name": "idx_push_tokens_user_device", + "idx_push_tokens_device": { + "name": "idx_push_tokens_device", "columns": [ - { - "expression": "user_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, { "expression": "device_id", "isExpression": false, diff --git a/packages/database/migrations/meta/_journal.json b/packages/database/migrations/meta/_journal.json index 613bc4f4b8..c34c126701 100644 --- a/packages/database/migrations/meta/_journal.json +++ b/packages/database/migrations/meta/_journal.json @@ -732,7 +732,7 @@ { "idx": 104, "version": "7", - "when": 1779942758520, + "when": 1779943832837, "tag": "0104_topic_usage_push_tokens_tasks_doc_shares", "breakpoints": true } diff --git a/packages/database/src/schemas/pushToken.ts b/packages/database/src/schemas/pushToken.ts index 6ff7cfe035..85f0aa96a2 100644 --- a/packages/database/src/schemas/pushToken.ts +++ b/packages/database/src/schemas/pushToken.ts @@ -6,8 +6,8 @@ import { users } from './user'; /** * Stores Expo push notification tokens registered by mobile clients. * - * One row per (userId, deviceId) — a single user may have multiple devices - * (e.g. iPhone + Android tablet), each receiving its own notifications. + * One row per device — on user switch the row is reassigned to the new user + * (re-registration upserts by deviceId). * * Tokens are validated at registration time but may become invalid over time * (app uninstall, OS reinstall). Cleanup happens via the Expo receipt cron @@ -38,8 +38,8 @@ export const pushTokens = pgTable( lastSeenAt: timestamptz('last_seen_at').defaultNow().notNull(), }, (table) => [ - /** Same user + device = one row; re-registration upserts in place */ - uniqueIndex('idx_push_tokens_user_device').on(table.userId, table.deviceId), + /** One row per device; re-registration upserts in place */ + uniqueIndex('idx_push_tokens_device').on(table.deviceId), /** PushChannel.deliver fans out by userId */ index('idx_push_tokens_user').on(table.userId), /** Future: cleanup long-inactive tokens by lastSeenAt */