Skip to content

Repository structure and conventions

Status: accepted for the first scaffold, 26 October 2026. It changes through pull requests that update this file and, for decisions, an ADR in docs/adr.

The reference architecture is the technical analysis in docs/GuestCraft-Technical-Analysis.pdf. Its chapter 4 covers the architecture, chapter 18 the engineering rules and chapter 20 the phases. This file turns those chapters into a repository layout with rules that CI checks. Section 9 says honestly what each check can and cannot prove.

  • One codebase, two runtimes. The same packages run on Vercel (Next.js with the API mounted inside) and in Docker (Next.js standalone plus a resident worker). PostgreSQL is the only mandatory service.
  • Boundaries that hold. The domain never imports infrastructure. Only the composition root wires adapters to use cases. MIT code never depends on AGPL code.
  • One reason per package. A package exists because of a dependency boundary, a license boundary or a distribution boundary. Packages are never created per feature, per bounded context or to satisfy a coverage threshold, and they appear only with their first real code.
  • Fast, honest feedback. Type checking and unit tests run in seconds. Database behaviour (RLS, locks, constraints) is tested on a real PostgreSQL 17, never on an in-memory imitation.
guestcraft/
├─ apps/
│ ├─ web/ # Next.js: the screens and the HTTP bridge to server/http under /api
│ ├─ mobile/ # Expo app that connects to any instance (MIT, ADR 0041)
│ └─ docs/ # documentation website over docs/, published to GitHub Pages
├─ packages/
│ ├─ core/ # domain model, use cases and ports, pure TypeScript
│ ├─ db/ # the whole SQL schema, migrations, RLS, role bootstrap, unit of work, repositories
│ ├─ api/ # Hono routes, OpenAPI 3.1, RFC 9457 errors
│ ├─ server/ # composition root: http, worker, migrate and config entry points
│ ├─ auth/ # Better Auth adapter and GuestCraft access control
│ ├─ jobs/ # job catalog, pg-boss worker, schedules, budgeted drain, dead letters
│ ├─ channex-client/ # typed HTTP client for the Channex API (MIT)
│ ├─ channex/ # Channex adapter: sync engine ports implemented on the client
│ ├─ channex-simulator/ # stateful Channex simulator for tests and local development (MIT)
│ ├─ identity-provider-simulator/ # OIDC and SAML identity provider simulator for SSO tests (MIT)
│ ├─ stripe-simulator/ # stateful Stripe simulator for tests and local development (MIT)
│ ├─ stripe/ # payment-provider adapter: the core PaymentProvider port on Stripe's HTTP API
│ ├─ countries/ # country packs: a fictitious test country and Italy
│ ├─ storage/ # object storage adapters: S3-compatible buckets and private Vercel Blob
│ ├─ sdk/ # GuestCraft TypeScript SDK (MIT)
│ ├─ react/ # TanStack Query hooks over the SDK (MIT)
│ ├─ mcp/ # MCP server over the public API, stdio and Streamable HTTP (MIT)
│ ├─ tokens/ # design tokens in DTCG format (MIT)
│ ├─ ui/ # web components of the design system
│ ├─ i18n/ # ICU messages shared by web and mobile (MIT)
│ ├─ testing/ # generic test helpers, independent of product packages (MIT)
│ └─ tsconfig/ # TypeScript presets per environment (MIT)
├─ tooling/
│ ├─ scripts/ # CI and maintenance scripts, shared test setup, the analyzers' fixtures
│ ├─ codegen/ # isolated code generation workspace with the TypeScript 6 API
│ └─ biome/, spectral/, quality/, requirements/ # lint rules, OpenAPI rules, budgets, tool versions
├─ docs/
│ ├─ adr/ # architecture decision records
│ ├─ architecture/ # this file, its reviews and other living design notes
│ ├─ developer/ # installation, operation and the workflow contracts
│ ├─ product/ # the product status
│ └─ analysis/ # sources of the technical analysis
├─ Dockerfile, docker-compose*.yml # the web, worker and migrate images and the reference runtime
└─ openapi/ # the generated GuestCraft OpenAPI document, versioned (MIT)

