System Architecture
Data Model
Key Services
Background Job System
- Frontend/planner calls
POST /tickets/{id}/run - Backend creates a
Jobrecord (QUEUED) and enqueues intojob_queuetable SQLiteWorkerpolls the queue, claims the task- Job runs in an isolated worktree, streams logs via in-memory broadcaster
- Job result triggers ticket state transition
Periodic Tasks
Async vs Sync Database
- FastAPI routes: Async SQLAlchemy via
database.get_db() - Background worker: Sync SQLAlchemy via
database_sync.get_sync_db() - Models are shared but sessions differ
- Use
db.expunge()before passing objects between contexts
Middleware
Idempotency
Atomic first-writer-wins via SQLite. Key includes(client_id, route, resource_scope, idempotency_key). Returns 409 Conflict for same key + different body.