Files
orion/docs/features/user-journeys/hosting.md
Samir Boulahtit 8b147f53c6
Some checks failed
CI / pytest (push) Failing after 49m20s
CI / validate (push) Successful in 24s
CI / dependency-scanning (push) Successful in 33s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped
CI / ruff (push) Successful in 10s
feat(hosting): add HostWizard platform module and fix migration chain
- Add complete hosting module (models, routes, schemas, services, templates, migrations)
- Add HostWizard platform to init_production seed (code=hosting, domain=hostwizard.lu)
- Fix cms_002 migration down_revision to z_unique_subdomain_domain
- Fix prospecting_001 migration to chain after cms_002 (remove branch label)
- Add hosting/prospecting version_locations to alembic.ini
- Fix admin_services delete endpoint to use proper response model
- Add hostwizard.lu to deployment docs (DNS, Caddy, Cloudflare)
- Add hosting and prospecting user journey docs to mkdocs nav

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:34:56 +01:00

20 KiB

Hosting Module - User Journeys

Personas

# Persona Role / Auth Description
1 Platform Admin admin role Manages the POC → live website pipeline, tracks client services, monitors renewals
2 Prospect No auth (receives proposal link) Views their POC website preview via a shared link

!!! note "Admin-only module" The hosting module is primarily an admin-only module. The only non-admin page is the POC Viewer — a public preview page that shows the prospect's POC website with a HostWizard banner. Prospects do not have accounts until their proposal is accepted, at which point a Merchant account is created for them.


Lifecycle Overview

The hosting module manages the complete POC → live website pipeline:

flowchart TD
    A[Prospect identified] --> B[Create Hosted Site]
    B --> C[Status: DRAFT]
    C --> D[Build POC website via CMS]
    D --> E[Mark POC Ready]
    E --> F[Status: POC_READY]
    F --> G[Send Proposal to prospect]
    G --> H[Status: PROPOSAL_SENT]
    H --> I{Prospect accepts?}
    I -->|Yes| J[Accept Proposal]
    J --> K[Status: ACCEPTED]
    K --> L[Merchant account created]
    L --> M[Go Live with domain]
    M --> N[Status: LIVE]
    I -->|No| O[Cancel]
    O --> P[Status: CANCELLED]
    N --> Q{Issues?}
    Q -->|Payment issues| R[Suspend]
    R --> S[Status: SUSPENDED]
    S --> T[Reactivate → LIVE]
    Q -->|Client leaves| O

Status Transitions

From Allowed Targets
draft poc_ready, cancelled
poc_ready proposal_sent, cancelled
proposal_sent accepted, cancelled
accepted live, cancelled
live suspended, cancelled
suspended live, cancelled
cancelled (terminal)

Dev URLs (localhost:9999)

The dev server uses path-based platform routing: http://localhost:9999/platforms/hosting/...

1. Admin Pages

Login as: admin@orion.lu or samir.boulahtit@gmail.com

Page Dev URL
Dashboard http://localhost:9999/platforms/hosting/admin/hosting
Sites List http://localhost:9999/platforms/hosting/admin/hosting/sites
New Site http://localhost:9999/platforms/hosting/admin/hosting/sites/new
Site Detail http://localhost:9999/platforms/hosting/admin/hosting/sites/{site_id}
Client Services http://localhost:9999/platforms/hosting/admin/hosting/clients

2. Public Pages

Page Dev URL
POC Viewer http://localhost:9999/platforms/hosting/hosting/sites/{site_id}/preview

3. Admin API Endpoints

Sites (prefix: /platforms/hosting/api/admin/hosting/):

Method Endpoint Dev URL
GET list sites http://localhost:9999/platforms/hosting/api/admin/hosting/sites
GET site detail http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}
POST create site http://localhost:9999/platforms/hosting/api/admin/hosting/sites
POST create from prospect http://localhost:9999/platforms/hosting/api/admin/hosting/sites/from-prospect/{prospect_id}
PUT update site http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}
DELETE delete site http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}

Lifecycle (prefix: /platforms/hosting/api/admin/hosting/):

Method Endpoint Dev URL
POST mark POC ready http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/mark-poc-ready
POST send proposal http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/send-proposal
POST accept proposal http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/accept
POST go live http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/go-live
POST suspend http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/suspend
POST cancel http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/cancel

Client Services (prefix: /platforms/hosting/api/admin/hosting/):

Method Endpoint Dev URL
GET list services http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services
POST create service http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services
PUT update service http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services/{id}
DELETE delete service http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services/{id}

