This project implements a config-driven workflow engine using:
- FastAPI → API layer
- Temporal → workflow orchestration
- PostgreSQL → persistence
- SQLAlchemy → ORM
- JSON configs → dynamic workflow definitions
The goal is to define workflows (multi-step forms) dynamically via configuration, rather than hardcoding logic.
A workflow is defined in JSON and consists of:
- Steps (e.g. location → financial → identifiers)
- Fields per step (used by UI)
- Activity per step (writes to DB)
- Next step logic
┌──────────────┐
│ Frontend │
│ (Dynamic UI) │
└──────┬───────┘
│
│ HTTP
▼
┌─────────────────────┐
│ FastAPI API │
│ (routers + validation)
└──────┬──────────────┘
│
│ calls
▼
┌──────────────────────────┐
│ WorkflowRuntimeService │
│ (starts workflows) │
└──────┬───────────────────┘
│
│ Temporal Client
▼
┌──────────────────────────┐
│ Temporal Server │
│ (orchestration engine) │
└──────┬───────────────────┘
│
│ executes
▼
┌──────────────────────────┐
│ Temporal Worker │
│ (workflows + activities) │
└──────┬───────────────────┘
│
│ DB writes
▼
┌──────────────────────────┐
│ PostgreSQL DB │
│ (case_data + workflow) │
└──────────────────────────┘
1. POST /cases/start
→ loads JSON config
→ starts Temporal workflow
2. GET /cases/{case_id}/state
→ returns current step + fields
3. POST /cases/{case_id}/submit
→ API validates input
→ sends signal to workflow
→ workflow runs activity
→ data saved in DB
→ workflow moves to next step
-
Loads environment variables using
pydantic-settings -
Defines:
- database connection
- Temporal address
- schema names
-
SQLAlchemy setup
-
Creates:
- engine
- session
get_db()dependency for FastAPI
-
SQLAlchemy models for business data:
CaseLocationCaseFinancialCaseRegistrationOperator
-
These are populated during workflow execution
-
(Optional / future)
-
Can store workflow metadata:
- case lifecycle
- status tracking
- audit logs
- Defines the object passed into Temporal:
WorkflowRuntimeInputContains:
case_idworkflow_code- full workflow JSON config
- Loads workflow definitions from:
app/workflow_configs/workflows.json
-
Provides:
get_workflow(workflow_code)
- Starts Temporal workflows
- Bridges API → Temporal
Handles:
- loading config
- creating workflow input
- starting workflow execution
- Central definition of all workflows
Example:
{
"workflows": {
"private_lending_v1": {
"start_step": "location",
"steps": {
"location": {
"activity": "save_location_step",
"next": "financial",
"fields": [...]
}
}
}
}
}Drives:
- UI rendering
- validation
- workflow progression
- Temporal workflow definition
Responsibilities:
- holds workflow state
- tracks current step
- processes step submissions
- moves to next step
Key methods:
run()→ initialize workflowget_state()→ return UI schemasubmit_step()→ process step
- Contains business logic for each step
Each activity:
- receives
{ case_id, data } - writes to database
Examples:
save_location_stepsave_financial_stepsave_identifiers_step
- Runs Temporal worker
Registers:
- workflows
- activities
Executes:
- workflow logic
- DB operations
- Main workflow API
Endpoints:
- Starts a workflow instance
-
Returns:
- current step
- fields
- validation errors
- Validates input
- Signals workflow
- Advances step
- FastAPI entrypoint
- Registers routers
- Initializes DB
- required fields
- type validation
- returns HTTP 422
- safety validation
- ensures workflow integrity
docker compose up --buildServices:
physical-api→ FastAPIphysical-worker→ Temporal workertemporal→ Temporal servertemporal-ui→ http://localhost:8080physical-db→ PostgreSQL
-
Config-driven → workflows defined in JSON
-
Separation of concerns
- API = validation + routing
- Temporal = orchestration
- Activities = persistence
-
Extensible → add new workflows without code changes
-
UI-agnostic → frontend generated from backend config
- Field-level validation (min/max, enums)
- File upload steps
- Persist workflow state in DB
- Role-based workflows
- Multi-user collaboration
- UI auto-generation
This system is a dynamic workflow engine where:
- workflows are defined in JSON
- Temporal controls execution
- FastAPI validates inputs
- activities persist data
This allows flexible, scalable workflow design without hardcoding flows.
process for updating workflows
update config update models update schemas update seeding for lookups update routers lookups