feat(api): approvals + ECO workflow API with YAML-configurable workflows
- Add internal/workflow/ package for YAML workflow definitions (Load, LoadAll, Validate)
- Add internal/db/item_approvals.go repository (Create, AddSignature, GetWithSignatures, ListByItemWithSignatures, UpdateState, UpdateSignature)
- Add internal/api/approval_handlers.go with 4 endpoints:
- GET /{partNumber}/approvals (list approvals with signatures)
- POST /{partNumber}/approvals (create ECO with workflow + signers)
- POST /{partNumber}/approvals/{id}/sign (approve or reject)
- GET /workflows (list available workflow definitions)
- Rule-driven state transitions: any_reject and all_required_approve
- Pack approvals into silo/approvals.json on .kc checkout
- Add WorkflowsConfig to config, load workflows at startup
- Migration 019: add workflow_name column to item_approvals
- Example workflows: engineering-change.yaml, quick-review.yaml
- 7 workflow tests, all passing
Closes #145
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/kindredsystems/silo/internal/modules"
|
||||
"github.com/kindredsystems/silo/internal/schema"
|
||||
"github.com/kindredsystems/silo/internal/storage"
|
||||
"github.com/kindredsystems/silo/internal/workflow"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
@@ -235,6 +236,19 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Load approval workflow definitions (optional — directory may not exist yet)
|
||||
var workflows map[string]*workflow.Workflow
|
||||
if _, err := os.Stat(cfg.Workflows.Directory); err == nil {
|
||||
workflows, err = workflow.LoadAll(cfg.Workflows.Directory)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Str("directory", cfg.Workflows.Directory).Msg("failed to load workflow definitions")
|
||||
}
|
||||
logger.Info().Int("count", len(workflows)).Msg("loaded workflow definitions")
|
||||
} else {
|
||||
workflows = make(map[string]*workflow.Workflow)
|
||||
logger.Info().Str("directory", cfg.Workflows.Directory).Msg("workflows directory not found, skipping")
|
||||
}
|
||||
|
||||
// Initialize module registry
|
||||
registry := modules.NewRegistry()
|
||||
if err := modules.LoadState(registry, cfg, database.Pool()); err != nil {
|
||||
@@ -258,7 +272,7 @@ func main() {
|
||||
// Create API server
|
||||
server := api.NewServer(logger, database, schemas, cfg.Schemas.Directory, store,
|
||||
authService, sessionManager, oidcBackend, &cfg.Auth, broker, serverState,
|
||||
jobDefs, cfg.Jobs.Directory, registry, cfg)
|
||||
jobDefs, cfg.Jobs.Directory, registry, cfg, workflows)
|
||||
router := api.NewRouter(server, logger)
|
||||
|
||||
// Start background sweepers for job/runner timeouts (only when jobs module enabled)
|
||||
|
||||
Reference in New Issue
Block a user