Skip to main content

EP-005A — Check-In / Check-Out Operations RTM

EPIC: EP-005A Check-In / Check-Out Operations Reconciled: 2026-05-24 (Wave 1 of RTM Reconciliation Scale-Out) Catalog source: 01-epic-catalog.md §EP-005 rows 137-158 (catalog has not yet split EP-005A/B/C/D; this RTM scopes to check-in/out + room move + registration + kiosk + walk-in stories only — folios/night-audit/cash belong to EP-005B/C and are excluded). Existing reviews: reviews/EP-005/US-005-001-review.md through US-005-009-review.md (9 files, dated 2026-03-07; stale — see D-005A-001). Pass-rate source of truth: hmp-docs/docs/platform-registry/2026-05-16-13-flow-demo-readiness.md (flow-6 6/13, flow-8 0/15) overlaid with hmp-frontdesk-service/CLAUDE.md Gotchas 28 (QA-CHECKIN reconciler shipped 2026-05-22) and 29 (AP-T05-005/006 room-move canonicalised 2026-05-23) which post-date the snapshot. Launch criticality: This EPIC is the BF-003 (Check-In) + BF-005 (Check-Out) launch-blocker spine — drift here cascades into BF-001 (onboarding), BF-004 (POS→folio), and BF-006 (night audit). Every drift finding is rated against that blast radius.

Status legend​

StatusMeaning
BuiltCode exists + tests exist + tests pass
Built-UntestedCode exists, no automated test coverage (or test exists but is a stub)
PartialCode exists for some acceptance criteria, gaps for others
StubCode is a placeholder / TODO / returns mock data
Not StartedNo code

Summary​

MetricCount
In-scope stories13 (US-005-001, -002, -008, -009, -010, -011, -012, -013, -014, -015 + US-005A-01, US-005A-02, US-005A-03 + US-005-005 + US-005-006)
Catalog claims "Built"7 (US-005-001, -002, -005, -006, -013, -015, US-005A-02 kiosk page)
Verified-Built4 (US-005-001, -002 with B2B/express caveats, US-005-013, US-005-015)
Built-Untested1 (US-005-005 — covered partially)
Partial6 (US-005-008, -009, -010, -011, -012, US-005-006)
Stub1 (US-005A-03 — re-uses /check-out/express; no auto-eligibility scan)
Not Started2 (US-005-014 smart lock, US-005A-01 batch check-in route exists but DTO + per-row recovery missing)
Drift findings (P0/P1/P2)16 (D-005A-001..D-005A-016; 6 P0 / 7 P1 / 3 P2)
[SME-PROPOSED] refinements32

Catalog vs EPIC numbering drift: catalog uses US-005-001..022 3-digit padding; EPIC body uses US-005-01..21 2-digit + US-005A-01..03 for sub-EPIC-A stories. This RTM normalises to the catalog scheme for cross-reference parity with EP-005B/C, with EPIC-body aliases shown inline. Surfaced as D-005A-002 below.


US-005-001 — Standard Check-In (Room Assignment + Registration)​

Catalog status: Built (P0, 8 points) — EPIC alias US-005-01 Verified status: Built

Code locations:

  • hmp-frontdesk-service/src/checkin/checkin.controller.ts:50-188 — POST /check-in/:reservationId, POST /check-in/batch, POST /express-check-in, POST /room-move, POST /walk-in, POST /walk-in/:id/recover, GET /properties/:propertyId/arrivals
  • hmp-frontdesk-service/src/checkin/checkin.service.ts — checkIn() orchestrator (CONFIRMED guard + arrival-date guard + VACANT_CLEAN room verification + folio bootstrap + RESERVATION_CHECKED_IN Kafka publish at line 685; QA-CHECKIN reconciler delegation per Gotcha 28)
  • hmp-frontdesk-service/src/checkin/dto/checkin.dto.ts — CheckInDto, ExpressCheckInDto, RoomMoveDto, WalkInDto (P1-A1 same-day duplicate detection)
  • hmp-frontdesk-service/src/common/reservation-status-reconciler.ts — D1 2026-05-22 stale-read-model healer
  • hmp-frontdesk-service/src/checkin/payment-capture.service.ts — non-blocking pre-auth capture at check-in
  • hmp-frontdesk-service/src/checkin/preference-matcher.service.ts — auto-assign matches guest preferences
  • hmp-frontdesk-service/src/checkin/id-photo-upload.controller.ts + .service.ts — multi-doc photo upload tied to check-in
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/check-in/[id]/page.tsx — dashboard check-in wizard
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/arrivals/page.tsx — arrivals board UI consumer

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/checkin.service.spec.ts — 20+ specs covering CONFIRMED-guard, occupied/dirty room rejection, VACANT_CLEAN auto-assign, keycard non-blocking failure, payment-capture non-blocking, Kafka publish path
  • hmp-frontdesk-service/src/checkin/checkin.service.p6.spec.ts — Phase-6 expanded coverage
  • hmp-frontdesk-service/src/checkin/checkin.controller.spec.ts — controller-layer assertions
  • hmp-frontdesk-service/src/checkin/drift-defense.spec.ts — anti-regression for D1 reconciler
  • hmp-frontdesk-service/src/checkin/preference-matcher.service.spec.ts, payment-capture.service.spec.ts, early-late-charge.service.spec.ts, id-photo-upload.service.spec.ts, id-photo-upload-route-order.spec.ts
  • hmp-frontdesk-service/src/checkin/__tests__/gsa-010-011-property-required.spec.ts — cross-tenant denial

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/flow-6-check-in.spec.ts :: "Indian + International + C-Form" — 6/13 PASS (Aadhaar format guard + C-Form passport guard + HK status propagation pending) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16) — launch blocker
  • hmp-infrastructure/testing/flow-tests/src/flows/front-desk-checkin.flow.spec.ts :: "front-desk happy path" — TBD (not in 13-flow doc) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes:

  • hmp-web-dashboard/e2e/check-in-flow.spec.ts — dashboard real-backend check-in smoke

E2E (Playwright):

  • hmp-web-dashboard/e2e/check-in-flow.spec.ts

Use cases referencing this story:

  • docs/requirements/use-cases/uc-checkin-flow.yaml [CITED-BUT-NOT-FOUND] (no UC file enumerates the canonical check-in flow — drift)
  • docs/requirements/use-cases/uc-staff-checkin-reconciler.yaml [CITED-BUT-NOT-FOUND] (QA-CHECKIN D1 healer needs a UC)

