Press ESC to exit fullscreen
🏗️ Project ⏱️ 300 minutes

Capstone: A Complete Operational Ontology

Build an end-to-end logistics ontology: shipments, hubs, vehicles, drivers — with actions and live functions

The brief

You are joining Northwind Freight as the first engineer on a new ontology team. The company runs international shipments. Three systems hold relevant data:

  • A dispatch operational DB (CDC stream into Kafka).
  • An HR system (REST API) for driver identity.
  • A vehicle telemetry stream (Kafka).

You have two weeks to deliver the first version of an ontology. It must support:

  1. Operations dispatchers — assign drivers, mark delivery, reroute.
  2. Finance — pull lifetime customer value, revenue rollups.
  3. Drivers — see their assignments, mark delivery from the mobile app.
  4. An LLM-based routing assistant — read access only.

This capstone walks through the deliverable. Work through it; commit it to your fork; treat it as your portfolio piece.

Deliverables

By the end of the capstone you will have:

  1. A design document in docs/design/v0.1.md covering the domain.
  2. The schema — object types, link types, interfaces, enums.
  3. Datasource bindings for batch and stream sources.
  4. Action types for every state transition.
  5. Functions for derived properties and analytics.
  6. Policies for object-, property-, row-level access, and action permissions.
  7. A test suite covering every action and every row rule.
  8. A README with how-to-run instructions and a tour.
  9. Three operational scenarios demonstrating the ontology in use.

Phase 1 — Design (Day 1–2)

Open the canvas. Build the model on paper before writing code.

The domain you are modeling

A Customer places an Order.
An Order produces one or more Shipments.
A Shipment travels through one or more ShipmentLegs.
Each Leg has an origin Hub and a destination Hub.
Each Leg is carried by a Vehicle and operated by an Operator
  (Driver or Courier — an Interface).
Vehicles and Drivers are based at a home Hub.
Shipments have status; Legs have status; Orders have status.
Telemetry pings update the current location of Vehicles continuously.

Object types (target list)

TypeWhy it exists
CustomerThe paying party
BillingAccountMulti-account customers
OrderA customer request
OrderLineItemized contents
ShipmentOne physical movement
ShipmentLegOne hop within a shipment
HubPhysical sorting facility
DriverInternal operator
CourierExternal operator
VehicleTruck / van / plane / etc.

10 object types. The Operator interface bridges Driver and Courier.

Action types (target list)

ActionNotes
placeOrdercreation, idempotency-keyed
cancelOrderstate transition
createShipmentFromOrdercreation
planShipmentRoutesets legs
assignOperatorToLeguses Operator interface
unassignOperatorinverse
markLegDispatchedstate transition
markLegArrivedstate transition
markShipmentDeliveredterminal state
markShipmentExceptionterminal state
rerouteShipmentatomic re-plan
cancelShipmentterminal state

Functions (target list)

FunctionReturns
orderTotalUsdMoney(USD)
customerLifetimeValueMoney(USD)
customerActiveOrderCountint
shipmentEstimatedArrivalTimestamp
shipmentInTransitDurationHoursdouble
operatorActiveLegCountint
hubBacklogCountint
routeDistanceKmdouble

Spend at least an hour with this list. Pin it to your wall. The next phase is implementation.

Phase 2 — Schema and datasources (Day 3–5)

Implement what you designed in Phase 1, using the project layout from Lesson 11.

Suggested order:

  1. Enums (Region, OrderStatus, ShipmentStatus, LegStatus, EmployeeStatus).
  2. Interface (Operator, Locatable).
  3. Object types — bottom-up: Hub, then Vehicle, Driver, Courier, then Customer, Order, OrderLine, Shipment, ShipmentLeg.
  4. Link types — once both endpoints exist.
  5. Datasource YAMLs and CSV fixtures with ~10 rows per source.

Don’t worry about perfect data — focus on the shape. You should be able to run:

pnpm ontology validate
pnpm ontology query "Customer.byId('cust_acme').placedOrders.placedShipments.legs"

…and see a result by end of Phase 2.

Phase 3 — Actions and functions (Day 6–8)

Implement at least:

  • 5 actions from the target list (recommend placeOrder, markShipmentDelivered, assignOperatorToLeg, markLegArrived, rerouteShipment).
  • 4 functions from the target list.

Each action needs:

  • Typed parameters.
  • ≥2 validations.
  • Effects.
  • Emit at least one domain event.
  • A unit test for the golden path and at least one failure mode.

Each function needs:

  • Typed parameters and return.
  • A pure body when possible.
  • A unit test.

By end of Phase 3 you can demonstrate the ontology moving — actions transitioning state, functions computing derived values, the test suite green.

Phase 4 — Security and policies (Day 9)

Add policies/:

  • roles.yaml with at least: ops_dispatcher, ops_supervisor, finance, driver, agent_router, admin.
  • object-policies.yaml covering each object type.
  • action-policies.yaml covering each action.
  • markings.yaml with PII, Confidential.

Add row rules for the driver self-service case (drivers only see their own shipments and legs).

Write tests:

