docs: complete customer flow architecture (lead → live service)

End-to-end design covering:
- Address fuzzy search → fibre availability (16,056 entries, 30 OLTs)
- Plan selection + pricing engine (FTTH 25M-1.5G, TV, Phone, combos)
- Checkout → Stripe → n8n automation pipeline
- ERPNext: Customer → Service Location → Subscriptions → Equipment
- Project/task auto-creation for installation workflow
- Dispatch job with preferred dates and tag-based tech matching
- Field tech barcode scanning → Service Equipment creation
- ACS auto-provisioning on device bootstrap (WiFi, VoIP, firmware)
- Lead funnel for non-covered addresses (phone-only, business)
- Customer portal (invoices, WiFi management, tickets)
- Full product catalog mapped from legacy (Internet/TV/Phone/discounts)
- 5-sprint build order with dependencies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-04-03 09:28:20 -04:00
parent 0536e04c86
commit e9324b45bc

View File

@ -0,0 +1,542 @@
# Complete Customer Flow — From Lead to Live Service
## Overview
```
┌──────────────────────────────────────────────────────────────────────┐
│ CUSTOMER-FACING WEBSITE │
│ www.gigafibre.ca │
│ │
│ [Vérifier la disponibilité] ← Visitor enters address │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ ┌──────────────────────────────┐ │
│ │ Address Fuzzy Search │───▶│ Supabase / Address Server │ │
│ │ (pg_trgm) │ │ 5.2M RQA addresses │ │
│ └─────────────────────┘ │ + fiber_availability table │ │
│ │ └──────────────────────────────┘ │
│ ▼ │
│ ┌──── AVAILABLE ────┐ ┌──── NOT AVAILABLE ────┐ │
│ │ Show plans/pricing │ │ "Pas encore disponible"│ │
│ │ Internet speeds │ │ Capture contact info │ │
│ │ TV packages │ │ → Lead / Waitlist │ │
│ │ Phone service │ └────────────────────────┘ │
│ └────────┬───────────┘ │
│ ▼ │
│ ┌──── CHECKOUT ─────┐ │
│ │ Summary: Internet │ │
│ │ + TV (1st free) │ │
│ │ + Phone optional │ │
│ │ Choose 3 dates │ │
│ │ Stripe payment │ │
│ └────────┬───────────┘ │
└───────────┼──────────────────────────────────────────────────────────┘
▼ WEBHOOK / API
┌──────────────────────────────────────────────────────────────────────┐
│ BACK-OFFICE AUTOMATION │
│ │
│ n8n / targo-hub │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 1. Create Customer in ERPNext │ │
│ │ 2. Create Service Location (address + OLT port) │ │
│ │ 3. Create Service Subscriptions (internet/tv/phone) │ │
│ │ 4. Create Project "Installation {customer}" │ │
│ │ └─ Task: Assign tech + schedule from chosen dates │ │
│ │ └─ Task: Prepare equipment (ONT + Deco + STB) │ │
│ │ └─ Task: Activate OLT port (VLAN provisioning) │ │
│ │ └─ Task: Configure WiFi/VoIP in provisioning DB │ │
│ │ 5. Create Dispatch Job (tech assignment) │ │
│ │ 6. Send SMS confirmation (Twilio) │ │
│ │ 7. Send email confirmation (Mailjet) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
▼ TECHNICIAN ARRIVES
┌──────────────────────────────────────────────────────────────────────┐
│ FIELD TECH APP │
│ │
│ 1. Open Dispatch Job → see address, OLT port, equipment list │
│ 2. Scan ONT barcode (RCMG/TPLG serial) → creates Service Equipment│
│ 3. Scan Deco barcode → links to Service Location │
│ 4. Scan STB barcode (if TV) → links to Service Location │
│ 5. Connect fiber → ONT powers up → TR-069 INFORM to ACS │
│ │
└──────────────────────────────────────────────────────────────────────┘
▼ DEVICE CONNECTS (TR-069 INFORM)
┌──────────────────────────────────────────────────────────────────────┐
│ ACS (GenieACS → Oktopus) │
│ │
│ ┌─── ON BOOTSTRAP (first connect) ───┐ │
│ │ 1. Identify device (OUI, model, SN) │ │
│ │ 2. Match to Service Equipment │ │
│ │ (serial tag → ERPNext lookup) │ │
│ │ 3. Apply device profile: │ │
│ │ - Bridge mode (Raisecom) │ │
│ │ - WiFi SSID/pwd (Deco) │ │
│ │ - VoIP SIP credentials │ │
│ │ - NTP, DSCP, UPnP settings │ │
│ │ 4. Push firmware if needed │ │
│ │ 5. Notify targo-hub (SSE) │ │
│ │ → "Device online" event │ │
│ └──────────────────────────────────────┘ │
│ │
│ ┌─── ON INFORM (periodic) ───┐ │
│ │ Refresh: IP, signal, hosts │ │
│ │ Check firmware version │ │
│ │ Report to monitoring │ │
│ └─────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
▼ SERVICE LIVE
┌──────────────────────────────────────────────────────────────────────┐
│ CUSTOMER PORTAL │
│ client.gigafibre.ca │
│ │
│ - View/pay invoices (Stripe QR) │
│ - View subscriptions │
│ - Change WiFi SSID/password → pushes to ACS │
│ - Open support tickets │
│ - View service status │
│ │
└──────────────────────────────────────────────────────────────────────┘
```
---
## Phase 1: Address Search & Availability
### Current State
- AvailabilityDialog.tsx exists on www.gigafibre.ca
- Fuzzy search via `search_addresses()` RPC (pg_trgm on Supabase)
- 5.2M RQA addresses loaded
- `fiber_availability` table with zone_tarifaire + max_speed
- Lead capture sends email to support@targo.ca via Mailjet
### What Needs to Change
**Address source**: The `fiber_availability` table needs to be linked to the `fibre` table (legacy). Currently fiber_availability has generic coverage data. It needs the actual OLT port availability:
```
fiber_availability (current)
uuidadresse → address → zone_tarifaire + max_speed
fiber_availability (target)
uuidadresse → address → fibre.id → OLT/slot/port → has_available_port (bool)
→ max_speed (from OLT capacity)
→ zone_tarifaire (pricing zone)
```
**The fibre table IS the availability database:**
- 16,056 entries = 16,056 physical fibre drops to premises
- 4,949 have an ONT installed (sn populated) = occupied port
- 11,107 have no ONT = available for new service (but 1,149 are "boitier_pas_install")
- Each entry has: address, OLT IP, frame/slot/port, ontid slot
**Matching RQA addresses to fibre entries:**
- fibre.rue + fibre.ville + fibre.zip → fuzzy match to RQA address
- OR fibre.latitude/longitude → nearest RQA address
- Once matched: each RQA address either has a fibre entry (available) or not
### OLT Capacity (30 OLTs, 25 locations)
| OLT | Location | Total | Connected | Available |
|-----|----------|-------|-----------|-----------|
| 172.17.16.2 | Saint-Anicet | 2,155 | 844 | 1,311 |
| 172.17.32.2 | Hemmingford | 1,742 | 689 | 1,053 |
| 172.17.48.2 | Saint-Antoine | 1,383 | 594 | 789 |
| 172.17.64.2 | Havelock | 1,347 | 484 | 863 |
| 172.17.208.4 | Athelstan | 1,167 | 589 | 578 |
| 172.17.112.2 | Saint-Louis | 1,054 | 329 | 725 |
| ... | ... | ... | ... | ... |
| **Total** | **25 locations** | **16,056** | **4,949** | **~11,000** |
---
## Phase 2: Pricing & Plan Selection
### Product Catalog (from legacy, combo_ready=1)
**Internet (Mensualités fibre):**
| SKU | Speed ↓/↑ | Price | Profile |
|-----|-----------|-------|---------|
| FTTH25 | 25/5 Mbps | $49.95 | LP:100 |
| FTTH80I | 80/80 Mbps | $79.95 | LP:101 |
| FTTH150I | 150/150 Mbps | $99.95 | LP:102 |
| FTTH500I | 500/500 Mbps | $99.95 | LP:103 |
| FTTH1500I | 1.5G/1G | $109.95 | LP:104 |
**TV (Mensualités télévision):**
| SKU | Name | Price | Note |
|-----|------|-------|------|
| TVBSKINNY | Skinny | $25 | Base package |
| TVBSTANDARD | Standard | $30 | Mid package |
| TVBEVO | Evo | $35 | Premium |
| TELE | Base TV | $0 | Included with internet? |
| + add-ons | Sports, Films, etc. | $5-$25 each | |
**Phone (Téléphonie):**
| SKU | Price | Note |
|-----|-------|------|
| TELEPMENS | $28.95/mo | Residential SIP line |
| SERV911 | $0.69/mo | 911 fee |
| ACTTELEP | $69.95 once | Activation |
**Discounts (combo):**
| SKU | Discount | Condition |
|-----|----------|-----------|
| RAB2X | -$5 | 2 services |
| RAB3X | -$10 | 3 services |
| RAB4X | -$15 | 4 services |
| RAB_X | -$20 | Special |
| RAB24M | -$15 | 24-month commitment |
| RAB36M | -$15 | 36-month commitment |
### Checkout Logic
```
Monthly total = Internet plan
+ TV package (if selected)
+ TV add-ons
+ Phone ($28.95 if selected)
+ 911 fee ($0.69 if phone)
- Combo discount (2x/3x/4x)
- Commitment discount (24m/36m)
One-time charges:
+ Installation ($0 for standard FTTH)
+ TV box: 1st FREE, 2nd+ at regular price
+ Phone activation ($69.95)
```
### First TV Box Credit
- Detect: if order includes TV + this is customer's first box
- Apply credit equal to STB equipment price
- Show on summary: "1er décodeur offert"
---
## Phase 3: Checkout & Order Submission
### Customer Input
1. **Service selection** (internet speed + TV package + phone yes/no)
2. **Address** (pre-filled from availability check)
3. **Contact info** (name, email, phone)
4. **Installation preference**:
- Choose from 3 available dates (next 2 weeks, exclude weekends)
- OR "Contactez-moi" (we call to schedule)
5. **Payment** via Stripe (first month + one-time charges)
### What Happens on Submit
```
POST /api/checkout
{
address: { fibre_id, rue, ville, zip, olt_port, lat, lng },
customer: { name, email, phone },
services: [
{ sku: "FTTH150I", type: "internet" },
{ sku: "TVBSTANDARD", type: "tv" },
{ sku: "TELEPMENS", type: "phone" }
],
preferred_dates: ["2026-04-07", "2026-04-09", "2026-04-11"],
stripe_payment_intent: "pi_xxx"
}
```
---
## Phase 4: Back-Office Automation (n8n + targo-hub)
### Trigger: New Order Webhook
```
n8n workflow: "New Customer Order"
═══════════════════════════════════
1. VALIDATE
- Verify Stripe payment
- Verify fibre port still available
- Verify address matches fibre.id
2. CREATE CUSTOMER (ERPNext API)
POST /api/resource/Customer
{
customer_name: "Jean Tremblay",
customer_group: "Résidentiel",
email_id, mobile_no,
legacy_customer_id: null (new customer)
}
3. CREATE SERVICE LOCATION
POST /api/resource/Service Location
{
customer, address_line, city, postal_code,
connection_type: "FTTH",
olt_name, olt_ip, olt_frame, olt_slot, olt_port, ont_id,
status: "Pending Install"
}
4. CREATE SUBSCRIPTIONS (one per service)
POST /api/resource/Service Subscription
× Internet: { item: FTTH150I, location, status: "Pending" }
× TV: { item: TVBSTANDARD, location, status: "Pending" }
× Phone: { item: TELEPMENS, location, status: "Pending" }
5. CREATE SERVICE EQUIPMENT (pre-assigned)
× ONT: { type: "ONT", serial: TBD (tech assigns on site) }
× Deco: { type: "Routeur", serial: TBD }
× STB: { type: "Décodeur TV", serial: TBD } (if TV)
× ATA: { type: "Téléphone IP", serial: TBD } (if phone)
6. CREATE PROJECT "Installation - Jean Tremblay"
Tasks:
☐ Préparer équipement (support)
☐ Assigner technicien (dispatch)
☐ Activer port OLT - frame/slot/port (support)
☐ Configurer WiFi dans DB provisioning (support)
☐ Configurer VoIP dans DB provisioning (if phone)
☐ Installation sur site (tech)
☐ Vérifier signal ONT (tech)
☐ Confirmer service fonctionnel (tech)
7. CREATE DISPATCH JOB
{
customer, location,
preferred_dates: [...],
required_tags: ["Fibre", "Installation"],
equipment_list: [ONT, Deco, STB?],
notes: "FTTH 150M + TV Standard + Phone"
}
8. RESERVE FIBRE PORT
UPDATE fibre SET sn = 'RESERVED-{order_id}'
WHERE id = {fibre_id} AND (sn IS NULL OR sn = '')
9. SEND NOTIFICATIONS
× SMS to customer: "Commande confirmée! Installation prévue le..."
× Email to customer: order summary
× SSE to Ops: new order event
× Slack/Teams to dispatch: new installation job
```
---
## Phase 5: Installation Day
### Field Tech App Flow
```
1. Tech opens Dispatch Job on mobile
→ Sees: address, customer info, equipment list, OLT port
2. Tech picks up equipment from warehouse
→ Scans each barcode:
- ONT: RCMG19E0XXXX → Service Equipment created, linked to location
- Deco: 403F8CXXXXXX → Service Equipment created
- STB: (ministra MAC) → Service Equipment created
3. Tech drives to site (GPS tracked via Traccar)
→ Customer gets SMS: "Technicien en route"
4. Tech installs fiber drop + ONT
→ ONT powers up → sends TR-069 BOOTSTRAP to ACS
5. ACS receives BOOTSTRAP
→ Matches ONT serial to Service Equipment
→ Applies provisioning profile:
- Bridge mode, VLANs, DSCP
- WiFi SSID/password (via ext script → provisioning DB)
- VoIP SIP credentials (if phone service)
- Firmware check/upgrade
6. Tech connects Deco router behind ONT
→ Deco sends TR-069 INFORM
→ ACS configures WiFi (SSID/password from DB)
7. Tech verifies:
☐ Internet speed test
☐ WiFi working on both bands
☐ TV channels loading (if applicable)
☐ Phone dial tone (if applicable)
8. Tech marks job complete in app
→ Service Location status → "Active"
→ Service Subscriptions → "Active"
→ Service Equipment status → "Actif"
→ Customer gets SMS: "Service activé!"
→ First invoice generated (pro-rated)
```
---
## Phase 6: ACS Provisioning (GenieACS → Oktopus)
### Current GenieACS Flow
```
ONT connects → CWMP INFORM
→ Preset matches (by ProductClass tag)
→ Provision script runs:
1. bootstrap: clear tree, force refresh
2. default: refresh hourly params (IP, MAC, hosts, firmware)
3. model-specific inform:
- HT803G-W: VoIP DSCP, NTP, bridge mode, UPnP off
- Device2 (Deco): WiFi from DB (ext→provisioning.js→MariaDB)
- XX230v/430v/530v: VoIP digit map, SIP server, DTMF
4. firmware-upgrade: auto-push if version mismatch
```
### Target Oktopus Flow
```
ONT connects → MQTT/CWMP
→ Device identified → matched to device group
→ Device profile applied:
1. Webhook to targo-hub: GET /devices/{serial}/provision
→ targo-hub looks up Service Equipment in ERPNext
→ Returns: WiFi config, VoIP config, VLAN settings
2. Oktopus pushes params to device
3. Webhook to targo-hub: POST /devices/{serial}/activated
→ targo-hub updates Service Equipment status
→ Broadcasts SSE event to Ops UI
```
### n8n Trigger for Device Events
```
Oktopus → MQTT topic: device/bootstrap/{serial}
→ n8n MQTT listener
→ n8n workflow:
1. Look up serial in ERPNext Service Equipment
2. If found: mark "Connected", update IP/firmware
3. If NOT found: create Issue "Unknown device {serial}"
4. Broadcast to targo-hub SSE
```
---
## Phase 7: Not Available → Lead Funnel
### When Address Has No Fiber
```
Visitor searches "123 rue Principale, Somewhere"
→ No fibre entry found
→ Show: "La fibre n'est pas encore disponible à votre adresse"
┌─────────────────────────────────────────────┐
│ Options presented: │
│ │
│ 📱 Phone service is available anywhere! │
│ VoIP works over any internet connection │
│ → [Voir les forfaits téléphonie] │
│ │
│ 🏢 Business fiber? Custom installation! │
│ → [Demander une soumission] │
│ │
│ 📧 Be notified when fiber arrives: │
│ [email/phone] → [M'aviser] │
└─────────────────────────────────────────────┘
On "M'aviser" submit:
→ Create Lead in ERPNext (name, contact, address, interest)
→ Tag with area/municipality for future coverage planning
→ n8n: if address is in planned expansion zone, notify sales
On "Demander une soumission" (business):
→ Create Lead with type "Enterprise"
→ Create Issue "Soumission fibre entreprise - {address}"
→ Assign to sales team
→ n8n: send email to sales@targo.ca
```
---
## Data Migration: What Needs to Happen
### 1. Link Fibre Table to RQA Addresses
```sql
-- Match fibre entries to RQA addresses by fuzzy address + postal code
-- This enables the website availability check to return OLT port info
UPDATE fiber_availability fa
SET fibre_id = f.id,
olt_ip = f.info_connect,
olt_port = CONCAT(f.frame, '/', f.slot, '/', f.port),
available = (f.sn IS NULL OR f.sn = '')
FROM fibre f
WHERE fa.address matches f.rue + f.ville (fuzzy)
```
### 2. Migrate Provisioning DB to ERPNext
```
For each device in genieacs.wifi:
→ Find Service Equipment by MAC (Deco) or serial (ONT)
→ Store WiFi SSID/password as custom fields on Service Equipment
→ Or: keep in a separate provisioning table that targo-hub queries
For each device in genieacs.voip:
→ Find Service Equipment by RCMG serial
→ Store SIP username/password as custom fields
→ Or: keep in Fonoster/Routr as SIP accounts
```
### 3. Map Legacy Customers to ERPNext
```
fibre.service_id → service.delivery_id → delivery.account_id
→ ERPNext Customer (legacy_customer_id = account_id)
```
---
## Systems Inventory
| System | Role | Current | Target |
|--------|------|---------|--------|
| **www.gigafibre.ca** | Website + availability | React/Vite + Supabase | Same + checkout flow |
| **Supabase** | Address DB + search | 5.2M RQA addresses | + fibre availability link |
| **ERPNext** | CRM, billing, inventory | Running | Add provisioning fields |
| **targo-hub** | SSE relay + API proxy | SMS, voice, telephony, ACS | + checkout webhook, device events |
| **n8n** | Workflow automation | Exists, minimal use | Order→project→dispatch pipeline |
| **GenieACS** | TR-069 ACS | Running, 7,550 devices | → Migrate to Oktopus |
| **Oktopus** | TR-369 ACS | At oss.gigafibre.ca | Take over from GenieACS |
| **Stripe** | Payments | Planned | Checkout + recurring billing |
| **Twilio** | SMS/Voice | Running via targo-hub | Order confirmations, tech ETA |
| **Mapbox** | Maps | Dispatch app | + coverage map on website? |
| **Traccar** | GPS tracking | Running for techs | Continue |
| **Fonoster/Routr** | SIP/VoIP | Running | SIP account provisioning |
| **MariaDB (10.100.80.100)** | Legacy + provisioning | wifi/voip tables | Migrate to ERPNext or keep |
| **MongoDB (10.5.2.116)** | GenieACS device DB | 7,550 devices | Archive after Oktopus migration |
---
## Build Order (Recommended)
### Sprint 1: Data Foundation (1 week)
1. Match fibre entries to RQA addresses (geo + fuzzy)
2. Expose OLT port availability via Supabase/API
3. Migrate product catalog to ERPNext Items (if not already done)
4. Create ERPNext provisioning fields on Service Equipment
### Sprint 2: Checkout Flow (1-2 weeks)
1. Build plan selection UI on website (internet + TV + phone)
2. Build checkout page (summary, date picker, Stripe)
3. Build targo-hub `/checkout` webhook endpoint
4. Build n8n "New Order" workflow (customer → location → subscriptions → project)
### Sprint 3: Dispatch Integration (1 week)
1. Auto-create Dispatch Job from new order
2. SMS notifications (confirmation, tech en route, completed)
3. Field tech app: barcode scanner → Service Equipment creation
### Sprint 4: Auto-Provisioning (2 weeks)
1. targo-hub `/devices/{serial}/provision` endpoint
2. Oktopus webhook integration (device connect → provision request)
3. WiFi/VoIP credential auto-push on device bootstrap
4. "Device online" SSE events to Ops UI
### Sprint 5: Customer Portal (1-2 weeks)
1. Login via email/SMS OTP (no legacy MD5)
2. Invoice list + Stripe payment
3. WiFi SSID/password change (pushes to ACS)
4. Support ticket creation