-- WhispAssist sync + recording-retention schema (Phase 9 / ADR-0010, ADR-0009). -- Forward-only migration. Mirrors docs/03-data-model.md. PRAGMA foreign_keys = ON; -- Recording retention flag on meetings (ADR-0009). audio_path becomes nullable in practice: -- a non-recorded meeting has no audio file. (SQLite keeps the existing column definition; -- new rows set recorded=0 and may leave audio_path empty.) ALTER TABLE meetings ADD COLUMN recorded INTEGER NOT NULL DEFAULT 0; -- Configured upload destinations. Secrets are NOT stored here — only a reference into the -- OS credential store (FR-SYNC-6). CREATE TABLE sync_targets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, kind TEXT NOT NULL, -- webdav|onedrive|dropbox|box provider_hint TEXT, -- nextcloud|owncloud|cloudreve|seafile|synology|generic base_url TEXT, remote_base_path TEXT NOT NULL DEFAULT '/WhispAssist', username TEXT, credential_ref TEXT NOT NULL, -- key into OS credential store enabled INTEGER NOT NULL DEFAULT 0, upload_transcript INTEGER NOT NULL DEFAULT 1, upload_notes INTEGER NOT NULL DEFAULT 1, upload_summary INTEGER NOT NULL DEFAULT 1, upload_recording INTEGER NOT NULL DEFAULT 0, trigger_on_finalize INTEGER NOT NULL DEFAULT 1, allow_plaintext_lan INTEGER NOT NULL DEFAULT 0, encrypt_before_upload INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL ); CREATE TABLE sync_jobs ( id TEXT PRIMARY KEY, target_id TEXT NOT NULL REFERENCES sync_targets(id) ON DELETE CASCADE, meeting_id TEXT NOT NULL REFERENCES meetings(id) ON DELETE CASCADE, artifact TEXT NOT NULL, -- transcript|notes|summary|recording local_path TEXT NOT NULL, remote_path TEXT NOT NULL, sha256 TEXT, status TEXT NOT NULL, -- pending|uploading|done|failed|skipped attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, next_attempt_at INTEGER, bytes_total INTEGER, bytes_sent INTEGER NOT NULL DEFAULT 0, updated_at INTEGER NOT NULL, UNIQUE(target_id, meeting_id, artifact) ); CREATE INDEX idx_syncjobs_status ON sync_jobs(status, next_attempt_at);