Rouic Ltd
SSG-Cloud / SSG-React
An integrated operating system for training and consultancy businesses: sell it in the CRM, schedule and book it in the course manager, deliver it via e-learning, take payment through Stripe, and measure all of it in a live analytics dashboard, across one secure, multi-tenant platform.

- Type
- Enterprise multi-tenant SaaS platform (B2B, realm-isolated)
- Status
- Live in production
- Role
- Full-stack engineering
// what it does
SSG replaces the half-dozen disconnected tools a training provider would otherwise stitch together (CRM, booking system, LMS, invoicing, reporting) with one platform where every part shares the same data.
CRM & sales pipeline
Organisations, contacts, opportunities, tasks, teams, and an activity/transaction history. Opportunities move through configurable stages with quotes, invoices, discounts, and approval workflows.
Course & session management
Scheduling, delegate bookings, tutors, exams, certificates, locations, and joining instructions, including private/onsite courses and multi-block sessions.
E-learning
Native integration with LearnWorlds and UKATA: enrolments and completions sync back into the platform so online learners are reported alongside classroom delegates.
Assessments & audits
Form-driven safety assessments and contractor audits with submission queues and AI-assisted analysis.
Payments & finance
Stripe checkout and webhooks, identity verification, invoicing, and Xero accounting sync.
Analytics dashboard
A configuration-driven, drag-and-drop widget system (charts, gauges, KPIs, tables, lists) built on a dynamic SQL query-builder, with live auto-refresh and per-tier gating.
Automation
A rules engine with triggers, delayed actions, and a database-backed job queue for emails and notifications fired by CRM events.
Multi-tenancy
Every customer (realm) is logically isolated; realm scoping is enforced on essentially every query, with per-realm settings and feature flags.
// the app suite
web
Public marketing site and course catalogue.
crm
The core operator app (~300 routes): contacts, organisations, opportunities, tasks, bookings, dashboards, team management.
admin
Platform governance, configuration, scheduling, and reporting.
account
User account, security, and preferences.
pay
Stripe-backed payment and invoice flows.
checkin
QR-based delegate attendance and roll-call.
tutor
Tutor scheduling and availability (FullCalendar).
assessed / audit
Safety assessments and contractor audits.
forms
Dynamic form builder and submissions.
Document generation, viewing, and annotation.
recorder
rrweb session recording and playback.
go
Branded short-link and redirect service.
// screenshots
Configurable analytics dashboard with drag-and-drop chart, KPI and gauge widgets.
// tech stack
- Monorepo
- Turborepo (npm workspaces): 13 apps + shared packages
- Frontend
- Next.js 15, React 18, TypeScript (strict)
- UI
- Tailwind CSS 3, Radix UI + Headless UI, a large in-house component package
- State / data
- Redux Toolkit + redux-persist, SWR
- Charts
- ApexCharts, Recharts, Tremor, Nivo, Billboard.js
- Rich text
- TipTap, Slate, Lexical, Plate, with Yjs + HocusPocus for multiplayer editing
- Scheduling
- FullCalendar, date-fns
- Maps
- Mapbox GL, Google Maps
- Documents
- PDFTron WebViewer, pdf.js, react-pdf, jsPDF
- Layout / DnD
- react-grid-layout (dashboards), dnd-kit
- Search
- Algolia InstantSearch
- Auth
- Firebase Auth + session cookies, WebAuthn passkeys, OTP/2FA
- Session replay
- rrweb (custom recorder app + SDK)
- Backend
- Node.js + Express (REST), modular by domain
- Database
- MySQL 8 on Google Cloud SQL: raw mysql2, no ORM, ~371 tables
- Caching
- MySQL-backed query/widget cache (no Redis dependency)
- Integrations
- Stripe, Nylas, Xero, Mailchimp, Zapier, LearnWorlds, UKATA, OpenAI, CloudConvert, SendGrid
- Storage / media
- Google Cloud Storage, Sharp image processing
- Hosting
- Vercel (frontend), Google App Engine + Firebase (backend)
- Monitoring
- Highlight.run, OpenReplay, Google Cloud Logging
// architecture & engineering
Realm-based multi-tenancy
A realm column on virtually every table provides logical isolation for hundreds of independent client organisations on one database. Realm is resolved from the authenticated session and threaded into queries server-side, so a client can never read across the tenant boundary, and per-realm settings and feature flags allow gradual, tenant-by-tenant rollout.
Configuration-driven dashboard engine
The analytics dashboard is fully data-driven: widgets are JSON configurations (data source, filters, grouping, aggregation, display options) rendered through a responsive drag-and-drop grid. A backend query-builder service translates that config into SQL across multiple data sources, handling time-bucketing, entity grouping, multi-series charts, and gauge targets, with results cached in MySQL on a per-widget TTL.
Append-only opportunity model
Opportunities are immutable-versioned: every edit inserts a new row sharing a composite ID, giving a built-in audit trail. Reads deduplicate to the latest revision (MAX(id) per composite ID), a subtlety that has to be respected in every aggregate query, or values multiply by the number of edits.
Booking-accurate revenue attribution
E-learning revenue is derived from the booking graph (bookings, courses, delegate slots) rather than from invoice line totals, with order-level web coupons resolved through the coupon-usage tables and apportioned across basket items, so per-course figures reflect what was actually sold, net of discounts, instead of double-counting shared invoices.
Live-ish dashboards
Widget data refreshes on a polling cadence plus tab-focus revalidation (SWR), with the auto-refresh path deliberately bypassing the read cache so a sale appears within the refresh window while the cache still protects cold loads and concurrent viewers. This also surfaced and fixed a class of bug where cache expiry was computed on the app clock but compared on the database clock.
Database-backed everything-else
Rather than adding Redis/Bull, the platform leans on MySQL for both caching (hashed query + params with TTL) and job queues (trigger queues and delayed actions polled on an interval), one fewer moving part to operate.
Deep third-party integration surface
Stripe (checkout, webhooks, identity), Nylas (two-way email/calendar sync), Xero (accounting), LearnWorlds and UKATA (e-learning), Mailchimp, Zapier, Algolia, and OpenAI are wired into the relevant domains rather than bolted on.
// notable problems solved
- Tenant isolation at scale: consistent realm scoping across ~371 tables and a thousand-plus endpoints, so multi-tenancy is enforced by construction, not convention.
- Correct aggregation over an append-only table: deduplicating opportunity revisions in every analytics query to avoid silent multiplied totals.
- Accurate e-learning revenue: moving from fragile invoice-notes parsing to a booking-graph calculation that mirrors the live basket, eliminating per-course over-counting from shared transactions.
- Dynamic, gated analytics: a JSON-configured widget system that compiles to SQL and caches per widget, with subscription/permission gating enforced server- and client-side.
- A maintainable 13-app front end: shared design system and domain logic in one ui package, with independent deploys per app via Turborepo.
// scope & results
- 13 front-end applications in one monorepo, sharing a single component/utility library.
- ~300 routes in the CRM app alone; tens more across web and admin.
- ~371 database tables spanning CRM, courses, sessions, bookings, opportunities, delegates, assessments, automation, payments, and integrations.
- Domain-modular Express backend (CRM, courses, opportunities, payments, e-learning, assessments, forms, integrations, sessions, and more) over MySQL with no ORM.
- Live in production with custom auth (Firebase + passkeys), live Stripe payments, and a broad integration ecosystem (Nylas, Xero, LearnWorlds, Mailchimp, Zapier).
// selected features
CRM & sales
Organisations, contacts, customers · opportunity pipeline with configurable stages, types, and tabs · quotes and invoices · line and order-level discounts · approval workflows · tasks with tags and assignments · teams and team-based filtering · activity feed and append-only transaction history · bulk export (chunked/scheduled) · Algolia-powered search.
Courses & bookings
Course catalogue · multi-block sessions · open and private/onsite courses · delegate bookings with per-delegate pricing · tutors and availability · exams, results, and certificates · joining instructions · QR check-in and roll-call · LearnWorlds and UKATA enrolment/completion sync · unified classroom + online delegate reporting.
Analytics dashboard
Drag-and-drop responsive widget grid · chart / mixed-chart / KPI / gauge / list / table widgets · JSON-configured data sources, filters, grouping, aggregation · time-bucketing and entity grouping · gauge targets · per-widget caching · live auto-refresh and focus revalidation · click-through view-data deep links · dashboard sharing and email snapshots · subscription/permission gating.
Platform
Realm-based multi-tenancy with per-realm settings and feature flags · Firebase auth with WebAuthn passkeys and OTP/2FA · Stripe payments, webhooks, and identity verification · Xero / Nylas / Mailchimp / Zapier integrations · automation engine with triggers and database-backed job queues · dynamic form builder · PDF generation and annotation · rrweb session replay · collaborative rich-text editing (Yjs/HocusPocus).