Worked example

Appointment Booking: a worked architecture, end to end

This is a worked example, not a real product. Example Clinic is a fictional practice of three staff that takes bookings through a widget on its own website. The system is invented; the records that describe it are written the way a real project's would be, and they point at one another, so you can follow a requirement to the decision that answers it, the contract that carries it across an interface, and the automated test that covers it. It exists to show how the records connect.

  • 14requirements
  • 7decisions
  • 1solution design
  • 3interface contracts
  • 20acceptance criteria with an automated test (of 23)

How the pieces connect

How the records connect: requirements, decisions, design, contracts, demo1 Requirements3 sets, 14 requirements2 Decisions7 ADRs, all accepted3 Design1 SAD, version 1.4, 11 sections4 Contracts3 ICRs, 2 agreed, 1 proposed5 Demo20 of 23 criteria, have automated tests
Requirements say what must be true. Decisions say how the design makes it true; those that answer a requirement cite it. The solution architecture design assembles the decisions into one picture. Interface contracts cite the decisions that shape each integration. The running demo has an automated test for most of the contracts' acceptance criteria, and what building it found was fed back into the records.Solid arrows follow the chain; dashed arrows are the findings from building the demo, fed back into the records.

Every record is a Markdown file in the public architecture-records repository, licensed CC BY 4.0. The demo is its own repository, with MIT-licensed code.

Requirements: what must be true

Written as "shall" statements with WHEN and THEN scenarios, in the form of this site's own OpenSpec proposals, so each one can be checked. They say what must hold, not how: the no-overlap guarantee, the five-minute hold, availability within 60 seconds, no message sent late.

  • Booking requirements

    Booking without an account, the no-overlap guarantee, the five-minute hold, changing and cancelling, repeated requests.

    5 requirements, 16 scenarios

  • Availability requirements

    What is shown as free, how fresh it is (60 seconds), the live check on confirm, and times across zones and daylight saving.

    4 requirements, 10 scenarios

  • Notification requirements

    Confirmations and reminders, and what must hold when the message provider is down.

    5 requirements, 13 scenarios

Decisions: how the design makes it true

Only major decisions are written up as architecture decision records: the ones that are hard or costly to reverse, that commit money or a vendor, or that fix a major quality. Each lists the options considered and its consequences; the design's section 3 adds what each one gives up. A smaller choice, such as the five-minute hold, is a requirement or a design note instead.

  1. ADR-AB-0001: Embed the booking widget in an iframe, loaded by a small script

    Status: acceptedDecided 2026-09-26.Cited by ICR-AB-0001.

  2. ADR-AB-0002: Expose booking as a public REST API behind a gateway, identified by a widget key

    Status: acceptedDecided 2026-10-02.Cited by ICR-AB-0001.Related requirements: booking requirements (reference).

  3. ADR-AB-0003: Show availability from a synchronised copy, and check it live on confirm

    Status: acceptedDecided 2026-09-26.Cited by ICR-AB-0001, ICR-AB-0002.Related requirements: booking requirements (relates to).

  4. ADR-AB-0004: Build calendar connectors on each provider's own API, rather than buy an aggregation platform

    Status: acceptedDecided 2026-10-02.Cited by ICR-AB-0002.Related requirements: availability requirements (reference).

  5. ADR-AB-0005: Share one database across businesses, with row-level isolation

    Status: acceptedDecided 2026-09-26.Cited by ICR-AB-0001.

  6. ADR-AB-0006: Run on containers in one Australian region, recoverable into a second

    Status: acceptedDecided 2026-10-02.Cited by ICR-AB-0001, ICR-AB-0003.

  7. ADR-AB-0007: Hold the booking data in a managed PostgreSQL database

    Status: acceptedDecided 2026-10-02.Cited by ICR-AB-0001, ICR-AB-0003.Related requirements: notification requirements (enables), booking requirements (reference).

Design: the solution architecture, in one document

The solution architecture design (version 1.4, status approved, last updated 2026-10-09) puts the requirements, the seven decisions and the contracts into one picture: the context, the components, three runtime scenarios, integration, data, security, deployment and recovery, cross-cutting concerns, and the risks it accepts. Its sections are 1. Executive Summary; 2. Business Context & Requirements; 3. Architecture Decisions (ADR Linkage); 4. System & Component Model; 5. Integration & Interface Design; 6. Data Architecture; 7. Security & Compliance Controls; 8. Deployment & Infrastructure; 9. Cross-cutting Concerns; 10. Risks, Assumptions & Technical Debt; 11. Glossary.

