4.8 KiB
Design: Scheduled Synthesis Generation with Email Delivery
Date: 2026-03-27 Scope: Per-theme scheduling (days + time), automatic generation + email to up to 3 addresses
Context
Users want automated weekly syntheses delivered by email without manually triggering generation. Each theme can have its own schedule (e.g. "AI News every Mon/Wed/Fri at 8am, emailed to 3 people").
The app already runs as a Docker daemon (restart: unless-stopped), so no external cron or daemon script is needed — the scheduler is an internal background task.
1. Data Model
New table: theme_schedules
CREATE TABLE theme_schedules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
theme_id UUID NOT NULL UNIQUE REFERENCES themes(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
enabled BOOLEAN NOT NULL DEFAULT true,
days JSONB NOT NULL DEFAULT '[]',
time_utc TEXT NOT NULL DEFAULT '08:00',
emails JSONB NOT NULL DEFAULT '[]',
last_run_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_theme_schedules_enabled ON theme_schedules(enabled) WHERE enabled = true;
theme_idis UNIQUE — one schedule per theme (1:1)days: JSON array of day codes["mon","tue","wed","thu","fri","sat","sun"]time_utc: execution time in UTC, format"HH:MM"emails: JSON array of up to 3 email addresseslast_run_at: prevents double runs on the same day
2. API Endpoints
GET /api/v1/themes/:id/schedule— get schedule for a theme (null if none)PUT /api/v1/themes/:id/schedule— upsert scheduleDELETE /api/v1/themes/:id/schedule— remove schedule
PUT body
{
"enabled": true,
"days": ["mon", "wed", "fri"],
"time_utc": "08:00",
"emails": ["user@example.com", "colleague@example.com"]
}
Validation
emails: max 3, each must be valid email formatdays: each must be one ofmon, tue, wed, thu, fri, sat, suntime_utc: must matchHH:MMformat (00:00-23:59)- Theme must belong to the authenticated user
3. Backend Scheduler
Background task in main.rs
// Scheduled synthesis generation (check every 60 seconds)
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(60));
loop {
interval.tick().await;
scheduler::run_scheduled_jobs(&state).await;
}
});
services/scheduler.rs
run_scheduled_jobs(state):
- Get current UTC time and day code (e.g.
"wed") - Query
theme_scheduleswhere:enabled = truedayscontains today's day codetime_utc <= current_timelast_run_atis NULL orlast_run_at::date < today
- For each due schedule:
- Check
job_store.has_active_job(user_id)— skip if manual generation in progress - Load theme settings
- Run
run_generation_innerwith a dummy watch channel (no SSE client) - On success: send synthesis email to all addresses in
emails - Update
last_run_at = now() - Log success/failure
- Check
Error handling: If generation or email fails, log the error and continue to the next schedule. Don't retry — the schedule will trigger again at the next interval if last_run_at wasn't updated.
Concurrency: Jobs run sequentially (one at a time) to avoid overwhelming LLM rate limits.
4. Frontend — Schedule Section in ThemeManager
New "Planification" section in the theme page, below sources.
UI components:
- Enable toggle: checkbox to enable/disable
- Day selector: 7 buttons (L M M J V S D), toggle on click, selected = highlighted
- Time picker:
<input type="time"> - Email list: up to 3 inputs with add/remove buttons
- Auto-save: changes sent immediately via
PUT /api/v1/themes/:id/schedule
Section hidden when no theme is selected.
5. Files
Backend
- Create:
backend/migrations/20260327000030_create_theme_schedules.sql - Create:
backend/src/models/schedule.rs - Create:
backend/src/db/schedules.rs - Create:
backend/src/handlers/schedules.rs - Create:
backend/src/services/scheduler.rs - Modify:
backend/src/models/mod.rs,db/mod.rs,handlers/mod.rs,services/mod.rs - Modify:
backend/src/router.rs— schedule routes - Modify:
backend/src/main.rs— spawn scheduler task - Modify:
CLAUDE.md— migration count
Frontend
- Create:
frontend/src/api/schedules.ts - Create:
frontend/src/components/settings/SettingsSchedule.tsx - Modify:
frontend/src/pages/ThemeManager.tsx - Modify:
frontend/src/i18n/fr.ts - Modify:
frontend/src/types.ts
Tests
- Create:
backend/tests/api_schedules_test.rs - Modify:
e2e/tests/themes.spec.ts