Skip to main content

BF-001 — Tenant + Property Onboarding

Business flow (cross-EPIC user journey). Reconciled 2026-05-24 as the first artefact in the RTM Reconciliation Pilot, intended to be the template for BF-002 through BF-013.

Each step names (a) the user story that owns the requirement, (b) the primary code path that runs it, (c) the closest automated test that exercises it, and (d) pre/post-conditions and notes. Where the spec contains no matching catalog story, the step is tagged [SME-PROPOSED] as a NEW story for the SME's intake — these are the gaps the RTM pilot is designed to surface.

Personas​

PersonaRoleSource
Tenant ADMINHotel owner / GM signing up for KeyNovauc-tenant-self-onboarding.yaml (AP-T01-004)
SUPER_ADMINKeyNova platform operator (provisioning B2B accounts)01-epic-catalog.md (EP-001 row)

Entry points​

EntryURLBacked by
Self-service signuphttps://admin.<env>.keynova.ai/signup (admin portal)hmp-admin-portal/src/app/(auth)/signup/page.tsx
Platform-provisioned adminn/a — POST /api/tenants (SUPER_ADMIN only)hmp-auth-service/src/tenants/tenants.controller.ts:68
First-login wizardhttps://dashboard.<env>.keynova.ai/settings/setup-wizardhmp-web-dashboard/src/app/(dashboard)/settings/setup-wizard/page.tsx

The 14-step journey​

Step 1: Tenant signs up​

  • Story: [SME-PROPOSED] new story — US-001-NEW-SIGNUP "Tenant self-registration via admin portal". Closest catalog story is US-001-011 (User CRUD) but that covers staff invites under an existing tenant, not the cold-start signup that creates the Tenant row and the first ADMIN user atomically. AP-T01-004 (uc-tenant-self-onboarding.yaml) ships the implementation but is not represented in 01-epic-catalog.md.
  • Code: hmp-auth-service/src/tenants/tenants.controller.ts:42 — @Public() @Post('signup') → tenants.service.ts::signup() (atomic tenant + admin user create, status PENDING_VERIFICATION, emailVerified=false, 4 compliance columns populated).
  • Test: hmp-auth-service/src/tenants/tenants.service.spec.ts :: tenant signup behaviour — PASS. Compliance-column DTO coverage in tenant-compliance-dto.spec.ts (9 specs).
  • Pre-conditions: Public internet access to admin portal. Valid email + 8+ char password.
  • Post-conditions: Tenant row with status=PENDING_VERIFICATION. ADMIN user row with emailVerified=false. Welcome email queued via user-invitation Kafka topic carrying a verify-email token.
  • Notes: Brute-force protection on signup is implicit (US-001-010 covers login surface; signup-flood protection is not in scope of US-001-010 per source map — likely a [SME-PROPOSED] follow-up).

Step 2: Admin verifies email​

  • Story: [SME-PROPOSED] new story — US-001-NEW-VERIFY-EMAIL "Verify email address via token". Implementation shipped under W3.E.7 but not in 01-epic-catalog.md. US-001-001 (Login) implicitly depends on a verified email but does not own the verification surface.
  • Code: hmp-auth-service/src/auth/auth.controller.ts:153 — @Public() @Post('verify-email') (W3.E.7) → auth.service.ts::verifyEmail() (clears emailVerified=false, advances tenant status=PENDING_VERIFICATION → ACTIVE once the first admin verifies).
  • Test: hmp-auth-service/src/auth/verify-email.spec.ts :: W3.E.7 email verification — PASS. signup-verification-wiring.spec.ts confirms the post-signup wiring.
  • Pre-conditions: Step 1 completed; welcome email delivered (SES in prod, SendGrid in legacy envs); user clicks token link within TTL.
  • Post-conditions: User.emailVerified=true. Tenant transitions to ACTIVE. Frontend pages hmp-admin-portal/src/app/(auth)/verify-email/page.tsx + hmp-web-dashboard/src/app/(auth)/verify-email/page.tsx render the success / failure state.
  • Notes: Generic 200 anti-enumeration response on invalid token. Token TTL aligned to the 72-h invitation-token window (QA-PMS-6).

