Technical reference · For consultants, IT evaluators, integration partners

Everything an evaluator needs to sign off.

This page exists so your technical advisor, integration partner, or in-house IT lead can verify the platform on their own terms — architecture, data model, tenancy isolation, real-time fan-out, observability, self-hosting, security. Open standards. Open-source dependencies. Predictable interfaces.

22Rust microservices
4front-end apps
1database per property
Sub-150msp95 push latency

Why this page exists

Most hospitality platforms ask buyers to trust a glossy demo. We expose the architecture, the API surface, the deployment topology, and the runtime so independent evaluators can verify the claims before signing.

What we don't expose

Proprietary algorithms (pricing models, anomaly detection, AI concierge prompts) and customer data live outside this reference. Everything below is the contract surface — interfaces, schemas, deployment shape.

For consultants

If you're advising a property on whether to adopt this platform, the sections below give you enough to write a defensible recommendation: data isolation, lock-in story, ops burden, and integration surface.

git clone https://github.com/your-org/guest-journey
cd guest-journey
./dev-start.sh        # brings up Postgres + every service in one command
open http://localhost:8000

Architecture

Four clients sit on top of Next.js BFFs that fan out to 22 Rust microservices. Each service owns its own data; cross-service reads only happen over the public API. Real-time updates flow over a shared event bus exposed as Server-Sent Events. Postgres-per-property gives tenants hard data isolation.

PMS Dashboard Next.js · web
Property Booking Site Next.js · web · CMS
Tenant Admin Next.js · web
Flutter Apps Concierge (guests) · Staff · iOS/Android/web
⇣ HTTPS · Server-Sent Events · WebSocket ⇣
BFF / Gateway Next.js rewrites · CORS · auth-cookie passthrough · SSE forward · rate-limit
auth8201
reservations8202
guest-services8204
guest-experience8205
messaging8206
housekeeping8207
loyalty8208
personalization8209
property-config8210
local-content8211
iot8212
transport8213
business-services8214
group8215
lock8216
concierge-ai8217
maintenance8218
revenue8219
payments8106
analytics8008
+ 2 moreinternal
PostgreSQL 16one database per property · sqlx · migrations on boot
Rediscache · rate-limit · session storage
S3-compatible object storeguest photos · receipts · ID scans

Service boundaries

Each Rust service owns its tables. Cross-service reads happen over the API. No shared schema, no shared transactions — services are deployable, restartable, and scalable independently.

BFF pattern

The Next.js dashboard ships its own server-side BFF that handles auth-cookie translation, request fan-out, and SSR. Mobile apps talk to the same gateway, so there's a single network boundary to harden.

Stateless services

No service holds session state in memory. Auth tokens are short-lived JWTs; refresh tokens are persisted. Every pod is interchangeable; rolling updates are zero-downtime.

Stack

No proprietary runtimes, no closed-source databases. Everything is community-supported, well-instrumented, and easy to fork.

Backend

  • Rust 1.95 · Tokio · Axum 0.7
  • SQLx 0.7 · compile-time-checked queries
  • tower-http · CORS · CompressionLayer · ServeDir
  • tokio::sync::broadcast for SSE pub/sub
  • governor rate limiting
  • OpenTelemetry · Prometheus exporter
  • JWT via jsonwebtoken · bcrypt for passwords
  • utoipa OpenAPI docs from Rust types

Frontend

  • Next.js 14 · App Router · standalone build
  • React 18 · Zustand state · TanStack Query
  • Theme system: 7 palettes × light/dark
  • Playwright e2e — 49+ specs
  • Vitest unit tests
  • OTel browser exporter

Mobile

  • Flutter 3.35 · Dart 3.9 · Material 3
  • Provider state · Dio HTTP
  • image_picker · mobile_scanner (QR)
  • qr_flutter for the rotating digital key
  • Custom SSE client with exponential backoff
  • Web · iOS · Android targets from one codebase

Operations

  • Docker Compose dev stack · K8s manifests
  • Argo Rollouts for canary deploys
  • Velero backup · per-tenant pg_dump
  • Falco runtime rules · ZAP DAST
  • k6 load · 5 scenarios
  • Trivy + cosign image supply chain
  • GitHub Actions CI with security gates

