Markdown Editor

Ticket and Hotel Booking System Design Template (Reference Design)

Seat and room inventory, holds with TTL, overbooking math, conditional writes, idempotency, payment saga, waiting room, search vs booking paths

시스템 설계전체designticketbookingmath

사용법: Use it when designing hotel, event or any reservation system where double sales must be impossible. Fill the inventory invariants (2.2) and onsale capacity (3) first, then the concurrency control and saga. The main pitfall is holding database locks across a payment call instead of modelling the hold as data with an expiry.

미리보기

System Design: [Booking system name]

Reference design for a hotel room and event ticket booking platform. It covers the inventory model for rooms (date-based allotments) and seats (individually identified), holds with a time to live, overbooking policy, concurrency control with optimistic and pessimistic locking and conditional writes, idempotency keys, payment integration through a saga with compensation, flash-sale traffic with a virtual waiting room, the split between the search path and the booking path, consistency boundaries, failure handling and fraud controls. It follows the structure of the System Design Document template and is pre-filled with a worked design to adapt. Replace every [bracketed] value and every row marked Example; values marked Example are assumptions. This is an engineering format, not legal, consumer-protection or payment-compliance advice.

Document control

FieldValue
Document ID[SDD-BOOK-001]
System / feature[Hotel and event booking]
Version[0.1]
Status[Draft / In review / Approved / Implemented / Superseded]
Author(s)[@author]
Reviewers[@reviewer-1], [@reviewer-2]
Last updatedYYYY-MM-DD
Classification[Internal]
Related[PRD], [Payment and ledger design], [Fraud policy], [Threat model]

Approvals

