Try it
A running process, not a recording.
One hekla instance, on the open internet, serving the console that ships inside the binary. The log is real, the read models are real, and the commands you send are appended to the same log everyone else is reading.
The movement you will see in it is generated: a script subscribes and unsubscribes 10 students of its own among 6 courses of its own, so the log and the projector positions are never sitting still. The 6 courses listed below are the ones it never touches.
Shared, and wiped every half hour.
It runs the courses project, the one on the Dynamic Consistency Boundary page. The Subscribe command shown there is the command running here, read from the same directory this site is built from.
Every 30 minutes the data directory is deleted and seeded again. Whatever you write lasts until then, and so does whatever anyone else writes.
Nothing here is a fixture. The seat counts you read came out of the log, the traces are chains the runtime recorded, and a refused command is refused by the same code you can run on your own machine in a minute.
Take the last seat.
Open the console, go to Commands, and run Subscribe with one of the course ids and one of the student ids below. They are registered already.
Concurrency seats 2, so 2 different students fill it and the next one back is course_is_full. Send the same student twice instead and you get already_subscribed, which is a different rule and is checked first. Then look at that course on Events: neither refusal is there, because a refused command appends nothing.
$ C=0190d1a1-0000-7000-8000-00000000c00a$ curl -sX POST https://demo.hekla.tqwewe.com/commands/Subscribe -H 'content-type: application/json' -d "{\"course_id\":\"$C\",\"student_id\":\"0190d1a1-0000-7000-8000-000000000001\"}"{"causation_id":"...","correlation_id":"...", "events":[{"tags":["course_id:...","student_id:...0001"],"type":"student.subscribed"}], "positions":{"first":214,"last":214}}$ curl -sX POST https://demo.hekla.tqwewe.com/commands/Subscribe -H 'content-type: application/json' -d "{\"course_id\":\"$C\",\"student_id\":\"0190d1a1-0000-7000-8000-000000000003\"}"{"causation_id":"...","correlation_id":"...", "error":{"code":"course_is_full","message":"that course has no seats left"}}Cryptography
0190d1a1-0000-7000-8000-00000000c007
seats 3
GraphTheory
0190d1a1-0000-7000-8000-00000000c008
seats 5
TypeTheory
0190d1a1-0000-7000-8000-00000000c009
seats 8
Concurrency
0190d1a1-0000-7000-8000-00000000c00a
seats 2
InformationRetrieval
0190d1a1-0000-7000-8000-00000000c00b
seats 12
MachineLearning
0190d1a1-0000-7000-8000-00000000c00c
seats 20
Students the seed registered
- 0190d1a1-0000-7000-8000-000000000001
- 0190d1a1-0000-7000-8000-000000000002
- 0190d1a1-0000-7000-8000-000000000003
- 0190d1a1-0000-7000-8000-000000000004
- 0190d1a1-0000-7000-8000-000000000005
- 0190d1a1-0000-7000-8000-000000000006
The bind address is still the boundary.
Nothing in hekla is authenticated, and this instance is no exception. It listens on loopback, exactly as it does on your machine, and a proxy in front of it is what decides which requests reach the port at all: every GET but the scrape, and POST to a command. Everything else is refused before it arrives.
That is the deployment story the documentation gives, run as written. Only an effect calls out, and this project declares none, so there is no path from a request here to a socket anywhere else.
POST /projectors/{name}/replay
Rebuilds a read model from position zero. Cheap here, and free to anyone who asks.
POST /effects/{name}/skip/{position}
Abandons an event permanently. This project declares no effects, so there is nothing to skip.
GET /metrics
The scrape. An operator surface rather than a visitor one, and the only GET refused.
Requests are rate limited per address, reads more generously than writes, under a second limit across every caller at once. A limit answers 429, which is distinguishable from the 503 a read model answers while it is catching up.