describe("policies", () => {
  it("a driver cannot read another driver's legs", async () => { ... });
  it("a driver cannot mark someone else's leg arrived", async () => { ... });
  it("ops_dispatcher in EU cannot see NA-only customers", async () => { ... });
  it("finance can read customer.taxId; ops cannot", async () => { ... });
});

Aim for ≥10 policy tests. They are cheap to write and catch leaks early.

Phase 5 — Polish (Day 10)

The final day is the part most projects skip — and it’s the part that makes the project look professional:

  • README.md — what the project does, how to run it, where to look.
  • docs/design/v0.1.md — the design from Phase 1, written up clean.
  • docs/scenarios/ — three operational scenarios (see below).
  • docs/rfcs/0001-initial-model.md — the “why this shape” decision record.
  • A CI badge in the README showing tests passing.

Three scenarios to demonstrate

Write each scenario as a script that exercises the ontology end-to-end. These serve as integration tests and demo material.

Scenario A — “A shipment from order to delivery”

// scenarios/a-end-to-end-delivery.ts
//
// 1. A customer places an order (placeOrder).
// 2. A shipment is created and planned (createShipmentFromOrder, planShipmentRoute).
// 3. A driver is assigned to the first leg (assignOperatorToLeg).
// 4. The leg is dispatched (markLegDispatched).
// 5. The leg arrives at the destination hub (markLegArrived).
// 6. The shipment is delivered to the recipient (markShipmentDelivered).
// 7. customerLifetimeValue should now include this order.

Scenario B — “A reroute mid-transit”

// scenarios/b-mid-route-reroute.ts
//
// 1. An in-flight shipment hits an exception (markShipmentException-like input).
// 2. Dispatch reroutes via a different intermediate hub (rerouteShipment).
// 3. The new leg plan replaces the old one atomically.
// 4. An audit trail shows the original plan and the corrected one.

Scenario C — “Driver self-service”

// scenarios/c-driver-self-service.ts
//
// 1. Authenticate as a driver identity.
// 2. List the driver's assigned legs (rowRule filtered).
// 3. Try to read another driver's legs — should fail.
// 4. Mark a leg arrived (markLegArrived).
// 5. Try to mark a leg arrived for a different driver — should fail.

Each scenario is ~30-60 lines of code that walks the model. They prove the ontology works as designed.

Acceptance checklist

Before you call the capstone done:

SCHEMA
[ ] At least 10 object types with descriptions
[ ] At least 1 interface
[ ] Link types covering every relationship in the design
[ ] Enums for every closed-set property
[ ] Markings on PII and Confidential properties

DATA
[ ] Datasource YAMLs for every backing source
[ ] CSV fixtures with realistic data (≥5 rows each)
[ ] Pin mapping for every property

ACTIONS & FUNCTIONS
[ ] ≥5 action types, each with ≥2 validations and a domain event
[ ] ≥4 functions, all with unit tests
[ ] Idempotency strategy documented per action
[ ] Derived properties bound on at least 2 object types

POLICIES
[ ] roles.yaml with ≥6 roles
[ ] Object policies for every object type
[ ] Property overrides where markings apply
[ ] Row rules for at least 2 roles
[ ] Action policies with explicit invoke lists

TESTS
[ ] Golden-path and failure tests for every action
[ ] At least 10 policy tests
[ ] All scenarios run end-to-end and pass

DOCS
[ ] README with run instructions
[ ] docs/design/v0.1.md
[ ] docs/rfcs/0001-initial-model.md
[ ] docs/scenarios/ (one per scenario)
[ ] Release notes draft for v0.1.0

If you can tick all those boxes — congratulations. You have built a real, production-shaped ontology.

What this would look like in real production

The capstone is a working prototype. To take it to real production you would add:

  • Live datasources instead of CSV fixtures (CDC from your operational DB; Kafka telemetry topics).
  • Identity provider integration for real roles and claims.
  • Persistent audit log with retention.
  • Index tuning for the queries you actually run.
  • Drift reconciliation jobs that compare ontology to sources.
  • A real consumer SDK generated from the schema.
  • Monitoring and alerting on data freshness SLAs.
  • A formal RFC process for major changes.

None of those change the shape of the ontology you built. They surround it. The model is the model.

Where to take it next

A few directions to extend the work:

  1. Add an AI agent that reads the ontology and proposes reroutes for at-risk shipments. The agent runs against the same API surface as humans, with stricter permissions.

  2. Build a small operational app — a React frontend that consumes the ontology SDK. Notice how little business logic the frontend needs.

  3. Add the BillingAccount and Invoice flow — a separate concern from operations, with finance-only permissions.

  4. Implement ML-powered functionsshipmentDelayRisk from a trained model, served through the ontology.

  5. Migrate to v0.2.0 — design a non-trivial change, write the migration, deprecate carefully, demonstrate the dance.

Any of those would be a great next project.

Closing

You have travelled the full arc — from “what is an ontology?” to a working, governed, operational model of a real business. The patterns in this course are the same ones used by teams running ontologies at the largest scales.

The hardest part of doing this in real life is not the technology. It is the discipline:

  • Designing before coding.
  • Saying no to shortcuts that go around the action layer.
  • Holding the naming bar.
  • Testing every row rule.
  • Documenting the “why.”

If you take that discipline forward, the rest is craft.


You did it. Go ship something. 🚢