Step 3: Admin logs in​

  • Story: US-001-001 — User Login with Email/Password.
  • Code: hmp-auth-service/src/auth/auth.controller.ts:58 — @Public() @Post('login') → auth.service.ts::login() (Redis-backed brute-force counter, audit log on success/failure). Dashboard NextAuth handler: hmp-web-dashboard/src/lib/auth.ts::authorize() parses /auth/me 401 body for MFA cascade.
  • Test: hmp-auth-service/src/auth/auth.service.spec.ts :: 7 login scenarios (valid/invalid/inactive/MFA paths) — PASS. Flow: hmp-infrastructure/testing/flow-tests/src/flows/flow-1-tenant-onboarding.spec.ts :: "S2 — admin login after signup" — PASS (S2 in passing subset of 5/10 per 2026-05-16-13-flow-demo-readiness.md).
  • Pre-conditions: Step 2 completed (emailVerified=true); tenant ACTIVE; user isActive=true.
  • Post-conditions: 15-min access JWT + 7-day refresh JWT issued. Session row in Redis (max 5 concurrent). Audit log row.
  • Notes: Per platform policy, ADMIN/SUPER_ADMIN without mfaEnabled=true would 401 with MFA_REQUIRED_FOR_ADMIN at the JwtAuthGuard from @hmp/auth@1.6.1. The MFA_ENFORCE_ADMIN=false kill-switch is currently ON in all 4 envs (per platform memory), so MFA is effectively optional today — see Step 4.

Step 4: Admin sets up MFA (TOTP)​

  • Story: US-001-004 (MFA Setup, TOTP) + US-001-005 (MFA Verification on Login).
  • Code: hmp-auth-service/src/auth/auth.controller.ts:164 — @MfaExempt() @Post('mfa/setup') (issues TOTP secret + QR), :179 @Post('mfa/verify') (verifies first code, flips mfaEnabled=true), :194 @Public() @Post('mfa/validate') (two-step login challenge). Dashboard UI: hmp-web-dashboard/src/app/(dashboard)/settings/security/mfa/page.tsx (QR + 10 bcrypt-hashed backup codes per implementation report).
  • Test: hmp-auth-service/src/auth/auth.service.spec.ts :: 5 verifyMfa specs incl. backup-code paths — PASS. Flow: hmp-infrastructure/testing/flow-tests/src/flows/mfa-totp.flow.spec.ts — SKIPPED in test/qa (SKIP_MFA_FLOW=true because enforcement is off).
  • Pre-conditions: Step 3 completed; authenticated session.
  • Post-conditions: User.mfaEnabled=true, mfaBackupCodes row populated, mfaFailedAttempts=0. On next login validateMfaLogin() issues a 5-min tempToken and challenges for the TOTP code.
  • Notes: With the kill-switch ON, this step is operator-optional in test/qa/staging/prod today; once SMS/Email MFA ships and MFA_ENFORCE_ADMIN=true is re-enabled, this step becomes a hard gate before any non-@MfaExempt() API call.

Step 5: Admin creates property​

  • Story: US-002-001 — Property Create & Configuration.
  • Code: hmp-property-service/src/properties/properties.controller.ts:36 — POST / (@Roles('SUPER_ADMIN','ADMIN'), assertTenantScope()). DTO: properties/dto/property.dto.ts (GSTIN + PAN regex per AP-T02-001; latitude/longitude/googleMapsUrl). Wizard entry: hmp-web-dashboard/src/app/(dashboard)/settings/setup-wizard/page.tsx Step 2.
  • Test: hmp-property-service/src/properties/properties.service.spec.ts :: 25 specs incl. lat/lng round-trip + GSTIN/PAN validation — PASS. properties.controller.spec.ts :: 12 specs — PASS. Flow: flow-2-property-onboarding.spec.ts :: "S1 — PUT /properties/:id with name/address/coords" — PASS (7/7).
  • Pre-conditions: Step 3 completed; tenant ACTIVE; ADMIN role; subscription plan permits ≥1 property (or tenant on PROFESSIONAL/ENTERPRISE for multi-property).
  • Post-conditions: Property row with tenantId, GSTIN/PAN, address+coords, default currentBusinessDate (AP-T09-004). TENANT_CREATED-equivalent read-model event emitted so cross-service consumers warm their caches.
  • Notes: Flow-1 S3/S4 currently FAIL on a stale-read-model race (property list 200s but missing the row) — drift candidate D-001. Property image upload (US-002-014, AP-T02-002/003) is exercised as flow-2 S2 in the same wizard step.

