OUT-3734 | Schema: add TaskReminderSent table + TaskReminderType enum#1229
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR introduces the
Confidence Score: 4/5Safe to merge; the schema and migration are internally consistent. Two non-blocking issues are worth revisiting before the reminder job ships. The migration and schema are in sync, CASCADE FK is correctly wired, and the dedup constraint aligns with the stated design intent. The main concerns are that the lifetime-once unique constraint may silently skip reminders after task state resets, and workspaceId has no index despite being the tenancy column — both are worth addressing before the reminder job is turned on in production but neither blocks the schema migration itself. prisma/schema/taskReminderSent.prisma — unique constraint semantics and missing workspaceId index. Important Files Changed
Reviews (1): Last reviewed commit: "feat(OUT-3734): add TaskReminderSents ta..." | Re-trigger Greptile |
| reminderType TaskReminderType | ||
| sentAt DateTime @default(now()) | ||
|
|
||
| @@unique([taskId, recipientId, reminderType]) |
There was a problem hiding this comment.
Permanent dedup blocks legitimate re-sends
The unique constraint on (taskId, recipientId, reminderType) has no time dimension, so each reminder type can only fire once per task-recipient pair for the lifetime of the record. For the NO_DUE_DATE_* types this creates a concrete gap: if a user adds a due date (making the "no due date" reminders irrelevant), then later removes it again, the 3-day and 7-day nudges will never re-fire because the old ledger rows still exist. The same applies to DUE_DATE_TODAY if a due date is postponed and then reset. At minimum a comment explaining why this lifetime-once behaviour is correct, or whether the job is expected to delete stale rows before re-arming, would help prevent future confusion.
| @@unique([taskId, recipientId, reminderType]) | ||
| @@map("TaskReminderSents") |
There was a problem hiding this comment.
Missing
workspaceId index for tenant-scoped queries. The column is explicitly carried "for tenancy parity" but has no index, so any query that filters or batches by workspace (e.g., the reminder job scanning pending tasks per workspace) will do a full table scan as the table grows.
| @@unique([taskId, recipientId, reminderType]) | |
| @@map("TaskReminderSents") | |
| @@unique([taskId, recipientId, reminderType]) | |
| @@index([workspaceId]) | |
| @@map("TaskReminderSents") |
Adds a minimal ledger to enforce reminder idempotency at the DB level. Unique constraint on (taskId, recipientId, reminderType) is the dedupe primitive so retries and manual re-triggers cannot double-send. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b4fdbe6 to
d3b94ad
Compare
|
Deployment failed with the following error: Learn More: https://vercel.link/multiple-function-regions |
Summary
TaskReminderTypeenum andTaskReminderSentstable — the idempotency ledger for reminder emails (Milestone 1).(taskId, recipientId, reminderType)is the dedupe primitive so retries and manual re-triggers cannot double-send.Tasks(id)withON DELETE CASCADE;workspaceIdcarried for tenancy parity with the rest of the schema.Test plan
prisma validatepassesprisma migrate devapplies cleanly on local Postgresprisma generateproduces the expected types(taskId, recipientId, reminderType)raises a unique-constraint violationTaskcascades and removes ledger rows🤖 Generated with Claude Code