|

Openfront Airline

Airline retailing, bookings, passenger service, and disruption operations.

Source · Catalog

Openfront Airline is an open-source airline retailing and passenger-service backend. It models direct and agent distribution, offers, bookings, fulfillment documents, payments, airport passenger service, baggage, and disruption recovery under carrier-owned data and permissions.

This is not flight operations or safety-critical aviation software. It does not calculate flight plans, dispatch releases, fuel, weight and balance, airworthiness, crew legality, ATC decisions, or operational control.

Install and configure

Use Node.js 20.9 or later and PostgreSQL. From the repository root:

npm ci

Create .env for the intended local database and session:

DATABASE_URL=postgresql://user:password@127.0.0.1:5432/openfront_airline
SESSION_SECRET=replace-with-at-least-32-random-characters
INITIAL_CARRIER_NAME=Openfront Airline
INITIAL_CARRIER_LEGAL_NAME=Openfront Airline
INITIAL_CARRIER_CODE=OF
INITIAL_CURRENCY_CODE=USD
INITIAL_TIMEZONE=UTC

A production deployment also needs APP_BASE_URL set to one trusted origin such as https://airline.example. It must not contain a path, credentials, query, or fragment. Internal GraphQL and MCP requests ignore request Host and forwarded-host headers.

Review and apply checked-in migrations, then start development:

npm run migrate
npm run dev

npm run dev also deploys migrations, so use it only with the database you intend to update. The app is served at /, the generated operator dashboard at /dashboard, and GraphQL at /api/graphql. Do not use schema push or destructive reset commands.

Run source checks with:

npm run lint
npm run typecheck
npm test
npm run build

npm run build generates Keystone schemas and builds Next.js without applying migrations.

Architecture

Carrier is the tenant root. Carrier-owned records carry a direct carrier relationship, and permissions are split by network, inventory, offers, bookings, passengers, ticketing, payments, airport service, disruptions, integrations, users, roles, and audit. Airport is shared reference data.

Current source registers 48 Keystone and Prisma models. Accepted offers, booking lines, booking segments, tickets, and financial records snapshot immutable commercial and service facts. Money uses integer minor units and explicit currency. Lifecycle and idempotency helpers control booking and passenger-service transitions.

The custom GraphQL boundary now exposes the bounded airlineFlightOptions projection plus eight commands: createOfferFromShopping, createBookingFromOffer, captureBookingPayment, issueBookingTickets, checkInBookingPassenger, acceptCheckedBag, transitionBookingStatus, and transitionPassengerService. Raw model CRUD remains available only where carrier access and field policy permit it; task workspaces call these carrier-scoped commands rather than assembling commercial state in the browser.

Data model

  • Network and schedule: airports, carriers, routes, recurring schedules, dated flight instances, cabins, seat maps, and seats.
  • Inventory and retailing: inventory buckets and holds, fare brands and rules, ancillary products, offers, and immutable offer items.
  • Orders and passengers: passengers, protected travel-document references, bookings and PNR locators, booking passengers, journeys, segments, and immutable booking lines.
  • Fulfillment: tickets and coupons, electronic miscellaneous documents and coupons, seat assignments, and service requests.
  • Airport service: check-in records, boarding passes, bags and bag events.
  • Disruption: disruptions, reaccommodation records, exchanges, and affected booking/service relationships.
  • Finance and integrations: payment sessions, payments, refunds, exchanges, payment providers, integration providers, provider connections, webhooks, approved agents, idempotency keys, and audit events.

Airline nouns remain explicit. Offers and bookings are not renamed ecommerce products and orders, and passenger-service documents are not generic fulfillment JSON.

Workflows

The commercial path is schedule and inventory -> priced offer with expiring hold -> booking/PNR with immutable lines -> payment and ticket/EMD fulfillment -> check-in, seat, boarding pass, and baggage service -> disruption and reaccommodation when required.

createOfferFromShopping creates an expiring hold from server-read inventory. createBookingFromOffer accepts that offer and consumes inventory inside the bounded transaction. The simulated demo path then captures payment, issues tickets/coupons, checks in one booking passenger, and accepts a bag. transitionBookingStatus and transitionPassengerService enforce allowed state changes, carrier scope, request-bound idempotency, actor evidence, and terminal-state protection.

Current first-user initialization can create an administrator and carrier from INITIAL_* values without fabricating network or commercial data. Separately, npm run seed:demo creates a fictional carrier/operator, OFR-DMI flight, fare, inventory bucket, seats, passenger, and simulated payment provider only when ALLOW_DEMO_SEED=1 and DATABASE_URL points to loopback PostgreSQL. The home page and authenticated Operations, Shop & hold, Booking desk, and Departure control workspaces exercise that synthetic path; generic model administration remains available. There is no public traveler booking storefront, live provider connection, or hosted demo URL advertised by these docs.

Integrations

The model defines boundaries for GDS, NDC, DCS, payment, identity, baggage, provider connections, webhooks, and appointed agents. Current source does not include live provider adapters or signed inbound webhook routes. A provider record or endpoint row does not establish a working airline connection.

Each adapter needs exact carrier scope, typed request and result contracts, credential isolation, provider idempotency, signed ingress and replay protection, bounded payload evidence, retries, reconciliation, observability, and an operator exception path. Inventory and booking adapters must also preserve the local hold and snapshot contracts instead of allowing provider responses to rewrite accepted commercial history.

Security

Carrier filters and field access restrict cross-carrier reads and writes. Permission grants cannot exceed the acting user's grant authority. Controlled operations recheck carrier ownership and bind idempotency to tenant, operation, target, and request content.

Travel documents use an encrypted or tokenized payload contract, masked metadata, and one-way lookup hashes. Payment records store provider references and masked instruments rather than PAN or CVV. Sensitive fields and audit metadata are bounded and hidden from ordinary output. Completion/MCP cookie forwarding is request-local, exact-origin and exact-path, rejects redirects, and does not patch process-global fetch.

Before real passenger data, complete the vault/encryption adapter, key rotation, retention and redaction jobs, signed provider ingress, cross-carrier runtime tests, rate and body limits, monitoring, backup restoration, incident response, and applicable identity, payment, privacy, consumer, accessibility, and aviation-service requirements.

Deployment

Current source contains eight checked-in migration directories, including the airline domain migration. npm run build generates Keystone artifacts and builds Next.js without applying migrations; npm run migrate deploys the checked history, while npm run dev applies it before starting development. Review and back up the target, migrate as a separate controlled deployment step, configure stable secrets and one trusted APP_BASE_URL, then run unit/schema checks, npm run test:integration, authenticated task-workspace checks, and rollback/restoration exercises against the exact release.

The source contains a serializable inventory transaction helper and concurrent offer/booking tests, but that does not prove capacity behavior under a deployment's real load, timeout, retry, and provider conditions. It also does not supply real encryption/key custody, GDS/NDC/DCS/payment/identity/baggage adapters, signed ingress, reconciliation, production observability, or a public traveler product. Do not accept real passenger or payment data until those boundaries and applicable operational requirements have been independently implemented and tested.

Extension paths

  • Add domain lists under features/keystone/models and register them explicitly in features/keystone/models/index.ts; preserve direct carrier ownership and immutable accepted snapshots.
  • Add commercial or passenger-service state changes under features/keystone/mutations using carrier checks, lifecycle adjacency, idempotency, transaction boundaries, and audit evidence. Do not make protected states freely writable.
  • Put GDS, NDC, DCS, payment, identity, baggage, and notification adapters behind typed provider modules. Keep secrets out of GraphQL, verify inbound signatures, claim event IDs, and reconcile external and local state.
  • Build traveler and agent storefront routes separately from authenticated reservation, airport, and disruption workspaces. Call narrow operations rather than reproducing offer acceptance or transition policy in the browser.
  • Extend initial carrier setup without turning environment defaults into operational network, fare, or inventory truth. Seed only synthetic evaluation data and keep production reference data operator-owned.
  • Add tests for cross-carrier access, hold expiry, concurrent inventory consumption, immutable snapshots, terminal transitions, idempotent replay, credential denial, duplicate callbacks, provider partial failure, and disruption servicing before enabling a new path.

On this page