Step 6: Configure room types​

  • Story: US-002-002 — Room Type CRUD with Amenities & Photos.
  • Code: hmp-property-service/src/room-types/room-types.controller.ts:27 — POST /room-types, POST /room-types/:id/duplicate. DTO: room-types/dto/room-type.dto.ts (code-format constraints). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/room-types/page.tsx.
  • Test: room-types.service.spec.ts :: 20 specs + room-types.controller.spec.ts :: 13 specs + dto/room-type.dto.spec.ts :: 10 specs — PASS. Flow: flow-2-property-onboarding.spec.ts :: "S3 — POST /room-types" — PASS (7/7). Real-backend smoke: smoke-settings-roomtype.real.spec.ts.
  • Pre-conditions: Step 5 completed; propertyId known.
  • Post-conditions: RoomType rows (Deluxe / Suite / etc.) with amenities, photos, default rate, max occupancy.
  • Notes: Photos handled via the shared image-upload-widget consuming the AP-T02-002 S3 presigned URL flow (US-002-014).

Step 7: Add rooms (inventory)​

  • Story: US-002-003 (Room Inventory) + US-002-010 (Room Features — smoking/accessible/connecting) + US-002-013 (multi-building, partial).
  • Code: hmp-property-service/src/rooms/rooms.controller.ts:37 — POST /rooms/bulk (preferred for bulk seed), POST /rooms, PUT /rooms/:id. DTO: rooms/dto/bulk-create-rooms.dto.ts, create-room.dto.ts (isSmoking, features[], building?).
  • Test: rooms.service.spec.ts :: 18 specs + rooms.controller.spec.ts :: 14 specs — PASS. Flow: flow-2-property-onboarding.spec.ts :: "S4 — POST /rooms/bulk" — PASS (7/7). Full lifecycle: rooms-crud.flow.spec.ts (P-GAP-1).
  • Pre-conditions: Step 6 completed; at least one room type exists.
  • Post-conditions: Room rows with numbers, floor, building, features, initial status AVAILABLE. Room counts surface in GET /properties/:propertyId/rooms/summary.
  • Notes: Floor Plan Visual Editor (US-002-012) is Not Started — manual room entry only today.

Step 8: Define rate plans​

  • Story: US-002-005 — Rate Plan CRUD (BAR, Corporate, Seasonal). (Optional next-tier: US-002-007 Seasonal & Dynamic Rate Management for season-bound rates.)
  • Code: hmp-property-service/src/rate-plans/rate-plans.controller.ts:33 — POST/GET/PUT/DELETE /rate-plans, GET/PUT /rate-plans/:id/rates, POST/GET /rate-plans/:id/restrictions. Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/rate-plans/page.tsx. Seasons: hmp-property-service/src/seasons/seasons.controller.ts:25.
  • Test: rate-plans.controller.spec.ts :: 14 specs + rate-plans.tenant-guard.spec.ts — PASS. Flow: flow-2-property-onboarding.spec.ts :: "S5 — rate plans" — PASS (7/7). Real-backend smoke: smoke-rate-plans.real.spec.ts. Seasons: smoke-seasons.real.spec.ts.
  • Pre-conditions: Step 6 completed; at least one room type exists.
  • Post-conditions: RatePlan row(s) (typically BAR + at least one corporate / promo) linked to room types with per-day rates and restrictions (min LOS, advance-purchase, etc.).
  • Notes: US-002-007 review file says NOT_IMPLEMENTED but Seasons module + 6 endpoints + settings/seasons/page.tsx all exist (drift D-004). Mark seasonal config as optional in BF-001 — required only if hotel wants automatic peak-season pricing.

