Feat v0.3.0 workflow schema (#14)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m23s
CI/CD / test-sqlite (push) Successful in 2m42s
CI/CD / build-and-deploy (push) Successful in 1m28s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #14.
This commit is contained in:
2026-03-27 17:52:29 +00:00
committed by xcaliber
parent 8580e1d93e
commit 965885a8f7
16 changed files with 414 additions and 161 deletions

View File

@@ -214,27 +214,39 @@ func (s *WorkflowStore) queryWorkflows(ctx context.Context, q string, args ...in
func (s *WorkflowStore) CreateStage(ctx context.Context, st *models.WorkflowStage) error {
formTpl := jsonOrEmpty(st.FormTemplate)
transRules := jsonOrEmpty(st.TransitionRules)
stageConfig := jsonOrEmpty(st.StageConfig)
branchRules := jsonOrEmpty(st.BranchRules)
stageMode := st.StageMode
if stageMode == "" {
stageMode = models.StageModeCustom
stageMode = models.StageModeForm
}
audience := st.Audience
if audience == "" {
audience = models.AudienceTeam
}
stageType := st.StageType
if stageType == "" {
stageType = models.StageTypeSimple
}
return DB.QueryRowContext(ctx, `
INSERT INTO workflow_stages (workflow_id, ordinal, name, persona_id, assignment_team_id,
form_template, stage_mode, history_mode, auto_transition, transition_rules,
INSERT INTO workflow_stages (workflow_id, ordinal, name, assignment_team_id,
form_template, stage_mode, audience, stage_type,
auto_transition, stage_config, branch_rules, starlark_hook,
surface_pkg_id, sla_seconds)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING id, created_at`,
st.WorkflowID, st.Ordinal, st.Name, st.PersonaID, st.AssignmentTeamID,
formTpl, stageMode, st.HistoryMode, st.AutoTransition, transRules, st.SurfacePkgID,
st.SLASeconds,
st.WorkflowID, st.Ordinal, st.Name, st.AssignmentTeamID,
formTpl, stageMode, audience, stageType,
st.AutoTransition, stageConfig, branchRules, st.StarlarkHook,
st.SurfacePkgID, st.SLASeconds,
).Scan(&st.ID, &st.CreatedAt)
}
func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]models.WorkflowStage, error) {
rows, err := DB.QueryContext(ctx, `
SELECT id, workflow_id, ordinal, name, persona_id, assignment_team_id,
form_template, stage_mode, history_mode, auto_transition, transition_rules,
SELECT id, workflow_id, ordinal, name, assignment_team_id,
form_template, stage_mode, audience, stage_type,
auto_transition, stage_config, branch_rules, starlark_hook,
surface_pkg_id, sla_seconds, created_at
FROM workflow_stages WHERE workflow_id = $1
ORDER BY ordinal ASC`, workflowID)
@@ -245,15 +257,16 @@ func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]mo
var result []models.WorkflowStage
for rows.Next() {
var st models.WorkflowStage
var formTpl, transRules []byte
var formTpl, stageConfig, branchRules []byte
if err := rows.Scan(&st.ID, &st.WorkflowID, &st.Ordinal, &st.Name,
&st.PersonaID, &st.AssignmentTeamID, &formTpl, &st.StageMode,
&st.HistoryMode, &st.AutoTransition, &transRules,
&st.AssignmentTeamID, &formTpl, &st.StageMode, &st.Audience, &st.StageType,
&st.AutoTransition, &stageConfig, &branchRules, &st.StarlarkHook,
&st.SurfacePkgID, &st.SLASeconds, &st.CreatedAt); err != nil {
return nil, err
}
st.FormTemplate = formTpl
st.TransitionRules = transRules
st.StageConfig = stageConfig
st.BranchRules = branchRules
result = append(result, st)
}
return result, rows.Err()
@@ -261,20 +274,31 @@ func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]mo
func (s *WorkflowStore) UpdateStage(ctx context.Context, st *models.WorkflowStage) error {
formTpl := jsonOrEmpty(st.FormTemplate)
transRules := jsonOrEmpty(st.TransitionRules)
stageConfig := jsonOrEmpty(st.StageConfig)
branchRules := jsonOrEmpty(st.BranchRules)
stageMode := st.StageMode
if stageMode == "" {
stageMode = models.StageModeCustom
stageMode = models.StageModeForm
}
audience := st.Audience
if audience == "" {
audience = models.AudienceTeam
}
stageType := st.StageType
if stageType == "" {
stageType = models.StageTypeSimple
}
_, err := DB.ExecContext(ctx, `
UPDATE workflow_stages
SET ordinal = $2, name = $3, persona_id = $4, assignment_team_id = $5,
form_template = $6, stage_mode = $7, history_mode = $8, auto_transition = $9,
transition_rules = $10, surface_pkg_id = $11, sla_seconds = $12
SET ordinal = $2, name = $3, assignment_team_id = $4,
form_template = $5, stage_mode = $6, audience = $7, stage_type = $8,
auto_transition = $9, stage_config = $10, branch_rules = $11, starlark_hook = $12,
surface_pkg_id = $13, sla_seconds = $14
WHERE id = $1`,
st.ID, st.Ordinal, st.Name, st.PersonaID, st.AssignmentTeamID,
formTpl, stageMode, st.HistoryMode, st.AutoTransition, transRules, st.SurfacePkgID,
st.SLASeconds)
st.ID, st.Ordinal, st.Name, st.AssignmentTeamID,
formTpl, stageMode, audience, stageType,
st.AutoTransition, stageConfig, branchRules, st.StarlarkHook,
st.SurfacePkgID, st.SLASeconds)
return err
}

