Skip to main content

J-06 — Stay, Modify, Check-Out

One-liner: During the stay, charges accumulate on the folio; on departure, payment is settled, the room is released, and lock credentials are revoked.

1. Purpose

While the guest stays, ad-hoc charges (room service, mini-bar, late-checkout fees, extras) accumulate on the folio. On departure, the folio is settled (cash / card / mixed), the room status is released to housekeeping, and lock credentials are revoked. Outcome: reservation Checked-out, folio Closed, room Vacant Dirty (HK queue updated), key credentials revoked, receipt issued.

2. Persona Context

  • Persona: Receptionist (primary actor); guest (subject); housekeeping (downstream).
  • Surface: Electron Desktop.
  • Primary BFF: bff-backoffice-service.
  • Backing services: folio-service, payments-service, lock-and-key-service, housekeeping-service, notification-service, audit-service.
  • Preconditions: Reservation in Checked-in state; folio open.
  • Trigger: Receptionist clicks "Check-out" on a reservation row OR adds a charge during the stay.

3. Entry Points

#EntryNotes
1Click "Check-out" on reservation rowDeparture flow
2Click "Add charge" on reservation rowMid-stay charge addition
3Click "Modify" on reservation rowDate change, room move
4"Late checkout request" notificationSee J-11

4. Screen-by-Screen Flow

4.1 FolioDetailScreen (mid-stay)

  • Layout: Folio header (guest, room, dates, balance), running ledger of charges, "Add charge" CTA, "Modify reservation" CTA, "Check out" CTA.
  • Components: FolioHeader, LedgerTable, AddChargeButton, Button (variants).
  • Offline: Reads from SQLite; charges added locally; outbox flushes on reconnect.
  • AI: None on ledger. Phase 2: AI categorisation suggestion for ambiguous charges.
  • Errors: Charge entered with mismatched currency -> validation error; lock unlock anomaly -> sidebar alert.
  • Loading: Sub-200 ms (local cache).
  • A11y: Ledger is a <table> with <th>s; balance announced on charge add.
  • RTL: Mirror.
  • Perf: Mount <= 200 ms.
  • Telemetry: frontend.folio.viewed { reservationId }; frontend.folio.charge_added { type, amount }.

4.2 AddChargeForm (modal)

  • Layout: Charge type (food, mini-bar, services), description, amount, tax behaviour, attach photo of bill (optional), notes.
  • Components: Form, ChargeTypeSelect, MoneyInput, Button ("Add").
  • Offline: Same as online; queued on add.
  • AI: Phase 2 — categorisation suggestion.
  • Errors: Negative amount disallowed; over-cap warning per tenant policy.
  • Loading: Spinner on submit.
  • A11y: Field-by-field labels; modal traps focus; Esc to close.
  • RTL: Mirror.
  • Perf: Submit <= 200 ms (local) / <= 500 ms (online RTT).
  • Telemetry: frontend.folio.charge_added.

4.3 ModifyReservationModal

  • Layout: Date pickers, room move selector, rate-impact preview, policy disclosure (cancellation / modification fee).
  • Components: DateRangePicker, RoomMoveSelector, RateImpactPreview, Button ("Apply").
  • Offline: Modifications queued; conflict warning if overlap risk.
  • AI: None.
  • Errors: Conflict with another reservation -> blocking modal with options (override, suggest alternative).
  • Loading: Rate impact recalculated <= 500 ms.
  • A11y: Date picker keyboard-navigable; impact preview announced.
  • RTL: Mirror.
  • Perf: Apply <= 1 s p95.
  • Telemetry: frontend.folio.modified { newRoomId?, newDates? }.

4.4 CheckoutWizardStep1ReviewBalance

  • Layout: Balance summary, taxes breakdown, voucher refund (if applicable), past payments list.
  • Components: BalanceSummaryCard, TaxBreakdown, Button ("Continue to settlement").
  • Offline: Reads from SQLite; settlement queued.
  • AI: None.
  • Errors: Suspect missing charge -> banner with link to add charge first.
  • Loading: Sub-200 ms.
  • A11y: Balance announced via aria-live.
  • RTL: Mirror.
  • Perf: Mount <= 200 ms.
  • Telemetry: frontend.checkout.balance_reviewed { reservationId }.

4.5 CheckoutWizardStep2Settlement

  • Layout: Payment-method selector (Cash / Card / Mixed); split-payment editor; payment provider element if card; cash drawer integration (P2 — log to drawer).
  • Components: PaymentMethodPicker, SplitPaymentEditor, PaymentProviderElement, CashDrawerLogger (P2), Button ("Settle").
  • Offline: Cash settlement local; card settlement queued (with policy disclosure: "Card will charge when online; if it fails, we'll notify").
  • AI: None.
  • Errors: Card decline -> alternate-method offer; partial payment short -> warning + option to write-off (with audit reason).
  • Loading: "Settle" spinner; success animation suppressed for accessibility.
  • A11y: Split-payment editor announces remaining balance.
  • RTL: Mirror.
  • Perf: Settle <= 2 s p95 (online card) / <= 200 ms (cash local).
  • Telemetry: frontend.checkout.settled { method, amount }.

