Slice 1: scaffolding + propose-to-super-draft vertical
Brings the §1 bot wrapper, the §4 cache (webhook + reconciler), the §5 schema (six numbered migrations), Gitea OAuth + §6 user provisioning, the §7 catalog left pane, and the propose-to-merge vertical: propose modal opens an idea PR against the meta repo, an owner merges from the pending-idea view, the cache picks it up via webhook or reconciler sweep, and the catalog renders the new super-draft. Per §1 the bot is the only Git writer; every commit, branch creation, and PR merge carries the §6.5 On-behalf-of: trailer and an `actions` audit row. Per §4 the cache is never written from a user action — it's webhook+reconciler only. Covered by `backend/tests/test_propose_vertical.py` against an in-process Gitea simulator. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
-- §5 / §6: users, permission events, and audit log.
|
||||
--
|
||||
-- The users table is the app-owned canonical account record. Per §6.1,
|
||||
-- role is one of owner / admin / contributor; anonymous is the absence
|
||||
-- of a row (or the absence of a session). The §6.2 app-wide write-mute
|
||||
-- lives here as `muted`, structurally distinct from the §15.6 per-RFC
|
||||
-- mute (on watches) and the §15.8 per-user mute (notification_user_mutes).
|
||||
--
|
||||
-- Per §15, the per-user notification preferences are inlined for
|
||||
-- proximity. The watched-RFC-churn category has no column per §15.4 —
|
||||
-- it is permanently off and surfaces in settings as a disabled toggle.
|
||||
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
gitea_id INTEGER UNIQUE NOT NULL,
|
||||
gitea_login TEXT UNIQUE NOT NULL,
|
||||
email TEXT,
|
||||
display_name TEXT NOT NULL,
|
||||
avatar_url TEXT,
|
||||
role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'contributor')),
|
||||
muted INTEGER NOT NULL DEFAULT 0, -- §6.2 app-wide write-mute
|
||||
email_personal_direct INTEGER NOT NULL DEFAULT 1, -- §15.4 default on
|
||||
email_watched_structural INTEGER NOT NULL DEFAULT 0, -- §15.4 default off
|
||||
email_admin_actionable INTEGER NOT NULL DEFAULT 1, -- §15.4 default on for admins/owners; ignored for contributors
|
||||
digest_cadence TEXT NOT NULL DEFAULT 'weekly' CHECK (digest_cadence IN ('off', 'weekly', 'daily')), -- §15.5
|
||||
notification_quiet_hours_start TEXT, -- §15.8 ISO-8601 local time HH:MM
|
||||
notification_quiet_hours_end TEXT,
|
||||
notification_quiet_hours_timezone TEXT, -- IANA tz name
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
last_seen_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_users_role ON users (role);
|
||||
|
||||
-- §6.5: permission-change audit. Append-only. Every mute, role grant,
|
||||
-- or capability override produces a row here.
|
||||
CREATE TABLE permission_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
actor_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
subject_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
event_kind TEXT NOT NULL, -- e.g. role_changed, muted, restored
|
||||
details TEXT, -- JSON blob with before/after, reason, etc.
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_permission_events_subject ON permission_events (subject_user_id, created_at);
|
||||
|
||||
-- §5: append-only action log. Every state transition, every graduation,
|
||||
-- every grant change. Includes the on-behalf-of trailer per §6.5 so the
|
||||
-- audit log and the Git log carry the same accountability.
|
||||
CREATE TABLE actions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
actor_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
on_behalf_of TEXT NOT NULL, -- the gitea_login the bot acted on behalf of
|
||||
action_kind TEXT NOT NULL, -- propose_rfc, merge_proposal, graduate, etc.
|
||||
rfc_slug TEXT,
|
||||
branch_name TEXT,
|
||||
pr_number INTEGER,
|
||||
bot_commit_sha TEXT,
|
||||
details TEXT, -- JSON blob with kind-specific extras
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX idx_actions_rfc ON actions (rfc_slug, created_at);
|
||||
CREATE INDEX idx_actions_actor ON actions (actor_user_id, created_at);
|
||||
Reference in New Issue
Block a user