Explicit use cases
Every business action becomes a first-class unit with a typed command, a clear execution path, and a typed result.
Your API layer is standardized. Your data layer is standardized. Your service layer is still where the chaos lives.
UseCaseCore gives business actions one explicit, typed, transactional execution model — across validation, state loading, policy checks, transitions, audit, idempotency, events, and side effects.
FastAPI ↓ Command model ↓ UseCaseCore ↓ Repositories / Session ↓ SQLModel / SQLAlchemy ↓ Postgres Alembic evolves schema
UseCaseCore does not replace your API framework, ORM, database, or workflow tools. It standardizes the execution boundary where business actions actually happen.
Every business action becomes a first-class unit with a typed command, a clear execution path, and a typed result.
Authoritative changes happen inside a visible transaction boundary, not across scattered helpers and side effects.
Retries stay safe. The same action can be handled once without duplicating writes or downstream effects.
Every state-changing action can leave a structured trace of who did what, when, and why.
Emit domain events and queue side effects consistently after truth has been updated.
Plug in policy engines, state machines, workflows, queues, and event buses without changing the core use-case model.
Every use case follows the same operational grammar. That makes the system easier to understand, easier to test, and easier to evolve.
Validated input arrives as a typed command from an API, job, or internal caller.
Repositories load the exact state the action depends on, including locking when needed.
Authorization, lifecycle rules, and domain conditions are evaluated in one place.
Authoritative writes happen inside a visible transaction boundary with commit or rollback.
Write audit, emit events, and queue follow-up jobs after truth has been updated.
A move looks trivial at the UI level. In reality it needs validation, current-state reads, permission checks, transaction boundaries, audit, and safe side effects.
| Flow | What actually happens |
|---|---|
| MoveInventoryCommand | Intent enters the system as a typed command instead of becoming route glue. |
| Load source + destination balances | Repositories fetch current state, including locking and consistency rules where needed. |
| Check permission + invariants | Policy, state transition rules, and domain conditions are enforced in one boundary. |
| Open transaction | Apply authoritative balance changes, write movement history, then commit or rollback. |
| Write audit + emit events + queue jobs | Side effects become explicit and repeatable instead of being mixed into handler code. |
| MoveInventoryResult | The action returns a typed result instead of an ad hoc response assembled on the fly. |
UseCaseCore is not a replacement for FastAPI, SQLModel, SQLAlchemy, Postgres, or Alembic. It is the runtime layer between validated input and committed writes.
class UseCase: def execute(self, command): self.validate(command) self.check_idempotency(command) state = self.load_state(command) self.check_policies(command, state) self.check_transitions(command, state) with self.transaction(): result = self.apply(command, state) self.write_audit(command, state, result) self.emit_events(command, state, result) self.enqueue_jobs(command, state, result) return result
Keep the use case as the center of execution while exposing clean integration surfaces for policies, transitions, workflows, events, and job systems.
Receive validated commands from routes and dependency-injected services.
Use typed models naturally without collapsing business actions into table definitions.
Keep direct control over sessions, transactions, queries, and locking.
Preserve the database as the authoritative store of truth.
Schema evolution stays independent while runtime behavior becomes standardized.
Plug in policy and authorization logic without leaking it across routes and helpers.
Handle lifecycle-heavy domains with explicit transition adapters.
Bridge long-running orchestration into the same application action model.
The missing standard is not another ORM, API framework, or queue. It is the layer that turns intent into safe, explicit, committed business actions.
| Concern | Typical Python app | With UseCaseCore |
|---|---|---|
| Business action boundaries | ScatteredRoutes, helpers, model methods, jobs, and one-off service code | ExplicitEach action has one typed command, one execution boundary, one result |
| Transaction semantics | InconsistentOften mixed with side effects or hidden inside utility layers | IntentionalCommit / rollback behavior is explicit and reusable |
| Auditability | Bolted onAdded later, partial, or easy to forget | Built inActor, request, and state-change context become first-class |
| Idempotency | Custom every timeOften absent or inconsistent across endpoints and jobs | StandardizedRetries and duplicate handling follow one predictable pattern |
| Policy / workflow integration | LeakyFramework-specific logic bleeds into unrelated app code | Adapter-basedPlug in policy, transition, queue, and workflow tools cleanly |
The fastest path to value is not more framework theory. It is one concrete business action implemented correctly with a reusable execution shape.
Commands, results, repositories, transactions, audit hooks, idempotency, and adapters.
Start with something real like MoveInventory, ReserveInventory, or CreateOrder.
Add policy engines, transitions, queues, or workflows only when the domain actually justifies them.
Make business actions explicit, transactional, auditable, idempotent, and integration-friendly — without replacing the stack you already trust.