4.6 CheckoutWizardStep3KeyRevokeAndRoomRelease

  • Layout: Lock credential revoke status (online vendor revoke vs offline-cert revoke); room status set to "Vacant Dirty"; HK assignment trigger automatic; "Done" CTA.
  • Components: KeyRevokePanel, RoomStatusUpdater, Button ("Complete").
  • Offline: Revoke via offline-cert; vendor reconciliation queued.
  • AI: None on revoke. Phase 2 — anomaly indicator if unusual unlock pattern detected during stay.
  • Errors: Vendor revoke 5xx -> queue for retry; status pill "Revoke pending".
  • Loading: Sub-200 ms.
  • A11y: Revoke status announced; "Complete" announces "Check-out complete".
  • RTL: Mirror.
  • Perf: Wizard total <= 60 s p95.
  • Telemetry: frontend.checkout.completed { reservationId }.

5. State Machine

6. Data Requirements

6.1 Server state (online)

OperationEndpointIdempotencyNotes
getFolioGET /api/v1/folios/:idn/aCached in SQLite
addChargePOST /api/v1/folios/:id/chargesX-Idempotency-Key
modifyReservationPATCH /api/v1/reservations/:idX-Idempotency-Key
getCheckoutBalanceGET /api/v1/folios/:id/checkout-quoten/a
settleFolioPOST /api/v1/folios/:id/settleX-Idempotency-KeyMulti-method splits
revokeKeyPOST /api/v1/lock/key/revokeX-Idempotency-Key
releaseRoomPOST /api/v1/front-desk/checkout/:id/release-roomX-Idempotency-Key
completeCheckoutPOST /api/v1/front-desk/checkout/:id/completeX-Idempotency-Key

6.2 Local persistence

  • SQLite tables: folios, folio_charges, payments_local, key_revokes_local, room_status_local, outbox.
  • Outbox flush ordered: charges -> settlement -> revoke -> release -> complete.

6.3 Idempotency

  • Per-action ULID; reused on retry.

7. AI Behavior

n/a in P1. P2: charge categorisation suggestion (HITL); unlock-pattern anomaly indicator.

8. Offline Behavior

  • Mid-stay charges added locally; flush on reconnect.
  • Modifications queued with conflict-warning UX.
  • Cash settlement local; card settlement queued; receipt printed locally.
  • Lock revoke via offline-cert; vendor reconciliation queued.
  • Room status "Vacant Dirty" set locally; housekeeping queue updated locally; reconciliation on reconnect.

9. Error States

ErrorTriggerUX shownRecoveryTelemetry
FOLIO_NEGATIVE_AMOUNTNegative charge enteredInline errorUser editsfrontend.folio.invalid_charge
FOLIO_OVER_CAP_WARNINGCharge > tenant capConfirm modalUser confirms or cancelsfrontend.folio.over_cap
RESERVATION_CONFLICT_ON_MODIFYNew dates / room overlapBlocking modal with optionsUser picks alt or overrides with reasonfrontend.folio.modify_conflict
PAYMENT_DECLINED (card)Card decline at settlementInline error; offer alternate / splitUser resolvesfrontend.checkout.payment_declined
LOCK_VENDOR_REVOKE_FAILEDVendor 5xxPill "Revoke pending"; offline-cert revoke localAuto retryfrontend.checkout.revoke_failed
OUTBOX_FLUSH_PARTIALSome events fail to syncSync Center shows failed itemsUser triggers manual retryfrontend.sync.partial_failure

10. E2E Test Gates

  • Composite gate G-DESK-2: stay -> charges added -> checkout -> settlement (cash/card) -> key revoked -> room released -> done. Online + offline variants.
  • Card decline at settlement -> alternate path -> success.
  • Modify reservation conflict -> override -> audit log entry.

11. Performance Requirements

MetricTarget
Folio mount<= 200 ms (local)
Charge add<= 200 ms local / <= 500 ms online
Settle (cash)<= 200 ms local
Settle (card)<= 2 s p95
Wizard total<= 60 s p95

12. Accessibility Requirements

  • All keyboard-completable.
  • Balance announcements via aria-live.
  • Focus management on wizard step changes.
  • Modals trap focus; Esc closes.
  • High contrast / reduced motion respected.

13. Telemetry

Frontend events

  • frontend.folio.viewed { reservationId }
  • frontend.folio.charge_added { type, amount }
  • frontend.folio.modified
  • frontend.checkout.balance_reviewed
  • frontend.checkout.settled { method, amount }
  • frontend.checkout.completed { reservationId }

Domain events emitted

  • melmastoon.folio.charge.added.v1
  • melmastoon.folio.modified.v1
  • melmastoon.folio.settled.v1
  • melmastoon.lock_and_key.credential.revoked.v1
  • melmastoon.front_desk.checkout.completed.v1
  • melmastoon.housekeeping.task.created.v1
  • melmastoon.audit.recorded.v1

14. Success Criteria

  • Folio total balance always reconciled to ledger sum (zero drift).
  • Receipts produced (printable + emailable) <= 5 s after settlement.
  • Housekeeping queue updated within 10 s of room release.
  • Key credentials revoked end-to-end; if vendor 5xx, offline-cert revoke local + reconciliation queued.
  • All checkout actions appear in audit log within 5 s.
  • Wizard total <= 60 s p95 online.

References