Service catalog

22 Rust microservices, each with a single bounded context. Ports below match the production deployment (one systemd unit per service).

ServicePortOwnsKey endpoints
auth8201Identity, JWT, RBAC, MFA, password hashing, MFA recoveryPOST /auth/login · GET /auth/me
reservations8202Reservations, room types, rate codes, availability, channel managerGET /api/v1/properties/:id/reservations
guest-services8204Transfers, lost & found, incidents, shifts, supply requests, team chat, inspections, uploadsPOST /api/v1/uploads/photo
guest-experience8205Concierge, room service, activities, spa, POS, diningGET /api/v1/properties/:id/concierge
messaging8206SMS (Twilio), email (SendGrid), push (Firebase), templatesPOST /messages/send
housekeeping8207Cleaning tasks, room status, schedule, suppliesGET /api/v1/properties/:id/housekeeping/rooms
loyalty8208Points, tiers, redemptionsGET /loyalty/members/:id
personalization8209Guest preferences, segmentation, recommendationsGET /personalization/profile/:id
property-config8210Per-property config: room types, rate plans, taxes, policiesGET /property-config/:id
local-content8211Local guides, activities, dining, things to doGET /local/:property_id/activities
iot8212Door sensors, energy, smart-room signalsPOST /iot/event
transport8213Airport transfers, EV charging spots, dispatchPOST /transport/transfer
business-services8214Meeting rooms, business centre bookingsGET /business/rooms
group8215Group bookings, MICE, contractsPOST /groups
lock8216Digital keys, rotating QR, lock event auditPOST /lock/issue-key
concierge-ai8217"Aria" conversational AI, intent → ticket routingPOST /concierge-ai/chat
maintenance8218Work orders, contractors, schedule, photo evidenceGET /maintenance/work-orders
revenue8219Pricing rules, demand forecast, AI rate recommendations, BAR overridesGET /revenue/calendar
payments8106Stripe + PayPal, folio, night audit, financial reportsPOST /payments/pre-authorize
analytics8008OLAP queries, cohort analysis, revenue mgmt KPIsGET /analytics/kpi
shared-libCommon types, error model, auth middleware, audit loggerlibrary only

API reference

REST + JSON over HTTPS. Every mutating endpoint requires a JWT (cookie or Authorization: Bearer). Every read endpoint returns a consistent envelope.

Response envelope

{
  "success": true,
  "data": { ... },        // shape varies per endpoint
  "meta": { "page": 1, "total": 42 }  // optional
}

Auth

POST /auth/login
// Body
{
  "email": "[email protected]",
  "password": "…",
  "property_id": "00000000-0000-…"
}
// 200 → sets HttpOnly access_token + refresh_token cookies

Common patterns

PatternExample
Property-scoped listsGET /api/v1/properties/:property_id/reservations
By-id readsGET /api/v1/properties/:property_id/reservations/:reservation_id
Status transitionsPUT /…/:id/status · body { "status": "checked_in" }
Bulk operationsPOST /…/bulk with an array body
File uploadPOST /api/v1/uploads/photo · multipart, 10MB cap, image/pdf only

OpenAPI

Each service exposes its own OpenAPI 3.1 doc generated from its Rust types via utoipa. The merged spec for the BFF is published at /api/openapi.json; the per-service docs live at :port/swagger-ui/.

Real-time (SSE)

Live updates use Server-Sent Events because they're a one-way fan-out, work through standard proxies, and need no protocol upgrade. Behind each stream is a topic-based tokio::sync::broadcast channel — slow subscribers are dropped, never block fast ones.

Subscribing

GET /api/v1/properties/:id/messaging/staff/channels/:cid/stream
// Server keeps the connection open; events look like:
event: created
data: {"id":"…","content":"Towels for villa 12","sender_name":"Aisha"}

event: updated
data: {"id":"…","status":"acknowledged"}

: keep-alive   // every 15s, ignore

Client (Flutter)