SME notes:

  • The D1 stale-read-model reconciler (reservation-status-reconciler.ts, Gotcha 28) is a 2026-05-22 fix that closed a SEV-2 production issue: a missed reservation.modified Kafka event left the frontdesk local Reservation read-model at PENDING while reservation-service canonical was CONFIRMED. The dashboard showed CONFIRMED but check-in 400'd. The reconciler heals via a service-account JWT round-trip. This is a load-bearing piece of code with no story or UC covering it.
  • FINDING-F6-01 (flow-6 Aadhaar format guard): CheckInDto.idDocumentNumber has @MinLength(4) but no Aadhaar-specific 12-digit @Matches(/^\d{12}$/). A 5-digit "12345" Aadhaar is silently accepted → check-in 201. This is a compliance defect — Aadhaar Act 2016 + UIDAI guidelines require 12-digit validation, and the C-Form/police-register feed (reporting-feeds/frontdesk/police-register) downstream depends on a valid ID. The flow test S2 currently fails by design.
  • FINDING-F6-02 (room HK status not DIRTY after check-in): After POST /check-in, the room's housekeepingStatus stays at CLEAN instead of transitioning to DIRTY. The check-in cascade in property-service flips Room.status to OCCUPIED but does not separately flip the HK lane to DIRTY. This breaks the EP-006 housekeeping board's "occupied & needing service" filter and breaks the Gotcha-around-room-status-machine that EP-002 D-006 already flagged.
  • FINDING-F6-03 (folio ID from check-in response unreliable): The check-in response sometimes returns a folioId for a folio not yet visible to GET /folios/:id — a likely transaction-timing or read-replica-lag bug. The flow test mitigates by using GET /folios/by-reservation/:id exclusively. Dashboard code may hit the same bug intermittently.
  • B2B GSTIN at check-in: Story does not capture the buyer GSTIN at check-in. Today it has to be retrofitted at folio-settle / e-invoice time. Indian-hospitality reality: corporate guests want GSTIN at check-in so the registration card carries it and the invoice fires cleanly at checkout. Most legacy PMS (Opera, IDS Next) capture GSTIN as a first-class check-in field.
  • Walk-in saga recovery (P1-A2, Gotcha 16) ships under this controller but story body doesn't enumerate the 4 side-effects (room status, reservation-service mirror, event publish, ID verification persist) or the POST /walk-in/:id/recover retry endpoint.

Drift findings:

D-005A-003 — [P0] [Story-vs-code + India-compliance] FINDING-F6-01 — Aadhaar format guard missing in CheckInDto. A 5-digit Aadhaar is silently accepted; check-in returns 201. Aadhaar Act 2016 mandates 12-digit format; the downstream reporting-feeds/frontdesk/police-register feed depends on a valid ID for FRRO / police compliance.

  • [SME-PROPOSED] Add AC: "When idDocumentType=AADHAAR, idDocumentNumber SHALL match /^\d{12}$/. Validation lives in CheckInDto via a conditional @Matches() decorator OR in CheckInService.checkIn() as a pre-DB guard. Returns 400 with code AADHAAR_INVALID_FORMAT on mismatch."
  • [SME-PROPOSED] Add AC: "When idDocumentType=PAN, idDocumentNumber SHALL match /^[A-Z]{5}[0-9]{4}[A-Z]$/. When VOTER_ID, /^[A-Z]{3}[0-9]{7}$/. When DRIVING_LICENSE, /^[A-Z]{2}[0-9]{2} ?[0-9]{11}$/. When PASSPORT, /^[A-Z][0-9]{7}$/ (India) — relaxed regex if issueCountry !== 'IN'. All return 400 with <TYPE>_INVALID_FORMAT codes."

D-005A-004 — [P0] [Cross-service-handoff + missing-validation] FINDING-F6-02 — Room housekeeping status does NOT transition to DIRTY on check-in. Property-service flips Room.status: VACANT_CLEAN → OCCUPIED but leaves Room.housekeepingStatus at CLEAN. Breaks EP-006 housekeeping board's "needs service" view and double-counts in MV room_occupancy_summary.

  • [SME-PROPOSED] Add AC: "On successful POST /check-in/:reservationId, the frontdesk check-in cascade SHALL emit a room.status.changed Kafka event whose payload sets housekeepingStatus=OCCUPIED_NEEDS_SERVICE (or whatever the canonical lane is) in addition to the existing status=OCCUPIED transition. Property-service consumes and writes both columns. A flow-6 S5 assertion SHALL pin the post-check-in housekeeping status."

D-005A-005 — [P1] [Story-incomplete + India-hospitality-critical] Story does not capture buyer GSTIN at check-in for corporate guests. GSTIN is retrofitted at folio-settle / e-invoice time — too late for the registration card and forces a manual re-keying. Today: CheckInDto has no buyerGstin / companyId field.

  • [SME-PROPOSED] Add AC: "CheckInDto SHALL accept optional buyerGstin (regex ^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$) and companyId (FK to crm Company). When present, CheckInService.checkIn SHALL set Folio.companyId + Folio.buyerGstin on the bootstrap folio AND include the GSTIN on the registration card PDF. Mismatch (GSTIN != Company.gstin) returns 400 with code BUYER_GSTIN_COMPANY_MISMATCH."

D-005A-006 — [P1] [Cross-service-data-consistency] FINDING-F6-03 — Check-in response sometimes returns a folio.id for a folio not yet visible to GET /folios/:id. Indicates the response is built from in-transaction state but the folio commit lags the response in some test envs. Flow test mitigates via GET /folios/by-reservation/:id; dashboard hits the same race.

  • [SME-PROPOSED] Add AC: "Check-in response SHALL only return folio.id values that are committed and immediately readable via GET /folios/:id. If the folio bootstrap fails post-transaction, the check-in itself SHALL return 500 (not 201 with a phantom folio reference)."

D-005A-007 — [P2] [Orphaned-code-without-UC] The D1 reconciler (reservation-status-reconciler.ts, 2026-05-22 SEV-2 fix) is load-bearing but undocumented in any story or UC. New engineers do not know it exists.

  • [SME-PROPOSED] Author uc-staff-checkin-reservation-reconciler.yaml covering: given stale local read model + canonical CONFIRMED → reconciler heals → check-in proceeds; given local PENDING + canonical PENDING → check-in rejects with RESERVATION_NOT_CONFIRMED; given reconciler timeout / 5xx from reservation-service → check-in rejects fail-safe with RESERVATION_RECONCILER_UNAVAILABLE.

US-005-002 — Standard Check-Out (Folio Settlement + Invoice)​

Catalog status: Built (P0, 8 points) — EPIC alias US-005-02 Verified status: Built (with B2B + express caveats — see drift)

Code locations:

  • hmp-frontdesk-service/src/checkout/checkout.controller.ts — POST /check-out/:reservationId, POST /check-out/express, POST /late-checkout, POST /early-checkout, GET /properties/:propertyId/departures, GET /properties/:propertyId/in-house, GET /early-checkin/preview/:reservationId
  • hmp-frontdesk-service/src/checkout/checkout.service.ts — checkOut(), lateCheckout(), earlyCheckout(), getDeparturesBoard(), getInHouseGuests(). Publishes RESERVATION_CHECKED_OUT + ROOM_STATUS_CHANGED + HOUSEKEEPING_TASK_CREATED. E-invoice auto-fires per checkout.service.ts:436 (per Gotcha 8 of folio reconciliation summary)
  • hmp-frontdesk-service/src/checkout/dto/checkout.dto.ts — CheckOutDto (PMS-2 fixed: @IsArray() + @ValidateNested({each:true}) on payments, Gotcha 0b), LateCheckoutDto, EarlyCheckoutDto, SplitPaymentLineDto
  • hmp-frontdesk-service/src/checkout/sponsored-billing.service.ts — Vishramgruh sponsor split (hospital authorization use case)
  • hmp-frontdesk-service/src/einvoice/ — EInvoiceService.generateIrnForFolio + EInvoiceJobProcessor retry queue + DLQ + demo-tenant guard (Gotcha 26)
  • hmp-frontdesk-service/src/folios/invoice-pdf.service.ts — PDF invoice with IRN / signed-QR rendering per AP-T08-001 (Gotcha 20)
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/check-out/[id]/page.tsx — checkout UI
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/departures/page.tsx

