1. Think in Blueprint
Blueprint separates what a domain means from how the platform executes it.
The authoring language is the direct Dart DSL. Canonical definition JSON, database DDL, protocol manifests, effective UI, and conformance artifacts are derived from it; none is a parallel authored source of truth.
| 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:
The 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 and UI 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:
The first complete blueprint
A small blueprint can contain one module and one entity:
final Entity areaEntity = Entity(
name: 'area',
title: 'Area',
pluralTitle: 'Areas',
db: const EntityDb(tableName: 'areas'),
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.single is a convenience. A real portfolio commonly declares multiple modules explicitly.
The module name is the semantic namespace. Its Postgres schema and default table names are derived through DbNamingStrategy unless ModuleDb or EntityDb declares an exceptional physical override. Protocol references do not change when physical storage naming changes.
Names are contracts
Use separate names for separate purposes:
name: stable machine identifier, normally snake case;title/pluralTitle: human labels;- the entity type,
<module>.<name>such asops.area, is globally stable; db.tableName: physical storage identity, when it differs from the derived plural;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.
Design principles: Why Blueprint.