1. Think in Blueprint
Blueprint separates what a domain means from how the platform executes it.
| Concern | Owner | Example |
|---|---|---|
| Grammar | Blueprint packages | Field, Facet, Action, Rule, Evidence |
| Domain program | Product blueprint | ops.area, activate, Area Type |
| Configuration | Tenant/site data | grants, thresholds, bindings, assignments |
| Execution | Generic runtime | validate, plan, lock, commit, emit, record |
| Projection | Generic consumers | Postgres, API, UI, timelines, analytics |
This is similar to source code, a configured process, and an operating system:
language syntax
-> source program
-> linked/configured program
-> running process
-> durable execution historyThe three planes
Declaration
Stable, versioned intent:
- fields and relationships;
- facets and entities;
- actions, rules, lifecycles, and events;
- evidence and audit requirements;
- modules, exports, and extension references;
- DB, UI, and seed hints.
Configuration
Values that vary by customer, environment, tenant, site, or time:
- effective grants and qualifications;
- policy values and locks;
- assignments and calendars;
- evidence-source bindings;
- external-system bindings;
- licensed application availability.
Configuration is not copied into the declaration. The runtime resolves it into an effective view and snapshots every value that influences a decision.
Execution
The domain-neutral interpreter:
ActionRequest
-> resolve immutable Blueprint revision
-> resolve effective configuration
-> evaluate rules
-> plan writes, evidence, events, and effects
-> commit atomically
-> dispatch external work
-> retain an immutable recordThe first complete blueprint
A small blueprint can contain one module and one entity:
final Entity areaEntity = Entity(
name: 'area',
title: 'Area',
pluralTitle: 'Areas',
tableName: 'areas',
schema: 'ops',
schemaType: 'ops.area',
facets: const [
IdentityFacet(),
],
);
final Blueprint learningBlueprint = Blueprint.single(
name: 'learning_ops',
version: '0.1.0',
schema: 'ops',
entities: [areaEntity],
);This is intentionally incomplete as a useful domain model, but it demonstrates the nesting:
Blueprint
└── Module
└── Entity
└── FacetBlueprint.single is a convenience. A real portfolio commonly declares multiple modules explicitly.
Names are contracts
Use separate names for separate purposes:
name: stable machine identifier, normally snake case;title/pluralTitle: human labels;schemaType: globally stable entity type such asops.area;tableName: physical storage identity;i18nKey: optional localization namespace.
Never derive a user-facing label from a database column when a declared title exists. Never use a title as a stable protocol identity.
Checkpoint
Explain this sentence in your own words:
Blueprint is domain-agnostic, a domain blueprint is domain-specific, and the execution runtime becomes domain-agnostic again.
Then continue to Fields, types, and rows.