The tree lists what exists. The dependency matrix also reserves two rows for planned packages: apps/worker, a host for server/worker (today the Docker worker image runs server/worker directly), and packages/webhooks, MIT Standard Webhooks primitives (today server/http signs deliveries and the SDK’s webhooks module verifies them). packages/cli, packages/fake and packages/apps are planned and arrive with their first real code; e-mail and outbound delivery adapters join packages/storage, the backend integration package, when they are written. Acceptance tests of the composed runtime live in packages/server/test/integration, and checks of the analyzers and artifacts in tooling/scripts/test/integration. The analysis puts the Channex simulator under tools/; here it is a package, because tests in several packages and the end-to-end server import it.

Dependencies in this table are internal production imports. External libraries, peer dependencies, presets and test tools are declared per package and checked separately.

Package and entry points License Responsibility Internal imports allowed
core/shared, core/<context> AGPL-3.0, private Domain calculations, use cases, ports (including the unit of work), domain events and error contracts. No I/O. none
db, db/auth, db/scheduler, db/migrations, db/bootstrap AGPL-3.0, private The single owner of GuestCraft’s SQL: schema, migrations (pg-boss’s schema among them), RLS, table inventory, role bootstrap, the unit of work and repositories implementing core ports. core
auth AGPL-3.0, private Better Auth adapter, identity-to-principal mapping, the guarded /api/auth/** handler, API key scopes and workspace access (ADR 0017). No migration journal of its own. core, db/auth
jobs AGPL-3.0, private Typed job catalog, the pg-boss worker and budgeted drain, schedules, recovery and the dead letter queue (ADR 0019). Enqueueing joins the current unit of work. The only package that imports pg-boss. core, db/scheduler
channex-client MIT, published later Portable Channex client with its own validated wire contracts. Knows nothing about GuestCraft. none
channex AGPL-3.0, private Channel-manager adapter; sync orchestration stays in core use cases. core, channex-client
channex-simulator MIT, published later Independent state machine of Channex and scenario oracle, in process and over HTTP. channex-client, type-only
identity-provider-simulator MIT, private Specification-driven OpenID Connect provider and SAML 2.0 identity provider for single sign-on tests, in process and over HTTP. Imported only by test and setup files; never imports the SSO, SAML or JOSE libraries it tests. none
stripe-simulator MIT, private Independent state machine of the Stripe endpoints GuestCraft uses, in process and over HTTP none
stripe AGPL-3.0, private Payment-provider adapter: the core PaymentProvider port on Stripe’s HTTP API core
countries/<id> (later countries/<id>/adapters), countries/conformance AGPL-3.0, private Country packs (ADR 0015): each country’s rules as dated data with their sources, behind the contract of core/countries, and the conformance kit. Protocols and portals are planned, in separate adapter subpaths. core
storage AGPL-3.0, private Object storage adapters behind the ObjectStore port of core/files: S3-compatible buckets (AWS S3, Cloudflare R2, MinIO, Supabase Storage) and private Vercel Blob stores (ADR 0046). core
api AGPL-3.0, private Pure Hono route and schema factory, middleware, error serialization, offline OpenAPI export (ADR 0016). Receives use cases and the auth handler as interfaces. core, i18n (the texts of problems)
server/http, server/worker, server/migrate, server/config AGPL-3.0, private The only composition root, one entry point per runtime (ADR 0010). core, db, auth, jobs, channex, channex-client, stripe, countries, storage, api, i18n, mcp
webhooks (planned) MIT, published later Standard Webhooks primitives; runtime-specific crypto behind explicit subpaths. Until it exists, server/http signs deliveries in its own webhooks module and sdk verifies them in its own; no package imports it. none
sdk MIT, private until release Generated client plus the hand-written transport, pagination, errors and webhook verification. It never retries a request. none
react MIT, private until release Query factories and hooks; React and TanStack Query are peers. sdk
mcp MIT, private until release The MCP server: tools and resources generated from the instance’s OpenAPI document and composed front-desk tools, called with the caller’s own identity over stdio or Streamable HTTP, with a server-enforced confirmation of destructive tools. A client of the public API only; server/http serves it at /api/mcp. sdk
tokens MIT, published when needed Platform-neutral design data. none
i18n MIT, published when needed Localization on the API’s wire formats (ADR 0012): language negotiation, formatting of money, dates and measures, reading of numbers people type, and the ICU catalogs with their linter and pseudo-locales. none
ui AGPL-3.0, private Web design system; React and its UI libraries are peers. tokens, i18n
testing MIT, private Generic clocks, random sources, fixture utilities, the PostgreSQL lifecycle with an injected migration step, PgBouncer in transaction mode, and MinIO for object storage. Imported only by test and setup files. none
tsconfig MIT, private Presets per environment, all with the same strictness. none
apps/web AGPL-3.0, private Hosts server/http in Next.js; the dashboard uses sdk, react and ui, plus the Better Auth client for identity and session flows only. server/http, sdk, react, ui, tokens, i18n
apps/worker (planned) AGPL-3.0, private Starts and stops server/worker; never imports Next.js. server/worker
apps/mobile MIT, private The Expo app for any instance: discovery, device sign-in, Today and housekeeping (ADR 0041). Its versions are the mobile pnpm catalog; Jest, not Vitest, tests it. sdk, i18n, tokens
apps/docs AGPL-3.0, private The documentation website: Astro Starlight over the repository’s Markdown, read in place, and the API reference of openapi/v1.json (README). tokens

AGPL-3.0 means AGPL-3.0-only in the SPDX headers, provisionally (ADR 0004). GuestCraft’s OpenAPI document, its schemas and the code generated from them are MIT.

  1. Separate graphs. Production imports, test and setup imports, and package manifests are checked separately. Development dependencies count for package cycles; a test-only edge never makes a production import legal.
  2. Default deny. An internal import is allowed only if section 3 allows it. Unresolved imports, imports outside another package’s exports, relative imports that cross a package, undeclared npm dependencies, devDependencies imported by shipped code, and import type edges are all checked. Some subpaths are narrower than their package: db/migrations and db/bootstrap only for server/migrate, db/auth only for auth, db/scheduler only for jobs and server, server/migrate for no runtime, and each app only its own runtime of server. A workspace package is any package of pnpm-workspace.yaml, and each needs a row in the matrix.
  3. The core is pure. core imports no workspace package and no Node.js built-in. Inside core, a bounded context reaches another only through its index.ts, and core/shared imports no context. Ambient I/O (fetch, timers, Date, Temporal.Now, Math.random, Intl, process) is rejected in core by lint rules, because an import graph cannot see it, and its sources are type-checked without Node.js types.
  4. One unit of work. Tenant data is reached only through the unit of work, which binds repositories, events, the outbox and job enqueueing to one transaction with the tenant context set locally (ADR 0009). Cross-tenant lookups use separate, named, narrowly privileged capabilities.
  5. One schema owner, one migration command. Only db defines tables; only server/migrate migrates; runtimes never hold migration credentials (ADR 0010).
  6. Import-safe composition. No module does work when imported. Each runtime initializes explicitly and owns its disposal.
  7. License direction. An MIT package never imports an AGPL package, not even a type. Published MIT packages are also checked as packed tarballs, outside the monorepo.
  8. The simulator is independent. channex-simulator may import types from channex-client, never its validators, transport or helpers: it must not share the client’s assumptions. stripe-simulator imports no workspace package at all.
  9. Tests stay on their side. Test files, fixtures, packages/testing and the simulators (channex-simulator, stripe-simulator, identity-provider-simulator) are reachable only from test and setup files. Tests may sit in src/ next to the code; their file names (*.unit.test.ts, *.property.test.ts, *.integration.test.ts, *.component.test.tsx) mark them as test code.
packages/<name>/
├─ package.json # "@guestcraft/<name>", "type": "module", explicit "exports", "license"
├─ tsconfig.json # extends a preset from @guestcraft/tsconfig
├─ vitest.config.ts # unit and property tests: defineProject with name and include
├─ vitest.integration.config.ts # integration tests, when the package has them
├─ README.md # purpose, public API, how to test
├─ src/
│ ├─ <entry>/index.ts # one index per subpath export
│ ├─ **/*.ts
│ └─ **/*.unit.test.ts, **/*.property.test.ts
└─ test/
├─ integration/*.integration.test.ts
└─ fixtures/

Every package that contains code declares the scripts typecheck and test (tooling/scripts has only integration tests, and packages/tsconfig has no code); packages with integration tests also declare test:integration. The core type-checks its sources and its tests as two programs, so that its sources never see Node.js types. pnpm test runs the fast suites without Docker. pnpm test:coverage runs everything in one Vitest process with coverage, and it is the command CI uses.

  • ESM only, Node.js 24 LTS, TypeScript 7 in strict mode with noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitOverride and noImplicitReturns.
  • Presets per environment, one strictness. base (no platform globals, for core), node, react (the DOM and JSX, for ui), next, expo (Metro’s resolution for apps/mobile); a library preset for published packages is planned. A consumer type-checks the sources it imports with its own options, so every preset must accept the whole internal source graph. Private source consumers do not set a narrow rootDir.
  • Source-first internal packages. exports point to src/*.ts; Vitest, Next.js and Node.js type stripping read the sources directly. No package is published yet; a publishable package will add a build and swap its entry points in publishConfig.
  • Only erasable syntax: no enums, namespaces or parameter properties. Relative imports carry the .ts extension.
  • No isolatedDeclarations by default: it rejects ordinary Zod, Drizzle and Hono inference (review finding R01). Public functions still declare their types by convention.
  • Wire formats are normalized at the boundary. Zod’s optional fields allow undefined; domain types with exactOptionalPropertyTypes do not. The conversion happens where data enters, explicitly.
  • The compiler API is isolated. Tools that need it receive TypeScript 6 through packageExtensions; the project compiler stays TypeScript 7 (ADR 0003).

7. Runtimes, artifacts and the contract pipeline

Section titled “7. Runtimes, artifacts and the contract pipeline”
  • server/http builds the Hono app (API plus the guarded auth handler); apps/web mounts it and owns everything specific to Next.js. server/worker builds the job runner and the scheduler, and its main.ts starts it and handles signals. server/migrate is a tooling entry point. server/config parses the environment for the runtime being started, never at import time.
  • The worker and migrate images run the TypeScript sources of a pnpm deploy of server, pruned by tooling/scripts/src/prune-runtime.ts to what their entry points load, with Node.js type stripping. The Next.js standalone output declares the workspace root. CI starts each artifact from an isolated directory.
  • The OpenAPI pipeline is one-way: route and schema registration in api → offline export to openapi/v1.json (no database, no auth, no worker) → generation of sdk in tooling/codegen → type checks and tests of the packed SDK in isolated consumers.
  • Ownership of planned work: email and outbound delivery adapters join the object storage adapters in storage, the one backend integration package; logging and tracing setup into server, Next.js instrumentation into apps/web; environment kill switches into server/config and the unit of work.
What Convention Example
Files kebab-case availability.ts, revision-feed.ts
Fast tests next to the code availability.unit.test.ts, availability.property.test.ts
Integration tests in test/integration rls.integration.test.ts
Types and classes PascalCase, no I prefix RatePlan, ChannexClient
Identifiers TypeID with a registered prefix, stored as UUIDv7 rsv_01k8…, type TypeId<"rsv">
Error codes dotted, lowercase, stable inventory.capacity_exceeded
Codes of the world ISO 3166-1 alpha-2, ISO 4217, canonical BCP 47 tags, CLDR unit names IT, EUR, pt-BR, square-meter
Message keys the namespace, then the problem code or the screen, dotted problems.money.invalid_amount.title, common.nights
Database snake_case, plural tables inventory_days, workspace_id
Environment variables GUESTCRAFT_ prefix, except standard names GUESTCRAFT_CRON, DATABASE_URL
Check Proves Does not prove
dependency-cruiser (pnpm boundaries) the import structure of sections 3 and 4, including type-only edges and npm packages; a canary edge proves the parser works; every workspace package has a row that code has no I/O, that SQL respects table ownership; undeclared imports of workspace packages are caught by resolution, not by this rule
Biome with core overrides no direct use of ambient I/O, process.env or Node.js modules where forbidden indirect access through aliases of globals
pnpm licenses:check and reuse lint declared license direction, private AGPL packages, a license for every file the licenses of a packed tarball (checked before publishing)
Type checks with the strict presets type correctness of every package with its consumers’ options; no Node.js types in the core’s sources runtime behaviour
Tests with coverage on PostgreSQL 17 behaviour, RLS matrix, constraints, privileges, isolation through a transaction pooler that the tests are meaningful: mutation testing measures that

The analyzers have fixtures that they must reject, in tooling/scripts/test/integration, so that disabling a rule cannot turn the gate green silently: dependency-cruiser on a workspace of deliberate violations; Biome’s core rules on a probe file; the license check on a workspace of bad manifests; the core’s source program, listed without Node.js types; the coverage thresholds, pinned to ADR 0005. Knip and REUSE have none: their configuration is small, and CI runs them on every pull request.

Change Packages
A new API endpoint route and schemas in api, use case in core, repository in db, wiring in server/http, regenerated openapi/ (pnpm --filter @guestcraft/api openapi) and SDK (ADR 0016)
A new problem code its status in PROBLEM_STATUS of api, its title and detail in the catalogs of i18n; the tests of api find codes without either
A new Channex operation schema, method and tests in channex-client; behaviour in channex-simulator; use in channex
A new domain rule core, with unit and property tests
A new table migration with its RLS policy, inventory entry and Drizzle definition in db (ADR 0011); the catalog and RLS tests cover it
A new country a subpath of countries with a manifest, dated and sourced rules and their tests, registered in the composition root; the conformance kit checks it (ADR 0015)
A new language its catalog in i18n/catalogs (pnpm i18n:catalogs writes the runtime files), its loader and CATALOG_LANGUAGES entry (or GUEST_LANGUAGES for guest pages), the CLDR area patterns regenerated (pnpm i18n:cldr); the compiler and the tests check it
A new message its English text and description in i18n/catalogs/en.json, then pnpm i18n:catalogs; the application ships English only, and translation in Weblate is planned (ADR 0013)
A new design token or colour the data in tokens/src, with every new colour pair in CONTRAST_PAIRS; css:build in tokens and theme:build in ui regenerate the stylesheets (ADR 0018)
A new web component ui, on React Aria, with its messages in the ui namespace of the catalogs, axe and keyboard tests for each state, and a place on the page of the style test
A new job catalog entry and handler in jobs, scheduling in server/worker (ADR 0019)
A new version of pg-boss the catalog version, then pnpm --filter @guestcraft/db scheduler:migration writes the migration of its schema (ADR 0019)

Each capability below names the packages that implement it, what works and what is still partial or planned. The product status is the operator-facing summary; the ADRs keep each decision and its history; the developer guides are the workflow contracts.

server/config validates the settings of the runtime being started; server/http composes the API, the guarded auth handler and first-run setup; server/worker runs the jobs and the scheduler; server/migrate is the only privileged step. apps/web mounts the HTTP handler under /api and renders the screens. Docker Compose runs the web, worker and migrate images; on Vercel, production builds migrate, previews never do, and authenticated requests and a daily cron wake bounded job pumps. Migrations follow expand/contract, so a runtime accepts a newer journal whose extra migrations are all expand. Release automation (images with provenance and SBOM attestations) is in place, but no version has been released yet. See ADRs 0010, 0020, 0037, 0038 and 0039, and the installation, one-click deployment and releasing guides.

api registers every operation with its schemas, permission and exact problem list; the offline export writes openapi/v1.json; tooling/codegen generates the SDK’s types and Zod validators; sdk adds the transport, pagination, errors and webhook verification; react adds the query factories. Cookie sessions, device tokens, workspace API keys, organization tokens and client sessions authenticate requests; auth/integration-credentials.ts is the one gateway of the integrations’ credentials. mcp turns the instance’s OpenAPI document into MCP tools that call the API through sdk, over stdio and Streamable HTTP; server/http serves it at /api/mcp, calling the API in process with each caller’s principal. Partial: the SDK, the React package and the MCP package are not published. See ADRs 0016, 0022 and 0047, the HTTP API, the SDK and the MCP server.

auth adapts Better Auth for identities and sessions. Workspaces, memberships, custom roles, the permission matrix (core/tenancy), property-scoped access, invitation links and the audit log stay in GuestCraft (db, db/auth). The Settings screens manage users, roles, property access, activity (which names an API key and its creator for actions taken with a key), the account, and the transfer of the organization’s ownership to another administrator. See ADRs 0017, 0030 and 0036, and roles and property access.

core/properties owns properties with their time zone and currency; core/reservations owns room types with occupancy limits and physical rooms, which are archived and restored. See properties and the front desk.

Reservations, availability and the front desk

Section titled “Reservations, availability and the front desk”

core/reservations holds the booking rules, the availability ledger (one row per room type and night) and the stay segments of each reservation room, each recording the room type its nights consume; db adds unit exclusion and per-property gates, so a room is never assigned twice and concurrent direct bookings cannot oversell. The screens cover Today, reservations, guests, check-in and check-out with readiness checks and same-day undo, housekeeping status, and the planning grid of ui/planning, which only emits intents (create, move, split, resize) that the web app confirms after a server preview. Guest identity management includes indexed strong duplicate and shared-contact review, audited dismissal undo, two-version merges with provenance, independent current consent decisions and histories, OTA contact snapshots with ordinary-edit Apply, and owning-property reassignment (ADR 0045, guest workflow); the database’s explicit guest-reference policy inventory is guarded against catalog drift. Direct bookings support several rooms from the screens and API. Planning supports edge resizing, keyboard move mode, protected stays and inverse Undo; housekeeping reschedules its tasks from those room changes. See ADRs 0023 to 0026 and 0042, reservations and the front desk.

core/reservations derives rate plans, effective nightly prices and six restrictions, quotes stays and freezes the price of each booked night; the rate-plan settings and the rate calendar edit them. Prices per person or occupancy and packages are planned. See ADR 0027 and rates.

core/reservations keeps property policies and the terms frozen on each booked room: simulated cancellation fees and waivers, no-shows that release inventory, and manual guarantee and prepayment tracking. core/channex reports an OTA booking’s no-show or invalid card to its channel through Channex (booking reports). Provider authorization and collection are planned. See ADR 0032 and policies.

core/blocks owns dated out-of-order blocks, which reduce availability and enqueue ARI changes, out-of-service blocks, which prevent physical assignment only, and maintenance tickets with assignees, dates, activity and fault photos behind the FileStore port of core/files, stored by db in PostgreSQL or, with object storage configured, in an S3-compatible bucket or a private Vercel Blob store through storage, with a worker job that collects orphaned objects and a command that moves the files between the two; a fault report can create a block through the same rules; Planning, Rooms and Maintenance show them. Automatic photo retention is planned. See ADR 0033 and ADR 0046.

core/reservations plans the tasks a stay owes (departure cleans, cleans of a room a move vacates, stayover service) and every reservation write reschedules them in its transaction; core/housekeeping generates days on demand, assigns tasks and runs their lifecycle, which sets the room status and check-in readiness. The web board and the mobile app’s “My tasks” work on them. The app’s offline outbox is part of the mobile offline layer and is planned here. See ADR 0046 and housekeeping.

core/folios keeps an append-only guest account: room charges frozen and reconciled by reservation writes in the same transaction, catalog extras, manual payments and refunds, check-out settlement at the last room, a printable non-fiscal statement and an audited re-rate. The asynchronous TaxCalculator port is where country modules compute taxes; no tax rules, fiscal documents, split accounts or online payment providers exist yet. See ADR 0029 and folios.

core/night-audits runs resumable manual and scheduled property audits, with separate settings and health: blocking stay checks, acknowledged folio and OTA warnings, option expiry, configured no-shows through frozen policies, room-charge reconciliation and a one-day business-date advance. The existing worker schedules local-time execution; ordinary Vercel traffic wakes due work after the response, with a daily cron safety net. core/cash-shifts owns drawer settings, opening float, server-attributed cash movements, counted closure and immutable reports. See ADR 0043 and the night audit.

core/reports and set-based SQL in db compute per-property performance with historical room/type/OOO capacity, daily pickup from captured reservation history, cash receipts/refunds by method and service date, and folio revenue by posting category/tax category and service date. Every report has a chart, table and CSV under the property-scoped reports.view grant. History starts at upgrade or property creation; pickup requires captured history, while older performance periods use labelled baseline inventory. See ADR 0031 and reports.

channex-client is the typed Channex client, channex the adapter, and core/channex the use cases. A workspace connects its own Channex key, stored encrypted under ENCRYPTION_KEYS. Booking import maps properties and room types, receives verified webhook signals, keeps a durable revision feed with erasable personal content, projects bookings into the availability ledger, acknowledges them and recovers from overbooking and quarantine. Administrators import a property’s existing bookings after a preview, and reinstated bookings become active again (ADR 0048). See ADRs 0021 and 0028, and booking import.

core/channex, channex and the server pumps publish absolute availability, prices and restrictions from the ledger and effective rates through a transactional outbox, after plan mapping and an explicit takeover, with numbered property leases, a booking barrier, shared pacing and health with resync. Lost sends are settled by provider request lookup, a nightly check repairs drift from Channex’s values, and alerts reach the property’s screens and the webhook catalog (ADR 0048). Partial: the certification run with Channex staff is planned. See ADR 0034 and ARI publication.

core/channex, channex and server/http activate the paid Channex Messages app per property, read threads from the property-filtered live feed into a shared inbox, and send replies, templates and booking or inquiry attachments through an outbox that never sends twice. Operators confirm booking and alteration decisions, pre-approve inquiries or send offers in the inquiry currency, configure workspace retention, and erase a selected guest’s local message content. Inquiry attachment delivery is simulator-verified; live Channex certification remains pending. Upstream copies and booking revision archives are outside Messages erasure. See ADR 0044 and Messages.

core/integrations narrows key grants to the creator’s live access, rotates keys and checks their IP allow-lists, and defines the event catalog (event-catalog.ts, the one place that lists delivered types), the events API, endpoints, replays and the delivery schedule; db writes a webhook outbox row with each catalog event in the same transaction and resolves each event’s property and reservation per kind of object; auth resolves gc_live_… bearer keys beside device tokens and judges each request by its own client address; server seals signing secrets, checks destinations and sends through the guarded transport; jobs dispatches and delivers. Settings manages keys, endpoints, replays and redeliveries, and lists events. The catalog renders each event in the version each endpoint chose; jobs runs one delivery job per workspace, and endpoints back off on their own. See ADR 0040 and API keys and webhooks.

OAuth applications and the built-in MCP server

Section titled “OAuth applications and the built-in MCP server”

auth runs Better Auth’s OAuth provider behind its guard and resolves gc_oat_… tokens through the same gateway as keys, at the resource they were issued for, as the consenting member’s live grant (core/integrations/oauth-applications.ts); db keeps the grants and Better Auth’s OAuth tables; server serves the discovery documents, the consent’s server side and /api/mcp, where @guestcraft/mcp calls the API in process as its caller and confirms destructive tools once through a ledger; apps/web has the consent page and Settings → Authorized applications. See ADR 0047, OAuth applications and the MCP server.

apps/mobile (Expo, MIT) reaches any instance through the SDK: public discovery at /.well-known/guestcraft, a browser sign-in that hands a revocable device session to the app, then Today, single-room housekeeping status, “My tasks” with one-tap status and Undo, task and room detail, and fault reports with photos. Partial: no store release exists; push notifications, offline changes and the other screens are planned. See ADR 0041 and discovery and device sessions.

core/countries is the contract; countries/it holds Italy’s cash rounding and consumer price rules, countries/fictitious a test country, and countries/conformance the kit that checks every pack. No workflow consumes the Italian rules yet, and Italy’s compliance modules (tourist tax, guest registration, e-invoicing) are planned. See ADR 0015.

i18n holds the English catalog and locale-aware formatting of money, dates and measures; tokens and ui provide the design system on React Aria, with light, dark and high-contrast themes and three densities. The application ships English only. See ADRs 0012, 0013 and 0018.

ADR 0049 extends the guarded identity capability with instance-admin organization provisioning, workspace settings and reversible archival. The public API and SDK expose these workflows; organization Activity reads the organization audit scope, and the browser directory resolves live access across memberships. The tenancy guide states archive consequences and the intentionally absent workspace locale/measurement defaults.