Stats (prefix: /platforms/hosting/api/admin/hosting/):

Method Endpoint Dev URL
GET dashboard stats http://localhost:9999/platforms/hosting/api/admin/hosting/stats/dashboard

Production URLs (hostwizard.lu)

In production, the platform uses domain-based routing.

Admin Pages & API

Page / Endpoint Production URL
Dashboard https://hostwizard.lu/admin/hosting
Sites https://hostwizard.lu/admin/hosting/sites
New Site https://hostwizard.lu/admin/hosting/sites/new
Site Detail https://hostwizard.lu/admin/hosting/sites/{id}
Client Services https://hostwizard.lu/admin/hosting/clients
API - Sites GET https://hostwizard.lu/api/admin/hosting/sites
API - Stats GET https://hostwizard.lu/api/admin/hosting/stats/dashboard

Public Pages

Page Production URL
POC Viewer https://hostwizard.lu/hosting/sites/{site_id}/preview

Data Model

Hosted Site

HostedSite
├── id (PK)
├── store_id (FK → stores.id, unique)        # The CMS-powered website
├── prospect_id (FK → prospects.id, nullable) # Origin prospect
├── status: draft | poc_ready | proposal_sent | accepted | live | suspended | cancelled
├── business_name (str)
├── contact_name, contact_email, contact_phone
├── proposal_sent_at, proposal_accepted_at, went_live_at (datetime)
├── proposal_notes (text)
├── live_domain (str, unique)
├── internal_notes (text)
├── created_at, updated_at
└── Relationships: store, prospect, client_services

Client Service

ClientService
├── id (PK)
├── hosted_site_id (FK → hosted_sites.id, CASCADE)
├── service_type: domain | email | ssl | hosting | website_maintenance
├── name (str)                        # e.g., "acme.lu domain", "5 mailboxes"
├── status: pending | active | suspended | expired | cancelled
├── billing_period: monthly | annual | one_time
├── price_cents (int), currency (str, default EUR)
├── addon_product_id (FK, nullable)   # Link to billing product
├── domain_name, registrar            # Domain-specific
├── mailbox_count                     # Email-specific
├── expires_at, period_start, period_end, auto_renew
├── notes (text)
└── created_at, updated_at

User Journeys

Journey 1: Create Hosted Site from Prospect

Persona: Platform Admin Goal: Convert a qualified prospect into a hosted site with a POC website

Prerequisite: A prospect exists in the prospecting module (see Prospecting Journeys)

flowchart TD
    A[View prospect in prospecting module] --> B[Click 'Create Hosted Site from Prospect']
    B --> C[HostedSite created with status DRAFT]
    C --> D[Store auto-created on hosting platform]
    D --> E[Contact info pre-filled from prospect]
    E --> F[Navigate to site detail]
    F --> G[Build POC website via CMS editor]

Steps:

  1. Create hosted site from prospect:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/from-prospect/{prospect_id}
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/from-prospect/{prospect_id}
  2. This automatically:
    • Creates a Store on the hosting platform
    • Creates a HostedSite record linked to the Store and Prospect
    • Pre-fills business_name, contact_name, contact_email, contact_phone from prospect data
  3. View the new site:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting/sites/{site_id}
    • Prod: https://hostwizard.lu/admin/hosting/sites/{site_id}
  4. Click the Store link to open the CMS editor and build the POC website

Journey 2: Create Hosted Site Manually

Persona: Platform Admin Goal: Create a hosted site without an existing prospect (e.g., direct referral)

flowchart TD
    A[Navigate to New Site page] --> B[Fill in business details]
    B --> C[Submit form]
    C --> D[HostedSite + Store created]
    D --> E[Navigate to site detail]
    E --> F[Build POC website]

Steps:

  1. Navigate to New Site form:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting/sites/new
    • Prod: https://hostwizard.lu/admin/hosting/sites/new
  2. Create the site:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites
    • Body: { "business_name": "Boulangerie du Parc", "contact_name": "Jean Müller", "contact_email": "jean@boulangerie-parc.lu", "contact_phone": "+352 26 123 456" }
  3. A Store is auto-created with subdomain boulangerie-du-parc on the hosting platform

Journey 3: POC → Proposal Flow

Persona: Platform Admin Goal: Build a POC website, mark it ready, and send a proposal to the prospect

flowchart TD
    A[Site is DRAFT] --> B[Build POC website via CMS]
    B --> C[Mark POC Ready]
    C --> D[Site is POC_READY]
    D --> E[Preview the POC site]
    E --> F[Send Proposal with notes]
    F --> G[Site is PROPOSAL_SENT]
    G --> H[Share preview link with prospect]

