← Documentation home

Series-X CRM

The CRM portal at crm.series-x.ai. React-free SPA (vanilla JS), Madnion SSO, Supabase backend (Postgres + edge functions).

Architecture

Browser ── nginx (crm.series-x.ai, TLS)
            ├── /crm/*.html        SPA pages (SSO-gated: auth_request → :8793)
            ├── /crm/*.js|css      assets (public, login page needs them)
            ├── /auth/*            login/callback/logout → serves auth.html (SPA)
            ├── /auth/session      POST: bridge token → crm_sso cookie; DELETE: logout
            ├── /auth/whoami       session profile (profile widget)
            └── /crm-api/* → edge function crm-api (Supabase, Madnion JWT)

Two auth layers:

  1. Nginx gate (server-side): crm_sso HttpOnly cookie, HMAC-signed, 12h TTL. Issued by the session service (/opt/crm-integrations/madnion-sso.js, port 8793) via POST /auth/session. The SPA bridges automatically after a successful Madnion sign-in.
  2. Edge function auth (data): the SPA keeps a Madnion access token in sessionStorage and sends Authorization: Bearer on every data call. The edge function verifies the token AND CRM-admin membership on each request.

Pages

Page Route Data source
Dashboard /crm/dashboard.html Supabase (cashflow_snapshots, crm_subscriptions)
Opportunities /crm/pipeline.html proposals table
Ideas canvas /crm/ideas.html mind-maps tables
Proposals /crm/proposals.html proposals table
Billing /crm/billing.html dataset billing (rebuilt nightly)
Cashflow /crm/cashflow.html dataset cashflow + snapshots
Subscriptions /crm/subscriptions.html crm_subscriptions + datasets payments-out, wise-deepdive
Reports / Updates datasets reports, updates
Projects ClickUp PMS proxy
Knowledge / Meetings AdvisorPro read integration

Data layer

Repository

github.com/series-a-uk/series-x-crm (private). Working copy /root/crm-repo. Deploy pages: rsync crm-pages/ → /var/www/proposals/crm/. Deploy services: copy to /opt/crm-integrations/, systemctl restart. Tests: node tests/session-bridge.mjs.

Proposal realms

Client proposal pages (/roshni/, /richard-bennett/, etc.) stay on classic basic auth deliberately. Do not convert them to SSO.