Ten small files, read in the right order, tell a complete story. This page
tells it using the same three facets every Ocean example uses — Horizon,
Voyage, and Implementation — so the shape becomes familiar before you meet
it again in other examples.
Task Manager models a task manager built around one persistent record: a
TodoItem, with a title, a due date, a priority, and a lifecycle status.
An API creates, finds, updates, and deletes tasks; a database persists
them; expressions apply the lifecycle rule that turns an overdue task
expired; a UI presents all of it.
flowchart LR
User((User)) --> UI[Todo UI]
UI -->|HTTP| API[Todo API]
API --> Expr[Expressions]
Expr --> DB[("Todo DB<br/>PostgreSQL")]
API --> DB
Actors: one human user, interacting through the UI or directly
through the API.
Services:TodoService (API, expressions, persistence) and TodoUi
(presentation), deployed separately.
API:TodoApi — REST, one base path.
Database:TodoDB — one entity, TodoItem.
Brokers: none. This example doesn’t touch messaging.
Model boundary: the Bundle describes the application structure shown
above; generators and imported reusable definitions participate in
producing the concrete implementation.
That’s the whole system. Everything past this point is the same picture,
in more detail.
The logic between API and database: CreateItem, GetItem, GetAll, AdjustItem, DeleteItem, and the lifecycle rule IsOverdue / CheckItem that marks a task expired.
Why it’s needed
Not every API call is a plain database pass-through — a created or fetched task needs its overdue status checked first. This is where that rule lives, in one place.
Referenced by
The service, which connects API operations to these expressions instead of straight to the database where a rule applies.
TodoService: the orchestration unit that wires configuration, the API implementation, the database, and the expressions together with connect.
Why it’s needed
Something has to decide, for each API operation, whether it’s a direct database call or one that runs through an expression first. This is that something.
Referenced by
Deployment, which materializes it as a running unit.
Six dashboards (view, search, create, edit, delete, about) made of typed widgets, composed by TodoUi into one navigable application connected to TodoApi.
Why it’s needed
A generated API is not, by itself, something most people want to use directly.
Referenced by
Deployment, as a separately deployed service from the API.
How TodoService and TodoUi become running units: replica counts, exported ports (9091 and 8081), and TodoService’s dependency on a Dockerized PostgreSQL instance.
Why it’s needed
A validated model isn’t a running system yet — this is what turns it into one.
Referenced by
Nothing further; this is where the model becomes runtime topology.
Authored Ocean DSL: the ten .ocn files above — this is what you,
or anyone extending this example, would edit.
Supporting the example, not part of the model:example.md (the
Atlas descriptor) and example-info/example-info.html (the Horizon and
Voyage explanation you’re reading a guided version of right now).
What the generator produces: a Go/Gin API, PostgreSQL persistence,
and an HTMX/Bootstrap/Go-template UI, per the example’s own
documentation.
Where custom logic belongs, and how regeneration behaves: this is
general to every Ocean project, not specific to Task Manager — see
The Everyday Workflow for the full
answer and the ownership table behind it.
This page reads the model; it doesn’t reproduce the example itself. For
the complete, canonical version — including the parts not walked through
above — see Task Manager directly.