Unit + integration tests:

  • hmp-frontdesk-service/src/checkout/checkout.service.spec.ts — full checkout, balance enforcement, force-checkout, multi-folio, keycard non-blocking, late-checkout, early-checkout, departures, in-house
  • hmp-frontdesk-service/src/checkout/checkout.controller.spec.ts
  • hmp-frontdesk-service/src/checkout/checkout-dto-validation.spec.ts — 8 new PMS-2 specs (Gotcha 0b)
  • hmp-frontdesk-service/src/checkout/express-checkout.spec.ts
  • hmp-frontdesk-service/src/checkout/split-payment.spec.ts
  • hmp-frontdesk-service/src/checkout/sponsored-billing.service.spec.ts — Vishramgruh path

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/flow-8-check-out.spec.ts :: "Check-out + GST e-invoice" — 0/15 PASS (worst on the platform) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16) — launch blocker
  • hmp-infrastructure/testing/flow-tests/src/flows/check-out-einvoice.flow.spec.ts :: "e-invoice IRN happy path + idempotency" — TBD (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)
  • hmp-infrastructure/testing/flow-tests/src/flows/noshow-late-checkout.flow.spec.ts :: "FT-9 late-checkout fee posting + no-show" — TBD (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)
  • hmp-infrastructure/testing/flow-tests/src/flows/cform-foreigner-reg.flow.spec.ts :: "C-Form list + PII masking" — TBD (P-GAP-1, not in 13-flow doc) (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes:

  • (covered via the check-in-flow smoke since express checkout is wired into checkout API)

E2E (Playwright): none specific (check-out covered by check-in-flow E2E end-state)

Use cases referencing this story:

  • docs/requirements/use-cases/uc-checkout-einvoice.yaml [CITED-BUT-NOT-FOUND]
  • docs/requirements/use-cases/uc-checkout-balance-enforcement.yaml [CITED-BUT-NOT-FOUND]

SME notes:

  • flow-8 0/15 PASS is the single worst result on the platform. The 2026-05-16 snapshot's root cause is "frontdesk nationality fallback" failure — the cross-service lookup from frontdesk's slim read-model Guest to a canonical nationality value 5xx'd when the read-model row was stale. This was tracked separately from the QA-CHECKIN D1 reconciler. Verify in Task 6 whether the 2026-05-22 D1 fix and the 2026-05-23 FU-55 dual-emit changes have moved the needle (need a re-measurement run).
  • AP-T08-001/006 (Gotcha 20): Folio.irn/signedQRCode/ackDate/ackNumber are denormalised from EInvoiceJob so the PDF reads from Folio directly. Old behaviour rendered literal 'Pending' placeholder; new behaviour renders 'DRAFT — IRN PENDING' watermark when IRN is null and the real IRN when set. The story body does not narrate this — a new engineer reading US-005-002 would not know the PDF endpoint is async-resilient.
  • AP-T08-007 (Gotcha 29): Credit-note IRN is queue-routed via EInvoiceJob.documentType='CRN' — same resilient queue as the primary invoice. Idempotent per (folioId, creditNoteNumber). Story body says nothing about credit notes — that whole surface is undocumented.
  • Demo-tenant guard (Gotcha 26): NIC IRP submission is SKIPPED for demo tenants regardless of EINVOICE_MOCK — stricter than the env flag, prevents demo bookings from polluting NIC live records. Story doesn't mention demo-tenant semantics.
  • Sponsored billing (Vishramgruh): The sponsored-billing.service.ts lives under checkout and handles the hospital-guest-house split-billing where the sponsor (Trust/NGO/CSR) covers part of the folio. Story body does not enumerate the sponsor flow at all.
  • B2B / e-invoice gap from US-005-002 review (2026-03-07): AC-9 (express checkout email) and AC-10 (B2B + IRN) were marked NOT_IMPL. Express checkout endpoint now exists (POST /check-out/express) per the controller, but the auto-eligibility scanner (US-005A-03) is not wired into night-audit. B2B IRN is shipped per AP-T08-003 (Gold-Standard Phase 1, 2026-05-19) but the dashboard buyer-GSTIN entry is not (D-005A-005).
  • forceCheckout semantics: Currently any user with FRONT_DESK role can pass forceCheckout: true to bypass the balance gate. This is overpermissive. Hotel operations practice: force-checkout requires a manager PIN / second-factor.
  • CGST/SGST/IGST split: Per AP-T07-004 (Gotcha 29), PosFolioChargeConsumer now derives the split from customerState. Folio settlement at checkout reads these columns; story body does not enumerate the determination algorithm. Indian-hospitality reality: intra-state vs inter-state determination is the #1 source of e-invoice rejections.

Drift findings:

D-005A-008 — [P0] [Test-vs-code + launch-blocker] flow-8 (15 scenarios) 0/15 PASS at 2026-05-16. This is the worst pass rate on the platform and the dominant Property #1 launch blocker. Root cause was "frontdesk nationality fallback"; downstream effects: e-invoice generation rejected, room status not flipped to DIRTY, departures board stale. A re-measurement after the 2026-05-22 D1 reconciler + 2026-05-23 FU-55 dual-emit + AP-T07-004 GST split fixes is required before claiming this is closed.

  • [SME-PROPOSED] Add AC: "flow-8 SHALL achieve ≥12/15 PASS before EP-005A is considered launch-ready. The 3 acceptable gaps are: (1) inter-tenant IRN cross-check (defers to a future tenant-isolation hardening pass), (2) sponsored-billing scenario (Vishramgruh-only), (3) credit-note PDF idempotency (covered by AP-T08-007 specs)."
  • [SME-PROPOSED] Add AC: "A CI gate SHALL run flow-8 on every hmp-frontdesk-service master push and block merge if pass rate regresses below the current baseline."

D-005A-009 — [P0] [Missing-validation + India-compliance] B2B buyer GSTIN cannot be captured at check-in (D-005A-005); at checkout it has to be entered ad-hoc into the invoice form. There is no model field, no validation, no GSTIN-state-prefix cross-check against Property.gstin state.

  • [SME-PROPOSED] Add AC: "Folio.buyerGstin SHALL be populated either at check-in (D-005A-005) or via PATCH /folios/:id/buyer-gstin before settlement. The first two digits of the buyer GSTIN SHALL determine intra-state vs inter-state for IGST resolution per AP-T07-004 — if buyerGstin[0:2] === property.gstin[0:2] → CGST+SGST; else → IGST. Mismatch with an existing customerState on the folio's transactions returns 400 with code BUYER_GSTIN_STATE_MISMATCH."
  • [SME-PROPOSED] Add AC: "B2B e-invoice generation SHALL be enabled only when Folio.buyerGstin is non-null. Missing GSTIN on a folioType=COMPANY folio returns 422 from POST /einvoice/generate with code B2B_REQUIRES_BUYER_GSTIN."

D-005A-010 — [P1] [Authorization-bypass] forceCheckout: true on POST /check-out/:reservationId lets any FRONT_DESK role bypass the balance gate. Real-world hotel operations require a manager PIN or supervisor approval for force-checkout.

  • [SME-PROPOSED] Add AC: "forceCheckout: true SHALL be honoured only when the caller's role is MANAGER, ADMIN, SUPER_ADMIN, or ACCOUNTS — OR when forceCheckoutAuthorizationCode (a 6-digit time-bound manager PIN) is supplied AND validated against the property's active manager PINs. Plain FRONT_DESK_AGENT with forceCheckout: true returns 403 with code FORCE_CHECKOUT_REQUIRES_MANAGER_APPROVAL. Audit log captures actorRole + (PIN-issuer if PIN-authorised)."

D-005A-011 — [P1] [Story-incomplete + India-compliance] Story does not enumerate IRN cancellation rules (NIC allows IRN cancellation within 24 h; after that requires credit note). No AC for the 24-h window.

  • [SME-PROPOSED] Add AC: "POST /einvoice/cancel SHALL be allowed only when now() - Folio.ackDate <= 24 hours. Beyond 24 h returns 422 with code IRN_CANCEL_WINDOW_EXPIRED and suggests POST /einvoice/credit-note (AP-T08-007) as the recovery path. UI MUST surface the remaining window."

US-005-005 — Room Grid / Floor Map View​

Catalog status: Built (P0, 3 points) — EPIC alias US-005-21 Verified status: Built-Untested for real-time WebSocket path; Built for polling path

Code locations:

  • hmp-frontdesk-service/src/front-desk/ — GET /front-desk/rooms/grid (room grid endpoint)
  • hmp-frontdesk-service/src/calendar/ — GET /front-desk/calendar (tape chart with roomBlocks per Plan 4 T15, Gotcha 23)
  • hmp-web-dashboard/src/components/modules/front-desk/room-grid.tsx [CITED-BUT-NOT-FOUND] (per US-005-005 review) — STATUS_CONFIG map, 30-s polling, RoomCard component
  • hmp-api-gateway/src/websocket/events.gateway.ts [CITED-BUT-NOT-FOUND] — Kafka → Socket.io bridge for room.status.changed, reservation.checked_in, etc.

Unit + integration tests:

  • hmp-frontdesk-service/src/calendar/*.spec.ts — AP-T13-001 cross-tenant assert + AP-T13-002 filter param coverage

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/flow-5-fd-hk-updates.spec.ts :: "room status propagation" — 11/12 PASS (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes:

  • (covered by dashboard smoke; no dedicated room-grid smoke)

E2E (Playwright): none dedicated to room-grid

Use cases referencing this story:

  • none

SME notes:

  • Frontend uses polling at 30 s; WebSocket bridge exists but the front-end never subscribes (per US-005-005 review). Real-time claim in the story is therefore wallpaper.
  • Tape chart calendar (/front-desk/calendar) now includes roomBlocks array (Plan 4 T15) — story doesn't reference this.

Drift findings:

D-005A-012 — [P1] [Test-vs-code] Story acceptance criteria say "real-time updates via WebSocket on check-in / status change". Backend Kafka → Socket.io bridge exists; frontend never subscribes — falls back to 30-s polling. Functionally the same UX as polling-only, but the story misrepresents the implementation.

  • [SME-PROPOSED] Add AC: "Front-end room-grid component SHALL subscribe to room.status.changed and reservation.checked_in/checked_out events via the dashboard's existing Socket.io client. On event receipt the grid SHALL invalidate the affected room's cache entry and re-render within 2 s. Polling SHALL drop to 60 s when the WebSocket is connected, 30 s when disconnected."

US-005-006 — Arrivals / Departures / In-House Lists​

Catalog status: Built (P0, 3 points) Verified status: Partial — backend complete; frontend pages are stubs per US-005-006 review (2026-03-07, may be stale — verify in Task 6)

Code locations:

  • hmp-frontdesk-service/src/checkin/checkin.service.ts — getArrivalsBoard() (summary: total, checkedIn, pending, vip)
  • hmp-frontdesk-service/src/checkout/checkout.service.ts — getDeparturesBoard() (summary + outstandingBalance) + getInHouseGuests() (nightsStayed, nightsRemaining, outstandingBalance)
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/arrivals/page.tsx
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/departures/page.tsx
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/in-house/page.tsx

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/checkin.service.spec.ts — 3 specs for getArrivalsBoard (summary counts, empty state, filter)
  • hmp-frontdesk-service/src/checkout/checkout.service.spec.ts — 5 getDeparturesBoard + 4 getInHouseGuests specs

Flow tests: none dedicated

Real-backend smokes: covered by sprint smoke flows

Use cases: none

SME notes:

  • Backend response shape is { arrivals, summary }; story expects { data, meta }. Pagination wrapper inconsistency vs other endpoints.
  • useArrivals hook uses POST /reservations/search instead of the dedicated GET /properties/:propertyId/arrivals — loses summary data per US-005-006 review GAP-8.
  • Auto-refresh uses staleTime: 60s (no refetchInterval: 30000) — story FR-9 requires 30 s.
  • Backend getArrivalsBoard Prisma query does NOT include group relation — group-arrival badge cannot be rendered (GAP-5).

Drift findings:

D-005A-013 — [P1] [Frontend-incomplete + drift-vs-review] US-005-006 review (2026-03-07) marks frontend as stubs with 4/15 ACs passing. The pages exist as files but may have been filled in since the review — Task 6 must verify whether the 2026-03-07 review is stale (similar to EP-002 D-011). If pages remain stubs, this is a launch blocker for Property #1 because arrivals/departures are the daily-driver views.

  • [SME-PROPOSED] Re-verify the three pages (arrivals, departures, in-house) post-2026-05-21 QA remediation. If still stubs, escalate to P0. If now functional, refresh the review file to PASS.

US-005-008 — Early Check-In / Late Check-Out Charges​

Catalog status: Partial (P1, 3 points) — EPIC alias US-005-13 Verified status: Partial — POST /late-checkout + POST /early-checkout + GET /early-checkin/preview/:reservationId shipped per controller; slab-based auto-calc, preview/confirm, GST on fee, manager waiver, VIP auto-waiver still missing per US-005-008 review

Code locations:

  • hmp-frontdesk-service/src/checkout/checkout.controller.ts — POST /late-checkout, POST /early-checkout, GET /early-checkin/preview/:reservationId
  • hmp-frontdesk-service/src/checkin/early-late-charge.service.ts + .spec.ts — exists (post-dates the 2026-03-07 review marking this NOT_IMPLEMENTED)
  • hmp-frontdesk-service/src/checkout/dto/checkout.dto.ts — LateCheckoutDto (manual fee amount)

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/early-late-charge.service.spec.ts (existence to verify in Task 6 — review claims NOT_IMPL but file exists)
  • hmp-frontdesk-service/src/checkout/checkout.service.spec.ts — 4 lateCheckout + 4 earlyCheckout specs

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/noshow-late-checkout.flow.spec.ts :: "Scenario 2 + 3 — late-checkout fee posting" — TBD (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes: none

Use cases referencing this story:

  • none

SME notes:

  • US-005-008 review verdict "NOT_IMPLEMENTED" is likely stale (2026-03-07). early-late-charge.service.ts + spec exist now. Pattern matches EP-002 D-011 (Seasons review-vs-code stale).
  • GST on late/early fees: review notes manual lateCheckoutFee is posted without tax. Indian-hospitality reality: SAC 996311 / accommodation charges attract 12% or 18% GST per declared tariff — the late fee is a continuation of the same supply and MUST inherit the same GST treatment.
  • Manager waiver: no role-based gate on POST /late-checkout lets the same agent post + waive. Indian compliance reality: waivers need an approval trail for the GST input-credit reversal.

Drift findings:

D-005A-014 — [P1] [Review-vs-code + India-compliance] Review marks NOT_IMPLEMENTED but early-late-charge.service.ts + spec exist (post-review). Verify file content in Task 6; if implemented, refresh the review verdict.

  • [SME-PROPOSED] Refresh reviews/EP-005/US-005-008-review.md post-verification.
  • [SME-PROPOSED] Add AC: "Late checkout fee SHALL inherit GST treatment from the linked rate plan's declared tariff: 0% if base tariff ≤ ₹1,000/night, 12% if ≤ ₹7,500, 18% if > ₹7,500. CGST/SGST/IGST split per Folio.buyerGstin resolution (D-005A-009). Fee transaction SHALL use transactionCode='LATE_CHECKOUT_FEE' with SAC 996311."
  • [SME-PROPOSED] Add AC: "Fee waiver SHALL require role ≥ MANAGER. A front-desk agent cannot post + waive in the same session. Waiver writes FolioTransaction.voidReason='WAIVED:<reason>' + voidedBy=<managerUserId>. Audit log captures the waiver event for GST input-credit reversal trail."

US-005-009 — Room Move / Upgrade During Stay​

Catalog status: Built (P1, 3 points) — EPIC alias US-005-14 Verified status: Built (post-AP-T05-005/006, Gotcha 29) — was Partial per 2026-03-07 review

Code locations:

  • hmp-frontdesk-service/src/room-ops/room-ops.service.ts — canonical impl (AP-T05-005, 2026-05-23). Handles VACANT_CLEAN target check with retry, FD_ROOM_MOVE_PRICING_VALIDATED safeguard, COMPLIMENTARY manager-auth gate, SAME_TYPE rate-realignment ADJUSTMENT, PAID-upgrade folio CHARGE inside the same $transaction (AP-T05-006).
  • hmp-frontdesk-service/src/room-ops/room-ops.controller.ts — POST /front-desk/room-move
  • hmp-frontdesk-service/src/room-ops/dto/room-move.dto.ts — RoomMoveDto with upgradeType (SAME_TYPE/COMPLIMENTARY/PAID) + managerAuthorizationCode
  • hmp-frontdesk-service/src/checkin/checkin.service.ts — CheckInService.roomMove is now a thin delegator to RoomOpsService.roomMove (Gotcha 29 "one canonical impl" charter)
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/ — no dedicated room-move dialog UI yet (per 2026-03-07 review GAP-8)

Unit + integration tests:

  • hmp-frontdesk-service/src/room-ops/room-ops.service.spec.ts — 3 AP-T05-005 + 3 AP-T05-006 cases (per Gotcha 29)
  • hmp-frontdesk-service/src/checkin/checkin.service.spec.ts — 3 roomMove delegation cases

Flow tests:

  • hmp-infrastructure/testing/flow-tests/src/flows/flow-5-fd-hk-updates.spec.ts :: "room move + extend" — 11/12 PASS (2026-05-16-13-flow-demo-readiness.md, 2026-05-16)

Real-backend smokes: none specific

Use cases referencing this story:

  • docs/requirements/use-cases/uc-room-move-canonical.yaml [CITED-BUT-NOT-FOUND] (AP-T05-005/006 deserve a UC)

SME notes:

  • 2026-05-23 AP-T05-005/006 closes the GAP-1 (no upgrade flow) + GAP-2 (no folio rate adjustment) + GAP-3 (no manager-auth for complimentary) gaps from the 2026-03-07 review. Review verdict stale.
  • Idempotency: PAID-upgrade dedup key roommove:{reservationId}:upgrade:{fromRoomId}->{toRoomId} on FolioTransaction.reference — retried call cannot double-bill. Good practice.
  • No dedicated dashboard dialog yet (GAP-8 from review).

Drift findings:

D-005A-015 — [P1] [Review-vs-code] 2026-03-07 review marks PASS_WITH_NOTES with 5/9 ACs and the upgrade flow as NOT_IMPL. AP-T05-005 (2026-05-23) ships the upgrade flow + manager auth + folio charge. Review is stale.

  • [SME-PROPOSED] Refresh reviews/EP-005/US-005-009-review.md to PASS with the 9/9 AC mapping per AP-T05-005/006.
  • [SME-PROPOSED] Add AC for keycard cascade on room move: "RoomOpsService.roomMove SHALL call keyCardService.revokeForCheckOut(oldRoomId) + keyCardService.encodeForCheckIn(newRoomId) non-blocking (mirrors check-in pattern). Failures logged but do not roll back the move."

US-005-010 — Walk-In Check-In (No Prior Reservation)​

Catalog status: Partial (P0, 5 points) — EPIC alias US-005-15 Verified status: Partial — POST /walk-in works + POST /walk-in/:id/recover saga retry shipped; UI flow still requires 6+ steps per EPIC body gap analysis #3

Code locations:

  • hmp-frontdesk-service/src/checkin/checkin.controller.ts — POST /walk-in, POST /walk-in/:reservationId/recover
  • hmp-frontdesk-service/src/checkin/checkin.service.ts — walkIn() + recoverWalkIn() (P1-A1 same-day duplicate detection, P1-A2 saga recovery, Gotcha 16)
  • hmp-frontdesk-service/src/checkin/dto/checkin.dto.ts — WalkInDto
  • hmp-web-dashboard/src/app/(dashboard)/front-desk/ — walk-in UI exists per EPIC §4.2 "Walk-In Quick Form — Partial"

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/checkin.service.spec.ts — walk-in path coverage in the 20+ spec suite
  • hmp-frontdesk-service/src/checkin/express-checkin.spec.ts — adjacent coverage

Flow tests: covered tangentially in flow-6

Real-backend smokes: none specific

Use cases referencing this story:

  • docs/requirements/use-cases/uc-walkin-saga-recovery.yaml [CITED-BUT-NOT-FOUND] (P1-A2 deserves a UC)

SME notes:

  • Walk-in saga (Gotcha 16): Reservation.walkInRecoveryState (Json) tracks 4 side-effect outcomes — room status, reservation-service mirror, event publish, ID verification persist. Recovery endpoint retries false flags. Idempotent.
  • EPIC §3.1 sub-bullet "Walk-in quick booking + immediate check-in" + §5 gap #3 "Walk-in flow requires too many steps (6+)" — UI streamlining is a P1 backlog item per EPIC.
  • Same-day duplicate detection (P1-A1): fat-finger walk-ins for the same guest on the same day surface a confirmation prompt. Story body doesn't mention.

Drift findings: (no new — feeds into D-005A-005 buyer-GSTIN and D-005A-003 ID format gaps)

  • [SME-PROPOSED] Author uc-walkin-saga-recovery.yaml covering the 4 side-effect retries + idempotency contract.
  • [SME-PROPOSED] Add AC: "Walk-in UI SHALL collapse to ≤ 3 steps (guest details, room+rate selection, payment + ID capture). The 6-step legacy flow SHALL be deprecated by end of Sprint 6."

US-005-011 — Registration Card Generation (PDF)​

Catalog status: Partial (P1, 3 points) — EPIC alias US-005-09 Verified status: Partial — GrcService exists; legal/format polish pending per EPIC §5 gap #4

Code locations:

  • hmp-frontdesk-service/src/grc/grc.controller.ts — POST /grc registration card generation
  • hmp-frontdesk-service/src/grc/grc.service.ts + .spec.ts

Unit + integration tests:

  • hmp-frontdesk-service/src/grc/grc.service.spec.ts

Flow tests: none dedicated

Real-backend smokes: none

Use cases referencing this story:

  • none

SME notes:

  • EPIC §5 gap #4: "Registration card PDF formatting (legal compliance risk)" — Indian-hospitality reality: registration card is a legal document under state Hotel Acts (e.g. Karnataka, Maharashtra Hotels & Lodging Houses regulations). Mandatory fields include: full name, age, sex, nationality, profession, address, purpose of visit, accompanying persons (with relationship), date+time of arrival, expected departure, last/next residence (intended), signature. Many states require police-register submission within 24 h.
  • Format polish today: spacing + signature placement + GSTIN row + property-state-specific field (Maharashtra mandates aadhaar-last-4 + relation to head; Tamil Nadu mandates police-permit-number for foreigners). No per-state template selector.

Drift findings:

D-005A-016 — [P1] [Story-incomplete + India-compliance] Registration card PDF is generated but does not branch by property state for state-specific mandatory fields (Maharashtra aadhaar-last-4, Tamil Nadu police-permit-number, Goa tourist-permit, etc.). Today: one-size-fits-all template.

  • [SME-PROPOSED] Add AC: "GrcService.generatePdf SHALL select a state-specific template based on Property.state (2-letter code). Bundled templates SHALL cover at minimum: MH (Maharashtra), KA (Karnataka), TN (Tamil Nadu), DL (Delhi), GA (Goa). Fallback to a national-generic template for other states with a one-line audit log warning."
  • [SME-PROPOSED] Add AC: "Registration card SHALL carry the buyer GSTIN (D-005A-005) when present. Signature panel SHALL accept tablet/kiosk capture (PNG base64) AND a printed-and-scanned upload. Both paths persist to GuestIdVerification.signatureUrl per the AP-T06-005 presigned-URL flow."

US-005-012 — Express Check-In (Mobile Pre-Registration)​

Catalog status: Partial (P2, 8 points) — EPIC alias US-005-16 Verified status: Partial — POST /express-check-in endpoint shipped; not wired to booking-engine guest pre-arrival link per EPIC §4.1 + §5 gap #1

Code locations:

  • hmp-frontdesk-service/src/checkin/checkin.controller.ts — POST /express-check-in
  • hmp-frontdesk-service/src/checkin/checkin.service.ts — expressCheckIn() streamlined flow
  • hmp-frontdesk-service/src/guest-checkin/ — GuestCheckInService.confirmCheckIn (mobile path; reconciler-wired per Gotcha 28 — D1)
  • hmp-frontdesk-service/src/self-checkin/ — kiosk variant (separate from express check-in but adjacent)

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/express-checkin.spec.ts
  • hmp-frontdesk-service/src/guest-checkin/guest-check-in.service.spec.ts

Flow tests: none dedicated

Real-backend smokes: none

Use cases referencing this story:

  • none

SME notes:

  • EPIC §5 gap #1 "Express check-in not connected to booking engine guest link" — the guest-facing pre-arrival web form does not exist; only the backend endpoint.
  • Express check-in DOES NOT enforce FRRO foreign-guest C-Form check (Gotcha 13). This is per design (express is a kiosk-style assignment-only flow) but the story body doesn't call it out — a new engineer enabling express for international guests would introduce a compliance gap.

Drift findings: (no new — story status correctly Partial)

  • [SME-PROPOSED] Add AC: "Express check-in SHALL be allowed only when Reservation.guest.nationality === 'IN' (Indian national). Foreign-guest reservations SHALL be redirected to the staff check-in flow (POST /check-in/:reservationId) which enforces P1-A6 FRRO Form-C + visa/passport expiry guards."
  • [SME-PROPOSED] Add AC: "Booking engine confirmation email SHALL embed a tokenised pre-arrival link (/guest-portal/checkin/:token) that opens the mobile express check-in flow. Token SHALL expire 24 h before scheduled arrival."

US-005-013 — Keycard Management (Encode/Re-encode/Deactivate)​

Catalog status: Built (P2, 5 points) — EPIC alias US-005-12 Verified status: Built

Code locations:

  • hmp-frontdesk-service/src/keycard/keycard.controller.ts — POST /keycards/encode, POST /keycards/reencode, DELETE /keycards/:id
  • hmp-frontdesk-service/src/keycard/keycard.service.ts + .spec.ts — retry-with-backoff (P1-A5, Gotcha 17: 3 attempts, 200/500 ms backoff)
  • @hmp/hardware package — RFID/BLE adapters (mock when HARDWARE_MOCK=true)

Unit + integration tests:

  • hmp-frontdesk-service/src/keycard/keycard.controller.spec.ts
  • hmp-frontdesk-service/src/keycard/keycard.service.spec.ts

Flow tests: none dedicated (covered tangentially in flow-6)

Real-backend smokes: none (hardware-gated)

Use cases referencing this story:

  • none

SME notes:

  • Smart-lock integration is mock-only (EPIC §4.1 + §5 gap #5; US-005-014 is the dedicated story for the real adapter).
  • keyCardService.encodeForCheckIn() returns {success, error?, attempts} so the dashboard can surface "encoded on retry" warnings (Gotcha 17).

Drift findings: (none net new)


US-005-014 — Smart Lock Integration (ASSA ABLOY / dormakaba / etc.)​

Catalog status: Not Started (P3, 8 points) — EPIC alias US-005-17 Verified status: Not Started (mock-only per @Integration(ServiceMode.MOCK) decorator)

Code locations:

  • hmp-frontdesk-service/src/smart-lock/ — module exists as scaffolding (mock adapter)
  • @hmp/hardware BLE adapter — mock implementation

Unit + integration tests: scaffolding only

Flow tests: none

Real-backend smokes: none (no real device)

Use cases: none

SME notes:

  • Real device wiring requires per-property BLE driver + per-vendor SDK (ASSA ABLOY Vingcard, dormakaba Saflok, Onity, etc.). Not a launch blocker — RFID magstripe via US-005-013 is the launch path.
  • Story body says "ASSA ABLOY" but Indian-market reality often includes Salto, Onity, ZKTeco. Spec should be vendor-agnostic.

Drift findings: (none — story-vs-reality matches Not Started)

  • [SME-PROPOSED] When implementation begins, AC SHALL be: "Smart-lock integration SHALL be vendor-agnostic via the @hmp/hardware SmartLockAdapter interface. Initial implementations: ASSA ABLOY Vingcard, dormakaba Saflok, Salto KS. Per-property selection via Property.smartLockVendor enum."

US-005-015 — ID Scanner Integration​

Catalog status: Built (P2, 5 points) — EPIC alias US-005-10 Verified status: Built

Code locations:

  • hmp-frontdesk-service/src/id-scanner/id-scanner.controller.ts — POST /id-scan/aadhaar, POST /id-scan/passport, POST /id-scan/dl
  • hmp-frontdesk-service/src/id-scanner/id-scanner.service.ts + .spec.ts — Aadhaar QR XML parser, Passport MRZ TD3 parser, DL parser
  • hmp-frontdesk-service/src/scanner/ — adjacent scanner abstraction

Unit + integration tests:

  • hmp-frontdesk-service/src/id-scanner/id-scanner.service.spec.ts

Flow tests: covered tangentially in flow-6

Real-backend smokes: none (hardware-gated)

Use cases: none

SME notes:

  • Aadhaar QR XML parser extracts UID. Aadhaar Act 2016 + UIDAI Circular: full UID storage by hotels is not permitted; only the last 4 digits + a masked display ("XXXX-XXXX-NNNN") are allowed. Critical gap: verify in Task 6 whether id-scanner.service.ts masks before persisting, OR whether the full UID is written to GuestIdVerification.
  • Passport MRZ TD3: standard 2-line 44-char format. Should auto-populate formC (Form C foreign-guest registration) on check-in for non-Indian guests.
  • No [SME-PROPOSED] AC for the scanner-to-check-in handoff: today the scanner returns parsed JSON but the front-end has to manually copy it into CheckInDto. Should be a single combined call.

Drift findings: (potentially P0 — verify in Task 6)

  • [SME-PROPOSED] Task 6 verification: confirm IdScannerService.scanAadhaar masks UID to last-4 before persistence, per Aadhaar Act 2016. If full UID is being stored, escalate to P0 with code AADHAAR_UID_NOT_MASKED and trace impact across GuestIdVerification, reporting-feeds/frontdesk/police-register, and analytics MVs.
  • [SME-PROPOSED] Add AC: "Passport MRZ scan for non-Indian guest SHALL auto-populate formC.{passportNo, nationality, dob, expiryDate} fields on the check-in payload. Visa fields (visaNo, visaType, visaExpiryDate) require a separate visa-page scan or manual entry."

US-005A-01 — Batch / Group Check-In​

Catalog status: Not Started (P2, 5 points in catalog as US-005-018) — EPIC body US-005A-01 = 8 points Verified status: Partial — POST /check-in/batch endpoint shipped (per checkin.controller.ts line 53); batch-checkin.spec.ts exists; max 50-row guard noted in controller comment

Code locations:

  • hmp-frontdesk-service/src/checkin/checkin.controller.ts:53 — POST /check-in/batch (max 50 rows per call)
  • hmp-frontdesk-service/src/checkin/batch-checkin.spec.ts

Unit + integration tests:

  • hmp-frontdesk-service/src/checkin/batch-checkin.spec.ts

Flow tests: none

Real-backend smokes: none

Use cases: none

SME notes:

  • EPIC body US-005A-01 says "Not Started"; catalog US-005-018 says "Not Started"; code says Partial. Drift.
  • Indian-market reality: group arrivals (corporate, wedding, tour) commonly hit 30-100 rooms in a single block. Sequential check-in burns 60-90 minutes; batch should close in <60 s.
  • Story says "publishes individual guest.checked_in Kafka events for each reservation" — verify the batch implementation actually does per-row events vs one bulk event (the former is required for downstream consumers like CRM loyalty earn which dedup per reservation).

Drift findings:

D-005A-001 — [P1] [Catalog-vs-code + catalog-vs-EPIC] Catalog row US-005-018 "Group Check-In (Batch)" says Not Started. EPIC body US-005A-01 says Not Started. Code says Partial — POST /check-in/batch + batch-checkin.spec.ts exist. A reviewer reading catalog or EPIC body would skip this story; a reviewer reading code would think it's done.

  • [SME-PROPOSED] Update catalog row US-005-018 status to Partial. Add EPIC body US-005A-01 status update to Partial with a Day-2 note enumerating: (a) per-row error reporting (no partial-failure summary today), (b) per-row Kafka event verification (vs bulk), (c) batch-aware folio-number generation (no gap between sequential folios in the same batch).
  • [SME-PROPOSED] Add AC: "Batch check-in SHALL publish one RESERVATION_CHECKED_IN event per reservation (not one bulk event) — required so CRM loyalty earn dedupes per reservation. Spec asserts event count == row count."

US-005A-02 — Kiosk Self-Check-In​

Catalog status: Not in catalog (EPIC body only — gap) Verified status: Partial — backend /self-checkin + /guest-portal/self-checkin shipped (presigned-URL flow per AP-T06-005, Gotcha 30); kiosk page shipped per EPIC; ID-mismatch and FRRO path coverage pending

Code locations:

  • hmp-frontdesk-service/src/self-checkin/self-checkin.controller.ts — kiosk endpoints
  • hmp-frontdesk-service/src/self-checkin/self-checkin.service.ts + .spec.ts — AP-T06-005 presigned-URL ID + signature upload (Gotcha 30 — 6 new specs)
  • hmp-frontdesk-service/src/guest-checkin/ — adjacent guest-initiated flow
  • hmp-web-dashboard/src/app/(dashboard)/kiosk/page.tsx — kiosk page
  • hmp-web-dashboard/src/app/(dashboard)/kiosk/keynova.tsx — KeyNova-branded kiosk variant

Unit + integration tests:

  • hmp-frontdesk-service/src/self-checkin/self-checkin.service.spec.ts (includes AP-T06-005 presigned-URL coverage)

Flow tests: none dedicated

Real-backend smokes: none

Use cases referencing this story:

  • none

SME notes:

  • Catalog gap: no US-NNN row for kiosk self-check-in. EPIC body has US-005A-02. New catalog row needed.
  • AP-T06-005 (Gotcha 30, 2026-05-23): switched from base64 ID + signature blobs to presigned-URL upload. The previous implementation accepted base64 and never persisted it — only logged hasIdDocument: !!dto.idImage. Now: real URL persistence as internalNotes markers (no dedicated columns yet — staff complete real ID verification on check-in handoff).
  • Kiosk flow: per EPIC, 5-step wizard. ID mismatch routes to front desk. Frontend coordination required (booking-engine must call /upload-url then /submit with URLs — base64 contract is gone).

Drift findings:

D-005A-002 — [P1] [Catalog-incomplete + numbering-drift] Catalog (01-epic-catalog.md) has no row for US-005A-02 (Kiosk Self-Check-In) or US-005A-01 (Batch) or US-005A-03 (Express Checkout). The EPIC body splits EP-005 into A/B/C/D with sub-IDs; the catalog has not followed. Two different numbering schemes for the same story IDs — see EP-002 D-007 for the equivalent precedent.

  • [SME-PROPOSED] Adopt the catalog as canonical, add sub-EPIC rows US-005A-01/02/03 (or renumber to US-005-018/019/020 to keep 3-digit padding). Either way, settle one scheme before BF-003/-005 land.
  • [SME-PROPOSED] Add AC for kiosk ID mismatch: "When the scanned ID name (last name, case-insensitive, ASCII-normalised) differs from Reservation.guest.lastName, the kiosk SHALL display 'Identity verification failed — please visit front desk' and NOT issue a keycard. A kiosk.id.mismatch Kafka event SHALL fire so analytics can track abandoned kiosk attempts."

US-005A-03 — Express Check-Out (Auto-Settle)​

Catalog status: Not in catalog (EPIC body only) Verified status: Stub — POST /check-out/express endpoint exists per Gotcha file, but the auto-eligibility scanner that runs during night audit (the actual "express" feature) is missing

Code locations:

  • hmp-frontdesk-service/src/checkout/checkout.controller.ts — POST /check-out/express
  • hmp-frontdesk-service/src/checkout/express-checkout.spec.ts

Unit + integration tests:

  • hmp-frontdesk-service/src/checkout/express-checkout.spec.ts

Flow tests: none

Real-backend smokes: none

Use cases: none

SME notes:

  • The "express" feature per EPIC body §US-005A-03 is automatic checkout during night audit for zero-balance departures with email on file. Today: the night-audit service does NOT call checkoutExpressEligible() — the express-checkout endpoint exists as a manual one-off, not as a batch auto-settle.
  • This is wired tangentially via PaymentCapturedConsumer (Gotcha 27, 2026-05-19) — payments captured from terminal/link automatically post to folios, which in theory zeros the balance. But the night-audit step is the missing piece.

Drift findings:

(no new — captured by D-005A-001 catalog/EPIC numbering)

  • [SME-PROPOSED] Add AC: "Night audit (EP-005C) SHALL invoke CheckoutService.processExpressCheckOuts(propertyId, businessDate) after the room-charge posting step. Method: iterate Reservation.findMany({status:CHECKED_IN, departureDate: businessDate, folio.balance: 0, guest.email: not null}), call checkOut({forceCheckout: false, source: 'EXPRESS'}) per row, mail invoice. Reports {succeeded, skipped, failed} count in the night-audit summary."
  • [SME-PROPOSED] Add AC: "Express auto-checkout SHALL be opt-in per property via Property.policies.expressCheckoutEnabled. Default OFF for compliance (some Indian states require explicit guest sign-off at checkout). Opt-in enabled via PATCH /properties/:id/policies."

Cross-cutting drift findings (this EPIC)​

(in addition to the per-story D-NNN findings above)

D-005A-016 is already attached to US-005-011 above for state-specific registration cards. Surfacing the cross-cutting items below as part of this section so they aren't lost.

D-005A-001 (US-005A-01 / batch) — see story section D-005A-002 (catalog vs EPIC numbering scheme drift) — see US-005A-02 section

Stale-review-file pattern​

Same systemic issue flagged in EP-002 D-011 — multiple US-005-NNN review files are 10+ weeks stale (2026-03-07 authorship) and predate:

  • AP-T05-005/006 room-move canonicalisation (2026-05-23) — closes US-005-009 GAP-1/2/3
  • QA-CHECKIN D1 reconciler (2026-05-22) — closes a SEV-2 not in any review
  • AP-T08-001/006 folio IRN denormalisation (2026-04-29) — closes US-005-007 GAP-1
  • AP-T08-007 credit-note queue routing (2026-05-23) — closes US-005-007 GAP-6
  • AP-T07-004 GST split derivation (2026-05-23) — closes US-005-002 invoice-line-item gap
  • FU-55 folio event dual-emit (2026-05-23) — closes 5 empty analytics MV root cause

A blanket review-refresh sweep is required.


Pass-rate caveat​

The 2026-05-16-13-flow-demo-readiness snapshot puts flow-6 at 6/13 and flow-8 at 0/15. Since the snapshot, the following landed:

  • 2026-05-22 D1 reconciler (Gotcha 28) — should fix the stale-read-model reservation status failures in both flows
  • 2026-05-23 AP-T05-005/006 room move canonicalisation (Gotcha 29) — orthogonal to flow-6/8 but in the same EPIC
  • 2026-05-23 AP-T07-004 GST split (Gotcha 29) — should reduce the e-invoice IRN generation failures in flow-8
  • 2026-05-23 FU-55 dual-emit (Gotcha 31) — should populate the post-checkout analytics MVs flow-8 verifies

Operator action (folds into D-005A-008): re-run flow-6 + flow-8 against the post-2026-05-23 hmp-frontdesk-service master build and update this RTM + the 13-flow demo-readiness doc with the new numbers before claiming launch readiness.


SME ground rules applied (PLAYBOOK reference)​

  • Aadhaar Act 2016 + UIDAI Circular: 12-digit format + UID masking (D-005A-003, US-005-015 SME notes)
  • Foreigners Act 1946 + FRRO Form C: Gotcha 13 in frontdesk CLAUDE.md (P1-A6) — passport + visa expiry check; story exists but not in any review file
  • GST CGST/SGST vs IGST: AP-T07-004 derivation (Gotcha 29) — D-005A-009
  • NIC e-invoice IRN: 24-h cancel window (D-005A-011), B2B requires buyer GSTIN (D-005A-009)
  • DPDPA 2023 right to erasure: AP-T08-005 (Gotcha 30) GuestErasedConsumer — story-untouched but production-deployed
  • Hotel-state-specific registration: Maharashtra / Karnataka / TN regs (D-005A-016)
  • PCI DSS: payment-service isolation — out of scope for this EPIC (lives in EP-015)