Skip to main content

Property #1 Readiness Audit — 2026-04-28

Verdict: NO-GO as of 2026-04-28 (15:30 IST).

The platform cannot onboard a paying property today. 47 P0 items are open across the 13 launch flows; 30+ would each be launch-blocking on its own. The heaviest blockers:

  • GST e-invoice IRN is mocked in staging-aws and prod-aws compose files; the printed/emailed PDF hardcodes the literal string IRN: Pending. Every invoice produced today is non-compliant under the Goods and Services Tax (Compulsory Generation of Invoice Reference Number) Notification 13/2020.
  • No Razorpay or merchant-account credentials are seeded anywhere. MerchantAccount is empty on QA. The first guest payment will 404 from MerchantAccountService.resolveForPayment.
  • The Kitchen Display app (hmp-kds-kiosk) connects to the wrong WebSocket namespace (/events instead of /kitchen), sends no JWT, and listens to event names (kot.received, kot.bumped) that no producer emits. It silently falls back to demo data. The wall-mounted KDS in the kitchen will never see a real KOT.
  • AWS QA Materialised Views are empty across the board. Every /api/reports/* endpoint returns {"data":[]} and every /api/analytics/dashboard/metrics field is zero. Reports & Dashboards (Flow 10) do not function on QA.
  • The Extend Stay flow does not recompute rate or post the additional-night folio charge for CHECKED_IN reservations. Going live would systematically under-bill every stay extension until night audit catches up.

Section A — Executive Verdict​

OverallNO-GO
Date / time2026-04-28, 15:30 IST
Flows audited13 / 13
Local Docker verdicts0 GO · 9 GO-WITH-MITIGATIONS · 4 NO-GO
AWS QA verdicts0 GO · 7 GO-WITH-MITIGATIONS · 6 NO-GO
P0 action items47
P1 action items41
P2 action items39
Could-not-verify items14 (see Section G)

The audit threshold is breached: > 30 P0 items is launch-blocking on its own.

The five heaviest blocks (each affects multiple flows):

  1. Compliance — e-invoice IRN mocked end-to-end; PDF hardcoded "Pending"; B2B path is dead code; no DPDPA erasure timer.
  2. Configuration / secrets — no Razorpay, ResAvenue, NIC, S3, SendGrid credentials in any compose file routed to QA or prod.
  3. Mobile surface — frontdesk-app does not exist; reservations UI absent in all 5 mobile apps; F&B mobile paths 404; KDS Electron app non-functional against real backend.
  4. QA data parity — QA RDS has 0 reservations on Property 40b29005-...; analytics MVs empty; default property referenced by docs is missing.
  5. Cross-service eventing — analytics dispatcher consumes 5 of 9 spec topics; night.audit.completed not consumed; kot:created never emitted; folio.posted vs folio.charge.posted name drift drops events silently.

Section B — Per-Flow Status Table​

#FlowDBBackendGatewayWeb UIMobile UIKDS/KioskTestsExternalLocalQAVerdict
1Tenant Onboarding✅⚠✅⚠n/an/a⚠❌❌ NO-GO❌ NO-GO❌ NO-GO
2Property Onboarding⚠⚠✅⚠❌n/a⚠❌⚠ MIT❌ NO-GO❌ NO-GO
3Booking Engine⚠✅✅⚠n/an/a✅⚠⚠ MIT⚠ MIT⚠ MIT
4Staff Reservations✅⚠✅✅❌n/a⚠⚠⚠ MIT⚠ MIT⚠ MIT
5Frontdesk / HK⚠⚠✅⚠⚠n/a⚠⚠⚠ MIT⚠ MIT⚠ MIT
6Check-In⚠✅✅⚠❌❌⚠❌⚠ MIT⚠ MIT⚠ MIT
7Room Service / KDS / Folio⚠⚠⚠✅❌❌⚠⚠⚠ MIT⚠ MIT⚠ MIT
8Check-Out + e-Invoice⚠⚠✅✅❌n/a⚠❌⚠ MIT⚠ MIT⚠ MIT
9Night Audit⚠⚠⚠✅❌n/a⚠⚠⚠ MIT✅ GO*⚠ MIT
10Reports & Dashboards⚠⚠⚠⚠❌n/a⚠⚠⚠ MIT❌ NO-GO❌ NO-GO
11ResAvenue / Channel✅✅❌⚠n/an/a❌❌⚠ MIT❌ NO-GO❌ NO-GO
12Pinelabs + Razorpay✅✅✅⚠❌n/a✅❌❓⚠ MIT❌ NO-GO
13Tape Chart (HERO)✅⚠✅⚠n/an/a⚠⚠⚠ MIT⚠ MIT⚠ MIT

Legend: ✅ implemented · ⚠ partial · ❌ broken/missing · ❓ unverifiable · n/a not in scope. MIT = GO-WITH-MITIGATIONS. (*) Flow 9 QA result is "endpoints respond, history empty, status NOT_STARTED" — no NA has been run.


Section C — Detailed Findings​

Flow 1 — Tenant Onboarding​

Verdict (local): NO-GO · Verdict (QA): NO-GO Summary: Self-service tenant signup endpoint works on both envs and Flow 1 jest spec passes, but the customer-facing "forgot password" form is broken end-to-end (DTO requires tenantId), no welcome email is wired, no plan selection / payment is in the signup path, and the admin-portal "Setup Wizard" is SUPER_ADMIN-only.

  • DB: Tenant, User, Session, PasswordHistory, SubscriptionPlan, TenantSubscription, Invoice all present in hmp-auth-service/prisma/schema.prisma. No drift detected from live calls.
  • Backend: POST /tenants/signup (tenants.controller.ts:34-56) is Public — verified 201 on both envs. OnboardingController (onboarding.controller.ts:32,58,84,110,136) gates EVERY post-signup wizard step on @Roles('SUPER_ADMIN'). A new tenant admin cannot run any step. OnboardingService self-marks DEPRECATED — uses xPrisma anti-pattern (onboarding.service.ts:15-29).
  • DTO: ResetPasswordRequestDto.tenantId is @IsNotEmpty @IsUUID (auth/dto/login.dto.ts:52-62). Dashboard forgot-password/page.tsx:25 POSTs {email} only and gets 400 on both envs.
  • Gateway: /tenants, /onboarding, /billing, /subscriptions registered (services.config.ts:19,31,54,875,888); @All decorators present (proxy.controller.ts:32-40,107-115).
  • Frontend: admin-portal has (auth)/login/page.tsx only — no /signup, no /forgot-password. Dashboard "Forgot your password?" link leads to a guaranteed 400.
  • Notification: dispatcher.service.ts:96-139 does NOT subscribe to TENANT_CREATED. No welcome email is ever sent.
  • Plan: signup creates no TenantSubscription row.
  • Tests: flow-1-tenant-onboarding.spec.ts (9 scenarios), tenant-onboarding-full.flow.spec.ts (10 scenarios), mfa-totp.flow.spec.ts (4 scenarios) — all green. None exercise email-only forgot-password.
  • Curl: local + QA POST /api/auth/password/reset {email} → 400 tenantId should not be empty. Local POST /api/auth/forgot-password → 503 (route absent). Local + QA GET /api/billing/plans → 401 (no public pricing).

Flow 2 — Property Onboarding​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): NO-GO Summary: Schema and CRUD exist for all 7 sub-flows and seeded data populates them, but image upload (S3) is broken in both envs, latitude/longitude is not accepted by the DTO, geocoding/Google Maps is not implemented, and QA's reference property 40b29005... has zero seeded onboarding data.

  • 2.i Address+Maps — latitude Float?/longitude Float? columns exist (schema.prisma:93-94) but are NOT in CreatePropertyDto/UpdatePropertyDto (property.dto.ts:60-219); service create block has zero matches for latitude|longitude. UI submits values that are silently dropped. No googleMapsUrl column. Zero geocoding code.
  • 2.ii Pictures — POST /api/assets/upload-url returns HTTP 500 "Could not load credentials from any providers" on both local AND QA. Zero S3_BUCKET/AWS_* env vars in any compose file. UI is URL-paste-only.
  • 2.iii Room Types — schema rich, CRUD works, but images=0 everywhere (no seeded room-type pictures); same S3 break.
  • 2.iv Rooms — bulk + single create work.
  • 2.v Rate plans — CRUD works; RatePlanRate empty in seed; calendar shows base rate only.
  • 2.vi Tax — CGST/SGST/IGST split works; no inclusive Boolean flag on TaxConfiguration.
  • 2.vii Cancellation policy — CRUD works; rules is free-form Json, no schema validator.
  • Parity — QA tenant 0001 (the documented one) has 0 properties. Property 40b29005-... 404s.

Flow 3 — Booking Engine Integration​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: Code path is fully implemented and wired end-to-end through gateway + payment-service, but booking-creation idempotency is missing, the public API key is a single shared seed string, and the booking-engine themes shipped are direction-a/b presets, not the documented Midnight Sovereign / Alabaster Court / Ink & Brass.

  • DB: Reservation.source = BOOKING_ENGINE works; no idempotencyKey column; only payment-initiate carries one (booking-engine.service.ts:1686). Double-submit unprotected.
  • API key: bookingEngineApiKey: 'hmp-default-public-booking-engine-key' baked into every property's settings JSON (seed-keynova-properties.sql:122). Same key for every tenant + property. PublicApiKeyGuard (api-key.guard.ts:50-119) falls back to "format-only" warning when no IApiKeyService is bound, so any 16+ char string passes. Major prod risk.
  • Backend: payment-v2 chain verified (controller :198 → service :1641-1717 → PaymentServiceClient.initiatePayment). Amount-mismatch guard ±1 rejects tampered totals (:1665).
  • Gateway: /booking-engine registered + @All decorators present (services.config.ts:896, proxy.controller.ts:1038-1046).
  • Frontend: 6 themes in src/lib/themes/presets/direction-{a,b}-{boutique,luxury,urban}.ts plus refined-hospitality.ts, modern-operations.ts, vibrant-approachable.ts — none are Midnight Sovereign / Alabaster Court / Ink & Brass. (Note: the booking-engine theme set is independent of the dashboard's default, which is now the KeyNova theme via @hmp/design-tokens.)
  • Tests: booking-flow.spec.ts, booking-full-flow.spec.ts, booking-mobile.spec.ts, manage-booking.spec.ts — green per memory 2026-04-16.
  • External: Razorpay creds and webhook URL registration on QA + prod could not be verified (no env access).

Flow 4 — Staff sees Reservations​

Verdict (local): GO-WITH-MITIGATIONS (cannot fully verify — the local stack ran but local credentials drift) · Verdict (QA): GO-WITH-MITIGATIONS Summary: Web list+detail are feature-complete and the cross-property 404 regression is fixed; QA has empty data, mobile reservations UI does not exist, guestName filter is silently ignored, and the detail page computes folio rows client-side from rate × nights instead of reading folios[].transactions[].

  • DB: schema rich and well-indexed for hot reads (schema.prisma:19-118).
  • Backend: findOne correctly tenant-scoped + ForbiddenException on cross-property; search() (reservations.service.ts:1831-1917) does NOT implement guestName — comment at l.1891: "skipped for now (guest model is in guest-service)". Live probe {guestName:"Smith"} returned 0 rows on QA without error.
  • Gateway: /reservations plus explicit /reservations/:id/folios override to frontdesk all wired.
  • Frontend (web): reservations/keynova.tsx and detail page render every business field; skipPropertyHeader: true on the detail fetch is verified (reservations.ts:155-161). Detail page's FolioTable is client-side rateAmount × nights ([id]/keynova.tsx:944-986) — diverges from real folio under split, amend, discount.
  • Frontend (mobile): ZERO matches for reservation across apps/{staff,manager,fnb,guest,housekeeping}. The frontdesk-app referenced in the audit prompt does not exist in this repo. No Detox/Maestro spec.
  • Tests: 8 backend specs + 5+ web E2E. Mobile: NONE.
  • QA data: GET /api/reservations?limit=3 → 200 {data:[],total:0}. Property #1 demo will look empty.

Flow 5 — Frontdesk / Housekeeping​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: Room-move and HK ops are wired end-to-end; Extend Stay does NOT recompute rate from new nights, does NOT post the extra-night folio charge on CHECKED_IN, and the housekeeping-service WebSocket namespace is not externally reachable on QA.

  • 5.i Room move: two endpoints exist (POST /front-desk/room-move room-ops.controller.ts:13; POST /room-move checkin.controller.ts:97). Tape-chart drag uses the latter, which has pricing safeguard but does not actually post the rate-difference charge.
  • 5.ii Extend: only PUT /reservations/:id with new departureDate. Rate recalc bug at reservations.service.ts:1321-1336 — totalAmount = Σ rr.rateAmount (frozen at create time), so 3→5 nights ≠ +2 nights' charge. No folio charge posted for extra nights on CHECKED_IN; only OVERSTAY_NIGHT from night audit (after departureDate < today).
  • 5.iii HK: gateway /housekeeping namespace fully implemented, JWT-validated, property-scoped, Redis-adapted. Mobile useRealtimeTasks connects directly to ${EXPO_PUBLIC_WS_URL}/housekeeping. Web uses /events aggregator namespace. QA Nginx (qa-nginx-hmp.conf:60-68) only exposes /socket.io/ to api-gateway. Curl :3006/socket.io/ timed out. Mobile HK app on a real phone cannot receive HK events on QA. Same blocker for /kitchen.

Flow 6 — Check-In (Indian + International + C-Form)​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: Staff-driven Indian + International check-in is solid (mandatory ID DTO, FRRO blocker enforcement, PDF C-Form with PII encryption); MHA portal submission is manual upload + ack-number tracking; kiosk and mobile-staff check-in are stubs.

  • Indian: ID type + number now mandatory (checkin.dto.ts:140-159); Aadhaar/PAN/DL regex client-side. GSTIN not collected at check-in (lives on Folio.companyId).
  • International: passport+visa hard-block enforced; visa+passport expiry must be ≥ departureDate. No FRRO portal API integration — cform.service.ts:445 PDF footer says "upload this PDF to https://indianfrro.gov.in"; staff calls POST /frontdesk/cform/:id/mark-submitted with manual ack number.
  • Visa stored as GuestIdentity{idType:OTHER} (cform.service.ts:260-262) — fragile; no dedicated visa columns/model.
  • Kiosk: useCheckInFlow.ts:12-41 is a hardcoded John Smith mock. All hardware mocked. Kiosk app is a UI prototype, not connected to backend.
  • Mobile: apps/staff/app/(tabs)/checkin.tsx is a 16-line <PlaceholderScreen>.
  • Two parallel C-Form controllers exist (frontdesk/cform.controller.ts and compliance/cform.controller.ts). Drift risk.
  • ID-photo upload uses inline base64 in idDocumentImageUrl (check-in-form.tsx:242-250) — does not call /uploads/presigned-url.
  • PII encryption: FieldEncryptionService is @Optional(). If ENCRYPTION_KEY is unset in prod, CForm stores plaintext silently.

Flow 7 — Room Service → KDS → Folio​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: Backend chain works for the dashboard surface, but the dedicated hmp-kds-kiosk Electron app talks to the wrong gateway namespace and wrong event names; emitKotCreated is dead code; tax breakdown CGST/SGST/IGST is dropped at the publisher; transactionCode is hardcoded 'FnB'; mobile F&B 404s on every gateway call.

  • Order entry: POST /api/orders works with full server-side reprice + auth. Dashboard /pos page wired correctly.
  • KDS server: KitchenGateway with JWT/RS256 in prod, multi-instance Redis, four emits (kot:created, kot:statusChanged, order:itemReady, order:updated).
  • emitKotCreated is never called from any service — only from the .spec.ts mock. New KOTs are not pushed in real time.
  • KDS Electron app (hmp-kds-kiosk): connects to ${VITE_GATEWAY_URL}/events (gateway namespace, not /kitchen), sends no auth.token, listens to kot.received/kot.bumped/kot.priority (none of which match server emits). Falls back to VITE_USE_DEMO=true demo data. Wall-mounted KDS will never see real orders.
  • Mobile F&B (apps/fnb): paths are /pos/orders, /pos/outlets/:id/menu. Gateway has no /pos prefix. Every Mobile F&B request 404s.
  • Folio consumer: PosFolioChargeConsumer is robust, idempotent, flag-gated; ENABLE_POS_FOLIO_CHARGE_CONSUMER=true set in all 4 compose files.
  • Tax breakdown lost: producer publishes taxAmount scalar only; CGST/SGST/IGST + customerState are dropped. Consumer recomputes from folio property state, NOT source.
  • transactionCode hardcoded 'FnB' (orders.service.ts:1218); no ROOM_SERVICE/CANTEEN/PREORDER differentiation.
  • Multi-station: KOT.station is a free-text String? hardcoded 'Kitchen'; no KitchenStation model; KDS station filter is decorative.

Flow 8 — Check-Out + GST e-Invoice (IRN)​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: Plumbing for settle → IRN → email is wired and event-driven, but EINVOICE_MOCK=true on staging-aws and prod-aws compose files (illegal under GST law), invoice PDF prints IRN: Pending verbatim, mobile/kiosk self-checkout is web-only, and DPDPA erasure log is never written on checkout.

  • Settle: 3 paths (settleBalance+mode inline, forceCheckout city-ledger, reject) with Redis lock 30s + Decimal-safe ±0.005 close threshold.
  • e-Invoice queue (EInvoiceJob): real retry / 5-min backoff / DEAD_LETTER. Provider resolved by EINVOICE_MOCK env: true → MockEInvoiceAdapter (SHA-256 deterministic IRN); false → NicEInvoiceAdapter calling ${baseUrl}/eicore/v1.03/Invoice with Bearer.
  • EINVOICE_MOCK=true on dev-all.yml:43, qa-aws.yml:41, staging-aws.yml:39, prod-aws.yml:39. No NIC_CLIENT_ID/SECRET/USERNAME/GSTIN in any compose file. Every "production" IRN is a SHA-256 of gstin|INV|folioNum|FY — legally invalid.
  • invoice-pdf.service.ts:534: const irn = 'Pending'; doc.text('E-Invoice QR: {IRN: ${irn}}') — every PDF generated by GET /folios/:id/invoice/pdf prints "Pending".
  • B2B IRN dead code: einvoice.service.ts:90-91 hardcodes company: null, guestAddress: null. Every invoice files as B2C "URP", regardless of corporate booking — silent compliance gap.
  • ESC/POS branded receipt template (@hmp/common/printing) exists but is NOT invoked from checkout — printer-print is unused.
  • SendGrid not configured on any compose file. Invoice emails fail silently in the channel layer.
  • GDPR/DPDPA: checkout does NOT write GdprErasureLog. No 90-day cron exists. GUEST_ERASED is consumed only by reservation-service + banquet-service (not by frontdesk, pos, housekeeping, analytics, crm, payment, notification).

Flow 9 — Night Audit​

Verdict (local): GO-WITH-MITIGATIONS (local creds drift — admin@keynovahotels.com rejected on local) · Verdict (QA): ✅ GO* (endpoints respond, history empty, status NOT_STARTED) Summary: Service-layer NA is mature (Redis-locked, single Prisma tx, idempotent re-run, Kafka-published, scheduler-driven), but businessDate is written into Property.settings JSON, mobile manager app has zero NA surface, no flow-test suite exists, and the analytics dispatcher does not subscribe to night.audit.completed.

  • Service: startNightAudit acquires audit:lock:{propertyId}, runs single 120s tx, advances businessDate, publishes Kafka, releases lock. Idempotent same-day guard at :227-241. Stale-RUNNING recovery on boot.
  • Scheduler: @Cron(EVERY_HOUR) ticks all active properties, compares local hour to settings.nightAuditHour (default 2). No k8s CronJob fallback — pod down at 02:00 IST = silent miss.
  • Rollback bug at :910-916: filter is transactionCode='ROOM' AND postedBy=audit.performedBy. OVERSTAY_NIGHT and NO_SHOW charges are NOT rolled back — left orphaned on folios.
  • Analytics gap: EventDispatcherService does NOT subscribe to night.audit.completed. CLAUDE.md claim of "5 MV consumers to 9 topics" is inaccurate. Daily reports MVs never refreshed by NA.
  • businessDate stored in Property.settings JSON via xPrisma, not a typed column. Untyped, un-indexed.
  • Gateway: @All('night-audit/*') exists but bare @All('night-audit') is missing — two-file rule violation (harmless today; existing routes all have sub-segments).
  • Mobile: zero NA references in hmp-mobile-apps.
  • Tests: unit + dashboard E2E exist; no flow-test suite.

Flow 10 — Reports & Dashboards​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): NO-GO Summary: The CQRS plumbing is solid on paper; in practice only local has populated MVs, the dashboard /metrics endpoint and the report endpoints don't share a source of truth, and the admin/mobile front-ends are still demo placeholders.

  • 9-topic dispatcher truth table:
    • reservation.created ✅, reservation.cancelled ✅, reservation.modified ❌ NOT subscribed
    • folio.posted ❌ (consumer subscribes to folio.charge.posted — name drift drops the topic)
    • folio.closed ❌ NOT subscribed
    • kot.completed ❌ NOT subscribed
    • order.closed ✅, task.completed ✅, channel.sync.failed ✅
    • Score 5/9.
  • MvAdrRevpar.adr and revpar columns are never written by ReservationConsumer. Local has non-zero values via an undocumented backfill path; QA has 0 across the board.
  • DashboardController.getMetrics returns revpar:0, adr:0, todayRevenue:0 while /reports/revenue/daily returns non-zero for the same day → two contradicting numbers on the same screen.
  • Mobile manager dashboardApi.getMetrics calls /analytics/dashboard/${propertyId} — backend route is /analytics/dashboard/metrics. 404/hang in production.
  • Admin portal /analytics page is 100% hardcoded demo data (page.tsx:26-110).
  • Dashboard /reports/[category]/page.tsx:23-79 falls back to a 40-entry hardcoded fake report list that does not match the backend catalog.
  • GSTR-3B: not implemented. /gst gateway prefix routes to analytics but no controller exists. No HSN summary, no place-of-supply aggregation.
  • QA: every /api/reports/* endpoint returns {"data":[]}; every /api/analytics/dashboard/metrics field is 0; /api/control-center/today all zeros. Producer side either not emitting or analytics consumer not connected on QA.

Flow 11 — ResAvenue / Channel Manager​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): NO-GO Summary: ResAvenue adapter is real code, real XML, real fetch — but the gateway never proxies its routes, no creds are provisioned anywhere, and no end-to-end test exists.

  • Adapters: ResAvenue (real HTTP + OTA 2003/05 XML, 30s timeout), Booking.com / Expedia / Agoda / MMT / Goibibo / Airbnb / TripAdvisor / Google / Amadeus / Sabre real adapter classes exist. STAAH / eZee / ChannelRush listed in CLAUDE.md but no provider folder — only intermediary/providers/resavenue/.
  • Gateway two-file rule violated: services.config.ts:499-516 registers /intermediary, /channel-stats, /channel-setup, /webhook-management but proxy.controller.ts has NO @All decorators for them. Confirmed: curl returns 404 on both local + QA.
  • MinLOS / MaxLOS NOT pushed: handleRestrictionPush filters only closedToArrival/Departure/Stay. The OTA_HotelBookingRuleNotifRQ LOS message is never built.
  • No RESAVENUE_* creds in any compose file. Code reads creds from IntermediaryConnection.credentials JSON; no row seeded for Property #1.
  • Outbound webhook URL not registered with ResAvenue.
  • CHANNEL_MODE is simulator on dev-all; unset on QA → DegradedModule (health-only).
  • Failure surface: CHANNEL_SYNC_FAILED topic produced + analytics consumer + dashboard AlertsPanel all wired ✅.

Flow 12 — POS Terminal + Razorpay PG​

Verdict (local): UNVERIFIABLE (payment-service container unhealthy on IPv4 bind, known) · Verdict (QA): NO-GO Summary: Code is shipped end-to-end and authenticates correctly on QA, but no real merchant account, no Razorpay key in env, and no terminal hardware tested — Property #1 cannot take a real card today without operator config.

  • Razorpay adapter is real (Orders API, refund, idempotency-key, MOCK/SANDBOX/LIVE driven by MerchantAccount.mode).
  • Webhook receiver @Public() POST /api/webhooks/:providerCode/:merchantAccountId is correct (raw body via body-parser.raw, HMAC verified, idempotent on WebhookEvent.@@unique([providerType, providerEventId])).
  • No RAZORPAY_* env vars in any compose file: qa-aws.yml, dev-all.yml, staging-aws.yml, prod-aws.yml all clean. The MerchantAccount table is meant to hold encrypted creds; no row exists for tenant 1 on QA (GET /api/merchant-accounts → {data:[]}). First payment will 404 from MerchantAccountService.resolveForPayment.
  • Pinelabs adapter (pinelabs-terminal.adapter.ts) is real (TCP/Plutus-ECR codec, 408 LOC, real socket). HARDWARE_MOCK=true in all 4 compose files; Terraform prod/compute.tf:50 overrides to false — but anyone using docker-compose.prod-aws.yml against prod RDS gets silent mock.
  • Razorpay payment_capture: 1 flag missing on Orders create body (razorpay-gateway.adapter.ts:79) — capture relies on Razorpay account default.
  • No reconciliation cron: missed webhooks during outage will leave Payment rows IN_PROGRESS forever.
  • No mobile terminal/Razorpay surface. Mobile is read-only on payments.
  • Two parallel hardware stacks: legacy @hmp/hardware still in frontdesk-service/package.json:28 despite per-folder CLAUDE.md claiming removal.

Flow 13 — Tape Chart Calendar (HERO)​

Verdict (local): GO-WITH-MITIGATIONS · Verdict (QA): GO-WITH-MITIGATIONS Summary: The HERO works end-to-end — drag-move, drag-extend, click-create, right-click block-room, OOO colors, virtualisation, WebSocket realtime, 46 unit tests, 4 e2e smokes. Real but shallow gaps: filter UI is cosmetic, multi-room continuity missing, extend/shorten context-menu redirects instead of using the in-place dialog.

OpWired?Notes
13.i drag-drop room move✅branches CHECKED_IN→/room-move vs CONFIRMED→/reservations/assign-room
13.ii drag-extend stay✅classifyExtend gates simple vs confirm
13.iii drag-shorten✅ partialonly right-edge inward; no resize-left
13.iv click-create✅POST /front-desk/quick-reservation
13.v context menu⚠ partialNO_SHOW action MISSING from BAR_ACTIONS; extend/shorten redirect to /reservations/:id (inconsistent with drag)
13.vi status visual✅full color map + per-property override; NO_SHOW + CHECKED_OUT colors not derived
13.vii multi-room continuity❌N independent bars; no link/connector
13.viii filter chips❌purely cosmetic — onClick is undefined; no backend filter params accepted
13.ix block multiple rooms⚠ partialsingle-cell PATCH only; no date-range / maintenance window UI
13.x virtualisation✅@tanstack/react-virtual; densities 28/36/44px; print mode disables
13.xi mobile/responsive⚠TouchSensor configured; toolbar overflows on <768px; no flex-wrap; phones unusable
  • Tenant-scope receiver assert MISSING: CalendarService.getCalendar (calendar.service.ts:81-99) does not call assertPropertyTenant(propertyId, tenantId). Relies entirely on the gateway's 5-min cache.
  • WebSocket auth is HS256 in current configuration; RS256 is required before production per root CLAUDE.md.

Section D — Cross-Cutting Findings​

IDPatternAffected flowsEvidence
CC-1Mobile staff surface is largely missing — frontdesk-app does not exist as a directory; reservations UI absent across all 5 mobile apps; Mobile F&B paths wrong (404); no payment/terminal UI; no NA widget4, 5, 6, 7, 9, 12apps/{staff,manager,fnb,guest,housekeeping} greps
CC-2Configuration drift across compose envs — EINVOICE_MOCK=true in prod-aws/staging-aws; HARDWARE_MOCK=true in prod-aws (Terraform overrides); zero Razorpay/NIC/ResAvenue/SendGrid/AWS-S3 env vars; consumer flags inconsistent7, 8, 10, 11, 12docker-compose.{dev-all,qa-aws,staging-aws,prod-aws}.yml
CC-3Gateway two-file rule broken or partial — intermediary, channel-stats, channel-setup, webhook-management missing decorators; night-audit bare-prefix missing; pos prefix not registered for mobile F&B; ai/query resolves to nothing7, 9, 10, 11proxy.controller.ts vs services.config.ts
CC-4Cosmetic-but-fake UI — booking-engine themes (direction-a/b vs spec); admin-portal /analytics 100% demo data; dashboard /reports/[category] 40-entry fake list; tape-chart filter chips with no onClick; AiSuggestionToast hardcoded copy3, 10, 13per finding evidence
CC-5Cross-service event chain gaps — analytics dispatcher consumes 5 of 9 spec topics; folio.posted vs folio.charge.posted name drift; night.audit.completed not consumed; kot:created never emitted by producer; RESERVATION_MODIFIED not emitted on room-move5, 7, 9, 10event-dispatcher.service.ts:49-75, kitchen.service.ts:138, room-ops.service.ts:131-159
CC-6Dead/deprecated code still in production paths — OnboardingService self-marked DEPRECATED; two parallel C-Form controllers; two parallel hardware stacks (@hmp/hardware still in frontdesk package.json); revenue-report stub at reports.controller.ts:171 returning hardcoded zeros1, 6, 10, 12per finding evidence
CC-7PII / GDPR / DPDPA gaps — no checkout-triggered erasure log; GUEST_ERASED consumed by 2 of 14 services (reservation, banquet); ENCRYPTION_KEY is @Optional() in CForm (silent plaintext if unset); decryption on retrieval not implemented in frontdesk; visa stored as idType=OTHER hack6, 8cform.service.ts:138, gdpr.service.ts:213-227
CC-8External integrations stubbed or unconfigured — MHA C-Form (manual PDF + ack number); NIC e-invoice (mock everywhere); ResAvenue (no creds); Razorpay (no creds); SendGrid (no creds); S3 (broken everywhere); Google Maps (no integration)2, 6, 8, 11, 12per finding evidence
CC-9WebSocket gateways HS256 in current config — /housekeeping, /kitchen, /events all run HS256. Root CLAUDE.md says RS256 required before production5, 7, 13housekeeping.gateway.ts, kitchen.gateway.ts:51-91
CC-10Idempotency holes — booking creation has no idempotencyKey column on Reservation; only payment-initiate carries one. Some critical paths protected (PosFolioChargeConsumer, terminal-charge), but creation-side double-submit unprotected3reservation/schema.prisma:19-118, booking-engine.service.ts:1686
CC-11Tenant-scope receiver-side asserts missing in places — CalendarService.getCalendar and createQuickReservation do not call assertPropertyTenant; rely on gateway's 5-min cache. Migration to ServiceClient-with-receiver-assert is partially done (T3-1)13calendar.service.ts:81-99
CC-12QA RDS data parity broken — Property 40b29005-... referenced by docs has 0 rows; reservations, MVs, merchant accounts, intermediary connections all empty. Either the seed regressed post-2026-04-27 or was never re-run2, 4, 10, 11, 12curl QA /api/properties, /api/reservations, /api/reports/*, /api/merchant-accounts

Section E — Action Plan​

P0 = launch-blocking. P1 = must-fix-soon. P2 = nice-to-have. Effort: S = ≤1 day, M = 1–3 days, L = 1 week+, XL = >2 weeks.

P0 — must close before launch (47)​

IDTitleFlowsRepoFilesEffortAcceptance
AP-T01-001Make tenantId optional on ResetPasswordRequestDto; resolve user by email1hmp-auth-servicesrc/auth/dto/login.dto.ts:52-62, src/auth/auth.service.ts:528+Sdashboard /forgot-password with {email} returns 200 + password.reset.requested event
AP-T01-002Subscribe notification dispatcher to TENANT_CREATED; render welcome + verify-email templates1hmp-notification-servicesrc/dispatcher/dispatcher.service.ts:96-139, src/templates/Msignup → email queued → received in MailHog (local) / SendGrid sandbox (QA)
AP-T01-003Allow ADMIN (not just SUPER_ADMIN) on OnboardingController, scoped to own tenant1hmp-auth-servicesrc/onboarding/onboarding.controller.ts:32,58,84,110,136Stenant created via signup can call /onboarding/:tenantId/property with own JWT
AP-T01-004Add (auth)/forgot-password/page.tsx and /signup page in admin-portal1hmp-admin-portalsrc/app/(auth)/Mfull tenant self-onboarding reachable from public URL
AP-T02-001Add latitude, longitude, googleMapsUrl to Property DTOs + schema + service map2hmp-property-servicedto/property.dto.ts:60-219, properties.service.ts:71-80, prisma/schema.prismaSPUT /api/properties/:id {latitude,longitude,googleMapsUrl} round-trips
AP-T02-002Provision S3 (AWS) for QA + prod and MinIO sidecar for local; add AWS_S3_* env; add PROPERTY_IMAGE/ROOM_TYPE_IMAGE to AssetType2hmp-infrastructure, hmp-property-servicecompose files, asset.service.ts:17MPOST /api/assets/upload-url returns 200 with presigned URL on local + QA
AP-T02-003Build dashboard image-upload widget (replace URL-paste); call /assets/process2hmp-web-dashboard(dashboard)/settings/property/page.tsx:2989+, room-type pageMdrag-drop upload writes to S3, persists 3-variant URLs to Property.images[]
AP-T02-004Re-seed QA Property 40b29005-... (or update docs/MEMORY to point to existing properties)2, 4, 10, 11, 12hmp-infrastructureseeds/seed-master.shSdoc + reality match; GET /api/properties/40b29005-... returns 200 with rooms/rate plans/taxes
AP-T03-001Add idempotencyKey to Reservation; enforce on POST /booking-engine/reservations and /bookings3hmp-reservation-serviceprisma/schema.prisma:19-118, booking-engine.controller.tsSduplicate POST returns first reservation, not a second
AP-T03-002Wire DB-backed IApiKeyService in reservation-service; populate per-property hashed ApiKey rows; rotate the shared seed3hmp-reservation-service, hmp-infrastructureapp.module.ts, seeds/seed-keynova-properties.sql:122Mguard validates against DB; rotating one property's key does not affect others
AP-T04-001Re-run seed-master.sh against QA RDS for Property #1; verify list returns ≥1 row4hmp-infrastructureseeds/seed-master.shSGET /api/reservations?limit=3 on QA returns ≥1 row
AP-T04-002Decide: does Phase 1 require mobile reservations? If yes, scaffold; if no, document explicit deferral4, 6, 9hmp-mobile-apps, hmp-docsapps/staff or new appXL or Swritten decision in Phase-1 readiness doc
AP-T05-001Fix rate recalc in reservations.service.update() to use per-night × new nights when departureDate changes5hmp-reservation-servicereservations.service.ts:1321-1336Sextending 3→5 nights produces totalAmount += 2×nightlyRate
AP-T05-002Post EXTENSION_NIGHT folio CHARGE for added nights when reservation is CHECKED_IN; emit FOLIO_CHARGE_POSTED5hmp-reservation-service, hmp-frontdesk-serviceextend handler + folio serviceMfolio balance reflects extra nights immediately, not at next NA
AP-T05-003Add Nginx /ws/housekeeping/ → housekeeping-service:3006 and /ws/kitchen/ → pos-service:3007 on QA + prod5, 7hmp-infrastructurenginx/qa-nginx-hmp.conf:60-68Swss://<host>/ws/housekeeping/socket.io/ returns 200 from outside cluster
AP-T06-001FRRO portal SOP runbook + future-state IndianFrroClient interface spec6hmp-docsnew compliance runbookSwritten runbook on submit-and-acknowledge; staff trained
AP-T06-002Replace idType=OTHER visa hack with Guest.visaNumber/visaType/visaExpiry columns or dedicated GuestVisa model6hmp-guest-serviceprisma/schema.prisma:33-228Mvisa records distinguishable from "OTHER ID" identity records
AP-T06-003Connect kiosk useCheckInFlow to real backend OR descope kiosk for Property #16hmp-kds-kiosk, hmp-docspackages/kiosk/src/renderer/hooks/useCheckInFlow.ts:12-41L or Skiosk either submits real check-in OR is removed from launch scope
AP-T06-004Build mobile staff frontdesk screen calling /check-in/:id OR descope mobile-staff for Property #16hmp-mobile-apps, hmp-docsapps/staff/app/(tabs)/checkin.tsx:1-16L or Sscreen submits real check-in OR descope is documented
AP-T07-001Rewrite KDS Electron app: target ${VITE_GATEWAY_URL}/kitchen namespace; pass JWT auth.token; subscribe to kot:created/kot:statusChanged/order:itemReady/order:updated; emit joinOutlet; remove VITE_USE_DEMO=true default7hmp-kds-kioskpackages/kds/src/renderer/hooks/useOrders.ts:134-138, packages/shared/src/hooks/useWebSocket.ts:47-62MKDS receives a real KOT in <2s after order entry on local + QA
AP-T07-002Wire kitchenGateway.emitKotCreated() into OrdersService.generateKOT after KOT row created7hmp-pos-serviceorders.service.ts:509-573, kitchen.gateway.ts:264Sunit test asserts call; Playwright e2e covers "order entry → KDS card visible"
AP-T07-003Drop /pos/ prefix from mobile F&B posApi paths to match gateway routing7hmp-mobile-appspackages/api-client/src/index.tsSmobile F&B order entry receives 200 from /api/orders
AP-T08-001Replace irn = 'Pending' literal with await jobRepo.getLatestForFolio(folio.id); render real IRN + base64 QR in PDF8hmp-frontdesk-servicesrc/folios/invoice-pdf.service.ts:520-545SPDF prints real 64-char IRN + QR
AP-T08-002Add NIC creds env vars to staging-aws + prod-aws compose; flip EINVOICE_MOCK to env-driven; require false for prod gate8hmp-infrastructuredocker-compose.{staging-aws,prod-aws}.ymlSprod build fails if EINVOICE_MOCK=true
AP-T08-003Wire GuestServiceClient.getCompany() + getGuestAddresses() into EInvoiceService.generateIrnForFolio (replace null company/guestAddress)8hmp-frontdesk-serviceeinvoice.service.ts:55-91MB2B invoice with company GSTIN files as B2B, not URP
AP-T08-004On _checkOut commit, schedule GuestRetentionTimer row at checkOutDate+90d; cron calls gdpr.service.eraseGuest + writes GdprErasureLog8hmp-frontdesk-service, hmp-guest-servicecheckout.service.ts:51-310, new cron in guest-serviceMDPDPA Section 8 timer runs nightly; old guest PII scrubbed
AP-T08-005Add GuestErasedConsumer to frontdesk, pos, housekeeping, analytics, crm, payment, notification8each servicenew consumer filesMerasure event scrubs Folio.guestName, Order.guestName, mv_*, Communication.metadata, Payment.metadata
AP-T09-001Extend rollback transactionCode filter to include OVERSTAY_NIGHT and NO_SHOW; add spec9hmp-frontdesk-servicenight-audit.service.ts:910-916Srollback voids all 3 transaction codes
AP-T09-002Wire analytics dispatcher subscription to night.audit.completed; add MV consumer; backfill via scripts/backfill-mv.ts9, 10hmp-analytics-serviceconsumers/event-dispatcher.service.ts:49-75, consumers/index.tsMa manual NA run refreshes daily-flash MV
AP-T10-001Wire MvAdrRevpar.adr and revpar on every upsert in reservation.consumer.ts; backfill historical rows10hmp-analytics-serviceconsumers/reservation.consumer.ts:91-107Spost-event ADR = totalRoomRevenue/roomsSold; RevPAR = totalRoomRevenue/totalRooms
AP-T10-002Make DashboardController.getMetrics query MvAdrRevpar for ADR/RevPAR/today-revenue (single source of truth)10hmp-analytics-servicedashboard.controller.ts:111-122, dashboard.service.tsS/dashboard/metrics and /reports/revenue/daily agree on the same number for the same date
AP-T10-003Investigate QA empty-MV root cause: confirm INTERNAL_SERVICE_TOKEN valid; confirm Redis Streams have producer messages; run scripts/backfill-mv.ts10hmp-analytics-service, hmp-infrastructurescriptsM/api/reports/occupancy returns ≥1 row on QA
AP-T10-004Fix mobile dashboardApi.getMetrics URL to /analytics/dashboard/metrics and inject X-Property-ID header10hmp-mobile-appspackages/api-client/src/dashboardApi.ts:7Smanager-app dashboard receives 200 with metrics object
AP-T10-005Build GSTR-3B prep endpoint aggregating EventStore einvoice payloads by HSN/PoS/B2B-vs-B2C; add controller behind /gst gateway prefix10hmp-analytics-servicenew gst/gstr3b.controller.tsMGET /reports/gstr3b?month=2026-04 returns valid aggregate JSON
AP-T11-001Add @All('intermediary'), @All('intermediary/*'), @All('channel-stats'), @All('channel-stats/*'), @All('channel-setup'), @All('channel-setup/*'), @All('webhook-management'), @All('webhook-management/*') decorators11hmp-api-gatewaysrc/proxy/proxy.controller.tsScurl /api/intermediary/connections reaches channel-service
AP-T11-002Provision real ResAvenue connection row for Property #1 via admin UI; document in launch runbook; set CHANNEL_MODE=sandbox (or live) on QA11hmp-channel-service, hmp-infrastructure, hmp-docsmanual seed + runbookMrate push to ResAvenue sandbox returns 200 with provider booking ID
AP-T11-003Register outbound webhook URL with ResAvenue (https://<qa-host>/api/webhooks/resavenue/{reservation,cancellation}); add to launch checklist11hmp-docsrunbookSinbound test booking from ResAvenue sandbox creates a Reservation row
AP-T12-001Seed MerchantAccount for tenant 1 on QA with Razorpay sandbox creds (encrypted at rest)12hmp-payment-service, hmp-infrastructureseedSGET /api/merchant-accounts → {data:[{...}]}
AP-T12-002Wire admin onboarding wizard → POST /api/merchant-accounts to encrypt and persist Razorpay keys per tenant12hmp-admin-portal, hmp-payment-servicenew wizard stepMtenant onboarding includes payment-provider step that creates encrypted MerchantAccount
AP-T13-001Add await this.propertyClient.assertPropertyTenant(propertyId, tenantId) to CalendarService.getCalendar and createQuickReservation13hmp-frontdesk-servicecalendar.service.ts:81-99,159-170Scross-tenant propertyId returns 403, not data
AP-T13-002Wire FilterChipsRow to local state → query params → backend filter (extend getCalendar with roomTypeId/floor/source/vipOnly) OR delete cosmetic chips13hmp-web-dashboard, hmp-frontdesk-servicetape-chart-shell.tsx:120-157, calendar.controller.tsMclicking a chip filters the calendar
AP-CC-1Audit all gateway prefixes for two-file-rule compliance; add CI check that fails build if prefix exists in services.config.ts but not as @All decorator (or vice versa)allhmp-api-gatewaynew CI scriptSCI script lists all unmatched prefixes
AP-CC-2Reseed QA RDS via seed-master.sh; verify reservations, MVs, merchant accounts, intermediary connections, ApiKey rows all populated2,4,10,11,12hmp-infrastructureseeds/seed-master.shSsmoke test passes 13/0/0 on QA
AP-CC-3RS256 migration for all WebSocket gateways before prod (/housekeeping, /kitchen, /events) — load JWT_PUBLIC_KEY env, fail-closed on HS256 in prod5, 7, 13hmp-housekeeping-service, hmp-pos-service, hmp-api-gatewaygateway filesMprod boot fails if RS256 keys missing
AP-CC-4Sync compose files: remove EINVOICE_MOCK=true and HARDWARE_MOCK=true from prod-aws; add NIC + Razorpay + ResAvenue + SendGrid env placeholders to QA + prod7,8,11,12hmp-infrastructurecompose filesSgrep _MOCK docker-compose.prod-aws.yml returns 0
AP-CC-5Provision SendGrid creds across QA + prod compose; e2e test for invoice email delivery1, 8hmp-infrastructure, hmp-notification-servicecompose + specSinvoice email arrives in SendGrid sandbox inbox

P1 — must-fix-soon (41)​

Selected highlights:

IDTitleFlowsEffort
AP-T01-005Expose Public GET /billing/plans (currently 401)1S
AP-T01-007Decide on OnboardingService xPrisma deprecation — delete or migrate to PropertyServiceClient1M
AP-T02-005Add inclusive Boolean column to TaxConfiguration2S
AP-T02-006Add structured class-validator schema for CancellationPolicy.rules[]2S
AP-T03-003Decide on theme strategy — implement KeyNova brand (Iris/Nova) OR document direction-a/b as official3S
AP-T03-004Verify Razorpay creds + webhook URL on QA + prod and document3, 12S
AP-T04-003Wire guestName in search() via GuestServiceClient.findByName OR strip the input4S
AP-T04-004Replace client-side FolioTable computation with rows from res.folios[].transactions[]4M
AP-T05-004Add "Move Room" + "Extend Stay" CTA buttons on /reservations/:id (currently only via tape chart)5S
AP-T05-005Consolidate RoomOpsService.roomMove and CheckInService.roomMove into one impl with pricing safeguard5M
AP-T05-006Post folio CHARGE for paid-upgrade rate-difference inside the room-move tx5S
AP-T06-005Switch dashboard ID-photo + signature uploads from base64 to /uploads/presigned-url → S36M
AP-T06-009Boot-time check: in NODE_ENV=production, fail fast if ENCRYPTION_KEY is unset6S
AP-T07-004Extend FOLIO_CHARGE_POSTED payload to carry CGST/SGST/IGST/customerState; consumer writes distinct rows7M
AP-T07-005Introduce KitchenStation model + per-item routing + per-station broadcast rooms7L
AP-T07-006Map transactionCode from orderType (ROOM_SERVICE/CANTEEN/PREORDER/FnB)7S
AP-T08-006Promote irn/signedQRCode/ackDate columns onto Folio8S
AP-T08-007Route credit-note IRN through EInvoiceJob queue with retry/DLQ8S
AP-T08-009Register NIC webhook callback URL during sandbox onboarding8S
AP-T09-003Implement night-audit-summary PDF/CSV generator9M
AP-T09-004Add typed currentBusinessDate Date? column on Property; migrate from JSON9M
AP-T09-005Promote NA scheduler to k8s CronJob with miss-detection alert9S
AP-T10-006Subscribe to reservation.modified, rename folio.charge.posted→folio.posted (or align producer), add folio.closed/kot.completed consumers10M
AP-T10-007Replace /reports/[category] fallback list with backend catalog only10S
AP-T10-008Replace admin /analytics demo data with GET /analytics/admin/platform-overview10M
AP-T10-009Fix MvDailyOccupancy.totalRooms upsert to read from PropertyServiceClient10S
AP-T11-004Implement MinLOS/MaxLOS push (OTA_HotelBookingRuleNotifRQ)11M
AP-T11-005Add flow-tests/flow-11-channel-manager.spec.ts end-to-end11M
AP-T11-006Set CHANNEL_MODE=simulator in docker-compose.qa-aws.yml until live creds land11S
AP-T12-003Add payment_capture: 1 to Razorpay order body12S
AP-T12-004Build WebhookReconcileService cron (every 15 min)12M
AP-T12-005Override HARDWARE_MOCK=false in docker-compose.prod-aws.yml12S
AP-T13-003Implement multi-room reservation visual continuity on tape chart13M
AP-T13-004Add mark-no-show to BAR_ACTIONS13S
AP-T13-005Replace window.location.href = /reservations/:id redirect with in-place dialog for extend/shorten13S
AP-T13-006Add date-range block UI (RoomBlock model or HK MaintenanceRequest)13M

P2 — nice-to-have (39, abbreviated)​

Includes Google Maps geocoding, amenity master catalog, multi-property booking-engine selector, multi-guest C-Form per foreign co-traveller, NLQ wiring, MV nightly self-heal, ESC/POS receipt printing in checkout, bulk-block toolbar, mobile responsive toolbar, drag/drop Playwright e2e, root CLAUDE.md ↔ per-folder CLAUDE.md drift cleanup, frroCity column, RatePlanRate seed back-fill.


Section F — Sequenced Fix Plan​

Wave 1 — independent P0s parallelizable across teams (≈5 person-days each, run concurrently for ~1 week wall-clock):

  1. AP-T01-001 (forgot-password DTO)
  2. AP-T01-002 (welcome email consumer)
  3. AP-T01-003 (OnboardingController role)
  4. AP-T02-001 (lat/lng/googleMapsUrl DTO)
  5. AP-T02-004 / AP-CC-2 (re-seed QA — unblocks T04, T10, T11, T12)
  6. AP-T03-001 (booking idempotency)
  7. AP-T05-001 (extend rate recalc)
  8. AP-T05-002 (extend folio charge)
  9. AP-T05-003 (Nginx /ws routes)
  10. AP-T07-002 (emitKotCreated)
  11. AP-T07-003 (drop /pos/ prefix in mobile)
  12. AP-T08-001 (PDF IRN literal)
  13. AP-T09-001 (rollback transactionCode filter)
  14. AP-T10-001 (ADR/RevPAR upsert)
  15. AP-T10-002 (single source of truth for metrics)
  16. AP-T10-004 (mobile dashboardApi URL)
  17. AP-T11-001 (gateway @All decorators for intermediary etc.)
  18. AP-T13-001 (CalendarService tenant-assert)
  19. AP-T13-004 (no-show action)
  20. AP-CC-4 (compose env hygiene)

Wave 2 — P0s that depend on Wave 1 (≈2 weeks wall-clock):

  1. AP-T01-004 (admin-portal /signup + /forgot-password pages — needs T01-001 + T01-002)
  2. AP-T02-002 (S3 provisioning — unblocks AP-T02-003 and AP-T06-005)
  3. AP-T02-003 (image upload widget — needs S3)
  4. AP-T03-002 (DB-backed API key — needs idempotency in place)
  5. AP-T06-002 (visa columns — needs schema migration coordination)
  6. AP-T06-003 / AP-T06-004 (kiosk + mobile staff — DECISION: build OR descope)
  7. AP-T07-001 (KDS Electron rewrite — needs emitKotCreated)
  8. AP-T08-002 (NIC creds, EINVOICE_MOCK=false in prod — needs T08-001 PDF first to render the real IRN)
  9. AP-T08-003 (B2B IRN cross-service include)
  10. AP-T08-004 (90-day retention timer)
  11. AP-T08-005 (GUEST_ERASED consumers)
  12. AP-T09-002 (analytics consumer for night.audit.completed)
  13. AP-T10-003 (QA MV root cause)
  14. AP-T10-005 (GSTR-3B endpoint)
  15. AP-T11-002 (ResAvenue connection seed — needs T11-001 gateway routing)
  16. AP-T11-003 (webhook URL registration)
  17. AP-T12-001 (MerchantAccount seed)
  18. AP-T12-002 (admin onboarding payment-provider step)
  19. AP-T13-002 (filter chips wiring)
  20. AP-CC-1 (CI two-file-rule check)
  21. AP-CC-3 (RS256 migration for WS gateways)
  22. AP-CC-5 (SendGrid)

After Wave 1 + Wave 2 complete, every P0 in Section E is closed.

Wave 3 — P1 (~3 weeks): the 41 P1 items above. Recommended grouping by team owner.

Wave 4 — P2 (post-launch backlog): 39 items.

Estimated total wall-clock to GO: 6-8 weeks at current team capacity.


Section G — What could not be verified​

IDItemWhy
CNV-1SSH inspection of AWS QA EC2Sandbox blocks SSH to shared host. All QA verification was HTTP-only.
CNV-2QA .env.qa-aws env var contents (Razorpay/NIC/ResAvenue/SendGrid/INTERNAL_SERVICE_TOKEN)requires SSH; could not read
CNV-3QA RDS schema diff vs schema.prisma on masterrequires DB connection (no psql to QA RDS without SSH)
CNV-4Whether the Razorpay webhook URL is registered at the Razorpay merchant dashboardrequires Razorpay dashboard access
CNV-5Whether the ResAvenue webhook URL is registered at ResAvenuerequires ResAvenue dashboard access
CNV-6NIC IRP sandbox onboarding status (GSTIN registered?)requires NIC portal access
CNV-7Real Pinelabs / EDC terminal hardware testrequires physical terminal device
CNV-8Real mobile-device boot test (housekeeping app, F&B app, manager app, staff app, guest app)sandbox cannot run physical Android/iOS device
CNV-9Local stack browser smoke test (clicking through tape-chart drag, check-in wizard, tape-chart calendar)sandbox does not have an active browser session against localhost:3020
CNV-10KDS kiosk Electron app live bootsandbox cannot run Electron in interactive mode
CNV-11Whether flow-results.json 102/102 still passes today after the 2026-04-28 audit changesnot re-run during this audit (audit-only mode)
CNV-12Whether the local stack login fails because the local seed used admin@hmphotel.com (memory says yes; Flow 9 audit confirms) — exact root-causerequires re-running seed-master locally; deferred
CNV-13Booking-engine end-to-end on local Docker (curl returned HTTP 000 from one subagent's shell)shell-context limitation; not necessarily broken — Flow 3 audit notes this
CNV-14ENCRYPTION_KEY presence on QA frontdesk containerrequires SSH

Section H — Methodology + Provenance​

Audit run: 2026-04-28, 14:00–15:30 IST.

Method:

  1. Bootstrap pass — git status across 23 repos; local Docker docker ps; QA HTTP probe.
  2. 13 parallel general-purpose subagents (one per business flow) each running the 7-check protocol on local + QA.
  3. Aggregation pass — collated 13 finding blocks; deduplicated cross-cutting patterns; produced action plan + sequenced fix plan.

Tools used: Read, Grep, Glob, Bash (curl + docker ps + python parsing), Agent.

Repo SHAs at time of audit (all on master):

RepoSHADirty files
hmp-api-gateway54c7e290
hmp-auth-service32c787f0
hmp-property-service69f00560
hmp-reservation-serviceec4eb1f0
hmp-guest-service27e01740
hmp-frontdesk-service7e261050
hmp-housekeeping-service4e59e0b0
hmp-pos-service1c4de5e0
hmp-banquet-service058b8ac0
hmp-channel-service047ee7d0
hmp-crm-service27502b90
hmp-analytics-serviceb0136350
hmp-notification-service16640a50
hmp-payment-servicecc4beeb0
hmp-spa-service1b5a9d00
hmp-web-dashboardb50f4457
hmp-admin-portal877b24b0
hmp-booking-engine8bee09c0
hmp-mobile-appsd06bbae1
hmp-kds-kioskd0328bf1
hmp-shared-packages69a09a60
hmp-infrastructure87a404619
hmp-docscd8fba19

Local Docker compose state (2026-04-28 15:10 IST):

  • All 14 backend services healthy except hmp-payment-service-1 (unhealthy — known IPv4-bind issue, see Workstream A memory).
  • All 5 frontends healthy.
  • Per-service postgres containers all healthy.

AWS QA state (HTTP-probed; no SSH):

  • GET /api/health → 200.
  • POST /api/auth/login → 200 with admin@hmphotel.com / <REDACTED> (tenant 00000000-0000-4000-a000-000000000001, property 40b29005-5196-4ba7-a71d-94323caee4dc).
  • GET /api/properties/40b29005-5196-4ba7-a71d-94323caee4dc → 404 (Flow 2 finding).
  • GET /api/reservations?limit=3 → 200 with {data:[],total:0} (Flow 4 finding).

Subagent invocation log:

FlowFiles inspected (approx)Curls runSubagent token usageWall time
1 — Tenant Onboarding258114k11 min
2 — Property Onboarding3010102k11 min
3 — Booking Engine220 (shell HTTP 000)95k5 min
4 — Staff Reservations185122k7 min
5 — Frontdesk / HK308160k12 min
6 — Check-In284144k11 min
7 — Room Service / KDS / Folio306164k7 min
8 — Check-Out + e-Invoice255134k9 min
9 — Night Audit184112k6 min
10 — Reports3014157k9 min
11 — Channel Manager226100k6 min
12 — Payments288144k7 min
13 — Tape Chart250131k5 min

End of report.