Step 9: Configure cancellation policy​

  • Story: US-002-006 — Cancellation Policy Configuration.
  • Code: hmp-property-service/src/cancellation-policies/cancellation-policies.controller.ts:32 — CRUD. DTO: cancellation-policies/dto/cancellation-policy.dto.ts. Zod v4 typed-rules validator: cancellation-policies/dto/cancellation-rules-validator.ts (AP-T02-006). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/cancellation-policies/page.tsx.
  • Test: cancellation-policy-rules.spec.ts :: 14 specs (Zod schema + DTO + validator helper) + cancellation-policies.tenant-guard.spec.ts — PASS. Flow: flow-2-property-onboarding.spec.ts :: "S7 — cancellation-policies" — PASS (7/7). Real-backend smoke: smoke-cancellation-policies.real.spec.ts.
  • Pre-conditions: Step 8 completed (rate plans need at least one policy attachable).
  • Post-conditions: CancellationPolicy row(s) with typed rules[] (days-before / charge-percent ladder). Default "Flexible" + "Non-Refundable" suggested by the wizard.
  • Notes: Duplicate-name guard shipped per US-002-006 implementation report.

Step 10: Configure taxes (GST)​

  • Story: [SME-PROPOSED] new story — US-002-NEW-TAX-CONFIG "Property tax configuration (CGST/SGST/IGST inclusive/exclusive)". Implementation closed under AP-T02-005 (uc-tax-configuration-inclusive.yaml) and exists end-to-end, but the user-story catalog has no US-002-NNN row for it. Closest catalog story is US-002-001 which treats tax as a property-config side-channel.
  • Code: hmp-property-service/src/tax/tax.controller.ts:163 — POST /tax/configurations (@Roles('SUPER_ADMIN','ADMIN')), :75 POST /tax/configurations/apply-indian-defaults (one-click GST seed), :39 POST /tax/calculate (inclusive flag — AP-T02-005). Dashboard surface inside settings/property/page.tsx "Taxes" tab.
  • Test: hmp-property-service/src/tax/tax.controller.spec.ts — PASS. tax-configuration-inclusive.spec.ts :: AP-T02-005 inclusive-flag specs — PASS. tax-no-fallback.spec.ts :: no-silent-default behaviour — PASS. Real-backend smoke: smoke-taxes.real.spec.ts. Flow: flow-2-property-onboarding.spec.ts :: "S6 — tax configurations" — PASS (7/7).
  • Pre-conditions: Step 5 completed; tenant has GSTIN populated (or marks property as unregistered).
  • Post-conditions: TaxConfiguration rows with HSN/SAC, rate, inclusive/exclusive flag. Used by reservation pricing (/tax/calculate), folio posting (frontdesk), POS orders, and e-invoice generation.
  • Notes: This is one of the most visible catalog gaps of the BF-001 reconciliation — the AP-T02-005 use case is closed but no US-002-NNN row exists in 01-epic-catalog.md. Drift D-005.

Step 11: Brand the booking engine​

  • Story: [SME-PROPOSED] new story — US-002-NEW-BRANDING "Brand the guest-facing booking engine (logo, palette, typography, hero copy, host-mapping)". Implementation shipped via PATCH /properties/:id/theme (host-mapping override → property theme → brand default cascade per booking-engine-theme skill) and the dashboard Branding page, but the catalog has no row.
  • Code: hmp-property-service/src/properties/properties.controller.ts:201 — @Patch(':id/theme') (set 1 of 9 KeyNova theme presets, per-property override). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/branding/page.tsx and settings/branding/theme/page.tsx. Booking-engine consumer: hmp-booking-engine/src/ (resolves theme on every page load).
  • Test: hmp-web-dashboard/src/app/(dashboard)/settings/branding/theme/__tests__/page.test.tsx — PASS. Backend theme-patch coverage embedded in properties.controller.spec.ts (12 specs).
  • Pre-conditions: Step 5 completed; logo asset uploaded via the AP-T02-002 image flow (US-002-014).
  • Post-conditions: Property.theme populated (one of 9 presets, 3 legacy + 6 direction-A/B-luxury/urban/boutique). Guest booking widget reflects new branding on next render.
  • Notes: Catalog gap. Host-mapping override is operator-only (not exposed in dashboard yet) — flag as Day-2 follow-up.

