-- v0.13.0 / roadmap item #11 — cookie consent. -- -- The framework now ships a non-modal cookie consent banner per the -- privacy-and-cookies UX (SPEC §14.5 / §14.6). Authenticated viewers -- get their choice persisted server-side so it survives sign-out / -- sign-in across devices; anonymous viewers persist their choice in -- localStorage only. -- -- Shape: a single row per user, three flags, plus a recorded-at stamp. -- The flags are: -- - essential: the framework's strictly-necessary cookies (session, -- itsdangerous-signed payloads, CSRF if any). Permanently -- true at the API surface — included in the row for -- symmetry with the analytics / other flags rather than -- because the user can switch it off. -- - analytics: reserved for the §13 analytics SDK gating that lands -- in v0.15.0. Off by default; opt-in via the banner. -- - other: everything else (third-party embeds, social widgets). -- Off by default; opt-in via the banner. -- -- A NULL recorded_at means "no choice yet" — the banner should re-prompt -- the next time the user signs in on a fresh device. Once recorded_at is -- set, the banner is hidden until the user re-opens it from the -- /settings/notifications "Privacy & cookies" tab. -- -- The row is created lazily on first PUT. Absence of a row is equivalent -- to NULL recorded_at — the banner shows. CREATE TABLE cookie_consent ( user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, essential INTEGER NOT NULL DEFAULT 1 CHECK (essential IN (0, 1)), analytics INTEGER NOT NULL DEFAULT 0 CHECK (analytics IN (0, 1)), other_cookies INTEGER NOT NULL DEFAULT 0 CHECK (other_cookies IN (0, 1)), recorded_at TEXT );