Steps:

  1. Build the POC website using the Store's CMS editor (linked from site detail page)
  2. When the POC is ready, mark it:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/mark-poc-ready
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/mark-poc-ready
  3. Preview the POC site (public link, no auth needed):
    • Dev: http://localhost:9999/platforms/hosting/hosting/sites/{id}/preview
    • Prod: https://hostwizard.lu/hosting/sites/{id}/preview
  4. Send proposal to the prospect:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/send-proposal
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/send-proposal
    • Body: { "notes": "Custom website with 5 pages, domain registration included" }
  5. Share the preview link with the prospect via email

!!! info "POC Viewer" The POC Viewer page renders the Store's storefront in an iframe with a teal HostWizard banner at the top. It only works for sites with status poc_ready or proposal_sent. Once the site goes live, the preview is disabled.


Journey 4: Accept Proposal & Create Merchant

Persona: Platform Admin Goal: When a prospect accepts, create their merchant account and subscription

flowchart TD
    A[Prospect accepts proposal] --> B{Existing merchant?}
    B -->|Yes| C[Link to existing merchant]
    B -->|No| D[Auto-create merchant + owner account]
    C --> E[Accept Proposal]
    D --> E
    E --> F[Site is ACCEPTED]
    F --> G[Store reassigned to merchant]
    G --> H[Subscription created on hosting platform]
    H --> I[Prospect marked as CONVERTED]

Steps:

  1. Accept the proposal (auto-creates merchant if no merchant_id provided):
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/accept
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/accept
    • Body: {} (auto-create merchant) or { "merchant_id": 5 } (link to existing)
  2. This automatically:
    • Creates a new Merchant from contact info (name, email, phone)
    • Creates a store owner account with a temporary password
    • Reassigns the Store from the system merchant to the new merchant
    • Creates a MerchantSubscription on the hosting platform (essential tier)
    • Marks the linked prospect as CONVERTED (if prospect_id is set)
  3. View the updated site detail:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting/sites/{id}
    • Prod: https://hostwizard.lu/admin/hosting/sites/{id}

!!! warning "Merchant account credentials" When accepting without an existing merchant_id, a new merchant owner account is created with a temporary password. The admin should communicate these credentials to the client so they can log in and self-edit their website via the CMS.


Journey 5: Go Live with Custom Domain

Persona: Platform Admin Goal: Assign a production domain to the website and make it live

flowchart TD
    A[Site is ACCEPTED] --> B[Configure DNS for client domain]
    B --> C[Go Live with domain]
    C --> D[Site is LIVE]
    D --> E[StoreDomain created]
    E --> F[Website accessible at client domain]

Steps:

  1. Ensure DNS is configured for the client's domain (A/AAAA records pointing to the server)
  2. Go live:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/go-live
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/go-live
    • Body: { "domain": "boulangerie-parc.lu" }
  3. This automatically:
    • Sets went_live_at timestamp
    • Creates a StoreDomain record (primary) for the domain
    • Sets live_domain on the hosted site
  4. The website is now accessible at https://boulangerie-parc.lu

Journey 6: Add Client Services

Persona: Platform Admin Goal: Track operational services (domains, email, SSL, hosting) for a client

flowchart TD
    A[Open site detail] --> B[Go to Services tab]
    B --> C[Add domain service]
    C --> D[Add email service]
    D --> E[Add SSL service]
    E --> F[Add hosting service]
    F --> G[Services tracked with expiry dates]

Steps:

  1. Navigate to site detail, Services tab:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting/sites/{site_id}
    • Prod: https://hostwizard.lu/admin/hosting/sites/{site_id}
  2. Add a domain service:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{site_id}/services
    • Body: { "service_type": "domain", "name": "boulangerie-parc.lu domain", "domain_name": "boulangerie-parc.lu", "registrar": "Namecheap", "billing_period": "annual", "price_cents": 1500, "expires_at": "2027-03-01T00:00:00", "auto_renew": true }
  3. Add an email service:
    • Body: { "service_type": "email", "name": "5 mailboxes", "mailbox_count": 5, "billing_period": "monthly", "price_cents": 999 }
  4. Add an SSL service:
    • Body: { "service_type": "ssl", "name": "SSL certificate", "billing_period": "annual", "price_cents": 0, "expires_at": "2027-03-01T00:00:00" }
  5. View all services for a site:
    • API Dev: GET http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{site_id}/services
    • API Prod: GET https://hostwizard.lu/api/admin/hosting/sites/{site_id}/services