RoleNameDecisionDate
Tech lead[@name][Approved / Changes requested]YYYY-MM-DD
Staff / principal engineer[@name][Decision]YYYY-MM-DD
Revenue management (overbooking)[@name][Decision]YYYY-MM-DD
Payments and fraud[@name][Decision]YYYY-MM-DD
SRE / operations[@name][Decision]YYYY-MM-DD
Security[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft for design review
0.2YYYY-MM-DD[@name]Example: Replaced row locks with conditional writes for seat holds
0.3YYYY-MM-DD[@name]Example: Added virtual waiting room for onsales above 10 000 seats
1.0YYYY-MM-DD[@name]Example: Approved

Contents

1. Overview

1.1 Problem statement

[Example: We sell hotel rooms from 4 000 partner properties and tickets for concerts and sports events. Last season a stadium onsale sold 312 seats twice because two application servers read the same "available" row before either wrote. The search page timed out for 18 minutes during the same onsale because availability queries ran against the booking database. Customers whose payment failed kept their seats locked for 30 minutes, and resale bots bought 40% of the best seats in the first two minutes.]

1.2 Proposed solution

[Example: Inventory lives in an inventory service that owns a strongly consistent store partitioned by event or property. A booking is a saga: hold inventory with a conditional write and a 10-minute expiry, authorise payment, confirm the hold, capture payment, issue tickets or a hotel confirmation. Every step is idempotent and has a compensating action. Search reads a denormalised availability index fed by inventory change events and is allowed to be a few seconds stale; the booking path always re-checks the source of truth. Large onsales go through a virtual waiting room that admits users at the rate checkout can sustain. Bot and fraud controls run at the waiting room and again before payment.]

1.3 Decisions requested from reviewers

IDQuestionRecommended optionSection
Q-01Example: Lock strategy for seats?Conditional write (compare-and-set on seat status and version), no long-held row locks7.3, 10
Q-02Example: Hold duration?10 minutes for tickets, 15 minutes for hotels, extendable once by 5 minutes during 3-D Secure7.2
Q-03Example: Overbooking?Hotels only, per property and night, capped by revenue management; never for seated events7.5
Q-04Example: Payment order?Authorise after hold, capture after confirm; void on any failure7.6
Q-05Example: Waiting room threshold?Mandatory for onsales forecast above 5 times normal checkout capacity7.7
[Q-nn][Question][Option][Section]

2. Requirements

2.1 Functional requirements

IDRequirementPriority
FR-01Example: Search hotels by destination, dates and guests; search events by artist, venue and dateMust
FR-02Example: Show a seat map with live seat status for reserved-seating eventsMust
FR-03Example: Hold selected seats or rooms for a limited time while the customer paysMust
FR-04Example: Book, pay and receive a confirmation and tickets or a hotel voucherMust
FR-05Example: Cancel within the rate's policy and refund automaticallyMust
FR-06Example: Limit tickets per customer per event (for example 6)Must
FR-07Example: Virtual waiting room with fair, randomised admission at onsale startMust
FR-08Example: Hotel overbooking within approved limits, with walk (relocation) workflowShould
FR-09Example: General-admission (unnumbered) inventory with counted capacityShould
FR-10Example: Waitlist for sold-out events, offered when holds expire or tickets are returnedCould
[FR-nn][Requirement][Must / Should / Could]

2.2 Non-functional requirements and invariants

IDQualityTargetMeasured as
NFR-01No double sale (identified inventory)Example: Zero seats sold twiceNightly audit of tickets per seat
NFR-02Allotment respected (counted inventory)Example: Sold room nights never exceed allotment plus approved overbookingNightly audit per property and night
NFR-03No silent lossExample: Every captured payment maps to exactly one confirmed booking or one refundDaily reconciliation
NFR-04Search latencyExample: p95 at or below 300 ms at 20 000 searches/sSynthetic and real-user monitoring
NFR-05Hold latencyExample: p99 at or below 250 ms for a hold of up to 8 seatsService timing
NFR-06Availability (booking path)Example: 99.95% monthly; onsale windows treated as criticalSLO
NFR-07Search freshnessExample: Availability index lag p99 at or below 5 sEvent age at index write
NFR-08FairnessExample: Waiting room position independent of arrival time before onsale opensAudit of queue assignment
[NFR-nn][Quality][Target][Measurement]

2.3 Out of scope

  • [Example: dynamic pricing algorithms (consumed as a price service)]
  • [Example: secondary-market resale and ticket transfer (separate design)]
  • [Example: the double-entry ledger (see Payment Ledger System Design (system-design/design-payment-ledger))]
  • [Example: channel manager integrations with property management systems beyond the allotment feed]
  • [Item deferred, with the release that will take it]

3. Capacity estimation

3.1 Assumptions

InputSymbolValueSource
Seats in the largest onsaleSSExample: 50 000Venue capacity
Average tickets per orderttExample: 2.5Past onsales
Users arriving in the first 10 minutesUUExample: 2 000 000Marketing forecast
Sustainable checkouts per secondCCExample: 300 orders/sPayment provider contract and load test
Share of admitted users who complete an orderkkExample: 0.6Past onsales
Peak hotel and event searches per secondQQExample: 20 000Traffic forecast
Hold TTL (tickets)ThT_hExample: 600 s7.2

3.2 Onsale throughput and admission rate

Orders needed to sell out:

O=St=50 0002.5=20 000 ordersO = \frac{S}{t} = \frac{50\,000}{2.5} = 20\,000 \ \text{orders}

At the sustainable checkout rate the sale takes about

Tsell=OC=20 000300≈67 sT_{sell} = \frac{O}{C} = \frac{20\,000}{300} \approx 67 \ \text{s}

The waiting room admits users at the rate checkout can absorb, allowing for users who browse and leave:

A=Ck=3000.6=500 users/sA = \frac{C}{k} = \frac{300}{0.6} = 500 \ \text{users/s}

Most of the 2 million users will not get tickets. Admitting at 500 users/s, only about 500×67≈33 500500 \times 67 \approx 33\,500 users are admitted before the event sells out; the rest must be told quickly and honestly (7.7), not left in a queue that cannot succeed.

3.3 Holds and contention

Active holds are bounded by inventory, not by users: at most S=50 000S = 50\,000 seat holds exist at once. Each hold attempt touches 1 to 8 seat rows in the partition of one event, so the hottest partition sees roughly

W=A×ktry×sˉ=500×1.5×2.5≈1 875 seat writes/sW = A \times k_{try} \times \bar{s} = 500 \times 1.5 \times 2.5 \approx 1\,875 \ \text{seat writes/s}

with ktry=1.5k_{try} = 1.5 hold attempts per admitted user (Example: some retry after losing a seat) and sˉ=2.5\bar{s} = 2.5 seats per attempt. That rate fits one well-provisioned partition but not one row lock queue, which is why 7.3 uses short conditional writes rather than long transactions.

3.4 Search

Search at Q=20 000Q = 20\,000 queries/s is served from the availability index and cache. With a cache hit ratio of 0.9, the index sees about 2 000 queries/s. The booking store sees no search traffic at all.

3.5 Hotel inventory size

ItemCalculationResult
Inventory rows (counted)4 000 properties x 8 room types x 365 nights11.7 million rows
Row sizeExample: 200 bytesabout 2.3 GB, before indexes and replicas
Booking records per yearExample: 6 million bookings x 2 KBabout 12 GB per year

3.6 Summary

QuantityEstimateDesign consequence
Onsale checkouts300 orders/sPayment capacity is the real ceiling; waiting room meters to it
Admission rate500 users/sWaiting room with token issuance
Hot partition writesabout 1 900 seat writes/sConditional writes, no row locks held across network calls
Search20 000 queries/sSeparate read path, cache plus index
Hotel inventoryabout 12 million rowsFits one sharded relational cluster

4. API design

4.1 Endpoints

Method and pathPurposeIdempotent
GET /v1/events/{id}/availabilitySeat map or section counts (from index)Yes (read)
GET /v1/hotels/search?dest=&checkin=&checkout=&guests=Hotel availability and prices (from index)Yes (read)
POST /v1/holdsHold seats or room nights; returns hold ID and expiryYes, with Idempotency-Key
DELETE /v1/holds/{id}Release a hold earlyYes
POST /v1/bookingsConvert a hold into a booking and start paymentYes, with Idempotency-Key
GET /v1/bookings/{id}Booking status (pending, confirmed, failed, cancelled)Yes (read)
POST /v1/bookings/{id}/cancelCancel under the rate or event policyYes, with Idempotency-Key
POST /v1/queue/{onsale}/joinJoin the waiting room; returns a queue tokenYes, per device and account

4.2 Request and response examples

A hold request names the inventory and carries the admission token during metered onsales; the response returns the server-set expiry and the price that the booking will be charged.

POST /v1/holds
Idempotency-Key: 8f1c2a7e-4d55-4b0e-9c61-2b1f0e9d7a10
Authorization: Bearer [token]
Content-Type: application/json

{"event_id": "evt_2291", "seats": ["A-12-07", "A-12-08"], "queue_token": "qt_9c1e4b"}
HTTP/1.1 201 Created
Content-Type: application/json

{"hold_id": "hld_77a1", "status": "held", "seats": ["A-12-07", "A-12-08"], "expires_at": "YYYY-MM-DDThh:mm:ssZ", "price": {"amount": 18000, "currency": "EUR"}}

4.3 Idempotency and errors

  • The server stores the key, a hash of the request body and the response for 24 hours. The same key with the same body returns the stored response; the same key with a different body returns 422.
  • A hold that loses a race returns 409 with the seats that are no longer available, so the client can offer alternatives without reloading the map.
  • An expired hold returns 410 on POST /v1/bookings.
  • Errors use RFC 9457 problem details with a stable type URI.
StatusProblem typeMeaning
409seat-unavailableOne or more requested seats were taken; body lists them
410hold-expiredHold TTL passed before booking
422idempotency-key-reusedSame key, different request
429queue-requiredOnsale is metered; join the waiting room
403purchase-limitPer-customer ticket limit reached

5. Data model

5.1 Entities

Seats are identified inventory (one row per seat per event). Hotel rooms are counted inventory (one row per property, room type and night).

5.2 Storage choices and invariants

DataStorePartition keyInvariant enforced by
SeatsExample: Distributed SQL or a key-value store with conditional writesevent_idUPDATE ... WHERE status = 'available' AND version = ?
Room nightsRelational, sharded by propertyproperty_idheld + sold + qty <= allotment + overbook_limit in the update predicate
Holds, bookingsRelational, same shard as the inventory they reference where possibleevent_id or property_idForeign keys and status state machine
Idempotency recordsSame database as bookingskeyUnique constraint on key
Availability indexSearch engine plus cachedestination, eventEventually consistent; never used to decide a sale
OutboxSame database as bookingsnoneWritten in the booking transaction

6. High-level design

Two paths share the inventory events but not the store: search is fast and stale by seconds, booking is exact.

ComponentResponsibilityScales by
Waiting roomQueue, randomise, admit at a metered rate, issue signed admission tokensStateless edge workers plus a counter store
Search APIQuery index and cache; never writesHorizontally
Booking APIValidate tokens and limits, call the sagaHorizontally
Inventory serviceHolds, releases, confirms with conditional writesPartitions (event or property)
Saga orchestratorRun booking steps and compensations durablyWorkflow workers
Payment serviceAuthorise, capture, void, refund through the PSPHorizontally; PSP limits apply
Hold expiry sweeperRelease expired holds and publish eventsOne worker per partition range

7. Detailed design

7.1 Inventory model

  • Identified inventory (seats): each seat has a status (available, held, sold, blocked), the hold that owns it and a version. A seat moves available -> held -> sold, or held -> available on expiry.
  • Counted inventory (room nights, general admission): one row holds allotment, held, sold and overbook_limit. A hold increments held only when the predicate still holds after the increment.
  • Multi-night stays must hold every night or none. All nights of one room type at one property live in one partition, so one transaction covers them.

7.2 Holds and TTL

  • A hold has expires_at set by the server. Clients see a countdown but the server clock decides.
  • Expiry is enforced twice: lazily (a hold past expires_at is treated as released by every read and by the conditional write predicate) and actively (the sweeper releases it and emits inventory.released so search and the waitlist learn about it).
  • A hold can be extended once while a 3-D Secure challenge is in progress, so a slow bank page does not lose the customer's seat during authorisation.
  • Example TTLs: tickets 10 minutes, hotels 15 minutes, extension 5 minutes.

7.3 Concurrency control

ApproachHow it worksUse here
Pessimistic lockingSELECT ... FOR UPDATE on the rows, then update, then commitOnly inside one short database transaction, never across a payment call
Optimistic lockingRead version, update WHERE version = v; retry on zero rows updatedSeat map edits by venue staff; low-contention admin flows
Conditional write (compare-and-set)Single statement whose predicate is the business ruleAll customer holds: seats and counted inventory
Serialised per partitionQueue all writes for one event through one workerFallback for extreme single-section contention

Seat hold, all or nothing for the requested seats:

UPDATE seat
SET status = 'held', hold_id = :hold_id, held_until = :expires_at, version = version + 1
WHERE event_id = :event_id
  AND seat_id IN (:seat_ids)
  AND (status = 'available' OR (status = 'held' AND held_until < now()));
-- In the same transaction: if affected rows < requested seats, roll back and return 409.

Counted inventory hold for one night:

UPDATE room_night
SET held = held + :qty, version = version + 1
WHERE property_id = :p AND room_type = :rt AND night = :n
  AND held + sold + :qty <= allotment + overbook_limit;

Holding locks while calling a payment provider is forbidden: a slow PSP would turn into a lock queue across the whole event. The hold itself is the long-lived "lock", expressed as data with an expiry.

7.4 Idempotency

Every mutating call carries an Idempotency-Key. The booking API writes the key, request hash and a processing marker in the same transaction as the hold or booking row; a concurrent duplicate waits or receives 409 request-in-progress. Saga steps carry their own step keys (booking_id:authorise, booking_id:capture) so retries after a crash do not authorise or capture twice. The payment provider receives the step key as its own idempotency key.

7.5 Overbooking policy

Overbooking applies to counted hotel inventory only, never to seated events. Revenue management sets overbook_limit per property, room type and night from historical no-show and late cancellation rates. With allotment NN, bookings nn and an independent show probability qq, the expected number of guests who arrive is nqnq, and the risk of more arrivals than rooms is

P(walk)=P(X>N),X∼Binomial(n,q)P(\text{walk}) = P(X > N), \qquad X \sim \text{Binomial}(n, q)

Example: N=200N = 200, no-show rate 8% so q=0.92q = 0.92, and n=210n = 210 (limit 10): mean arrivals 210×0.92=193.2210 \times 0.92 = 193.2, standard deviation 210×0.92×0.08≈3.93\sqrt{210 \times 0.92 \times 0.08} \approx 3.93. With a normal approximation and continuity correction, z=(200.5−193.2)/3.93≈1.86z = (200.5 - 193.2)/3.93 \approx 1.86, so the probability of walking at least one guest is about 3% (the exact binomial value is about 2.4%; compute it exactly when the spreadsheet allows). Revenue management approves the acceptable walk risk; the system enforces the resulting limit, records every overbooked night and triggers the walk workflow (relocation, compensation, notification) when arrivals exceed rooms.

7.6 Booking saga and compensation

The saga is orchestrated by a durable workflow so each step survives process crashes. Steps and compensations:

StepActionCompensation if a later step fails
S1Hold inventory (7.3)Release hold
S2Fraud score and purchase limit checkNone (read only)
S3Authorise paymentVoid authorisation
S4Confirm inventory: held -> sold for this hold onlyReturn to available and publish release
S5Capture paymentRefund
S6Issue tickets or hotel confirmation; notify the propertyCancel tickets; send cancellation to property

A payment timeout is unknown, not failed: the orchestrator queries the PSP by idempotency key before deciding to void or proceed. Capture after confirm means a customer is never charged for a seat they did not get; the cost is that an authorisation can occasionally be voided after the customer saw a success screen for authorisation, which the UI avoids by showing success only after S4.

7.7 Flash sales and the virtual waiting room

  • Users who arrive before onsale time get a random queue position when the sale opens, so refreshing early gives no advantage (NFR-08). Users arriving after opening join the back of the queue.
  • The room admits users at rate AA (3.2), adjusted every 10 seconds by observed checkout latency and payment error rate.
  • Admission issues a signed, short-lived token bound to account and device. The booking API rejects holds without a valid token during metered sales.
  • When remaining inventory minus active holds reaches zero for a section, the room tells queued users that the section is sold out and offers the waitlist instead of keeping them waiting.
  • The waiting room page is static and served from the CDN, so the origin sees only the token and counter calls.

7.8 Search path versus booking path

ConcernSearch pathBooking path
StoreAvailability index and cacheInventory store
FreshnessSeconds (NFR-07)Exact
Failure modeShow stale or approximate availabilityReject the hold with 409 and suggest alternatives
ScalingReplicas and cachePartitions
Load during onsaleAbsorbed by CDN for seat maps of hot sectionsMetered by waiting room

The index is fed by inventory events from the outbox. A seat map shows "likely available"; the hold is the only authoritative check.

7.9 Consistency boundaries

  • Strongly consistent inside one inventory partition: one event's seats, or one property's room nights.
  • A booking spanning two partitions (a hotel plus a concert package) is a saga across two holds, not a distributed transaction. Either both holds succeed or the first is released.
  • Booking and payment states converge through the saga and daily reconciliation with the PSP (NFR-03); the ledger is the financial source of truth.

8. Scalability and performance

ConcernApproachLimit before redesign
Hot event partitionConditional writes; sub-partition by section for stadiumsExample: about 5 000 seat writes/s per partition in load test
Payment provider throughputWaiting room meters to contracted rate; second PSP as overflowContracted orders/s
Search spikesCDN for seat-map tiles, cache with 2-second TTL for hot eventsIndex replicas
Hold expiry stormsSweeper spreads releases; lazy expiry in predicatesSweeper lag p99 under 5 s
Hotel inventory growthShard by property; archive past nightsShard count

Latency budget for POST /v1/holds (target p99 250 ms):

StepBudget
Token and limit validation10 ms
Conditional write and commit40 ms
Idempotency record and outbox write (same transaction)included above
Response and network30 ms
Headroom for retries on contention170 ms

9. Reliability, security and operations

9.1 Failure modes

IDFailureImpactDetectionMitigation
FM-01Payment provider timeoutUnknown payment stateSaga step timeoutQuery by idempotency key; void if not authorised
FM-02Saga worker crash mid-bookingBooking stuck in pendingAge of pending bookingsDurable workflow resumes from last completed step
FM-03Sweeper stoppedSeats stuck as heldExpired-but-held countLazy expiry in predicates keeps selling correct; alert and restart
FM-04Index lagSearch shows sold seatsEvent age at indexBooking path re-checks; banner on seat map
FM-05Inventory partition failoverHolds fail for one eventError rate per partitionWaiting room pauses admission for that event
FM-06Duplicate client submitDouble booking attemptIdempotency conflicts metricIdempotency key returns first result
[FM-nn][Failure][Impact][Signal][Mitigation]

See Software FMEA (ops/fmea-software) to score these, and Chaos Experiment Plan (ops/chaos-experiment) to test FM-01 and FM-02 before the first large onsale.

9.2 Security, abuse and fraud

IDThreatControl
SEC-01Bots buying inventory for resaleEdge bot management, waiting room randomisation, token bound to account and device, purchase limits per account, payment instrument and address
SEC-02Inventory hoarding through holds without paymentHolds per account limited; repeated expiry without purchase lowers admission priority
SEC-03Card testing on the booking endpointRate limits per account and IP, fraud score before authorisation, 3-D Secure
SEC-04Token replay or forgerySigned tokens with expiry, one use per hold
SEC-05Account takeover to use stored cardsStep-up authentication for new device plus stored card
SEC-06Card data exposureHosted payment fields from the PSP; no card data on our servers
[SEC-nn][Threat][Control]

Model the remaining threats in a Threat Model (security/threat-model).

9.3 Observability

SignalMetricAlert threshold
Double sale auditSeats with more than one ticketAny
Hold conflicts409 share of hold attempts per eventAbove 30% for 5 min (UX problem, not a fault)
Saga ageBookings pending over 2 minAbove 0.5%
Checkout rate vs admission rateOrders/s against admitted users/sRatio drift above 20%
Payment errorsDecline and timeout rate by PSPDoubling vs. baseline
Index lagp99 event ageAbove 5 s

9.4 Cost estimate

ItemUnit costQuantityMonthly cost
Inventory and booking database[USD per node-month]Example: 6 nodes[USD]
Search index and cache[USD per node-month]Example: 8 nodes[USD]
Waiting room (edge compute, requests)[USD per million requests][Requests][USD]
Workflow engine[USD per month]1 cluster[USD]
Total[USD]

10. Trade-offs and alternatives

DecisionOptionsChosenWhyWhat we give up
Seat concurrencyRow locks across checkout; optimistic retry; conditional write with hold rowsConditional write plus TTL holdShort transactions, no lock queues during onsalesHold state must be expired and swept
Payment timingCharge first, then reserve; reserve, authorise, captureReserve, authorise, confirm, captureNever charge without inventoryAuthorisation voids for expired holds
Cross-service bookingTwo-phase commit; sagaSaga with compensationsPartitions and PSP cannot join a 2PCTemporary intermediate states visible
Onsale controlAutoscale everything; rate limit; waiting roomWaiting room metered to checkout capacityPayment capacity cannot autoscaleUsers wait; queue must be fair and honest
Search freshnessQuery inventory store; index with lagIndex with lagProtects booking store from search loadSeat map can be seconds stale
OverbookingNone; per property limitPer property, room type and night, hotels onlyRecovers no-show revenue within approved riskWalk workflow and customer cost
[Decision][Options][Chosen][Why][Cost]

11. Delivery plan and risks

11.1 Milestones

MilestoneScopeExit criterionTarget date
M1Inventory service, conditional holds, sweeperZero double sales in a 10 000 concurrent-user load testYYYY-MM-DD
M2Booking saga with payment authorise, capture, voidChaos test of PSP timeout passes; reconciliation clean for 14 daysYYYY-MM-DD
M3Search index from outbox eventsIndex lag p99 under 5 s at forecast loadYYYY-MM-DD
M4Waiting room for onsalesRehearsal onsale at 2 times forecast with fair admission auditYYYY-MM-DD
M5Hotel overbooking with walk workflowRevenue management sign-offYYYY-MM-DD

11.2 Rollout and rollback

[Example: Migrate one venue at a time; the old and new inventory never own the same event. Run the first large onsale on the new system with a rehearsal the week before using synthetic users. Rollback for an event before onsale is a configuration switch; after onsale, the event stays on the system that sold it.]

11.3 Risks

IDRiskLikelihoodImpactMitigationOwner
R-01Example: PSP throughput lower than contracted during peakMediumHighRehearsal with PSP; second provider; waiting room adapts admission[@name]
R-02Example: Bots defeat device bindingHighMediumLayered controls; post-sale cancellation of abusive orders[@name]
R-03Example: Overbooking limits too aggressive for a propertyLowHighWeekly review of walks; automatic limit reduction after a walk[@name]
R-04Example: Consumer law on displayed queue times and pricingMediumMediumLegal review of waiting room and checkout copy[@name]
[R-nn][Risk][L / M / H][L / M / H][Mitigation][@name]

12. Appendices

12.1 Traceability

RequirementDesign elementVerification
NFR-017.3 conditional seat writeLoad test with competing clients; nightly audit
NFR-027.3 counted predicate, 7.5 limitsNightly allotment audit
NFR-037.6 saga, 7.4 step keysDaily PSP reconciliation
NFR-047.8 search pathLoad test at 20 000 queries/s
NFR-087.7 randomised admissionQueue assignment audit
[ID][Element][Test]

12.2 Open questions

IDQuestionOwnerDue
OQ-01Example: Should accessible seats be held back until 24 hours before onsale closes?[@name]YYYY-MM-DD
OQ-02Example: Do partner hotels accept overbooking on non-refundable rates?[@name]YYYY-MM-DD
[OQ-nn][Question][@name]YYYY-MM-DD

12.3 Glossary

TermMeaning
AllotmentNumber of rooms of a type a property makes available for a night
HoldTemporary reservation of inventory with an expiry
Identified inventoryInventory where each unit is distinct (a seat)
Counted inventoryInventory tracked as a quantity (rooms of a type, general admission)
SagaSequence of local transactions with compensating actions instead of a distributed transaction
WalkRelocating a hotel guest who cannot be accommodated because of overbooking
Waiting roomQueue in front of the booking path that admits users at a controlled rate

12.4 References

ReferenceUse
RFC 9457 Problem Details for HTTP APIsError format in 4.3
IETF draft "The Idempotency-Key HTTP Header Field"Idempotency semantics in 7.4 (draft; pin the revision)
Garcia-Molina and Salem, "Sagas", ACM SIGMOD 1987Saga pattern in 7.6
Payment Ledger System Design (system-design/design-payment-ledger)Payment states and ledger
Event Sourcing and CQRS Design (architecture/event-sourcing-cqrs)Read model for the availability index
System Design Document (system-design/system-design-document)General structure
Capacity Plan (ops/capacity-plan)Onsale capacity planning

Standard and licence note

Based on common industry practice for inventory, reservation and ticketing systems and on the references in 12.4; the Idempotency-Key header field is an IETF draft, not a published RFC. This is a reference design to adapt, with illustrative numbers; it is a format, not legal, consumer-protection or payment-compliance advice. Check the current version of every cited specification. Original text written for this collection. Template licence: MIT.

관련 템플릿