-- libreDecision v3 — initial schema. Runtime data: never dropped, never rewritten. -- Dates are RFC 3339 UTC strings (sortable). CREATE TABLE identities ( id TEXT PRIMARY KEY, -- idty: | inv: | dev: kind TEXT NOT NULL, -- g1 | invite | dev display_name TEXT NOT NULL, address TEXT, -- SS58 seen at the last Ğ1 sign-in, display only g1_member INTEGER NOT NULL DEFAULT 0, admin INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, last_seen_at TEXT ); CREATE TABLE sessions ( token_hash TEXT PRIMARY KEY, identity_id TEXT NOT NULL REFERENCES identities(id), created_at TEXT NOT NULL, expires_at TEXT NOT NULL ); CREATE TABLE invitations ( token_hash TEXT PRIMARY KEY, label TEXT NOT NULL, admin INTEGER NOT NULL DEFAULT 0, groups TEXT NOT NULL DEFAULT '[]', -- JSON array of group slugs granted on acceptance created_by TEXT, created_at TEXT NOT NULL, expires_at TEXT NOT NULL, used_at TEXT, identity_id TEXT ); CREATE TABLE groups ( slug TEXT PRIMARY KEY, name TEXT NOT NULL, parent TEXT, policy TEXT NOT NULL, -- g1-members | managed hidden INTEGER NOT NULL DEFAULT 0, position INTEGER NOT NULL ); CREATE TABLE memberships ( group_slug TEXT NOT NULL REFERENCES groups(slug), identity_id TEXT NOT NULL REFERENCES identities(id), granted_by TEXT, granted_at TEXT NOT NULL, PRIMARY KEY (group_slug, identity_id) ); CREATE TABLE documents ( id TEXT PRIMARY KEY, group_slug TEXT NOT NULL REFERENCES groups(slug), slug TEXT NOT NULL, title TEXT NOT NULL, -- JSON {lang: text} summary TEXT NOT NULL, -- JSON {lang: text} source_lang TEXT NOT NULL, vote_floor REAL NOT NULL, -- C, minimal number of "for" votes publish_path TEXT, -- path in the texts repository; NULL = never published created_at TEXT NOT NULL, UNIQUE (group_slug, slug) ); CREATE TABLE units ( id TEXT PRIMARY KEY, doc_id TEXT NOT NULL REFERENCES documents(id), code TEXT NOT NULL, section TEXT, -- grouping key of the seed (introduction, technique…) position REAL NOT NULL, inertia TEXT NOT NULL, -- low | standard | high | max in_force_id TEXT, -- proposals.id of the version in force, NULL = empty slot created_at TEXT NOT NULL ); CREATE INDEX units_doc ON units(doc_id); -- A proposal is a version of a unit: proposed, in force, or past. CREATE TABLE proposals ( id TEXT PRIMARY KEY, unit_id TEXT NOT NULL REFERENCES units(id), kind TEXT NOT NULL, -- text | remove | inertia inertia_target TEXT, title TEXT NOT NULL, body TEXT NOT NULL, status TEXT NOT NULL, -- draft | open | in_force | superseded | withdrawn origin TEXT NOT NULL, -- seed | member label TEXT, author_id TEXT REFERENCES identities(id), revision INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, submitted_at TEXT, entered_at TEXT, -- entered into force by vote; NULL for a seed a minima left_at TEXT, confirmed_at TEXT -- a seed a minima that later reached its threshold ); CREATE INDEX proposals_unit ON proposals(unit_id); CREATE TABLE revisions ( id INTEGER PRIMARY KEY AUTOINCREMENT, proposal_id TEXT NOT NULL REFERENCES proposals(id), revision INTEGER NOT NULL, kind TEXT NOT NULL, -- initial | typo | substantive title TEXT NOT NULL, body TEXT NOT NULL, author_id TEXT, created_at TEXT NOT NULL ); CREATE INDEX revisions_proposal ON revisions(proposal_id); CREATE TABLE votes ( proposal_id TEXT NOT NULL REFERENCES proposals(id), identity_id TEXT NOT NULL REFERENCES identities(id), choice TEXT NOT NULL, -- for | against revision INTEGER NOT NULL, -- counted only while equal to proposals.revision cast_at TEXT NOT NULL, PRIMARY KEY (proposal_id, identity_id) ); CREATE TABLE signals ( id TEXT PRIMARY KEY, proposal_id TEXT NOT NULL REFERENCES proposals(id), target_proposal_id TEXT NOT NULL REFERENCES proposals(id), reason TEXT NOT NULL, author_id TEXT NOT NULL REFERENCES identities(id), created_at TEXT NOT NULL, lifted_at TEXT, lifted_by TEXT -- identity id, or 'revision' when the text changed ); CREATE TABLE translations ( proposal_id TEXT NOT NULL REFERENCES proposals(id), lang TEXT NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, source_hash TEXT NOT NULL, -- hash of the source title + body it translates origin TEXT NOT NULL, -- seed | member updated_by TEXT, updated_at TEXT NOT NULL, PRIMARY KEY (proposal_id, lang) ); CREATE TABLE adoptions ( id INTEGER PRIMARY KEY AUTOINCREMENT, proposal_id TEXT NOT NULL, unit_id TEXT NOT NULL, doc_id TEXT NOT NULL, kind TEXT NOT NULL, votes_for INTEGER NOT NULL, votes_against INTEGER NOT NULL, electorate INTEGER NOT NULL, required INTEGER NOT NULL, params TEXT NOT NULL, at TEXT NOT NULL ); CREATE TABLE outbox ( id INTEGER PRIMARY KEY AUTOINCREMENT, doc_id TEXT NOT NULL, reason TEXT NOT NULL, created_at TEXT NOT NULL, attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, next_at TEXT NOT NULL, done_at TEXT, commit_sha TEXT ); CREATE TABLE feedback ( id INTEGER PRIMARY KEY AUTOINCREMENT, identity_id TEXT, route TEXT NOT NULL, body TEXT NOT NULL, context TEXT, created_at TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'new' ); CREATE TABLE settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL );