Files
TS_Proto/docs/wiki/02-domain-model.md
nilesh.pandClaude Opus 4.8 035711f08c Add project guidance, security/governance/hygiene rules, and product wiki
- CLAUDE.md + AGENTS.md: canonical guiding principles for AI agents and
  developers (tenant isolation, no RLS, stack, security, conventions,
  environment gotchas)
- SECURITY.md: required security controls (isolation, secrets, auth,
  input handling, least privilege) with VAPT status
- GOVERNANCE.md: how changes are validated before merge — deterministic
  gates + AI review, risk tiers, human accountability
- CONTRIBUTING.md: code hygiene, definition of done, file hygiene
- docs/wiki/: product reference (overview, domain model, features,
  roles & access, API reference, glossary)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-10 13:31:04 +05:30

3.0 KiB

Domain model

Entities

Entity Scope Purpose
Tenant — A travel agency. The owner of all tenant-scoped data.
User per-tenant Agency staff who sign in (admin or agent).
Airport global Reference data (IATA code, city, country, timezone).
Airline global Reference data (IATA code, name).
Flight per-tenant Sellable inventory: a route on a date at a fare, with seats.
Booking per-tenant A confirmed sale against a flight.
Passenger per-tenant A traveller on a booking.

"Per-tenant" entities carry a tenant_id and cascade-delete with the tenant. "Global" entities are shared by all tenants and have no tenant.

Relationships

Tenant 1───* User
Tenant 1───* Flight ───* Booking ───* Passenger
                 │             │
          Airline, Airport   User (the agent who sold it)
          (global refs)
  • A Flight references a global Airline and two global Airports (origin, destination), but belongs to one tenant — so the same physical route exists as a separate, independently-priced Flight row per tenant.
  • A Booking references a Flight, the User who made it, and has many Passengers.

Key fields & rules

Tenant — slug (unique), name, status ∈ {active, suspended}. A suspended tenant's users cannot sign in, and it is hidden from the public tenant list.

User — email, password_hash (bcrypt), full_name, role ∈ {admin, agent}. Email is unique per tenant, not globally — the same person can hold accounts at several agencies.

Flight — flight_number, departure_time/arrival_time, cabin_class ∈ {economy, premium_economy, business, first}, base_price, currency, seats_total, seats_available, status ∈ {scheduled, delayed, cancelled}. Constraints guarantee seats_available ≤ seats_total and arrival_time > departure_time.

Booking — booking_reference (the PNR, unique per tenant), passenger_count, total_amount, currency, status ∈ {confirmed, cancelled}, contact email/phone.

Passenger — name, optional date of birth, passport number, seat.

Invariants the system must uphold

  • No overselling. A booking is created in a transaction that row-locks the flight (SELECT … FOR UPDATE) before reading availability, so two concurrent sales of the last seat cannot both succeed — the second gets a 409.
  • Seat accounting round-trips. Confirming a booking decrements seats_available by the passenger count; cancelling returns them (guarded so a double-cancel can't credit twice).
  • PNR uniqueness is per tenant, generated from an alphabet that omits easily-confused characters (no I/O/0/1).
  • Tenant isolation on every read and write (see Overview and SECURITY.md).

The authoritative schema is in backend/migrations/001_init.sql.