// staff_app/lib/services/sse_client.dart
SseClient.instance
  .subscribe(
    '/api/v1/properties/$propertyId/transfers/stream',
    auth: authService,
  )
  .listen((evt) {
    // evt.event ∈ {'created','updated','deleted'}
    // evt.json carries the entity
  });

Topics shipping today

  • chat::<property_id>::<channel_id>
  • transfers::<property_id>
  • supply_requests::<property_id>
  • incidents::<property_id>
  • room_service::<property_id>

Data & tenancy

Database-per-property tenancy. Each property has its own Postgres instance behind a control-plane registry. Cross-property queries go through analytics-service, which has read-replica access to all of them.

How a request resolves

  1. Client sends a request with a JWT.
  2. Service decodes the JWT and extracts property_id.
  3. shared_lib::tenant_pool looks up the connection string in the control-plane DB.
  4. The request executes against that property's pool.

Migrations

Each service ships its own migrations/ directory. On boot, sqlx::migrate!() runs against the connected pool. guest-services-service additionally falls back to in-memory mode when no DATABASE_URL is set, so the demo runs offline.

Backups

Velero schedules pg_dump per tenant nightly. Restore drills are part of the launch readiness checklist (see Phase 23 in LAUNCH_READINESS_PLAN.md).

Self-hosting

Two paths: Docker Compose for evaluation and dev, Kubernetes (Helm + Argo Rollouts) for production.

1 · Docker Compose (5 minutes)

git clone https://github.com/your-org/guest-journey
cd guest-journey
cp env.example .env
docker compose -f docker-compose.dev.yml up -d
./dev-start.sh   # builds + runs every service

Hits localhost:8000 for the dashboard, localhost:8080 / :8090 for the Flutter web builds.

2 · Kubernetes

helm repo add guest-journey https://charts.your-org.example
helm install gj guest-journey/platform \
  --set postgres.host=… \
  --set redis.host=… \
  --set objectStorage.endpoint=…

Manifests are in k8s/; the chart wraps them with sensible defaults and Argo Rollouts annotations for canary deploys.

Required env

VariablePurpose
DATABASE_URLDefault tenant pool
CONTROL_DATABASE_URLControl-plane (tenants registry)
REDIS_URLCache + rate-limit backing store
JWT_SECRETToken signing (rotate per env)
STRIPE_SECRET_KEYPayments
SENDGRID_API_KEYTransactional email
TWILIO_AUTH_TOKENSMS
STAFF_UPLOADS_DIRPath for uploaded photos (or S3 endpoint)

Observability

OpenTelemetry traces, Prometheus metrics, structured logs. Every service exposes /health, /metrics, and labelled spans on every handler.

What's wired

  • Prometheus scrape configs and Grafana dashboards in infrastructure/grafana/
  • OTLP traces over gRPC; sampling configurable per service
  • SLO templates and burn-rate alerts in Alertmanager
  • Falco runtime rules under compliance/runtime/
  • k6 load profiles for 5 critical journeys

Default SLOs

SurfaceLatencyAvailability
Dashboard reads (p95)< 250 ms99.9%
Mutations (p95)< 500 ms99.9%
SSE push (p95)< 150 ms99.5%
Photo upload (p95)< 3 s99.0%

Testing & quality

Tests are first-class; the launch checklist gates promotions on coverage and end-to-end pass rate.

Rust

397 tests passing across shared-lib · guest-services-service · payments-service · reservations-service · maintenance-service · guest-experience-service. Run with cargo test --workspace.

Frontend

Vitest unit tests for hooks and the API client. Playwright e2e covers auth, reservations, dashboard rendering, and 9 critical journeys. Run with npm test / npx playwright test.

Mobile

flutter analyze is clean on both apps. Widget tests scaffolded for new modules.

Security

Snyk SAST · cargo-audit · OWASP Dependency-Check · gitleaks · ggshield · Trivy + cosign in the build pipeline; ZAP DAST profiles in compliance/dast/.

Contributing

Issues, PRs, and discussions welcome. The repo is an Apache-2.0 monorepo. The codebase is opinionated but the conventions are documented.

Open the repo on GitHub → Talk to us