Step 12: Configure roles + invite first staff users​

  • Story: US-001-006 (RBAC, 9 roles — catalog text vs 11 roles in code, drift D-002) + US-001-011 (User CRUD — Invite, Activate, Deactivate).
  • Code: Custom roles: hmp-auth-service/src/roles/roles.controller.ts (POST/GET/PATCH/DELETE /roles, @Roles('SUPER_ADMIN','ADMIN')). Staff invite: hmp-auth-service/src/auth/auth.service.ts::createUser() (QA-PMS-6 ships uuidv4() token in Redis password-reset:<token> 72-h TTL, emits setupLink via user-invitation Kafka event). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/users/page.tsx, settings/roles/page.tsx.
  • Test: auth.service.spec.ts :: 6 createUser specs + QA-PMS-6 invitation-token specs — PASS. users/users.service.spec.ts :: listStaff() for cross-service consumers — PASS. Flow: tenant-onboarding-full.flow.spec.ts :: "Scenario 8 — 3 staff users with roles" — TBD pass count (not in 13-flow doc). Real-backend smokes: smoke-users.real.spec.ts, smoke-roles.real.spec.ts. Custom-roles flow: custom-roles.flow.spec.ts (P3-11).
  • Pre-conditions: Step 5 completed (property exists so role scope can attach to it); ADMIN session.
  • Post-conditions: Role rows (built-in 11 + custom). User rows with role assignments, isActive=true, emailVerified=false pending invitation acceptance. Each invited user receives a setup-password email via the same reset-password surface (US-001-007).
  • Notes: US-001-006 catalog title "RBAC (9 Roles)" vs actual 11-role enum is drift D-002. Frontend sidebar/permission-gate wiring still has gaps per review file (D-006).

Step 13: API key generation (optional — for hotels using HMP API directly)​

  • Story: US-001-014 — API Key Management for Third Parties. (Note: not in the EP-001 onboarding-subset RTM — covered in the broader EP-001 catalog; pulled in here because it is the standard "hotels integrating directly" path. Also: per-property booking-engine API key via uc-property-api-key.yaml AP-T03-002 living in reservation-service.)
  • Code: Enterprise tenant-level keys: hmp-auth-service/src/api-keys/api-key.controller.ts (@Roles('SUPER_ADMIN','ADMIN'), POST /, PUT /:id/rotate, GET /:id/usage, DELETE /:id). Booking-engine property-scoped keys: hmp-reservation-service/src/booking-engine/ API-key controller (POST /properties/:propertyId/api-keys/rotate, DELETE /properties/:propertyId/api-keys/:keyId). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/api/page.tsx.
  • Test: api-keys/api-key.service.spec.ts :: 10 specs (create/list/rotate/revoke/validate). hmp-reservation-service/src/booking-engine/__tests__/api-key.service.spec.ts. Flow: api-key.flow.spec.ts (create/list/rotate/revoke + tenant isolation, /api/auth/api-keys).
  • Pre-conditions: Step 12 completed; ADMIN role.
  • Post-conditions: Hashed key stored (SHA-256 for property-scoped per AP-T03-002), plaintext returned once. Scopes, IP allowlist, rate limit configured.
  • Notes: Flow-3 (booking-engine) fails 3/7 because seed doesn't rotate the per-property API key post-AP-T03-002 — drift D-007. Optional step: only hotels integrating directly with the HMP API or running their own booking widget need this.

