This plan covers two related milestone features:
- Issue #8: Automatic milestone completion when due date is reached
- Issue #9: Notifications when milestone due date is approaching
Add a new field to the Milestones model in prisma/schema.prisma:
model Milestones {
// ... existing fields ...
automaticCompletion Boolean @default(false) // NEW FIELD
}Files to modify:
app/[locale]/projects/milestones/[projectId]/AddMilestoneModal.tsxapp/[locale]/projects/milestones/[projectId]/[milestoneId]/MilestoneFormControls.tsxapp/[locale]/admin/milestones/MilestoneFormDialog.tsx
Changes:
- Add
automaticCompletionto form schema (Zod) - Add a Switch component for "Auto-complete on due date" - only enabled when a due date (
completedAt) is set - Include the field in form submission data
File to modify: workers/forecastWorker.ts
Add a new job type JOB_AUTO_COMPLETE_MILESTONES that:
- Queries for all milestones where:
isCompleted = falseisDeleted = falseautomaticCompletion = truecompletedAt <= now()(due date has passed)
- For each matching milestone, mark it as completed:
- Set
isCompleted = true - Optionally cascade to child milestones if they also have
automaticCompletion = true
- Set
Add translations for all 3 locales (en-US, es-ES, fr-FR):
milestones.fields.automaticCompletion: "Auto-complete on due date"- Help text for the field
Add a new field to the Milestones model:
model Milestones {
// ... existing fields ...
notifyDaysBefore Int @default(0) // 0 = no notifications, positive = days before due date
}Add a new notification type to the NotificationType enum:
enum NotificationType {
// ... existing types ...
MILESTONE_DUE_REMINDER
}Files to modify:
app/[locale]/projects/milestones/[projectId]/AddMilestoneModal.tsxapp/[locale]/projects/milestones/[projectId]/[milestoneId]/MilestoneFormControls.tsxapp/[locale]/admin/milestones/MilestoneFormDialog.tsx
Changes:
- Add
notifyDaysBeforeto form schema (Zod) - must be >= 0 - Add a number input field for "Notify days before due date"
- Disabled when no due date is set
- Auto-enabled with default of 5 when due date is set
- Value of 0 means notifications are disabled
- Include the field in form submission data
File to modify: workers/forecastWorker.ts
Add a new job type JOB_MILESTONE_DUE_NOTIFICATIONS that:
- Queries for all milestones where:
isCompleted = falseisDeleted = falsenotifyDaysBefore > 0completedAtis set (has a due date)- Due date is within
notifyDaysBeforedays from now, OR due date is today/past
- For each matching milestone:
- Find all users with assigned work (via
TestRuns.testCases.assignedToIdandSessions.assignedToId) - Calculate days remaining (or days overdue)
- Send notification with appropriate message
- Find all users with assigned work (via
File to modify: lib/services/notificationService.ts
Add a new method:
static async createMilestoneDueNotification(
userId: string,
milestoneName: string,
projectName: string,
daysRemaining: number, // negative if overdue
milestoneId: number,
projectId: number
)File to modify: workers/emailWorker.ts
Add URL builder for MILESTONE_DUE_REMINDER notification type:
- URL:
/projects/milestones/{projectId}/{milestoneId}
Add translations for all 3 locales:
milestones.fields.notifyDaysBefore: "Notify days before due date"milestones.notifications.dueSoon: "Milestone "{name}" is due on {dueDate}"milestones.notifications.overdue: "Milestone "{name}" was due on {dueDate}"- Help text for the field
Note: Avoid relative date terms like "today" or "in X days" to prevent timezone confusion. Always show explicit dates formatted according to user locale.
- Add both new fields to
Milestonesmodel inprisma/schema.prisma - Add
MILESTONE_DUE_REMINDERtoNotificationTypeenum - Run
npx zenstack generateto regenerate ZenStack hooks - Create and run database migration
- Update
AddMilestoneModal.tsx:- Add
automaticCompletionto Zod schema with defaultfalse - Add Switch field (disabled when no due date)
- Wire up conditional enabling when due date is set
- Add to form submission
- Add
- Update
MilestoneFormControls.tsxwith same changes - Update
MilestoneFormDialog.tsx(admin) with same changes - Add translations
- Update
AddMilestoneModal.tsx:- Add
notifyDaysBeforeto Zod schema with default0 - Add number input field (disabled when no due date)
- Auto-set to 5 when due date is first set
- Add to form submission
- Add
- Update
MilestoneFormControls.tsxwith same changes - Update
MilestoneFormDialog.tsx(admin) with same changes - Add translations
- Add new job types to
forecastWorker.ts:JOB_AUTO_COMPLETE_MILESTONESJOB_MILESTONE_DUE_NOTIFICATIONS
- Implement processor logic for both job types
- Add job scheduling (likely via cron job that runs daily)
- Add
createMilestoneDueNotificationmethod toNotificationService - Update
emailWorker.tsto handleMILESTONE_DUE_REMINDERtype - Add email template for milestone due notifications
- Test auto-completion with various due date scenarios
- Test notification sending with various day ranges
- Verify notifications go to correct users (those with assigned work)
- Test edge cases (milestone completed manually, due date changed, etc.)
| File | Changes |
|---|---|
prisma/schema.prisma |
Add automaticCompletion, notifyDaysBefore fields and MILESTONE_DUE_REMINDER enum |
app/[locale]/projects/milestones/[projectId]/AddMilestoneModal.tsx |
Add form fields for both features |
app/[locale]/projects/milestones/[projectId]/[milestoneId]/MilestoneFormControls.tsx |
Add form fields for both features |
app/[locale]/admin/milestones/MilestoneFormDialog.tsx |
Add form fields for both features |
workers/forecastWorker.ts |
Add job types and processing logic |
lib/services/notificationService.ts |
Add milestone notification method |
workers/emailWorker.ts |
Handle MILESTONE_DUE_REMINDER URL building |
messages/en-US.json |
Add English translations |
messages/es-ES.json |
Add Spanish translations |
messages/fr-FR.json |
Add French translations |
- Scheduling: The worker jobs for auto-completion and notifications should run daily (e.g., at midnight UTC or a configurable time)
- Timezone handling:
- Due dates are stored as
DateTimewith timezone (Timestamptz) - All comparisons should use UTC to avoid timezone issues
- Notification messages should display explicit dates (e.g., "due on Dec 15, 2025") rather than relative terms like "today" or "in 3 days" to avoid confusion across timezones
- Dates should be formatted according to user's locale preference
- Due dates are stored as
- Multi-tenant support: Both features must respect multi-tenant architecture already in place
- Cascade behavior: Auto-completion should respect existing cascade logic for child milestones
- Notification deduplication: Ensure users don't receive duplicate notifications for the same milestone on the same day