-- Unified Schedule & Cadence Layer (ADP v0.1) CREATE TABLE schedules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, schedule_kind VARCHAR(16) NOT NULL DEFAULT 'interval' CHECK (schedule_kind IN ('interval', 'weekdays')), interval_days INT NULL CHECK (interval_days IS NULL OR interval_days > 0), weekday_mask INT NOT NULL DEFAULT 0, pause_until DATE NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_schedules_tenant ON schedules(tenant_id); ALTER TABLE recurring_elements ADD COLUMN IF NOT EXISTS schedule_id UUID NULL REFERENCES schedules(id) ON DELETE SET NULL; ALTER TABLE recurring_elements ADD COLUMN IF NOT EXISTS action_id UUID NULL REFERENCES actions(id) ON DELETE CASCADE; CREATE UNIQUE INDEX idx_recurring_elements_action ON recurring_elements(action_id) WHERE action_id IS NOT NULL; ALTER TABLE actions ADD COLUMN IF NOT EXISTS schedule_id UUID NULL REFERENCES schedules(id) ON DELETE SET NULL; -- Backfill: one schedule per recurring without schedule_id DO $$ DECLARE r RECORD; sid UUID; idays INT; BEGIN FOR r IN SELECT id, tenant_id, interval_days FROM recurring_elements WHERE schedule_id IS NULL LOOP idays := GREATEST(COALESCE(r.interval_days, 1), 1); INSERT INTO schedules (tenant_id, schedule_kind, interval_days, weekday_mask) VALUES (r.tenant_id, 'interval', idays, 0) RETURNING id INTO sid; UPDATE recurring_elements SET schedule_id = sid WHERE id = r.id; END LOOP; END $$;