Email Archive Feature Design
Date: 2026-02-09 Status: Approved
Problem
The "Sent" filter tab in the Email Schedules table and the separate "Logs" page show overlapping information. Completed one-time emails clutter the main list, making it harder to focus on actionable items.
Solution
- Remove the "Sent" filter tab — replaced by a new "Archived" tab
- Add Archive functionality — terminal-state one-time emails are auto-archived
- Keep the Logs page — serves as a detailed audit trail (separate concern)
- "All" tab excludes archived emails — main list stays clean
Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| What gets archived? | Sent + failed + cancelled one-time emails | All terminal-state one-time emails are "done" |
| Archive mechanism | Auto-archive + manual unarchive | Auto keeps things tidy; unarchive provides safety net |
| Logs page | Keep as-is, remove "Sent" filter tab | Logs = audit trail (different purpose from Archive) |
| Database implementation | is_archived boolean column | Preserves original status (sent vs failed vs cancelled) |
Data Model Changes
New column on email_schedules
sql
ALTER TABLE email_schedules
ADD COLUMN is_archived boolean NOT NULL DEFAULT false;Auto-archive trigger
Fires when email_schedules.status changes to 'sent', 'failed', or 'cancelled' AND mode IN ('manual', 'scheduled') (one-time only). Sets is_archived = true.
Recurring emails are never auto-archived.
Migration steps
- Add
is_archivedcolumn (default false) - Backfill: set
is_archived = truefor existing terminal one-time emails - Create trigger function for auto-archive on future status changes
- Add index on
is_archivedfor efficient filtering
UI Changes
Filter tabs
Before: [All] [Pending] [Sent] [Failed] [Recurring]After: [All] [Pending] [Failed] [Recurring] [Archived]
| Tab | Filter Logic |
|---|---|
| All | is_archived === false (excludes archived) |
| Pending | is_archived === false AND status IN (draft, scheduled, processing) |
| Failed | is_archived === false AND status IN (failed, cancelled) |
| Recurring | mode === 'recurring' (unaffected by archive) |
| Archived | is_archived === true |
Row actions
- Archived emails: Unarchive action (sets
is_archived = false) - Non-archived terminal-state emails: Archive action (manual archive)
Stats cards
Replace "Sent" count with "Archived" count.
Service & Hook Changes
EmailScheduleService
typescript
// New method
static async setArchived(id: string, isArchived: boolean): Promise<void>useEmailSchedules hook
typescript
// New actions
archiveSchedule(id: string): Promise<void> // sets is_archived = true
unarchiveSchedule(id: string): Promise<void> // sets is_archived = falseClient-side filtering
typescript
type FilterStatus = "all" | "pending" | "failed" | "recurring" | "archived";Files to Modify
| File | Change |
|---|---|
supabase/migrations/YYYYMMDD_add_email_archive.sql | New migration |
src/features/email-schedules/types.ts | Add is_archived to EmailSchedule type |
src/features/email-schedules/services/EmailScheduleService.ts | Add setArchived() method |
src/features/email-schedules/hooks/useEmailSchedules.ts | Add archive/unarchive actions |
src/features/email-schedules/components/EmailSchedulesTable.tsx | Update filters, tabs, row actions |
src/app/(admin)/(pages)/email-schedules/index.tsx | Update stats cards |
src/lib/supabaseTypes.ts | Regenerate types |