Step 14: Onboarding wizard completion​

  • Story: US-002-009 — Onboarding Wizard (Guided Setup). [SME-PROPOSED] follow-up — US-002-NEW-WIZARD-7-STEPS "Onboarding wizard 7-step expansion" because the spec wants 7 steps but the dashboard has 4.
  • Code: Auth-service orchestrator: hmp-auth-service/src/onboarding/onboarding.controller.ts:50 — POST /onboarding/start, POST /onboarding/:tenantId/property, POST /onboarding/:tenantId/rooms, POST /onboarding/:tenantId/activate, GET /onboarding/:tenantId/status (saga via PropertyServiceClient post-AP-T01-007). Property-service worker: hmp-property-service/src/onboarding/onboarding.controller.ts — POST /onboarding, GET /onboarding/:propertyId/status, POST /onboarding/seed-defaults (stub flagged AP-T01-007 follow-up). Dashboard: hmp-web-dashboard/src/app/(dashboard)/settings/setup-wizard/page.tsx (4-step UI today), (dashboard)/onboarding/property/page.tsx, (dashboard)/onboarding/migrate/page.tsx.
  • Test: hmp-auth-service/src/onboarding/onboarding.service.spec.ts :: 15 saga specs — PASS. onboarding.controller.spec.ts :: 4 tenant-scope specs (AP-T01-003) — PASS. Property-side onboarding.service.spec.ts + seed-defaults.spec.ts — PASS. Flow: admin-onboarding.flow.spec.ts (4-step saga end-to-end) + tenant-onboarding-full.flow.spec.ts (10-scenario full wizard) — TBD pass counts (not in 13-flow doc). E2E: hmp-web-dashboard/e2e/onboarding-wizard.spec.ts.
  • Pre-conditions: Steps 1, 3, 5, 6, 7 completed at minimum. Wizard tolerates partial completion (resume-from-last-step semantics via GET /onboarding/:tenantId/status).
  • Post-conditions: Property.onboardingState=COMPLETED (via PATCH /:id/onboarding). Property.activatedAt set (via POST /:id/activate). Tenant ready for first reservation. Subscription transitions out of trial if POST /onboarding/:tenantId/activate was hit.
  • Notes: The onboarding wizard lives in TWO services — orchestration in auth-service, per-property seed in property-service. This is the cross-EPIC seam that BF-001 has to narrate. POST /onboarding/seed-defaults exists but the saga still treats seedPropertyDefaults as a stub per AP-T01-007 follow-up — drift D-003.

Failure modes worth testing​

#ScenarioExpected behaviourCoverage todayOwning story
F1Signup with duplicate email409 with generic anti-enumeration bodytenants.service.p2002.spec.ts (6 specs) — PASS[SME-PROPOSED] US-001-NEW-SIGNUP
F2Login before email verified401 / 403 with EMAIL_VERIFICATION_REQUIRED codeauth.service.spec.ts invalid-flow specs — PASSUS-001-001
F320 failed logins → account lockoutExponential backoff (60s → 5m → 15m → 30m); CERT-In eventbrute-force-lockout.flow.spec.ts (compose-only, MODE=compose)US-001-010
F4ADMIN without MFA hits non-@MfaExempt() endpoint401 MFA_REQUIRED_FOR_ADMIN (currently masked by MFA_ENFORCE_ADMIN=false kill-switch in all 4 envs)jwt-auth.guard.spec.ts (40 specs incl. kill-switch) — PASSUS-001-004 / US-001-005
F5Property create with malformed GSTIN400 with field-level errorproperties/dto/property.dto.spec.ts (11 GSTIN/PAN specs) — PASSUS-002-001
F6Bulk-create rooms with duplicate room number400 / 409 with per-row validation errorsrooms.service.spec.ts (18 specs) — PASSUS-002-003
F7Cancellation rule with invalid Zod shape (days_before negative, charge_percent > 100)400 with typed validator failurecancellation-policy-rules.spec.ts (14 specs) — PASSUS-002-006
F8Cross-tenant property fetch (ADMIN of tenant A requests property of tenant B)403 with TENANT_MISMATCHproperty-cross-tenant-denial.spec.ts — PASS; tenant-isolation.flow.spec.ts — TBD pass countUS-002-001 / US-001-006

Day-2 onboarding (first 30 days, NOT in pilot scope)​

