feat(db): migration 0004 — phase 2 schema + 4 new tokens
users: adds pull_quote, member_number (unique partial index, NULLs allowed), focus_tags. title already exists from 0003 — not re-added. Backfills member_number for existing cab users in COALESCE(cab_joined_date, created_at) asc, tiebreak id asc. Lars gets #1. events: rebuild required to widen the kind CHECK constraint (SQLite can't ALTER it in place). Adds working_session as a new kind. Same rebuild adds four new columns: audience, duration_label, action_label, notes_url. Data preserved. dispatches: new entity, status enum draft/published/archived, kind enum decision/update/behind_the_scenes/note. published_at nullable until publishPulse-equivalent stamps it. Indexes on (status, published_at) and author_id. Tokens (src/styles/tokens.css): adds --surface-card, --surface-card-border, --ink, --ink-text, --ink-muted. Spec called these out as the only additions; existing --radius-lg covers the spec's --border-radius-lg reference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7f6668f909
commit
865347f682
2 changed files with 81 additions and 0 deletions
74
migrations/0004_phase_two.sql
Normal file
74
migrations/0004_phase_two.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
-- Phase 2 — council portal revisions
|
||||||
|
-- Adds pull_quote/member_number/focus_tags to users (title already exists
|
||||||
|
-- from 0003), rebuilds events to widen the kind CHECK + add four columns,
|
||||||
|
-- creates dispatches, backfills member_numbers for existing cab users.
|
||||||
|
|
||||||
|
-- ── users: new columns ─────────────────────────────────────────────
|
||||||
|
ALTER TABLE users ADD COLUMN pull_quote TEXT;
|
||||||
|
ALTER TABLE users ADD COLUMN member_number INTEGER;
|
||||||
|
ALTER TABLE users ADD COLUMN focus_tags TEXT; -- JSON array, capped 3 × 24 chars at app layer
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX idx_users_member_number ON users(member_number) WHERE member_number IS NOT NULL;
|
||||||
|
|
||||||
|
-- Backfill member_numbers for existing CAB users in member-since order,
|
||||||
|
-- tiebreaking on user.id ascending. Deterministic across machines.
|
||||||
|
WITH ranked AS (
|
||||||
|
SELECT id,
|
||||||
|
ROW_NUMBER() OVER (ORDER BY COALESCE(cab_joined_date, created_at) ASC, id ASC) AS rn
|
||||||
|
FROM users
|
||||||
|
WHERE role = 'cab'
|
||||||
|
)
|
||||||
|
UPDATE users
|
||||||
|
SET member_number = (SELECT rn FROM ranked WHERE ranked.id = users.id)
|
||||||
|
WHERE role = 'cab' AND member_number IS NULL;
|
||||||
|
|
||||||
|
-- ── events: rebuild for widened kind enum + 4 new columns ─────────
|
||||||
|
-- SQLite can't ALTER a CHECK constraint; full rebuild required.
|
||||||
|
CREATE TABLE events_new (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
slug TEXT UNIQUE NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
kind TEXT NOT NULL DEFAULT 'dinner'
|
||||||
|
CHECK(kind IN ('dinner','office_hours','summit','virtual','working_session')),
|
||||||
|
description TEXT NOT NULL DEFAULT '',
|
||||||
|
location TEXT NOT NULL DEFAULT '',
|
||||||
|
starts_at TEXT NOT NULL,
|
||||||
|
ends_at TEXT,
|
||||||
|
capacity INTEGER,
|
||||||
|
photo_url TEXT,
|
||||||
|
audience TEXT,
|
||||||
|
duration_label TEXT,
|
||||||
|
action_label TEXT,
|
||||||
|
notes_url TEXT,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
created_by INTEGER REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO events_new
|
||||||
|
(id, slug, title, kind, description, location, starts_at, ends_at, capacity, photo_url, created_at, created_by)
|
||||||
|
SELECT id, slug, title, kind, description, location, starts_at, ends_at, capacity, photo_url, created_at, created_by
|
||||||
|
FROM events;
|
||||||
|
|
||||||
|
DROP TABLE events;
|
||||||
|
ALTER TABLE events_new RENAME TO events;
|
||||||
|
|
||||||
|
CREATE INDEX idx_events_starts_at ON events(starts_at);
|
||||||
|
|
||||||
|
-- ── dispatches ────────────────────────────────────────────────────
|
||||||
|
CREATE TABLE dispatches (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
body TEXT NOT NULL,
|
||||||
|
excerpt TEXT,
|
||||||
|
kind TEXT NOT NULL DEFAULT 'note'
|
||||||
|
CHECK (kind IN ('decision','update','behind_the_scenes','note')),
|
||||||
|
author_id INTEGER NOT NULL REFERENCES users(id),
|
||||||
|
status TEXT NOT NULL DEFAULT 'draft'
|
||||||
|
CHECK (status IN ('draft','published','archived')),
|
||||||
|
published_at TEXT,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_dispatches_published ON dispatches(status, published_at);
|
||||||
|
CREATE INDEX idx_dispatches_author ON dispatches(author_id);
|
||||||
|
|
@ -41,6 +41,13 @@
|
||||||
--pigment-indigo: #5a6d83;
|
--pigment-indigo: #5a6d83;
|
||||||
--pigment-heather: #8d7a85;
|
--pigment-heather: #8d7a85;
|
||||||
|
|
||||||
|
/* --- Phase 2: white card surfaces + deep ink accent --- */
|
||||||
|
--surface-card: #ffffff;
|
||||||
|
--surface-card-border: rgba(0, 0, 0, 0.08);
|
||||||
|
--ink: #2c3a52; /* deep indigo — membership card + event hero */
|
||||||
|
--ink-text: #e8e0d0; /* readable cream on --ink */
|
||||||
|
--ink-muted: #b8a989; /* muted label tone on --ink */
|
||||||
|
|
||||||
/* --- Semantic state mappings --- */
|
/* --- Semantic state mappings --- */
|
||||||
--color-success: var(--pigment-copper);
|
--color-success: var(--pigment-copper);
|
||||||
--color-warning: var(--pigment-ochre);
|
--color-warning: var(--pigment-ochre);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue