J-13 — Onboard New Tenant (Single Hotel Operator)
One-liner: A new operator signs up, configures their property, theme, payments, lock vendor, and goes live in under a day.
1. Purpose
A new operator (single property) signs up to Melmastoon, completes onboarding (tenant identity, property setup, theme, payment provider, lock vendor, locale + currency), publishes their tenant booking site, and starts taking bookings the same day. Outcome: tenant live, theme published, booking site reachable on <slug>.melmastoon.app, Electron app primer ready, first booking demo passes.
2. Persona Context
- Persona: Owner / Operator.
- Surfaces: Control Plane Web (
apps/web-control-plane), Electron Desktop (download + setup).
- Primary BFFs:
bff-control-plane-service.
- Backing services:
tenant-service, theme-config-service, payment-providers-adapter, lock-and-key-service, notification-service, identity-service.
- Preconditions: Operator has email + phone; tenant slug is unique; payment provider account is creatable.
- Trigger: Operator signs up at
https://control.melmastoon.com/signup.
3. Entry Points
| # | Entry | Notes |
|---|
| 1 | Direct signup | Default |
| 2 | Sales-led invite link | Pre-filled fields |
| 3 | Self-service trial | P2 |
4. Screen-by-Screen Flow
4.1 SignupScreen
- Layout: Email + phone, password / OTP, locale / currency picker, terms checkbox; "Create account" CTA.
- Components:
Form, OtpInput, LocaleSelect, CurrencySelect.
- Offline: Disabled.
- AI: None.
- Errors: Email taken; OTP invalid.
- Loading: Spinner.
- A11y: Field labels; OTP keyboard-friendly.
- RTL: Mirror.
- Perf: Submit <= 1 s p95.
- Telemetry:
frontend.tenant.signup_completed.
4.2 TenantSetupWizardStep1Identity
- Layout: Tenant name, slug picker (live availability check), country, timezone, languages spoken.
- Components:
SlugInput (live check), CountrySelect, TimezoneSelect, LanguageMultiSelect.
- Offline: Disabled.
- AI: None.
- Errors: Slug taken -> live error; reserved slug rejected.
- Loading: Slug check <= 200 ms debounced.
- A11y: Live error announced.
- RTL: Mirror.
- Perf: Mount <= 200 ms.
- Telemetry:
frontend.tenant.identity_completed.
4.3 TenantSetupWizardStep2Property
- Layout: Property name, address (autocomplete), GPS, room types editor (name, capacity, base rate, sample photos).
- Components:
AddressAutocomplete, RoomTypeEditor, PhotoUpload.
- Offline: Disabled.
- AI: Phase 2 — auto-fill room descriptions from photos.
- Errors: Address invalid; rate invalid.
- Loading: Photo upload progress.
- A11y: Field labels; map preview alt-text.
- RTL: Mirror.
- Perf: Photo upload <= 10 s per file.
- Telemetry:
frontend.tenant.property_completed.
4.4 TenantSetupWizardStep3Theme
- Layout: Logo upload, primary brand colour, font picker, layout preset, content blocks (intro, amenities, gallery, contact); live preview iframe.
- Components:
LogoUploader, ColorPicker, FontPicker, LayoutPresetPicker, BlockEditor, PreviewIframe.
- Offline: Disabled.
- AI: Phase 1 — palette suggestion from logo (HITL); Phase 2 — copy suggestions.
- Errors: Contrast warning if combination fails AA.
- Loading: Preview refresh <= 500 ms.
- A11y: All editors keyboard-operable; preview iframe focus-trapped or labelled.
- RTL: Mirror.
- Perf: Preview iframe ready <= 1 s.
- Telemetry:
frontend.tenant.theme_configured.
4.5 TenantSetupWizardStep4Payments
- Layout: Payment provider picker (Stripe / HBL / etc.); per-provider connect flow (OAuth or key entry); cash-on-arrival policy toggle; tax setup.
- Components:
ProviderConnectButton, Form, ToggleField, TaxRuleEditor.
- Offline: Disabled.
- AI: None.
- Errors: Provider connect failure -> retry / different provider.
- Loading: Connect flow varies by provider.
- A11y: Connect status announced.
- RTL: Mirror.
- Perf: Provider connect <= 30 s wall-clock.
- Telemetry:
frontend.tenant.payments_connected { provider }.
4.6 TenantSetupWizardStep5LockVendor
- Layout: Lock vendor picker (Salto / Onity / TTLock / "skip"); per-vendor connect; encoder driver download instructions.
- Components:
VendorPicker, ConnectButton, DriverDownloadCard.
- Offline: Disabled.
- AI: None.
- Errors: Vendor connect failure -> retry.
- Loading: Sub-second.
- A11y: Driver download link announced; "skip" path clear.
- RTL: Mirror.
- Perf: Connect <= 10 s p95.
- Telemetry:
frontend.tenant.lock_configured { vendor }.
4.7 TenantSetupWizardStep6PublishAndTest
- Layout: Final review; "Publish booking site" CTA; "Download Electron desktop app" CTA; "Make a test booking" link.
- Components:
FinalReviewCard, Button (variants).
- Offline: Disabled.
- AI: None.
- Errors: Final validation gate.
- Loading: Publish <= 5 s.
- A11y: Review announces sections.
- RTL: Mirror.
- Perf: Publish <= 5 s p95.
- Telemetry:
frontend.tenant.published { tenantId }.
5. State Machine
6. Data Requirements
6.1 Server state
POST /api/v1/tenants (signup)
PATCH /api/v1/tenants/:id (per step)
POST /api/v1/themes/:tenantId/publish
POST /api/v1/payment-providers/:id/connect
POST /api/v1/lock-vendors/:id/connect
POST /api/v1/tenants/:id/go-live
6.2 Local persistence
- Web app caches form drafts in IndexedDB; cleared on publish.
6.3 Idempotency
- All mutations carry
X-Idempotency-Key.
7. AI Behavior
| Surface | Step | Purpose | Model | Edge / Cloud | HITL | Provenance | Fallback |
|---|
ColorPicker | Step 3 | Palette suggestion from logo | small image-to-palette | Cloud | Canonical card | Pill | Manual selection |
| Copy suggestions (P2) | Step 3 | Block copy suggestions | small text | Cloud | Canonical card | Pill | Manual |
8. Offline Behavior
- Onboarding requires online.
- Operator can save drafts and resume; resume token TTL 7 days.
9. Error States
| Error | Trigger | UX shown | Recovery | Telemetry |
|---|
SLUG_TAKEN | Live check | Inline error | User picks another | frontend.tenant.slug_taken |
PAYMENT_PROVIDER_CONNECT_FAILED | OAuth failure | Retry banner; alternate provider option | User retries | frontend.tenant.payments_failed |
THEME_CONTRAST_FAIL | Combination fails AA | Inline warning + suggested adjustments | User adjusts | frontend.tenant.theme_contrast_warn |
PUBLISH_VALIDATION_FAILED | Server-side rule | Banner with field link | User fixes | error.surfaced { code } |
10. E2E Test Gates
- Composite gate
G-CP-1: signup -> identity -> property -> theme -> payments -> lock -> publish -> test booking ok.
- Provider connect failure -> retry path.
- Resume-from-draft flow.
| Metric | Target |
|---|
| Each step mount | <= 200 ms |
| Slug live check | <= 200 ms debounced |
| Photo upload (per file) | <= 10 s |
| Provider connect | <= 30 s |
| Publish | <= 5 s p95 |
12. Accessibility Requirements
- All keyboard-completable.
- Live preview iframe accessible with skip link.
- Contrast warnings actionable.
13. Telemetry
Frontend events
frontend.tenant.signup_completed
frontend.tenant.{identity, property, theme}_completed
frontend.tenant.payments_connected { provider }
frontend.tenant.lock_configured { vendor }
frontend.tenant.published { tenantId }
Domain events emitted
melmastoon.tenant.created.v1
melmastoon.tenant.property.added.v1
melmastoon.theme.published.v1
melmastoon.tenant.live.v1
14. Success Criteria
- Operator goes from signup to live in <= 1 day (mostly user time).
- Booking site reachable on
<slug>.melmastoon.app.
- First test booking succeeds.
- Electron app downloads and runs primer fetch successfully.
References