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
| Persona | Role | Source |
|---|---|---|
| Tenant ADMIN | Hotel owner / GM signing up for KeyNova | uc-tenant-self-onboarding.yaml (AP-T01-004) |
| SUPER_ADMIN | KeyNova platform operator (provisioning B2B accounts) | 01-epic-catalog.md (EP-001 row) |
Entry points
| Entry | URL | Backed by |
|---|---|---|
| Self-service signup | https://admin.<env>.keynova.ai/signup (admin portal) | hmp-admin-portal/src/app/(auth)/signup/page.tsx |
| Platform-provisioned admin | n/a — POST /api/tenants (SUPER_ADMIN only) | hmp-auth-service/src/tenants/tenants.controller.ts:68 |
| First-login wizard | https://dashboard.<env>.keynova.ai/settings/setup-wizard | hmp-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 theTenantrow and the first ADMIN user atomically. AP-T01-004 (uc-tenant-self-onboarding.yaml) ships the implementation but is not represented in01-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, statusPENDING_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 intenant-compliance-dto.spec.ts(9 specs). - Pre-conditions: Public internet access to admin portal. Valid email + 8+ char password.
- Post-conditions:
Tenantrow withstatus=PENDING_VERIFICATION. ADMIN user row withemailVerified=false. Welcome email queued viauser-invitationKafka 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 in01-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()(clearsemailVerified=false, advances tenantstatus=PENDING_VERIFICATION → ACTIVEonce the first admin verifies). - Test:
hmp-auth-service/src/auth/verify-email.spec.ts:: W3.E.7 email verification — PASS.signup-verification-wiring.spec.tsconfirms 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 toACTIVE. Frontend pageshmp-admin-portal/src/app/(auth)/verify-email/page.tsx+hmp-web-dashboard/src/app/(auth)/verify-email/page.tsxrender 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/me401 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 per2026-05-16-13-flow-demo-readiness.md). - Pre-conditions: Step 2 completed (
emailVerified=true); tenantACTIVE; userisActive=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=truewould 401 withMFA_REQUIRED_FOR_ADMINat theJwtAuthGuardfrom@hmp/auth@1.6.1. TheMFA_ENFORCE_ADMIN=falsekill-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, flipsmfaEnabled=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=truebecause enforcement is off). - Pre-conditions: Step 3 completed; authenticated session.
- Post-conditions:
User.mfaEnabled=true,mfaBackupCodesrow populated,mfaFailedAttempts=0. On next loginvalidateMfaLogin()issues a 5-mintempTokenand 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=trueis 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.tsxStep 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:
Propertyrow withtenantId, GSTIN/PAN, address+coords, defaultcurrentBusinessDate(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;
propertyIdknown. - Post-conditions:
RoomTyperows (Deluxe / Suite / etc.) with amenities, photos, default rate, max occupancy. - Notes: Photos handled via the shared
image-upload-widgetconsuming 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:
Roomrows with numbers, floor, building, features, initial statusAVAILABLE. Room counts surface inGET /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:
RatePlanrow(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.tsxall 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:
CancellationPolicyrow(s) with typedrules[](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 noUS-002-NNNrow 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')),:75POST /tax/configurations/apply-indian-defaults(one-click GST seed),:39POST /tax/calculate(inclusive flag — AP-T02-005). Dashboard surface insidesettings/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:
TaxConfigurationrows 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-NNNrow exists in01-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 viaPATCH /properties/:id/theme(host-mapping override → property theme → brand default cascade perbooking-engine-themeskill) and the dashboardBrandingpage, 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.tsxandsettings/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 inproperties.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.themepopulated (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 shipsuuidv4()token in Redispassword-reset:<token>72-h TTL, emitssetupLinkviauser-invitationKafka 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:
Rolerows (built-in 11 + custom).Userrows with role assignments,isActive=true,emailVerified=falsepending invitation acceptance. Each invited user receives a setup-password email via the same reset-password surface (US-001-007). - Notes:
US-001-006catalog 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.yamlAP-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 viaPropertyServiceClientpost-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-sideonboarding.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(viaPATCH /:id/onboarding).Property.activatedAtset (viaPOST /:id/activate). Tenant ready for first reservation. Subscription transitions out of trial ifPOST /onboarding/:tenantId/activatewas 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-defaultsexists but the saga still treatsseedPropertyDefaultsas a stub per AP-T01-007 follow-up — drift D-003.
Failure modes worth testing
| # | Scenario | Expected behaviour | Coverage today | Owning story |
|---|---|---|---|---|
| F1 | Signup with duplicate email | 409 with generic anti-enumeration body | tenants.service.p2002.spec.ts (6 specs) — PASS | [SME-PROPOSED] US-001-NEW-SIGNUP |
| F2 | Login before email verified | 401 / 403 with EMAIL_VERIFICATION_REQUIRED code | auth.service.spec.ts invalid-flow specs — PASS | US-001-001 |
| F3 | 20 failed logins → account lockout | Exponential backoff (60s → 5m → 15m → 30m); CERT-In event | brute-force-lockout.flow.spec.ts (compose-only, MODE=compose) | US-001-010 |
| F4 | ADMIN without MFA hits non-@MfaExempt() endpoint | 401 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) — PASS | US-001-004 / US-001-005 |
| F5 | Property create with malformed GSTIN | 400 with field-level error | properties/dto/property.dto.spec.ts (11 GSTIN/PAN specs) — PASS | US-002-001 |
| F6 | Bulk-create rooms with duplicate room number | 400 / 409 with per-row validation errors | rooms.service.spec.ts (18 specs) — PASS | US-002-003 |
| F7 | Cancellation rule with invalid Zod shape (days_before negative, charge_percent > 100) | 400 with typed validator failure | cancellation-policy-rules.spec.ts (14 specs) — PASS | US-002-006 |
| F8 | Cross-tenant property fetch (ADMIN of tenant A requests property of tenant B) | 403 with TENANT_MISMATCH | property-cross-tenant-denial.spec.ts — PASS; tenant-isolation.flow.spec.ts — TBD pass count | US-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.tscovers UI; full saga inuc-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-contractsv1 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.buildingfilter and add aBuildingentity 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.)
| ID | Type | Severity | Description | Surfaced by step |
|---|---|---|---|---|
| D-001 | Test-vs-code | P1 | flow-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-002 | Catalog-vs-code | P1 | US-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-003 | Use-case-vs-impl | P1 | POST /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-004 | Review-vs-code | P0 | reviews/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-005 | Catalog-gap | P0 | Tax 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-006 | Catalog-vs-code | P2 | US-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-007 | Test-vs-seed | P1 | Flow-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
| Step | Spans | Why cross-EPIC |
|---|---|---|
| 1 → 2 | EP-001 (auth) | Catalog gap — signup + email verification are not catalogued; implementation is. |
| 3 → 4 | EP-001 (auth) | Login + MFA, gated by kill-switch. |
| 5 → 11 | EP-002 (property) | Linear property-setup spine. |
| 12 | EP-001 ↔ EP-002 | Roles + staff invites loop back into EP-001 surface. |
| 13 | EP-001 ↔ EP-003 (reservations) | Enterprise keys in auth-service; booking-engine keys in reservation-service. |
| 14 | EP-001 ↔ EP-002 | Wizard 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.