Dynamic Consistency Boundaries (DCB) Event Sourcing in Gleam !!! factos.hexdocs.pm
eventsourcing dcb dynamic-consistency-boundaries gleam
README.md

Course subscriptions #

A runnable Gleam and Factos simulation of the DCB course subscriptions example.

Challenge #

Students subscribe to courses under constraints that cross traditional aggregate boundaries:

  • course identifiers must be unique;
  • a course cannot exceed its current capacity;
  • a student cannot subscribe to the same course twice;
  • a student cannot subscribe to more than five courses.

Course capacity can also change after the course is defined.

The source article uses a ten-course student limit. This compact runnable package sets the same configurable constraint to five.

DCB approach #

StudentSubscribedToCourse is tagged with both course:<course_id> and student:<student_id>. A subscription command builds one decision context from two items: the course history needed to calculate capacity and occupancy, and the student's history needed to calculate their subscription count.

Factos folds matching events into command-specific state. The tests use factos/simulate for deterministic scenarios, while the development app dispatches the same commands through factos_sqlight into in-memory SQLite.

The package also demonstrates:

  • unique course definition;
  • course-capacity changes;
  • domain errors for missing, full, unchanged, and duplicate cases;
  • synchronized concurrent subscription attempts against the same course;
  • a JSON encoder returning factos.Event(json.Json) and a schema decoder selected by event type and version.

The dispatch builder receives the encoder and decoder factory directly. Malformed payloads become factos.DecodeError; unsupported event types or versions become factos.InvalidSchema.

The server component uses lustre.application; its init and update functions return managed Lustre effects instead of performing database work directly. Effects dispatch projection results back through messages. The command message wraps course_subscription.Command, so the UI exercises the domain model directly. Strong subscriptions update both projections in the same transaction as the event append.

The command-to-state flow is diagrammed in the module documentation in src/course_subscription.gleam.

Run it #

Requirements: Gleam.

Run the tests:

gleam test

Run the Ewe development server, then open http://127.0.0.1:8080:

gleam run -m course_subscriptions_dev

No database or container runtime is required.

Package layout #