How do I add a new codegen entity model?
Table of Contents
Entity models drive C++ + SQL codegen. The current form is a literate
ores.<component>.<entity>.org file under the component's modeling/
directory; codegen discovers it from the modeling_dir manifest entry
by matching #+type: ores.codegen.entity in the frontmatter. The
shape is documented in the Codegen org-entity meta-model.
1. Question
How do I add a new codegen entity model?
2. Answer
2.1. Scaffold the file
projects/ores.compass/compass.sh add entity_org \ --slug <entity> --component <component> \ --description "<one-line description of the modelled entity>" \ --shape <shape>
--shape is the important part: pick the domain_entity shape that
matches the entity being commissioned —
simple-text-key (country-like), fk-scoped (book-like),
hierarchical-composite (party/counterparty-like), richest
(currency-like, every optional knob exercised), or timeseries
(market_observation-like, no presentation drawer). Each pre-populates the
scaffold's Flags/SQL/Presentation sections with that shape's knobs already
set correctly,
sampled from a real, proven-correct reference entity — omit --shape
only to get the old bare, unknobbed skeleton. Individual
--entity-<knob> flags (e.g. --entity-has-tenant-id false)
override any preset value. Anything a shape can't derive (actual
columns, foreign-key targets, display fields, …) is left as a
visible, one-line TODO in the output — never silently omitted. See
Codegen org-entity meta-model for the full knob catalogue behind each
shape.
The scaffold writes
projects/ores.<component>/modeling/ores.<component>.<entity>.org
with the required frontmatter (#+type: ores.codegen.entity and
friends) and the shape's knobbed sections (Flags, Primary key,
Natural keys, Columns, SQL, optionally Foreign keys=/=Insert
trigger, C++, optionally Presentation).
2.2. Fill in the model
Open the scaffolded file and resolve every TODO — the shape sets
knobs, not entity-specific facts like actual columns, foreign-key
targets, or display fields. The meta-model documents every required
property and the well-known block kinds (e.g. additional repository
declarations / implementations / includes) that custom methods attach
to via :implements <kind-UUID>. Once the model compiles and
generates cleanly, work through the post-generation checklist — the
fixed manual integration steps (registrar wiring, NATS event-relay
wiring, …) codegen does not and will not wire up for you.
2.3. Wire the component (first entity in a component only)
If projects/ores.<component>/modeling/ is the first org model in
this component, add a modeling_dir entry to the component's
COMPONENTS record in
projects/ores.codegen/src/codegen/manifest.py:
"<component>-cpp": Component( name="<component>-cpp", modeling_dir="projects/ores.<component>/modeling", ),
Existing components that already have modeling_dir set need no change
to add another entity.
2.4. Regenerate
./compass.sh codegen regenerate \
--component <component>-cpp --address ores.cpp
Codegen discovers models through modeling_dir alone: org files whose
#+type: says ores.codegen.entity.
3. Script
projects/ores.compass/compass.sh add entity_org — the scaffold
itself. The codegen template is
projects/ores.codegen/library/templates/doc_entity_org.org.mustache.
4. Tested by
The pilot entity ores.refdata.party under
projects/ores.refdata/modeling/. Regenerating refdata picks it
up via the modeling_dir entry and produces byte-identical output to
the legacy party_entity.org location.
5. Two things a new entity needs that the build does not enforce
Adding an entity to an existing component passes compass build, the model
drift check and every test, and can still miss the database. The schema parser
reports both of the problems below, and CI runs it with --strict, so either
one fails the pull request. Run it yourself first to see them before CI does:
python3 projects/ores.codegen/src/plantuml_er_parse_sql.py \ --create-dir projects/ores.sql/create --drop-dir projects/ores.sql/drop \ --output /tmp/er_model.json \ --ignore-file projects/ores.sql/utility/validation_ignore.txt --warn
On a clean tree it prints Warnings: 0. A deliberate exception goes in
projects/ores.sql/utility/validation_ignore.txt with its reason.
1. List the table in the component's create and drop aggregates (WIRE_001).
projects/ores.sql/create/<component>/<component>_create.sql is hand-written in
every component, not generated. It lists \ir ./... lines in dependency order,
with prose for each block. A new table is absent from a recreate until you add
it, and the recreate still reports success. Do the same in
projects/ores.sql/drop/<component>/drop_<component>.sql, children first, so
nothing is dropped while a reference holds.
2. Set :rls_tenant_isolation: true on a tenant-scoped entity (RLS_001).
Without the flag the table has a tenant_id and no row-level security policy,
so every tenant can read every other tenant's rows. Set it under * SQL /
** Flags, next to :tablename:.
6. See also
- Codegen org-entity meta-model — the spec the scaffold mirrors.
- Codegen entity — post-generation checklist — the manual wiring codegen doesn't do for you.
- How do I create a new entity? — the older JSON-based recipe (kept for components not yet migrated).