You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ai_synth/docs/superpowers/specs/2026-03-27-scheduled-genera...

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_id is 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 addresses
  • last_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 schedule
  • DELETE /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 format
  • days: each must be one of mon, tue, wed, thu, fri, sat, sun
  • time_utc: must match HH:MM format (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):

  1. Get current UTC time and day code (e.g. "wed")
  2. Query theme_schedules where:
    • enabled = true
    • days contains today's day code
    • time_utc <= current_time
    • last_run_at is NULL or last_run_at::date < today
  3. For each due schedule:
    • Check job_store.has_active_job(user_id) — skip if manual generation in progress
    • Load theme settings
    • Run run_generation_inner with 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

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