Back
Super Admin: Customers & Onboarding — Spec V2.2

Table of Contents

1) Goal & Preconditions

Goal. Give Super Admin end‑to‑end control to capture first login, review BoQs, watch subscriptions, trigger onboarding, assign onboarding owners, connect IoT via OAuth2 (hard‑lock per tenant), add/link devices, validate first data, and mark facilities Onboarded.

  • Preconditions
    • Roles exist: super_admin, tenant_admin (scoped to selected customers), tenant_user.
    • BoQ & payment lifecycle active; states visible to Super Admin.
    • Supported IoT platforms integrable via OAuth2; connection status shown in Platforms tab.
    • Exactly one IoT platform per tenant (hard‑locked after first successful selection).

2) User Flow (Mermaid)

Note: Mermaid diagram omitted for compatibility; sequence:
New login → Customers list (Ready to Onboard banner) → Assign owner → Start Onboarding →
Step 1 Facility → Step 2 Platform (OAuth2 + Lock) → Step 3 Devices → Step 4 Link → Step 5 Validate → Finish

3) Functional Requirements

3.1 Customers tab

  • New customers auto‑listed after first login with name, email, createdAt, verification status.
  • Panels per customer: (a) BoQs; (b) Users; (c) Requests (description + createdAt); (d) Subscription summary; (e) Facilities + onboarding status + map pin (from BoQ) + last activity.
  • Actions: resend verification, invite tenant admin, open BoQ, assign onboarding owner, open subscription page.

3.2 BoQ & Payment lifecycle

BoQ states: draft_teaser → priced_active → priced_expired → ordered → paid_otc → cancelled.
Payment states: Pending | Paid | Failed. “Ready to onboard” at paid_otc.

3.3 Notifications

In‑app only (banner/toast + Tasks entry).

3.4 Platforms tab (OAuth2)

List supported platforms; Connect starts OAuth2; once connected + selected, platform is hard‑locked per tenant. Device add only when connected.

3.5 Onboarding Wizard

  1. Facility (map pin default from BoQ, editable)
  2. IoT Platform (OAuth2 or show connected)
  3. Devices (connectionType, deviceId, externalId, metadata)
  4. Link Device→Asset
  5. Validate ≥1 reading; Finish marks Onboarded.

3.6 Assets/Hierarchy

Facility → Location → Space → Subspace. Asset fields: name, type, level. Facility may have multiple Locations; each Location multiple Spaces; each Space multiple Subspaces.

3.7 Facility tab (Super Admin)

Status chips, onboarding owner, locked platform, device count, linking completeness, map pin, per‑facility subscription summary (details in Subscription tab).

3.8 Audit Log

Full audit log available in Super Admin dashboard; capture platform connect, BoQ/payment transitions, assignments, device adds, asset links, status changes.

4) Non‑Functional Requirements

  • RBAC: least privilege by role & tenant scope.
  • Idempotency: payment webhooks, OAuth callbacks, device creation.
  • Performance: Customers tab p95 < 1.5s; Facility view p95 < 2s (pagination/lazy loads).
  • Observability: onboarding duration, time‑to‑first‑reading, OAuth2 success %.
  • Notifications: in‑app only.
  • Security: store OAuth2 tokens securely; audit trail immutable.

5) Data & Validation Cheatsheet

Tenant: { id, name, primary_contact, platform_id(immutable after set), created_at, status }
BoQ: { id, tenant_id, total, currency, state, payment_state, created_at }
Facility: { id, tenant_id, name, address, tz, lat, lng, status, onboarding_owner_id, mapPin(lat,lng from BoQ) }
Asset: { id, tenant_id, facility_id, parent_id?, level(Facility|Location|Space|Subspace), name, type }
Device: { id, tenant_id, facility_id, asset_id, platform_id, connection_type(pull|webhook), device_id, external_id, metadata, last_reading_at }
Subscription: { id, tenant_id, facility_id, plan_id, status(Active|Trialing|PastDue|Canceled), renew_at, invoice_url }
Request: { id, tenant_id, submitted_by, description, created_at }
Validation: device_id unique within tenant; charset letters/digits/"-"/"_"/"."; platform_id must equal tenant.platform_id; Single IoT platform per tenant (hard‑lock)

6) API Stubs (shapes)

