Run the demo
Five example applications ship with the source. They run side by side on one engine, on five subdomains, with no restart between them. They are the fastest way to see what a MatterData application looks like before you write one.
Requirements
Section titled “Requirements”- Go 1.27
- a local clone of the repository
- Node 22 and Bun 1.4, only if you also build this documentation site
Start all five applications
Section titled “Start all five applications”From the repository root, create the five demo tenants:
make demo-tenantsThe target writes one SQLite file per tenant under .local/tenants. Start the engine in a second
terminal:
make engineThe engine now serves all five applications. *.localhost resolves to your own machine, so the
addresses below work without a hosts-file entry.
Sign in
Section titled “Sign in”Every demo account uses the password fixture-password-2026.
| Application | Address | Accounts |
|---|---|---|
| Sports club | club.localhost:8080 |
board@, trainer@, member@club.example |
| Local newspaper | news.localhost:8080 |
chief@, editor@, author@, reader@news.example |
| Calendar | calendar.localhost:8080 |
public; admin@calendar.example |
| School | school.localhost:8080 |
head@school.example |
| Feature gallery | showcase.localhost:8080 |
admin@, editor@, supervisor@, guest@showcase.example |
Sign in at /matterdata/login. The calendar application opens its main page to anybody.
Each application has more than one account, because a role decides what a person sees. Open the
same address as two different people and compare the result. A page that a role cannot open is not a refusal
you can see: the link to it is absent, and the address answers 404.
What each application demonstrates
Section titled “What each application demonstrates”The sports club is the broadest one. It has member records with photographs, a fee group that
refuses to be deleted while members still use it, and a public event signup that closes when the
event is full. The two refusals are written in different places. The fee group uses a hook in
dsl/examples/sports-club/logic/, because it asks a question about other rows. The capacity
check is a deny when rule on the signup form itself. Sign in as member@club.example to see
a page bound to your own record, and as board@club.example to see the administrative pages
that the member has no link to.
The local newspaper shows editorial states. An article moves from draft through review to
published, and each move is a button that only appears when the actor may make that move from
that state. The article body is Markdown, its word count is written by a hook, and its reading
time is calculated from the word count. Published articles are public at /{slug}; a draft is
readable only through a preview link.
The calendar is the smallest application and the only one whose main write is anonymous.
A visitor picks the groups they care about and gets a calendar address to subscribe to. Open
calendar.localhost:8080/kingshot_calendar/calendar/sub-calendar for a seeded subscription and its feed. The feed
is the same query as the page, in the format a phone understands.
The school installs empty. It exists for its schema: 25 tables, an application-wide scope
that puts every page in one school term, and grades marked sensitive. There is no demo data for
it, so expect empty listings.
The feature gallery is not an application of anything. It is one page per language feature,
and the address says which: /types/text, /regions/matrix, /access/row-filter,
/time-zones/reader. Every page carries a note saying what it demonstrates and what to try. It uses
every column type and every region type the language has, which the other four do not — each of
them uses the part it needs.
The gallery is open without signing in, except for two kinds of page. The pages under Access show how a rule narrows what a login sees, so they need a login. Eight pages need a session for a reason that is itself a feature:
- The sheet, the post form, the event form and the line-item form draw a
refcontrol, which lists another table’s rows. A form open to visitors may not draw one. - The form, the list and the event pages over
signupsread a table the season scope filters. A visitor without a session has no season.
Navigation shows only what the current reader can open, so a signed-out visitor’s menu has no Access group. Sign in with the shared demo password shown above to see the rest. Any of the four gallery logins opens the pages that need a session. The Access pages differ by role.
Small menus show up to five links directly. Larger menus show a Menu control that opens the navigation groups. The panel uses columns on desktop and stacked sections on phones. Select a group to expand its links. Both layouts work without JavaScript. The engine counts only links that your account can open.
Open it as two different accounts to see authorization move. /access/sensitive shows a marked
column to admin@ and hides it from supervisor@ on the same page. The four pages under
/time-zones draw the same records in four different time zones.
Run only the club application
Section titled “Run only the club application”For the shortest path, create one tenant and start the engine:
make engine-tenantmake engineThen open club.localhost:8080/matterdata/login.
Run make demo-tenants again. The target deletes the five named tenants and recreates them, so
keep nothing you care about in those databases.