Property #1 Launch Roadmap — 2026-05-06
Source: property-1-launch-review-2026-05-06.md (audit verdict: NO-GO; 11 RED + 2 AMBER + 0 GREEN; ~73 P0 findings).
Decision target: ship a credible Property #1 launch in 6–8 weeks.
Team assumption: 5 senior engineers across services + 1 PM/release engineer.
§0 — Wave plan (one-page summary)
| Wave | Window | Theme | Exit gate |
|---|---|---|---|
| W0 | Day 0–3 | Decision & containment | Boot guards in place; flags flipped; route disablements done; CLAUDE.md drift fixed; team committed to a wave plan. No code changes that introduce risk; only switches/guards. |
| W1 | Week 1–2 | Money & compliance hard blockers | A guest cannot complete a booking that bypasses HMAC; FRRO is enforced on every check-in path; invoice numbers are gap-free; e-invoice cannot run in mock in prod. |
| W2 | Week 3–4 | Operational completeness | Tape Chart can perform every operation a front-desk agent needs; night audit is idempotent at the DB level; KPI tiles render correct numbers; reports respect property timezone. |
| W3 | Week 5–6 | Hardening & P1 sweep | Build script fails on TS errors; xPrisma migration plan signed-off (not necessarily complete); audit trail on every privileged mutation; mobile HK photo flow works. |
| W4 | Week 7–8 | Launch gate & soak | Hero-feature E2E suite ≥ 20 specs all green; real NIC IRP sandbox passes 50 invoices end-to-end; one-week soak run on QA with synthetic traffic; security + compliance signoff. |
Each wave has an explicit gate. No wave starts until prior gate passes. The gate is the launch contract.
§1 — Tracks (work splits within each wave)
Five concurrent tracks let 5 engineers operate without stepping on each other:
| Track | Owner skill | Services touched | Wave 0 → 4 commitment |
|---|---|---|---|
| A — Money flow | Backend + payments | reservation, payment, frontdesk, notification | 60% / 100% / 60% / 40% / 30% |
| B — Compliance | Backend + Indian regulatory | frontdesk, guest, notification | 80% / 100% / 40% / 20% / 30% |
| C — Operations UX | Frontend + dashboard | hmp-web-dashboard, hmp-mobile-apps | 20% / 60% / 100% / 40% / 30% |
| D — Data & reports | Backend + analytics | analytics, reservation, property | 20% / 30% / 80% / 80% / 30% |
| E — Platform hygiene | DevEx + infra | shared-packages, infrastructure, all services | 60% / 30% / 30% / 100% / 60% |
Percentages are share of the engineer's week dedicated to that track during the wave.
§2 — Wave 0 — Decision & Containment (Day 0–3)
Goal: stop the worst outcomes from happening while we plan the real fixes. No new features, only switches, guards, and disablements. Each item ≤ 0.5 day.
W0.1 — Production boot guards
| ID | Action | File | Owner | Effort | Done when |
|---|---|---|---|---|---|
| W0.1.1 | Add boot validator: throw when NODE_ENV='production' && EINVOICE_MOCK !== 'false' | hmp-frontdesk-service/src/einvoice/einvoice.module.ts | Track B | 0.25d | Service refuses to start in prod with mock IRN |
| W0.1.2 | Add boot validator: throw when NODE_ENV='production' && (RAZORPAY_KEY_ID undefined OR RAZORPAY_KEY_SECRET undefined) for any property using booking engine | hmp-payment-service/src/main.ts + hmp-reservation-service/src/booking-engine/booking-engine.module.ts | Track A | 0.5d | Service refuses to start without keys |
| W0.1.3 | Add boot validator: ENCRYPTION_KEY required in frontdesk-service for ID document storage | hmp-frontdesk-service/src/checkin/checkin.module.ts | Track B | 0.25d | Service refuses fallback-to-plaintext path in prod |
W0.2 — Route / endpoint disablements
| ID | Action | File | Owner | Effort | Done when |
|---|---|---|---|---|---|
| W0.2.1 | Disable POST /express-check-in until W1 implements it (return 503 "feature disabled") | hmp-frontdesk-service/src/checkin/checkin.controller.ts | Track B | 0.25d | Route returns 503 |
| W0.2.2 | Add API-key gate to booking-engine search/availability/calendar (currently REQUIRE_API_KEY=false) | hmp-reservation-service/src/booking-engine/booking-engine.controller.ts:71,86,94,104 | Track A | 0.5d | Anonymous request → 401 |
| W0.2.3 | Add gateway rate-limit bucket for booking-engine search (10/min/IP) | hmp-api-gateway/src/middleware/rate-limit.middleware.ts | Track A | 0.5d | Burst denied with 429 |
W0.3 — Documentation drift
| ID | Action | File | Owner | Effort | Done when |
|---|---|---|---|---|---|
| W0.3.1 | Remove SUBSCRIPTION_VIA_PAYMENT_SERVICE_ENABLED flag claim from root CLAUDE.md (flag is gone from code) | CLAUDE.md | Track E | 0.25d | CLAUDE.md matches code |
| W0.3.2 | Remove MenuItem.hsnCode exists claim from hmp-pos-service/CLAUDE.md (column does not exist) | hmp-pos-service/CLAUDE.md | Track E | 0.25d | Doc matches schema |
| W0.3.3 | Replace JWT_PUBLIC_KEY hard-coded PEM in docker-compose.dev-all.yml:32 with env-var resolution; rotate the leaked key in any environment that used it | hmp-infrastructure/docker/docker-compose.dev-all.yml | Track E | 0.5d | No PEM in master |
| W0.3.4 | Move hmp-booking-engine from feature/be-goat-phase-8 back to master (or accept the branch is the launch artifact and document it) | hmp-booking-engine repo | Track A | decision | Decision recorded; branch policy clear |
W0.4 — Wave plan signoff
| ID | Action | Owner | Done when |
|---|---|---|---|
| W0.4.1 | PM + tech leads review this roadmap; assign engineers to tracks; set start-of-wave-1 date | PM | All-hands signoff captured in writing |
| W0.4.2 | Decide which P1 items get pulled into W1–W2 vs deferred to W3 | PM + leads | Tagged in this document |
W0 exit gate (must all be green to start W1):
- All boot guards merged and deployed to staging.
- Express check-in route disabled in staging + prod compose.
- Booking-engine search behind API key + rate limit.
- CLAUDE.md drift fixed.
- JWT PEM rotated out of dev-all compose; old key revoked from any system that trusted it.
- Roadmap signed off; engineers assigned to tracks.
§3 — Wave 1 — Money & Compliance Hard Blockers (Week 1–2)
Goal: close every defect that costs money or violates Indian law. Two highest-blast-radius areas: the booking → payment → folio money path, and the FRRO / IRN compliance surface.
W1 — Track A: Money flow
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W1.A.1 | Booking last-room race — add SELECT … FOR UPDATE per (propertyId, roomTypeId, date) lock row inside createBooking transaction; add @@unique([propertyId, roomTypeId, date]) on a per-night inventory row | hmp-reservation-service/src/booking-engine/booking-engine.service.ts:981-1068; prisma/schema.prisma:187 | 3d | Concurrency regression test: N parallel createBooking calls for last room produce exactly 1 CONFIRMED |
| W1.A.2 | Razorpay verifyPayment HMAC bypass — remove the "mock fallback for dev/demo" branch; force verifyPayment to fail closed when keys absent | hmp-reservation-service/src/booking-engine/booking-engine.service.ts:1741-1754, 1888-1938 | 1d | Test asserts: PENDING → CONFIRMED only on valid HMAC; missing keys = 500, never auto-confirm |
| W1.A.3 | Idempotency-Key on createBookingFromEngine | hmp-reservation-service/src/booking-engine/booking-engine.service.ts:1508 | 0.5d | Double-click test: duplicate request → 1 reservation |
| W1.A.4 | FOLIO_PAYMENT_RECEIVED publish from inline checkout payments | hmp-frontdesk-service/src/checkout/checkout.service.ts:236 | 0.5d | Reservation paidAmount/balanceDue updates after every checkout payment |
| W1.A.5 | IRN ack number overwrites sequential invoice number — drop the overwrite; keep sequential value | hmp-frontdesk-service/src/einvoice/einvoice-job.processor.ts:64 | 0.5d | After IRN, Folio.invoiceNumber retains FY-sequential value; Folio.ackNumber holds NIC ack |
| W1.A.6 | Two divergent invoice-number generators — delete getNextInvoiceNumber in invoice-pdf.service.ts; pull from canonical FoliosService.getNextInvoiceNumber | hmp-frontdesk-service/src/einvoice/invoice-pdf.service.ts:601-618 | 1d | Single-source-of-truth test |
| W1.A.7 | Split-payment support at checkout — extend CheckOutDto to payments: { mode, amount, reference, cardLast4? }[]; loop inline settle | hmp-frontdesk-service/src/checkout/dto/checkout.dto.ts:30; checkout.service.ts:215-267 | 3d | Cash + card split test passes; Payment.cardLast4/cardType populated |
| W1.A.8 | Invoice attachment on thank-you email — publish typed folio.settled event; dispatcher fetches PDF and attaches via SendGrid | hmp-frontdesk-service/src/checkout/checkout.service.ts; hmp-notification-service/src/dispatcher/dispatcher.service.ts:130-132 | 1.5d | Test: checkout → email arrives with PDF attachment |
| W1.A.9 | Service-charge GST hardcoded 0.18 — read from property tax config | hmp-pos-service/src/orders/orders.service.ts:140, 807, 952 | 0.5d | GST-exempt property has 0% service-charge GST |
| W1.A.10 | Razorpay terminal adapter sends defunct X-Payment-Idempotency-Key | hmp-payment-service/src/adapters/razorpay/razorpay-terminal.adapter.ts:184, 293 | 0.25d | Header replaced with X-Razorpay-Idempotency-Key matching gateway adapter |
Track A wave-1 effort: ≈ 11.75 engineer-days.
W1 — Track B: Compliance
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W1.B.1 | ID photo upload — switch to S3 presigned upload | hmp-web-dashboard/src/app/(dashboard)/front-desk/check-in/[id]/keynova.tsx:444-446, 966; hmp-frontdesk-service/src/checkin/dto/checkin.dto.ts:152-159 | 2d | E2E: file picked → uploaded to S3 → check-in submitted with HTTPS URL → 201 |
| W1.B.2 | Empty-nationality bypass FRRO — reject check-in with nationality === '' OR null | hmp-frontdesk-service/src/checkin/checkin.service.ts:189-194 | 0.5d | Test: nationality blank → 400 with message "Nationality required" |
| W1.B.3 | Walk-in path FRRO enforcement — add identical FRRO block to walkIn(); WalkInDto accepts formC | hmp-frontdesk-service/src/checkin/checkin.service.ts walkIn(); dto/checkin.dto.ts:212-278 | 1d | Test: foreign walk-in without formC → 400 |
| W1.B.4 | Express check-in implementation — full check-in flow OR keep route disabled with explicit doc | hmp-frontdesk-service/src/checkin/checkin.service.ts:691-752 | 1d | Either implemented (with FRRO) or disabled with operator-facing notice |
| W1.B.5 | Police-register PII feed — decrypt formCDataEncrypted, populate columns, respect DPDPA logging | hmp-frontdesk-service/src/reporting-feeds/reporting-feeds.service.ts:458 | 2d | Test: feed includes passport/Aadhaar last-4 with audit trail of access |
| W1.B.6 | arrivedFrom / purposeOfVisit / visaType plumbing — dashboard inputs flow through to Form C PDF | hmp-frontdesk-service/src/cform/cform.service.ts:312, 318-319; dashboard check-in page | 1d | Test: PDF includes operator-supplied arrivedFrom, visaType |
| W1.B.7 | Signature field name mismatch — rename or add alias | hmp-web-dashboard/src/lib/api/front-desk.ts:37; hmp-frontdesk-service/src/checkin/dto/checkin.dto.ts:156 | 0.25d | Signature persisted from dashboard payload |
| W1.B.8 | GuestIdVerification plaintext fallback — hard-fail in prod when ENCRYPTION_KEY absent (boot guard W0.1.3 already deployed; remove fallback path) | hmp-frontdesk-service/src/checkin/checkin.service.ts:91-95 | 0.5d | Plaintext branch removed |
| W1.B.9 | HOUSEKEEPING_TASK_CREATED dedup at HK consumer | hmp-housekeeping-service/src/events/events.service.ts:155 | 0.5d | Test: checkout → 1 HK task, not 2 |
| W1.B.10 | Folio.guestGstin field for individual B2B guests; place-of-supply inference for B2C | hmp-frontdesk-service/prisma/schema.prisma; einvoice.service.ts:99-110 | 1.5d | Test: B2C guest from different state → IGST split |
Track B wave-1 effort: ≈ 10.25 engineer-days.
W1 — Track E: Platform support (parallel)
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W1.E.1 | Build script || true removed in 16 backend services | every backend package.json "build" field | 1d | TS error → build fails → CI red |
| W1.E.2 | Two-file rule fixes — /extra-charges, /seasons decorator/config additions | hmp-api-gateway/src/proxy/proxy.controller.ts; src/config/services.config.ts | 0.5d | Smoke test: paths route correctly |
Track E wave-1 effort: ≈ 1.5 engineer-days.
Wave 1 total effort: ≈ 23.5 engineer-days. Across 5 engineers × 10 working days = 50 engineer-days available. Slack for context-switch + reviews + bugs.
W1 exit gate:
- Concurrency test in CI proves last-room race is closed.
- No code path exists to confirm a reservation without HMAC verification.
- Foreign-guest check-in (booking engine, walk-in, dashboard) all enforce FRRO; empty nationality is rejected.
- ID photo + signature persist correctly end-to-end on a real S3 bucket.
- Police-register feed returns real (decrypted, audited) data.
- Invoice numbers are gap-free per FY; IRN does not overwrite the sequential value.
- One end-to-end test covers: booking → payment → check-in (Indian) → folio → checkout → invoice email with PDF.
- One end-to-end test covers: booking → payment → check-in (international, with FRRO) → folio → checkout → invoice email.
§4 — Wave 2 — Operational Completeness (Week 3–4)
Goal: the front desk and operations dashboards become trustable. Tape Chart works as advertised. Night audit is safe under crash + concurrency. Reports show real numbers.
W2 — Track C: Tape Chart hero feature
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W2.C.1 | Wire BarContextMenu + CellContextMenu into v2 shell | hmp-web-dashboard/src/components/modules/front-desk/tape-chart-v2/tape-chart-v2-shell.tsx:339-372 | 1d | Right-click bar → menu opens; click action → mutation fires |
| W2.C.2 | Replace 'coming in Phase 2' placeholder toasts with real handler dispatch | tape-chart-v2-shell.tsx:365-372 | 0.5d | Check-in / check-out / cancel from DetailPanel actually work |
| W2.C.3 | Replace v2 chart-grid.tsx body with v1 virtualized renderer | tape-chart-v2/chart-grid.tsx:143-265; reuse tape-chart/virtual/virtual-row-renderer.tsx | 1d | 100×30 grid renders in ≤ 1s on mid-tier laptop |
| W2.C.4 | Reservation version: Int @default(0) for optimistic concurrency + If-Match header | hmp-reservation-service/prisma/schema.prisma; drag handlers | 2d | Test: simultaneous drag → second write rejected with 412 |
| W2.C.5 | Restore BulkActionToolbar in v2; add OOO range-block action | tape-chart-v2/ + reuse tape-chart/bulk/ | 1.5d | Multi-select + stop-sell across rooms × dates works |
| W2.C.6 | 20-spec Playwright suite for tape chart — drag-move, drag-extend, walk-in click, context-menu cancel, conflict reject, overlap rejection, virtualization perf assertion | hmp-web-dashboard/e2e/tape-chart-*.spec.ts | 2d | Suite runs green in CI |
Track C wave-2 effort: ≈ 8 engineer-days.
W2 — Track D: Night audit + reports
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W2.D.1 | @@unique([propertyId, auditDate]) on frontdesk NightAuditLog; remove "proceeding without lock" path | hmp-frontdesk-service/prisma/schema.prisma:346-367; night-audit.service.ts:147 | 0.75d | Concurrency test: 2 parallel runs → 1 succeeds, 1 errors with unique violation |
| W2.D.2 | Dedup window timezone math — property-local midnight to property-local-tomorrow window | hmp-frontdesk-service/src/night-audit/night-audit.service.ts:453-455, 225 | 0.5d | Test for IST property at 23:00 IST: dedup excludes UTC-day-boundary charges correctly |
| W2.D.3 | Read today's nightly rate from RatePlanRate instead of rateAmount/nights average | hmp-frontdesk-service/src/night-audit/night-audit.service.ts:392-410 | 1d | Mid-stay rate change reflected in next night's posting |
| W2.D.4 | Cancellation-policy-aware no-show fee | hmp-frontdesk-service/src/night-audit/night-audit.service.ts:559-655 | 1d | Test matrix: prepaid plan / refundable plan / pay-at-hotel — each gets right fee |
| W2.D.5 | Outbox pattern for reservation.no_show + night.audit.completed | hmp-frontdesk-service/src/night-audit/night-audit.service.ts:691-703, 295-304 | 2d | Broker outage test: events still delivered after recovery |
| W2.D.6 | POS day-close cascade — POST /pos/outlets/:id/close-business-day; gate night-audit start on all outlets closed | hmp-pos-service/src/outlets/; hmp-frontdesk-service/src/night-audit/night-audit.service.ts | 2d | Test: open outlet at 02:00 IST → audit refuses to start with clear message |
| W2.D.7 | PDF + JSON snapshot to S3 with 5-year retention | hmp-frontdesk-service/src/night-audit/night-audit-pdf.service.ts + S3 lifecycle policy | 1d | Test: completed audit → S3 object with retention metadata |
| W2.D.8 | validatePreAudit failure mode tightening — cross-service unavailability surfaces RED, not zero | hmp-frontdesk-service/src/night-audit/night-audit.service.ts:1028-1083, 1207-1217 | 0.5d | Property-service offline → pre-audit shows ERROR not "all clear" |
Track D wave-2 effort: ≈ 8.75 engineer-days.
W2 — Track A: Money flow continued
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W2.A.1 | POS v2 GST split read at receiver | hmp-frontdesk-service/src/folios/consumers/pos-folio-charge.consumer.ts:108-155, 373-383; folios.service.ts:507-516 | 1d | Test: POS event with explicit CGST/SGST split → folio line carries the split, not re-derived |
| W2.A.2 | MenuItem.hsnCode + gstRate + admin UI + seed migration + propagation into v2 event | hmp-pos-service/prisma/schema.prisma:111-139; admin menu page; v2 event payload | 3d | New menu item carries HSN; e-invoice line gets HSN |
| W2.A.3 | Refund modal in dashboard | hmp-web-dashboard/src/app/(dashboard)/front-desk/folio/[id]/page.tsx; payment-service refund endpoint already exists | 1.5d | Frontdesk manager triggers partial refund from UI |
| W2.A.4 | PineLabs batch-settlement reconciliation OR explicit "card-present launch out of scope" decision | hmp-payment-service/src/adapters/pinelabs/pinelabs-terminal.adapter.ts:246-252; new reconciliation service | 4d (if implemented) | Daily T+1 reconciliation report; mismatches flagged |
Track A wave-2 effort: ≈ 9.5 engineer-days (or 5.5 if W2.A.4 is descoped).
W2 — Track D: Reports correctness
| ID | Blocker | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W2.D.9 | KPI tile reportIds — fix every wrong ID in tile components | hmp-web-dashboard/src/components/modules/operations-hub/tiles/kpi/{revpar,adr,occupancy,arrivals-today,departures-today,inhouse-count,no-shows-today}.tile.tsx | 0.5d | Vitest contract test: every tile-registry id ∈ definitions-registry |
| W2.D.10 | Reports timezone (UTC → property TZ) | hmp-analytics-service/src/reporting/reports/shared/period-helpers.ts:9-40; reservation.consumer.ts:103,221,249,286; night-audit.consumer.ts:121; dashboard.service.ts:255,1243 | 2d | Test: report run at 23:00 IST returns IST-day data |
| W2.D.11 | roomsSold increments per room-night, not per booking | hmp-analytics-service/src/consumers/reservation.consumer.ts:175,200 | 0.5d | ADR for 3-night reservation = total / 3, not total / 1 |
| W2.D.12 | MvDailyOccupancy.totalRooms seeding at 00:00 IST not lazy on first event | hmp-analytics-service/src/backfill/; new daily cron | 1d | RevPAR shows real value at 00:01 IST every day |
| W2.D.13 | Top-room-types report — add MvRoomTypeRevenue MV + folio consumer write path | hmp-analytics-service/prisma/schema.prisma; room-type-revenue.definition.ts:37 | 2d | Report runs in ≤ 200ms, not O(events) |
Track D wave-2 effort: ≈ 6 engineer-days.
Wave 2 total: ≈ 32.25 engineer-days (or 28.25 if PineLabs deferred). 50 engineer-days available across 5 × 10 days. Comfortable.
W2 exit gate:
- Tape Chart Playwright suite ≥ 20 specs all green; performance p95 ≤ 1s for 100×30.
- Night audit cannot double-post for same
(propertyId, businessDate)even with Redis down. - No-show fees match cancellation-policy contract terms.
- POS open shift blocks night audit start.
- All Operations Hub home tiles render numbers (not error/empty cards).
- One report run between 18:30 IST and midnight returns IST-day data, not UTC-day data.
- Refund flow demoable from dashboard.
§5 — Wave 3 — Hardening & P1 Sweep (Week 5–6)
Goal: clean up the architecture debt that the audit surfaced as cross-cutting risks. The platform should stay shippable, not just become shippable.
W3 — Track E: Platform hygiene
| ID | Item | Files | Effort | Acceptance criteria |
|---|---|---|---|---|
| W3.E.1 | xPrisma migration plan — choose for each foreign-model read site: (a) keep as read-model + harden sync consumer with replay test, (b) replace with @hmp/service-clients call. Decide per service. Document. | 79 sites in channel-service + reservation-service (per audit cross-cutting §4.2) | 5d (plan + 10 highest-risk migrations); rest in W4 | Decision matrix committed; 10 highest-risk sites migrated; replay-drift test added per remaining read-model |
| W3.E.2 | Webhook idempotency race in channel-service — @@unique partial index OR Redis SETNX | hmp-channel-service/prisma/schema.prisma:317-355; resavenue-webhook.controller.ts:480-488, 758-765 | 1d | Concurrent retry test: 1 event accepted, retry returns same deduped: true |
| W3.E.3 | itemsProcessed count fix | hmp-channel-service/src/intermediary/providers/resavenue/resavenue-xml.parser.ts:27,31 | 0.5d | 360-rate push reads as itemsProcessed=360 |
| W3.E.4 | Stay-only restrictions surfaced as errors | hmp-channel-service/src/intermediary/providers/resavenue/resavenue.adapter.ts:84-89 | 0.5d | Stay-only push returns 200 with errors[] non-empty OR auto-routes via pushRates |
| W3.E.5 | DB-level idempotency on outbound retries in channel-service | hmp-channel-service/src/sync/sync.service.ts:130-156 | 1d | Retry with same payload doesn't duplicate provider-side |
| W3.E.6 | Audit-log writes for tenant lifecycle | hmp-auth-service/src/tenants/tenants.service.ts:29, 225, 248; onboarding.service.ts:65-164 | 1d | All signup/suspend/reactivate/start/activate produce hash-chained audit rows |
| W3.E.7 | Email verification flow | hmp-auth-service/src/tenants/; User.emailVerified column; verify landing page in admin portal | 2.5d | New tenant cannot log in until verified |
| W3.E.8 | TenantStatus state machine replaces isActive boolean | hmp-auth-service/prisma/schema.prisma:19-58 and consumers | 2d | PENDING / ACTIVE / SUSPENDED / CANCELLED transitions enforced |
| W3.E.9 | MFA enrollment forced for ADMIN at create | hmp-auth-service/src/tenants/tenants.service.ts:72-84; onboarding.service.ts:128-140 | 1d | New admin's first login requires /auth/mfa/setup completion |
| W3.E.10 | Tenant suspension session invalidation | hmp-auth-service/src/tenants/tenants.service.ts:236-243 | 0.5d | Suspended tenant's user is logged out within 60 seconds |
Track E wave-3 effort: ≈ 15 engineer-days (significant — likely 2 engineers).
W3 — Track A/B/C residual P1s
| ID | Item | Files | Effort |
|---|---|---|---|
| W3.A.1 | OnboardingService migrates to SubscriptionsModule (typed TenantSubscription row) | hmp-auth-service/src/onboarding/onboarding.service.ts:401; subscriptions/subscription.service.ts | 2d |
| W3.A.2 | seedPropertyDefaults real implementation — non-stub | hmp-shared-packages/.../property-service.client.ts:530-550; new endpoint in hmp-property-service/src/onboarding/ | 2d |
| W3.B.1 | Aadhaar Verhoeff checksum | hmp-guest-service/src/guests/guests.service.ts:104 | 0.5d |
| W3.B.2 | DPDPA 90-day retention timer for GuestIdVerification rows | hmp-frontdesk-service/src/checkin/; cron job | 1d |
| W3.B.3 | S3 SSE explicit on uploads | hmp-shared-packages/packages/infra/src/lib/storage/storage.service.ts:60-109 | 0.5d |
| W3.C.1 | Reservation list search box wires query → backend | hmp-web-dashboard/src/lib/api/reservations.ts:124; reservations.service.ts:2210-2302 | 0.5d |
| W3.C.2 | Modify and Reg card buttons wired | hmp-web-dashboard/src/app/(dashboard)/reservations/.../keynova.tsx:1388-1393 | 1d |
| W3.C.3 | Folio tab on detail page reads real folios from frontdesk-service | keynova.tsx:947-992 | 1d |
| W3.C.4 | Guest profile reads via GuestServiceClient not local Prisma | hmp-reservation-service/src/reservations/reservations.service.ts:1438, 2286, 1339, 1399, 1665 | 1.5d |
| W3.C.5 | Cmd+K global search — implement aggregator OR delete the affordance | hmp-web-dashboard/src/lib/hooks/use-global-search.ts:85; new gateway endpoint OR removal | 2d |
| W3.C.6 | Mobile housekeeping <PhotoUpload taskId={task.id}> widget | hmp-mobile-apps/apps/housekeeping/app/task/[id].tsx; components/PhotoUpload.tsx:16 | 1d |
| W3.C.7 | Two /room-move controllers — delete duplicate; route gateway to canonical | hmp-frontdesk-service/src/checkin/checkin.controller.ts:97; room-ops.controller.ts:13 | 0.5d |
| W3.C.8 | Folio realignment on room move (date-segmented rate schedule) | hmp-frontdesk-service/src/room-ops/room-ops.service.ts:118-122; folio CHARGE adjustment posting | 2d |
| W3.C.9 | Explicit POST /reservations/:id/extend with availability + rate + policy + OTA push | hmp-reservation-service/src/reservations/reservations.service.ts:1606-1647 | 2d |
| W3.C.10 | ENABLE_POS_FOLIO_CHARGE_CONSUMER default ON (or in-tx writes) | hmp-frontdesk-service/src/folios/consumers/pos-folio-charge.consumer.ts:70 | 0.25d |
| W3.D.1 | Reports v2 saved-views frontend completeness | hmp-web-dashboard/src/app/(dashboard)/reports/v2/saved/ | 2d |
| W3.D.2 | /actions endpoint OR remove ActionsQueueSection | hmp-analytics-service/src/; hmp-web-dashboard/src/components/modules/operations-hub/actions-queue-section.tsx | 1.5d |
Track residual wave-3 effort: ≈ 21.25 engineer-days.
Wave 3 total: ≈ 36 engineer-days. Tight on 50-day budget; expect to defer 1–2 items into W4.
W3 exit gate:
- Build script fails CI on TS error.
- xPrisma migration plan published; 10 highest-risk read sites migrated; replay-drift tests added.
- Tenant lifecycle has audit trail + state machine + email verification + MFA enforcement.
- Mobile HK photo flow works end-to-end.
- Reservation list search and detail page render real data with no client-side fabrication.
- Refund flow demoable; subscription row landing in typed table.
§6 — Wave 4 — Launch Gate & Soak (Week 7–8)
Goal: prove the system runs cleanly for a week of synthetic-traffic soak. Capture compliance evidence. Sign off launch.
W4.1 — Test matrices
| ID | Item | Effort | Done when |
|---|---|---|---|
| W4.1.1 | E2E suite: 50-spec property-#1 happy + adversarial path coverage | 5d | All green in CI for 3 consecutive nights |
| W4.1.2 | Hero feature (Tape Chart) E2E ≥ 20 specs | (covered in W2) | Already done in W2 |
| W4.1.3 | Concurrency: 100 parallel bookings for 1 last-room property | 1d | Exactly 1 succeeds; 99 get 409 |
| W4.1.4 | Night audit chaos: kill the process at 5 different points; verify resume / rollback | 1.5d | No double-post; clean rollback |
| W4.1.5 | OTA storm: replay 24h of ResAvenue webhook traffic at 10× speed | 1d | All inbound dedup'd; folio totals match expected |
W4.2 — Compliance evidence packet
| ID | Item | Effort | Done when |
|---|---|---|---|
| W4.2.1 | Real NIC IRP sandbox: 50 invoices end-to-end (B2B + B2C, intra + inter-state, GST 12% + 18%) | 2d | All 50 have valid IRN + ACK; cancellation path verified |
| W4.2.2 | FRRO Form C generation evidence: 20 sample foreign-guest check-ins; PDFs verified by FRRO submission template | 1d | 20 PDFs in hmp-docs/Integrations/FRRO/cert-evidence-2026-XX-XX.md |
| W4.2.3 | GSTR-1 reconciliation: invoice numbers gap-free for the soak week | 1d | SQL query confirms |
| W4.2.4 | DPDPA evidence: ID document encrypted at rest; access audited; retention timer firing | 0.5d | S3 object inspection + audit log review |
| W4.2.5 | Police register: state guest-register CSV generated for the soak week | 0.5d | CSV with real (decrypted, audited) PII |
| W4.2.6 | PCI evidence: log-redaction proven across all paths; SAQ-A scope confirmed | 1d | Sanitizer test + log review |
| W4.2.7 | CERT-In incident-reporting wiring smoke test | 0.5d | Dummy incident → 6h SLA timer fires |
W4.3 — Operational readiness
| ID | Item | Effort | Done when |
|---|---|---|---|
| W4.3.1 | Runbook for night-audit failure recovery | 1d | Operator can rollback + resume |
| W4.3.2 | Runbook for OTA outage | 0.5d | Stop-sell procedure + DLQ replay |
| W4.3.3 | Runbook for payment provider outage | 0.5d | Pay-at-hotel fallback procedure |
| W4.3.4 | Performance baseline: dashboard p95, tape chart render p95, search p95 | 1d | Numbers captured; SLO defined |
| W4.3.5 | Security review (external + internal pen test on staging) | 3d | Findings triaged; high-severity closed |
| W4.3.6 | Monitoring alerts: 16+ alert rules per CLAUDE.md verified firing in chaos drills | 1d | All alerts proven; PagerDuty routing verified |
Wave 4 total: ≈ 20 engineer-days. Mostly testing + signoff, lighter than build waves.
W4 exit gate (launch readiness):
- All E2E suites green for 3 consecutive nights.
- One full week of QA soak complete with no P0/P1 regressions.
- Compliance evidence packet committed to
hmp-docs/Integrations/. - All runbooks reviewed by ops.
- Pen test report signed off.
- Property #1 GM has done a 4-hour scripted walkthrough on QA without finding a blocker.
- Go/no-go meeting recorded.
§7 — Effort summary
| Wave | Effort (eng-days) | Available (5 eng × 10 working days) | Slack |
|---|---|---|---|
| W0 | ~5d | 5d (3 calendar days × 2 of the team) | tight |
| W1 | ~23.5d | 50d | comfortable |
| W2 | ~32.25d (or 28.25 with PineLabs deferred) | 50d | comfortable |
| W3 | ~36d | 50d | tight (defer 1-2 items expected) |
| W4 | ~20d | 50d | lots of slack for fix-on-find |
| Total | ~117d (105d if PineLabs descoped) | 200d available | enough headroom |
Audit identified ~73 P0 + ~80 P1. Roadmap addresses all P0 in W0–W2 and all P1 in W3. Anything not in this roadmap is post-launch P2.
§8 — Dependencies
W0 ──► W1 ──► W2 ──► W3 ──► W4
│ │
│ ├── Track A: Money flow ─── continues into W3 with refund modal
│ ├── Track B: Compliance ─── continues into W4 with NIC IRP cert
│ └── Track D: Reports ────── continues into W3 with saved-views
│
└── Track E: Platform hygiene ───── biggest in W3 (xPrisma)
Hard dependencies:
- W1.A.1 (booking lock) blocks W4.1.3 (concurrency test).
- W1.A.5+A.6 (invoice numbering) blocks W4.2.3 (GSTR-1 reconciliation).
- W2.A.2 (HSN codes) blocks W4.2.1 (NIC IRP sandbox).
- W2.D.1 (night-audit unique constraint) blocks W4.1.4 (chaos test).
- W2.C.1+C.2+C.3 (tape chart wiring) blocks W2.C.6 (E2E suite).
- W3.E.6 (audit log) blocks W4.2.4 (DPDPA evidence).
Soft dependencies: W3.E.1 (xPrisma) is large; if it slips into W4, the soak still passes — just leaves architecture debt for post-launch.
§9 — Risks & escape hatches
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Real NIC IRP sandbox enrolment delayed | Medium | High | Start enrolment on day 1 of W0; if sandbox is unreachable by start of W4, ship with EINVOICE_MOCK=true flagged at GM-aware "draft" watermark on every invoice — formal launch gated on real IRN going forward. |
| Tape Chart v1→v2 plumbing breaks more than it fixes | Medium | Medium | Keep v1 shell as fallback flag; ship v2 behind FLAG_TAPE_CHART_V2; flip per property only after operator validation. |
| xPrisma migration drags on | High | Medium | Cap at 10 sites in W3; defer the rest with replay-drift tests as the bridge. |
| Booking concurrency test reveals deeper schema redesign | Low | High | Worst case escalates W1.A.1 from 3d → 8d; absorb via W3 slack. |
| ResAvenue partner response on cert v2 evidence delayed | Medium | Medium | Ops-only switch; not on the launch critical path; can launch direct-only. |
| PineLabs reconciliation requires new cron job we don't have time for | High | Medium | Descope card-present launch; manual EOD reconciliation as documented operator procedure. |
| Pen test finds new P0 in W4 | Medium | High | Reserve 5d of W4 slack; have a 1-week rollover plan if findings are deep. |
§10 — Decisions needed (before W0 ends)
| # | Decision | Default | Stakeholder |
|---|---|---|---|
| D1 | Property #1 launches with card-present POS terminal? | YES → adds 4d to W2 | Property GM + finance |
| D2 | Property #1 launches with real NIC IRP integration? | YES → adds 2d to W4 | Compliance/finance lead |
| D3 | Property #1 launches with Cmd+K global search? | NO (delete affordance, save 2d) | Product |
| D4 | xPrisma migration scope in W3: 10 sites or all 79? | 10 sites + drift tests | Engineering lead |
| D5 | hmp-booking-engine GoaT Phase 8 features ship with launch? | NO — launch from master after merging only the urgent fixes | Product + engineering |
| D6 | Mobile housekeeping app ships with launch? | YES — needed for HK photo proof flow | Property GM |
| D7 | Express check-in route enabled at launch? | NO — keep disabled until W3 implementation lands | Property GM |
| D8 | Any P1 deferred to post-launch besides what this roadmap already lists? | Capture during W0.4 | PM + leads |
§11 — Single-page status checklist (for daily standups)
W0 ─ Decision & Containment ───────────────── [ ]
├─ Boot guards (3) [ ]
├─ Route disablements (3) [ ]
├─ Doc drift fixes (4) [ ]
└─ Plan signoff [ ]
W1 ─ Money & Compliance Hard Blockers ──────── [ ]
├─ Track A: 10 items (~12d) [ ]
├─ Track B: 10 items (~10d) [ ]
└─ Track E: 2 items (~1.5d) [ ]
W2 ─ Operational Completeness ──────────────── [ ]
├─ Tape Chart hero (~8d) [ ]
├─ Night audit (~9d) [ ]
├─ Money flow continued (~9.5d) [ ]
└─ Reports correctness (~6d) [ ]
W3 ─ Hardening & P1 Sweep ──────────────────── [ ]
├─ Platform hygiene (~15d) [ ]
└─ Residual P1 across tracks (~21d) [ ]
W4 ─ Launch Gate & Soak ────────────────────── [ ]
├─ Test matrices (~9d) [ ]
├─ Compliance evidence (~7d) [ ]
└─ Operational readiness (~7d) [ ]
Document owner: PM + tech leads. Update at end of every wave. Close out at GM go-live signoff.
Files for cross-reference:
- Audit source:
hmp-docs/docs/platform-registry/property-1-launch-review-2026-05-06.md - Gold-standard charter:
hmp-docs/docs/platform-registry/property-1-gold-standard-fix-plan-2026-04-28.md - Visual roadmap:
hmp-docs/docs/platform-registry/property-1-launch-roadmap-2026-05-06.html