Journey 7: Dashboard & Renewal Monitoring

Persona: Platform Admin Goal: Monitor business KPIs and upcoming service renewals

flowchart TD
    A[Navigate to Dashboard] --> B[View KPIs]
    B --> C[Total sites, live sites, POC sites]
    C --> D[Monthly revenue]
    D --> E[Active services count]
    E --> F[Upcoming renewals in 30 days]
    F --> G[Navigate to Client Services]
    G --> H[Filter by expiring soon]
    H --> I[Renew or update services]

Steps:

  1. Navigate to Dashboard:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting
    • Prod: https://hostwizard.lu/admin/hosting
  2. View dashboard stats:
    • API Dev: GET http://localhost:9999/platforms/hosting/api/admin/hosting/stats/dashboard
    • API Prod: GET https://hostwizard.lu/api/admin/hosting/stats/dashboard
    • Returns: total_sites, live_sites, poc_sites, sites_by_status, active_services, monthly_revenue_cents, upcoming_renewals, services_by_type
  3. Navigate to Client Services for detailed view:
    • Dev: http://localhost:9999/platforms/hosting/admin/hosting/clients
    • Prod: https://hostwizard.lu/admin/hosting/clients
  4. Filter by type (domain, email, ssl, hosting) or status
  5. Toggle "Expiring Soon" to see services expiring within 30 days

Journey 8: Suspend & Reactivate

Persona: Platform Admin Goal: Handle suspension (e.g., unpaid invoices) and reactivation

Steps:

  1. Suspend a site:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/suspend
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/suspend
  2. Site status changes to suspended
  3. Once payment is resolved, reactivate by transitioning back to live:
    • The suspended → live transition is allowed
  4. To permanently close a site:
    • API Dev: POST http://localhost:9999/platforms/hosting/api/admin/hosting/sites/{id}/cancel
    • API Prod: POST https://hostwizard.lu/api/admin/hosting/sites/{id}/cancel
  5. cancelled is a terminal state — no further transitions allowed

Journey 9: Complete Pipeline (Prospect → Live Site)

Persona: Platform Admin Goal: Walk the complete pipeline from prospect to live website

This journey combines the prospecting and hosting modules end-to-end:

flowchart TD
    A[Import domain / capture lead] --> B[Enrich & score prospect]
    B --> C[Create hosted site from prospect]
    C --> D[Build POC website via CMS]
    D --> E[Mark POC ready]
    E --> F[Send proposal + share preview link]
    F --> G{Prospect accepts?}
    G -->|Yes| H[Accept → Merchant created]
    H --> I[Add client services]
    I --> J[Go live with domain]
    J --> K[Website live at client domain]
    K --> L[Monitor renewals & services]
    G -->|No| M[Cancel or follow up later]

Steps:

  1. Prospecting phase (see Prospecting Journeys):
    • Import domain or capture lead offline
    • Run enrichment pipeline
    • Score and qualify the prospect
  2. Create hosted site: POST /api/admin/hosting/sites/from-prospect/{prospect_id}
  3. Build POC: Edit the auto-created Store via CMS
  4. Mark POC ready: POST /api/admin/hosting/sites/{id}/mark-poc-ready
  5. Send proposal: POST /api/admin/hosting/sites/{id}/send-proposal
  6. Share preview: Send https://hostwizard.lu/hosting/sites/{id}/preview to prospect
  7. Accept proposal: POST /api/admin/hosting/sites/{id}/accept
  8. Add services: POST /api/admin/hosting/sites/{id}/services (domain, email, SSL, hosting)
  9. Go live: POST /api/admin/hosting/sites/{id}/go-live with domain
  10. Monitor: Dashboard at https://hostwizard.lu/admin/hosting

  1. Journey 2 - Create a site manually first (simplest path, no prospect dependency)
  2. Journey 3 - Walk the POC → proposal flow
  3. Journey 4 - Accept proposal and verify merchant creation
  4. Journey 5 - Go live with a test domain
  5. Journey 6 - Add client services
  6. Journey 7 - Check dashboard stats
  7. Journey 1 - Test the prospect → hosted site conversion (requires prospecting data)
  8. Journey 8 - Test suspend/reactivate/cancel
  9. Journey 9 - Walk the complete end-to-end pipeline

!!! tip "Test Journey 2 before Journey 1" Journey 2 (manual creation) doesn't require any prospecting data and is the fastest way to verify the hosting module works. Journey 1 (from prospect) requires running the prospecting module first.