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

@@ -24,8 +24,28 @@ type Condition struct {
// StageConfig holds non-routing config from stage_config JSON.
type StageConfig struct {
AutoAssign string `json:"auto_assign,omitempty"`
OnAdvance *OnAdvanceReference `json:"on_advance,omitempty"`
AutoAssign string `json:"auto_assign,omitempty"`
RequiredRole string `json:"required_role,omitempty"`
Validation *ValidationConfig `json:"validation,omitempty"`
OnAdvance *OnAdvanceReference `json:"on_advance,omitempty"`
}
// ValidationConfig defines multi-party sign-off requirements for a stage.
type ValidationConfig struct {
RequiredApprovals int `json:"required_approvals"` // e.g. 2
RequiredRole string `json:"required_role,omitempty"` // role needed to sign off
RejectAction string `json:"reject_action,omitempty"` // "cancel" | stage name
}
// ParseStageConfig unmarshals a stage_config JSON blob into StageConfig.
// Returns zero-value StageConfig on empty/invalid input.
func ParseStageConfig(raw json.RawMessage) StageConfig {
var sc StageConfig
if len(raw) == 0 || string(raw) == "{}" || string(raw) == "null" {
return sc
}
_ = json.Unmarshal(raw, &sc)
return sc
}
// OnAdvanceReference points to a Starlark hook for on_advance processing.