Logical architecture of Appointment BookingBooking widgetiframe on the business's siteAdmin consoleAPI gatewaykey, origin, rate limitAvailability serviceBooking servicehold, confirm, changeBooking storebookings and outboxEvent streamCalendar connectorsbusy times, bookingsNotification workereach message onceGoogle Calendar /Microsoft 365Email and SMSproviderlive check at confirmationoutbox relaydashed boxes: outside the platform
Scroll the diagram sideways to see all of it; the text below describes it in full.Logical architecture (design section 4.1, simplified). A customer's booking widget, running in a frame on the business's own web page, and the admin console both call the API gateway over HTTPS. The gateway passes requests to the availability service and the booking service, which read and write the booking store. When a booking is confirmed, the booking service asks the calendar connectors to check that one time against the staff member's own calendar. The store's outbox is relayed to an event stream, which feeds the calendar connectors and the notification worker. The connectors exchange busy times and bookings with Google Calendar or Microsoft 365, and the notification worker hands messages to an email and SMS provider. The two providers are outside the platform.

The flow the design depends on most: confirming a booking

  1. The widget sends the confirmation with an idempotency key, so a repeated request creates nothing new.
  2. The booking service asks the calendar connector to check that one time against the staff member's own calendar.
  3. If the provider answers and the time is taken, the customer is told so and offered the next free times. If it is free, the booking goes ahead.
  4. If the provider cannot be reached, the check is recorded as skipped and the booking still goes ahead. A double booking against an event the platform had not yet seen is possible; the design accepts that deliberately (ADR-AB-0003) and reconciles the calendar afterwards.
  5. The booking and its outbox rows are written in one transaction, and the widget is told it is confirmed.
  6. The outbox is relayed: the calendar connector writes the event once, and the notification worker sends the confirmation once.

The design also draws the system context (design section 4.3), two more runtime flows (a staff member's calendar changing, and a booking changing while the message provider is down), and, in section 4.5, places each component on the integration and data platform reference architectures (the Integration reference architecture on this site). Section 5.1 names the library pattern behind each of its four integrations; the contracts below show the three that have a contract.

Interface contracts: what crosses each boundary

An integration contract record states what one party provides and another depends on: purpose, parties, interaction, flows, errors, service levels, and numbered acceptance criteria. Each cites the decisions that shaped it and the library pattern it follows.ICR-AB-0001 (version 1.2.0) and ICR-AB-0003 (version 1.1.0) are agreed and ICR-AB-0002 (version 0.11.0) is proposed, as each states in its front matter. The Calendar synchronisation contract stays proposed until the platform lead agrees the renewal schedule and alert and they are tried against a real provider. Within the Booking API, extending and releasing a hold remain proposed (acceptance criterion 8).

Running demo: automated tests for the contracts

The demo is a working version of the system: a widget in the fictional clinic's web page and, behind it, a real API, a calendar connector and a notification worker, run on your own computer against stand-in providers. Nothing is sent anywhere. Its point is that a contract is not just a document.

What it shows

  • 20 of the 23 acceptance criteria in the three contracts have an automated test, and a conformance test fails if a criterion loses its test.
  • Fifty simultaneous confirmations of one slot produce exactly one booking and 49 conflict responses that list alternatives.
  • The database itself refuses an overlapping booking when a row is inserted directly, bypassing the application.
  • With the message provider down, bookings still succeed, and when it returns every pending message is sent exactly once.

What building it found

Seven places where the records were silent or wrong, for example no way to extend or release a hold, and a retry window counted from the wrong moment. All seven were fed back into the records; most are now checked by an acceptance criterion with an automated test. That loop is what the dashed arrows in the diagram show.

Where it differs from the design

  • It uses SQLite with an overlap trigger where the design uses PostgreSQL. Tenant isolation is by code, not by the database's row-level security, which is weaker; its tests exercise the code, not the database.
  • Events travel through an in-process log, not a message broker, and the calendar and message providers are stand-ins.
  • Search latency (p95 under 400 ms) is measured on an empty server, not under load; the load test is still to be built, so the test shows the algorithm is fast, not that production load is met.
  • 3 criteria, which check the contracts' examples against a specification file (OpenAPI, AsyncAPI, or a schema not yet written), are not automated, because the demo has none.
  • Accessibility is checked with an automated checker and by keyboard; a check with a real screen reader is still owed.

To run it, clone the appointment-booking-demo repository. node tools/serve.mjs runs the in-browser version and needs only Node; npm run demo runs the real API and needs Node 22.13 or later. The repository's README has the conformance table, criterion by criterion.

Templates behind this example

All of the templates are free to copy; Tools & Templates has the full list.