View File

@@ -152,26 +152,38 @@ func (s *WorkflowStore) CreateStage(ctx context.Context, st *models.WorkflowStag
st.ID = store.NewID()
st.CreatedAt = time.Now().UTC()
formTpl := jsonOrEmpty(st.FormTemplate)
transRules := jsonOrEmpty(st.TransitionRules)
stageConfig := jsonOrEmpty(st.StageConfig)
branchRules := jsonOrEmpty(st.BranchRules)
stageMode := st.StageMode
if stageMode == "" {
stageMode = models.StageModeCustom
stageMode = models.StageModeForm
}
audience := st.Audience
if audience == "" {
audience = models.AudienceTeam
}
stageType := st.StageType
if stageType == "" {
stageType = models.StageTypeSimple
}
_, err := DB.ExecContext(ctx, `
INSERT INTO workflow_stages (id, workflow_id, ordinal, name, persona_id, assignment_team_id,
form_template, stage_mode, history_mode, auto_transition, transition_rules,
INSERT INTO workflow_stages (id, workflow_id, ordinal, name, assignment_team_id,
form_template, stage_mode, audience, stage_type,
auto_transition, stage_config, branch_rules, starlark_hook,
surface_pkg_id, sla_seconds, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
st.ID, st.WorkflowID, st.Ordinal, st.Name, st.PersonaID, st.AssignmentTeamID,
formTpl, stageMode, st.HistoryMode, boolToInt(st.AutoTransition), transRules,
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
st.ID, st.WorkflowID, st.Ordinal, st.Name, st.AssignmentTeamID,
formTpl, stageMode, audience, stageType,
boolToInt(st.AutoTransition), stageConfig, branchRules, st.StarlarkHook,
st.SurfacePkgID, st.SLASeconds, st.CreatedAt.Format(time.RFC3339))
return err
}
func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]models.WorkflowStage, error) {
rows, err := DB.QueryContext(ctx, `
SELECT id, workflow_id, ordinal, name, persona_id, assignment_team_id,
form_template, stage_mode, history_mode, auto_transition, transition_rules,
SELECT id, workflow_id, ordinal, name, assignment_team_id,
form_template, stage_mode, audience, stage_type,
auto_transition, stage_config, branch_rules, starlark_hook,
surface_pkg_id, sla_seconds, created_at
FROM workflow_stages WHERE workflow_id = ?
ORDER BY ordinal ASC`, workflowID)
@@ -182,16 +194,17 @@ func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]mo
var result []models.WorkflowStage
for rows.Next() {
var stg models.WorkflowStage
var formTpl, transRules string
var formTpl, stageConfig, branchRules string
var autoTrans int
if err := rows.Scan(&stg.ID, &stg.WorkflowID, &stg.Ordinal, &stg.Name,
&stg.PersonaID, &stg.AssignmentTeamID, &formTpl, &stg.StageMode,
&stg.HistoryMode, &autoTrans, &transRules,
&stg.AssignmentTeamID, &formTpl, &stg.StageMode, &stg.Audience, &stg.StageType,
&autoTrans, &stageConfig, &branchRules, &stg.StarlarkHook,
&stg.SurfacePkgID, &stg.SLASeconds, st(&stg.CreatedAt)); err != nil {
return nil, err
}
stg.FormTemplate = json.RawMessage(formTpl)
stg.TransitionRules = json.RawMessage(transRules)
stg.StageConfig = json.RawMessage(stageConfig)
stg.BranchRules = json.RawMessage(branchRules)
stg.AutoTransition = autoTrans != 0
result = append(result, stg)
}
@@ -200,19 +213,30 @@ func (s *WorkflowStore) ListStages(ctx context.Context, workflowID string) ([]mo
func (s *WorkflowStore) UpdateStage(ctx context.Context, st *models.WorkflowStage) error {
formTpl := jsonOrEmpty(st.FormTemplate)
transRules := jsonOrEmpty(st.TransitionRules)
stageConfig := jsonOrEmpty(st.StageConfig)
branchRules := jsonOrEmpty(st.BranchRules)
stageMode := st.StageMode
if stageMode == "" {
stageMode = models.StageModeCustom
stageMode = models.StageModeForm
}
audience := st.Audience
if audience == "" {
audience = models.AudienceTeam
}
stageType := st.StageType
if stageType == "" {
stageType = models.StageTypeSimple
}
_, err := DB.ExecContext(ctx, `
UPDATE workflow_stages
SET ordinal = ?, name = ?, persona_id = ?, assignment_team_id = ?,
form_template = ?, stage_mode = ?, history_mode = ?, auto_transition = ?,
transition_rules = ?, surface_pkg_id = ?, sla_seconds = ?
SET ordinal = ?, name = ?, assignment_team_id = ?,
form_template = ?, stage_mode = ?, audience = ?, stage_type = ?,
auto_transition = ?, stage_config = ?, branch_rules = ?, starlark_hook = ?,
surface_pkg_id = ?, sla_seconds = ?
WHERE id = ?`,
st.Ordinal, st.Name, st.PersonaID, st.AssignmentTeamID,
formTpl, stageMode, st.HistoryMode, boolToInt(st.AutoTransition), transRules,
st.Ordinal, st.Name, st.AssignmentTeamID,
formTpl, stageMode, audience, stageType,
boolToInt(st.AutoTransition), stageConfig, branchRules, st.StarlarkHook,
st.SurfacePkgID, st.SLASeconds, st.ID)
return err
}