Schema Generation
Protean can generate standard JSON Schema (Draft 2020-12) documents for all data-carrying domain elements: aggregates, entities, value objects, commands, events, and projections.
Generated schemas are useful for:
- Contract testing — validate that payloads conform to expected shapes
- Schema registries — publish schemas to Confluent Schema Registry, AWS Glue, or similar
- OpenAPI integration — JSON Schema Draft 2020-12 is natively supported by OpenAPI 3.1
- Documentation — auto-generate API docs from schema definitions
- Code generation — generate client SDKs in other languages from schemas
Generating schemas
Use the protean schema generate command to produce JSON Schema files for
every data-carrying element in your domain.
From a live domain
protean schema generate --domain=my_app.domain
This loads the domain, builds the IR, and writes schemas to .protean/schemas/.
From an IR file
protean schema generate --ir=domain-ir.json
If you already have a serialized IR (from protean ir show), you can generate
schemas directly from it.
Custom output directory
protean schema generate --domain=my_app.domain --output=build
Inspecting a single schema
Use protean schema show to print the JSON Schema for a specific element:
# By short name
protean schema show OrderPlaced --domain=my_app.domain
# By fully qualified name
protean schema show my_app.ordering.OrderPlaced --domain=my_app.domain
# Raw JSON for piping
protean schema show OrderPlaced --domain=my_app.domain --raw | jq .
If multiple elements share the same short name, the command lists all matching FQNs and asks you to disambiguate.
Output structure
Schemas are organized by aggregate cluster:
.protean/
├── ir.json
└── schemas/
├── Order/
│ ├── aggregates/
│ │ └── Order.v1.json
│ ├── commands/
│ │ └── PlaceOrder.v1.json
│ ├── entities/
│ │ └── LineItem.v1.json
│ ├── events/
│ │ └── OrderPlaced.v2.json
│ └── value_objects/
│ └── Money.v1.json
└── projections/
└── OrderDashboard.v1.json
Filenames include the element version (v1, v2, etc.) for events and
commands. Other element types default to v1.
Schema structure
Each generated schema is a standard JSON Schema object with Protean-specific
metadata in x-protean-* extension fields:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "OrderPlaced",
"type": "object",
"properties": {
"order_id": { "type": "string" },
"customer_name": { "type": "string" },
"total": { "type": "number" }
},
"required": ["customer_name", "order_id", "total"],
"x-protean-element-type": "event",
"x-protean-fqn": "my_app.ordering.OrderPlaced",
"x-protean-aggregate": "my_app.ordering.Order",
"x-protean-version": 1,
"x-protean-type": "Ordering.OrderPlaced.v1"
}
Extension fields
| Field | Description |
|---|---|
x-protean-element-type |
Element kind: aggregate, entity, value_object, command, event, projection |
x-protean-fqn |
Fully qualified name in the domain |
x-protean-aggregate |
FQN of the owning aggregate |
x-protean-version |
Event/command version number |
x-protean-type |
Message type string |
x-protean-published |
true if the event is part of the published contract |
x-protean-is-fact-event |
true if auto-generated from aggregate changes |
x-protean-auto-generated |
true if generated by the framework |
x-protean-identity-field |
Identity field name (aggregates only) |
x-protean-is-event-sourced |
true if the aggregate uses event sourcing |
Nested structures
Value objects and entities referenced by an aggregate are resolved as $defs
with $ref pointers:
{
"properties": {
"shipping_address": { "$ref": "#/$defs/ShippingAddress" }
},
"$defs": {
"ShippingAddress": {
"type": "object",
"properties": {
"street": { "type": "string", "maxLength": 255 },
"city": { "type": "string", "maxLength": 100 }
},
"required": ["city", "street"]
}
}
}
Optional fields
Optional fields use the anyOf pattern with null:
{
"total": {
"anyOf": [
{ "type": "number", "minimum": 0.0 },
{ "type": "null" }
]
}
}
Validating payloads
Generated schemas work with any JSON Schema validator. For example, using
Python's jsonschema library:
import json
import jsonschema
with open(".protean/schemas/Order/events/OrderPlaced.v1.json") as f:
schema = json.load(f)
payload = {
"order_id": "order-123",
"customer_name": "Alice",
"total": 99.99,
}
jsonschema.validate(payload, schema) # Passes