Feat v0.3.4 team roles + multi-party validation (#18)

Custom team roles: removed CHECK constraint on team_members.role,
roles stored in teams.settings, roles API, stage_config.required_role
enforced on claim. Multi-party signoff: workflow_signoffs table,
validation gate in advanceInternal, SubmitSignoff engine method,
signoff HTTP API. Frontend: dynamic role management, stage config
validation UI, signoff panel. Design docs for extension lifecycle
and trigger composition. 20 store tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 00:22:04 +00:00
parent dba718b914
commit 748da6c2b4
22 changed files with 952 additions and 19 deletions

View File

@@ -22,8 +22,7 @@ CREATE TABLE IF NOT EXISTS team_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
team_id UUID NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role VARCHAR(20) NOT NULL DEFAULT 'member'
CHECK (role IN ('admin', 'member')),
role VARCHAR(50) NOT NULL DEFAULT 'member',
joined_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(team_id, user_id)
);

View File

@@ -131,3 +131,19 @@ CREATE INDEX IF NOT EXISTS idx_workflow_assignments_team_status
ON workflow_assignments(team_id, status);
CREATE INDEX IF NOT EXISTS idx_workflow_assignments_assigned
ON workflow_assignments(assigned_to) WHERE assigned_to IS NOT NULL;
-- ── Workflow Signoffs (v0.3.4) ────────────────
CREATE TABLE IF NOT EXISTS workflow_signoffs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
instance_id UUID NOT NULL REFERENCES workflow_instances(id) ON DELETE CASCADE,
stage TEXT NOT NULL,
user_id TEXT NOT NULL,
decision TEXT NOT NULL CHECK (decision IN ('approve', 'reject')),
comment TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(instance_id, stage, user_id)
);
CREATE INDEX IF NOT EXISTS idx_workflow_signoffs_instance_stage
ON workflow_signoffs(instance_id, stage);

View File

@@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS team_members (
id TEXT PRIMARY KEY,
team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('admin', 'member')),
role TEXT NOT NULL DEFAULT 'member',
joined_at TEXT DEFAULT (datetime('now')),
UNIQUE(team_id, user_id)
);

View File

@@ -120,3 +120,19 @@ CREATE INDEX IF NOT EXISTS idx_workflow_assignments_team_status
ON workflow_assignments(team_id, status);
CREATE INDEX IF NOT EXISTS idx_workflow_assignments_assigned
ON workflow_assignments(assigned_to);
-- ── Workflow Signoffs (v0.3.4) ────────────────
CREATE TABLE IF NOT EXISTS workflow_signoffs (
id TEXT PRIMARY KEY,
instance_id TEXT NOT NULL REFERENCES workflow_instances(id) ON DELETE CASCADE,
stage TEXT NOT NULL,
user_id TEXT NOT NULL,
decision TEXT NOT NULL CHECK (decision IN ('approve', 'reject')),
comment TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(instance_id, stage, user_id)
);
CREATE INDEX IF NOT EXISTS idx_workflow_signoffs_instance_stage
ON workflow_signoffs(instance_id, stage);