PlantUML ER diagram conventions

Table of Contents

ER diagrams document the live SQL schema — every table, its columns, and the foreign-key relationships between them. The doc-add-er-diagram skill drives the authoring; this doc captures how the diagram looks. The schema lives in ores.sql. Return to Knowledge.

File location

Generation pipeline

The ER diagram is generated, not hand-written. It's the canonical example in the project of the automated codegen route (see MASD for the routes architecture): codegen parses already-generated artefacts, derives a model from them, and renders new artefacts from that model.

The pipeline has three stages, all driven by projects/ores.codegen/plantuml_er_generate.sh:

Stage Reads Tool Writes
Parse projects/ores.sql/create/**/*.sql projects/ores.codegen/src/plantuml_er_parse_sql.py build/output/codegen/plantuml_er_model.json
Render the intermediate JSON + a mustache template projects/ores.codegen/src/plantuml_er_generate.py (pystache) projects/ores.sql/modeling/ores_schema.puml
Diagram the .puml PlantUML (system plantuml, or plantuml.jar) <code>projects/ores.sql/modeling/ores_schema.png</code>

The intermediate model file is not committed and not literate. It lives under build/output/ (gitignored) because it is regenerated on every run and carries no information a human is expected to read or edit. The format is JSON for the same reason: a generated artefact doesn't benefit from org-mode literate prose, drawers, or block-paste mechanisms — those are reserved for the authored models humans maintain (under each component's modeling/ directory).

The .puml and .png are committed because reviewers and readers benefit from seeing schema-shape diffs in PRs and viewing the diagram without rebuilding.

Skeleton

' GPL header
@startuml

title ORES Database Schema
hide circle
skinparam linetype ortho

' <<< BODY GOES HERE >>>

' Local Variables:
' compile-command: "java -Djava.awt.headless=true -DPLANTUML_SECURITY_PROFILE=UNSECURE -DPLANTUML_LIMIT_SIZE=65535 -jar /usr/share/plantuml/plantuml.jar ores_schema.puml"
' End:
@enduml

Entity styling

Use the entity keyword with the appropriate stereotype:

Stereotype Colour When
<<temporal>> #C6F0D8 Tables with valid_from / valid_to columns.
<<junction>> #ECECEC Many-to-many association tables.
(none) #F7E5FF Current-state tables without temporal support.

Example:

entity accounts <<temporal>> #C6F0D8 {
    * id : uuid <<PK>>
    --
    * username : text <<unique>>
    * email : text <<unique>>
    * valid_from : timestamptz
    * valid_to : timestamptz
}

Field notation

  • * prefix marks NOT NULL fields.
  • <<PK>> for primary keys, <<FK>> for foreign keys, <<unique>> for unique constraints.
  • A -- separator divides the primary key block from the rest of the columns.

Domain packages

Group related entities into packages by domain:

Domain Colour
IAM (Identity & Access) #E8F4FD
RBAC (Role-Based Access Control) #FFF3E0
Assets (Images & Currencies) #F3E5F5
Variability (Feature Flags) #E8F5E9

A package looks like:

package "IAM (Identity & Access Management)" #E8F4FD {
    entity accounts <<temporal>> #C6F0D8 {
        ...
    }
}

Relationships

Standard ER cardinality:

Notation Meaning Example
\vert\vert--o{ One-to-many accounts \vert\vert--o{ sessions
\vert\vert--o\vert One-to-one accounts \vert\vert--o\vert login_info
Junction table Many-to-many Use a <<junction>> entity

Always label the arrow with descriptive text:

accounts ||--o{ sessions : "creates"
roles ||--o{ role_permissions : "has"

Notes

Add a note next to any entity that benefits from explanation:

note right of accounts
User accounts with authentication credentials.
Supports optimistic locking via the version field.
end note

Temporal conventions

ORE Studio uses bitemporal data management. Most tables have:

  • valid_from / valid_to — validity period (temporal support).
  • version — optimistic locking.
  • modified_by — audit trail.

Junction tables typically carry:

  • assigned_by — who created the association.
  • assigned_at — when the association was created.

Schema source

SQL schema lives at projects/ores.sql/create/. Two file kinds:

  • *_create.sql — table definitions with triggers.
  • *_notify_trigger.sql — PostgreSQL NOTIFY triggers for change events.

Read these to confirm:

  • Column types, constraints, primary key shape (incl. composite).
  • Indexes (incl. partial indexes for "current" records).
  • Temporal trigger presence.

Evaluation checklist

Check How
All tables represented Compare with projects/ores.sql/create/*_create.sql.
FK arrows correct Verify against the SQL REFERENCES clauses.
Proper stereotypes Temporal tables <<temporal>>, junctions <<junction>>.
Domain packages Related entities grouped logically.
Syntax valid cmake --build --target generate_ores_schema_diagram.

See also

Emacs 29.1 (Org mode 9.6.6)