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.mdthroughUS-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-66/13,flow-80/15) overlaid withhmp-frontdesk-service/CLAUDE.mdGotchas 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
| Status | Meaning |
|---|---|
Built | Code exists + tests exist + tests pass |
Built-Untested | Code exists, no automated test coverage (or test exists but is a stub) |
Partial | Code exists for some acceptance criteria, gaps for others |
Stub | Code is a placeholder / TODO / returns mock data |
Not Started | No code |
Summary
| Metric | Count |
|---|---|
| In-scope stories | 13 (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-Built | 4 (US-005-001, -002 with B2B/express caveats, US-005-013, US-005-015) |
| Built-Untested | 1 (US-005-005 — covered partially) |
| Partial | 6 (US-005-008, -009, -010, -011, -012, US-005-006) |
| Stub | 1 (US-005A-03 — re-uses /check-out/express; no auto-eligibility scan) |
| Not Started | 2 (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] refinements | 32 |
Catalog vs EPIC numbering drift: catalog uses
US-005-001..0223-digit padding; EPIC body usesUS-005-01..212-digit +US-005A-01..03for 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/arrivalshmp-frontdesk-service/src/checkin/checkin.service.ts—checkIn()orchestrator (CONFIRMED guard + arrival-date guard + VACANT_CLEAN room verification + folio bootstrap +RESERVATION_CHECKED_INKafka 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 healerhmp-frontdesk-service/src/checkin/payment-capture.service.ts— non-blocking pre-auth capture at check-inhmp-frontdesk-service/src/checkin/preference-matcher.service.ts— auto-assign matches guest preferenceshmp-frontdesk-service/src/checkin/id-photo-upload.controller.ts+.service.ts— multi-doc photo upload tied to check-inhmp-web-dashboard/src/app/(dashboard)/front-desk/check-in/[id]/page.tsx— dashboard check-in wizardhmp-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 pathhmp-frontdesk-service/src/checkin/checkin.service.p6.spec.ts— Phase-6 expanded coveragehmp-frontdesk-service/src/checkin/checkin.controller.spec.ts— controller-layer assertionshmp-frontdesk-service/src/checkin/drift-defense.spec.ts— anti-regression for D1 reconcilerhmp-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.tshmp-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 blockerhmp-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 missedreservation.modifiedKafka event left the frontdesk local Reservation read-model atPENDINGwhile reservation-service canonical wasCONFIRMED. The dashboard showedCONFIRMEDbut 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.idDocumentNumberhas@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'shousekeepingStatusstays atCLEANinstead of transitioning toDIRTY. The check-in cascade in property-service flipsRoom.statustoOCCUPIEDbut does not separately flip the HK lane toDIRTY. 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
folioIdfor a folio not yet visible toGET /folios/:id— a likely transaction-timing or read-replica-lag bug. The flow test mitigates by usingGET /folios/by-reservation/:idexclusively. 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/recoverretry 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,idDocumentNumberSHALL match/^\d{12}$/. Validation lives inCheckInDtovia a conditional@Matches()decorator OR inCheckInService.checkIn()as a pre-DB guard. Returns 400 with codeAADHAAR_INVALID_FORMATon mismatch." - [SME-PROPOSED] Add AC: "When
idDocumentType=PAN,idDocumentNumberSHALL match/^[A-Z]{5}[0-9]{4}[A-Z]$/. WhenVOTER_ID,/^[A-Z]{3}[0-9]{7}$/. WhenDRIVING_LICENSE,/^[A-Z]{2}[0-9]{2} ?[0-9]{11}$/. WhenPASSPORT,/^[A-Z][0-9]{7}$/(India) — relaxed regex ifissueCountry !== 'IN'. All return 400 with<TYPE>_INVALID_FORMATcodes."
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 aroom.status.changedKafka event whose payload setshousekeepingStatus=OCCUPIED_NEEDS_SERVICE(or whatever the canonical lane is) in addition to the existingstatus=OCCUPIEDtransition. 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: "
CheckInDtoSHALL accept optionalbuyerGstin(regex^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$) andcompanyId(FK to crmCompany). When present,CheckInService.checkInSHALL setFolio.companyId+Folio.buyerGstinon the bootstrap folio AND include the GSTIN on the registration card PDF. Mismatch (GSTIN !=Company.gstin) returns 400 with codeBUYER_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.idvalues that are committed and immediately readable viaGET /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.yamlcovering: given stale local read model + canonical CONFIRMED → reconciler heals → check-in proceeds; given local PENDING + canonical PENDING → check-in rejects withRESERVATION_NOT_CONFIRMED; given reconciler timeout / 5xx from reservation-service → check-in rejects fail-safe withRESERVATION_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/:reservationIdhmp-frontdesk-service/src/checkout/checkout.service.ts—checkOut(),lateCheckout(),earlyCheckout(),getDeparturesBoard(),getInHouseGuests(). PublishesRESERVATION_CHECKED_OUT+ROOM_STATUS_CHANGED+HOUSEKEEPING_TASK_CREATED. E-invoice auto-fires percheckout.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})onpayments, Gotcha 0b),LateCheckoutDto,EarlyCheckoutDto,SplitPaymentLineDtohmp-frontdesk-service/src/checkout/sponsored-billing.service.ts— Vishramgruh sponsor split (hospital authorization use case)hmp-frontdesk-service/src/einvoice/—EInvoiceService.generateIrnForFolio+EInvoiceJobProcessorretry 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 UIhmp-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-househmp-frontdesk-service/src/checkout/checkout.controller.spec.tshmp-frontdesk-service/src/checkout/checkout-dto-validation.spec.ts— 8 new PMS-2 specs (Gotcha 0b)hmp-frontdesk-service/src/checkout/express-checkout.spec.tshmp-frontdesk-service/src/checkout/split-payment.spec.tshmp-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 blockerhmp-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/ackNumberare denormalised fromEInvoiceJobso the PDF reads fromFoliodirectly. 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.tslives 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). forceCheckoutsemantics: Currently any user withFRONT_DESKrole can passforceCheckout: trueto 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),
PosFolioChargeConsumernow derives the split fromcustomerState. 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-servicemaster 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.buyerGstinSHALL be populated either at check-in (D-005A-005) or viaPATCH /folios/:id/buyer-gstinbefore settlement. The first two digits of the buyer GSTIN SHALL determine intra-state vs inter-state for IGST resolution per AP-T07-004 — ifbuyerGstin[0:2] === property.gstin[0:2]→ CGST+SGST; else → IGST. Mismatch with an existingcustomerStateon the folio's transactions returns 400 with codeBUYER_GSTIN_STATE_MISMATCH." - [SME-PROPOSED] Add AC: "B2B e-invoice generation SHALL be enabled only when
Folio.buyerGstinis non-null. Missing GSTIN on afolioType=COMPANYfolio returns 422 fromPOST /einvoice/generatewith codeB2B_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: trueSHALL be honoured only when the caller's role isMANAGER,ADMIN,SUPER_ADMIN, orACCOUNTS— OR whenforceCheckoutAuthorizationCode(a 6-digit time-bound manager PIN) is supplied AND validated against the property's active manager PINs. PlainFRONT_DESK_AGENTwithforceCheckout: truereturns 403 with codeFORCE_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/cancelSHALL be allowed only whennow() - Folio.ackDate <= 24 hours. Beyond 24 h returns 422 with codeIRN_CANCEL_WINDOW_EXPIREDand suggestsPOST /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 withroomBlocksper 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_CONFIGmap, 30-s polling, RoomCard componenthmp-api-gateway/src/websocket/events.gateway.ts[CITED-BUT-NOT-FOUND]— Kafka → Socket.io bridge forroom.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 includesroomBlocksarray (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.changedandreservation.checked_in/checked_outevents 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.tsxhmp-web-dashboard/src/app/(dashboard)/front-desk/departures/page.tsxhmp-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 forgetArrivalsBoard(summary counts, empty state, filter)hmp-frontdesk-service/src/checkout/checkout.service.spec.ts— 5getDeparturesBoard+ 4getInHouseGuestsspecs
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. useArrivalshook usesPOST /reservations/searchinstead of the dedicatedGET /properties/:propertyId/arrivals— loses summary data per US-005-006 review GAP-8.- Auto-refresh uses
staleTime: 60s(norefetchInterval: 30000) — story FR-9 requires 30 s. - Backend
getArrivalsBoardPrisma query does NOT includegrouprelation — 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/:reservationIdhmp-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— 4lateCheckout+ 4earlyCheckoutspecs
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
lateCheckoutFeeis 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-checkoutlets 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.mdpost-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.buyerGstinresolution (D-005A-009). Fee transaction SHALL usetransactionCode='LATE_CHECKOUT_FEE'with SAC996311." - [SME-PROPOSED] Add AC: "Fee waiver SHALL require role ≥
MANAGER. A front-desk agent cannot post + waive in the same session. Waiver writesFolioTransaction.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-movehmp-frontdesk-service/src/room-ops/dto/room-move.dto.ts—RoomMoveDtowithupgradeType(SAME_TYPE/COMPLIMENTARY/PAID) +managerAuthorizationCodehmp-frontdesk-service/src/checkin/checkin.service.ts—CheckInService.roomMoveis now a thin delegator toRoomOpsService.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— 3roomMovedelegation 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}onFolioTransaction.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.mdto PASS with the 9/9 AC mapping per AP-T05-005/006. - [SME-PROPOSED] Add AC for keycard cascade on room move: "
RoomOpsService.roomMoveSHALL callkeyCardService.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/recoverhmp-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—WalkInDtohmp-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 suitehmp-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 retriesfalseflags. 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.yamlcovering 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 /grcregistration card generationhmp-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.generatePdfSHALL select a state-specific template based onProperty.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.signatureUrlper 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-inhmp-frontdesk-service/src/checkin/checkin.service.ts—expressCheckIn()streamlined flowhmp-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.tshmp-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/:idhmp-frontdesk-service/src/keycard/keycard.service.ts+.spec.ts— retry-with-backoff (P1-A5, Gotcha 17: 3 attempts, 200/500 ms backoff)@hmp/hardwarepackage — RFID/BLE adapters (mock whenHARDWARE_MOCK=true)
Unit + integration tests:
hmp-frontdesk-service/src/keycard/keycard.controller.spec.tshmp-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/hardwareBLE 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/hardwareSmartLockAdapter interface. Initial implementations: ASSA ABLOY Vingcard, dormakaba Saflok, Salto KS. Per-property selection viaProperty.smartLockVendorenum."
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/dlhmp-frontdesk-service/src/id-scanner/id-scanner.service.ts+.spec.ts— Aadhaar QR XML parser, Passport MRZ TD3 parser, DL parserhmp-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.tsmasks before persisting, OR whether the full UID is written toGuestIdVerification. - 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 intoCheckInDto. Should be a single combined call.
Drift findings: (potentially P0 — verify in Task 6)
- [SME-PROPOSED] Task 6 verification: confirm
IdScannerService.scanAadhaarmasks UID to last-4 before persistence, per Aadhaar Act 2016. If full UID is being stored, escalate to P0 with codeAADHAAR_UID_NOT_MASKEDand trace impact acrossGuestIdVerification,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_inKafka 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 toPartialwith 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_INevent 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 endpointshmp-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 flowhmp-web-dashboard/src/app/(dashboard)/kiosk/page.tsx— kiosk pagehmp-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 asinternalNotesmarkers (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-urlthen/submitwith 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. Akiosk.id.mismatchKafka 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/expresshmp-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: iterateReservation.findMany({status:CHECKED_IN, departureDate: businessDate, folio.balance: 0, guest.email: not null}), callcheckOut({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 viaPATCH /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)