GET /admin/customers?query=&page=1
→ 200 { items:[{ tenantId, name, primaryContact, usersCount, facilitiesCount, platform,
                subscription:{ status, renewAt },
                latestBoq:{ id, state, paymentState, total, currency },
                onboarding:{ countByStatus }, createdAt }], nextPage }

GET /admin/customers/{tenantId}
→ 200 { tenant, users:[...], facilities:[...], boqs:[...], requests:[...], subscriptionSummary:{...} }

POST /admin/customers/{tenantId}/onboarding/assign
{ ownerUserId } → 200 { assigned:true }

POST /admin/customers/{tenantId}/platform/connect/start
{ providerId, redirectUri } → 200 { authUrl }

POST /admin/customers/{tenantId}/platform/connect/callback
{ code, state } → 200 { platformId, connected:true }

POST /admin/customers/{tenantId}/platform/select   // hard-lock after connect
{ platformId } → 200 { platformId }

POST /admin/facilities
{ tenantId, name, address, tz, lat, lng } → 201 { facilityId }

POST /admin/assets
{ tenantId, facilityId, parentId, level, name, type } → 201 { assetId }

POST /admin/devices
{ tenantId, facilityId, assetId?, platformId, connectionType, deviceId, externalId?, metadata? } → 201 { deviceId }

POST /admin/devices/{deviceId}/link-asset
{ assetId } → 200 { linked:true }

GET /admin/devices/{deviceId}/health
→ 200 { lastReadingAt, status:{ ok | no_data | error }, details? }

POST /admin/facilities/{facilityId}/onboard/mark
→ 200 { status:"Onboarded" }

GET /admin/subscriptions/{tenantId}   // summary; details live in Subscription tab
→ 200 { perFacility:[{ facilityId, status, renewAt }] }

7) UX Copy & Errors (EN/AR)

  • Banner — Ready to Onboard (EN): Payment confirmed. Start onboarding this customer.
  • Banner — Ready to Onboard (AR): تم تأكيد الدفع. ابدأ عملية الإعداد لهذا العميل.
  • Platform locked (EN): This tenant is connected to: {{platformName}} (locked).
  • Platform locked (AR): هذا المستأجر متصل بـ {{platformName}} (مقفل).
  • No readings yet (EN): We haven’t received device data yet. Try Re‑check or review connection settings.
  • No readings yet (AR): لم نستلم بيانات من الجهاز بعد. أعد الفحص أو راجع إعدادات الاتصال.
  • Error (EN): Device ID must be unique within this tenant.
  • Error (AR): يجب أن يكون مُعرّف الجهاز فريدًا داخل المستأجر.
  • Error (EN): Cannot mark facility as Onboarded: device not linked.
  • Error (AR): لا يمكن وضع المنشأة كـ مُكتملة: لم يتم ربط الجهاز.

8) Edge Cases

  • BoQ Paid but Subscription not provisioned yet → block finish with reason & retry.
  • Tenant already connected to a platform; change attempt → locked (migration flow out of scope).
  • Invoices & plan management live in Subscription tab (separate).

9) Acceptance Criteria (Given/When/Then)

  • Given a new user logs in, When Super Admin opens Customers, Then the customer is visible with createdAt and default status.
  • Given a BoQ payment becomes Paid, When Super Admin is in app, Then a Ready to Onboard notification appears with Start/Assign actions.
  • Given a tenant connects a platform via OAuth2 and selects it, When onboarding other facilities, Then the platform is fixed (hard‑locked).
  • Given ≥1 device is linked to an asset and has ≥1 reading, When finishing onboarding, Then Mark Onboarded is enabled; else disabled with reasons.
  • Given the tenant has facilities, When viewing the tenant, Then per‑facility subscription status is visible (details in Subscription tab).

10) Analytics (events)

customer_first_login { tenantId, userId }
boq_state_changed { tenantId, boqId, from, to }
payment_state_changed { tenantId, boqId, from, to }
onboarding_assigned { tenantId, ownerUserId }
platform_oauth_started { tenantId, provider }
platform_connected { tenantId, platformId }
platform_locked { tenantId, platformId }
facility_created { tenantId, facilityId }
asset_created { tenantId, assetId, level }
device_added { tenantId, deviceId, connectionType }
device_linked_to_asset { tenantId, deviceId, assetId }
device_health_checked { deviceId, status, lastReadingAt }
facility_marked_onboarded { facilityId }
subscription_status_seen { tenantId, facilityId }