Sketch aggregates, events, and bounded contexts. In Protean that model is the architecture, and everything else, the API, the docs, the contracts, is derived from it.
@domain.aggregate class Order: customer_id: Identifier(required=True) status: String(max_length=20, default="draft") items = HasMany("OrderItem") @invariant.post def must_have_items_when_placed(self): if self.status != "draft" and not self.items: raise ValidationError(...) # rejected at construction. invalid state cannot exist. Order(customer_id="c-1", status="confirmed") ValidationError: Order must have at least one item
All four come from one idea: the model is the source of truth, trustworthy enough to build everything else on.
Protean parses your model into a machine-readable Intermediate Representation. Docs, API specs, and contracts are derived from it, so they cannot drift from the code.
Domain objects are always valid, or they do not exist. Four layers of validation run on every change, and the structure is checked before the first request.
Start with plain domain-driven design. Add CQRS or event sourcing for one aggregate at a time, in the same codebase, with no rewrite.
Your domain knows nothing about databases, brokers, or caches. You swap them in configuration, and the model, the tests, and the rules stay untouched.
A real Protean domain, running on Pyodide in this page. Press check and Protean reads the design back: what each aggregate enforces, what it is missing, why it matters, and how to fix it. The code is editable, and nothing leaves your browser.
Order has no pre/post invariants (own or
inherited); it enforces no business rules and may be an anemic data holder.@invariant.pre or
@invariant.post methods expressing the business rules the aggregate must
always satisfy, or reconsider whether this concept is an aggregate at all.Order has no command handler, no write
path existsFirst check downloads the Python runtime, about 8 MB over the wire, then it is cached by the browser.
Add a field to an Order in most stacks and you touch it in nine places: the model, the migration, the schema, the spec, the client types, the docs, the fixtures, the event, the version.
In Protean you touch the model. Everything else follows from it, so nothing drifts from the drawing.
Your domain model does not change. Protean moves the seams, from in-process calls to a message broker, through configuration, so the deployment shape becomes a setting you choose.
Every external concern sits behind a port. Choose an adapter, or write one, and Protean wires it into your domain.
One source of truth, an always-valid domain, and why both matter more now that machines write the code.
Built for backend systems whose hard part is the business rules and the states things move through. It is the wrong fit for raw speed, very high data volume, or table-first apps. Is Protean for you?
About twenty minutes from install to a running, event-driven domain, with no infrastructure decisions to make first.