Items the hotel typically tackles in the first 30 days post go-live. Not in BF-001 scope but flagged so BF-002…BF-013 know where to pick up:

  • Channel manager bootstrap — connect to Booking.com / Expedia / GoMMT (BF-TBD channel-onboarding).
  • OTA rate parity rules — configure rate parity guardrails (US-002-007 partial; revenue-strategy service).
  • Razorpay merchant onboarding — smoke-merchant-account.real.spec.ts covers UI; full saga in uc-tenant-payment-onboarding.yaml.
  • POS outlet setup — outlets, menus, KOT printers (EP for POS, out of scope).
  • Housekeeping SOPs — task templates, staff assignments (EP-HK, out of scope).
  • CRM templating — welcome emails, post-stay survey (@hmp/notification-contracts v1 events).
  • Hardware provisioning — door locks, payment terminals (@hmp/hardware).
  • First night audit dry-run — verify business-date advance + folio reconciliation (US-009, out of scope).
  • DSAR / consent log review — GDPR / DPDPA compliance dashboard (out of scope).
  • Migrate from legacy PMS — eZee / Hotelogix / Opera importers (US-002-008 — Partial).
  • Booking engine go-live — public DNS, payment provider live keys, branded confirmation email templates.
  • First-3-day pilot reservation — verify end-to-end PMS → folio → check-out → invoice for one real guest before opening channels.
  • Floor plan editor — when US-002-012 ships, replace manual room entry with visual editor.
  • Multi-building expansion — US-002-013 (Partial) — operationalise the Room.building filter and add a Building entity if the catalog ever calls for it.

Drift summary​

The 7 BF-001-surfaced drifts that Task 6 must adjudicate. (P0 = blocks pilot sign-off; P1 = ships next sprint; P2 = backlog.)

IDTypeSeverityDescriptionSurfaced by step
D-001Test-vs-codeP1flow-1-tenant-onboarding.spec.ts S2a/S3/S4 fail because property list read model is stale after TENANT_CREATED propagation. Race between property POST and read-model sync via Kafka.Step 5
D-002Catalog-vs-codeP1US-001-006 catalog text says "9 Roles" but enum in hmp-auth-service/CLAUDE.md lists 11 (SUPER_ADMIN through HOSPITAL_STAFF). Catalog wording out of date.Step 12
D-003Use-case-vs-implP1POST /onboarding/seed-defaults endpoint exists in hmp-property-service/src/onboarding/onboarding.controller.ts but uc-tenant-onboarding-saga.yaml still treats seedPropertyDefaults as a stub. Either wire the saga to call it, or delete the endpoint.Step 14
D-004Review-vs-codeP0reviews/EP-002/US-002-007-review.md says "NOT_IMPLEMENTED, 0/10" but seasons.controller.ts ships 6 endpoints, settings/seasons/page.tsx exists, and smoke-seasons.real.spec.ts passes. Review file is stale.Step 8
D-005Catalog-gapP0Tax configuration (CGST/SGST/IGST inclusive flag) shipped under AP-T02-005 with full controller + 3 spec files + frontend + smoke test, but no US-002-NNN row exists in 01-epic-catalog.md. Add catalog row or merge into US-002-001.Step 10
D-006Catalog-vs-codeP2US-001-006 review file flags frontend sidebar/permission-gate wiring as incomplete (7/9 ACs). Backend RBAC is fully wired; UI conditional-render gate is partial.Step 12
D-007Test-vs-seedP1Flow-3 (booking-engine) fails 3/7 because seed-master doesn't rotate the per-property API key post-AP-T03-002. Update seed-master.sh or relax the seed contract.Step 13

Cross-EPIC narrative summary​

StepSpansWhy cross-EPIC
1 → 2EP-001 (auth)Catalog gap — signup + email verification are not catalogued; implementation is.
3 → 4EP-001 (auth)Login + MFA, gated by kill-switch.
5 → 11EP-002 (property)Linear property-setup spine.
12EP-001 ↔ EP-002Roles + staff invites loop back into EP-001 surface.
13EP-001 ↔ EP-003 (reservations)Enterprise keys in auth-service; booking-engine keys in reservation-service.
14EP-001 ↔ EP-002Wizard saga lives in both services — auth-service orchestrates, property-service seeds.

The "wizard lives in two services" seam (Step 14) and the catalog gaps on signup / email-verify / tax / branding (Steps 1, 2, 10, 11) are the primary BF-001 findings the SME must act on.