Back to Projects

Portal

Sole Developer & Architect

SaaSMulti-tenantB2B
Visit Project

The core SaaS platform powering the entire LaunchThat ecosystem. 36 plugin packages mount independently via a WordPress-inspired hooks system (addAction/addFilter). 18 Convex components provide domain isolation. Multi-tenant with subdomain + custom domain routing, org-scoped data isolation, and plugin-contributed RBAC. 108+ Next.js pages, 33 API routes, 200+ components.

36
Plugin Packages

CRM, LMS, e-commerce, support, calendar, discord, tasks, and more

18
Convex Components

Each domain (tenant, access, notifications, etc.) encapsulated as a Convex component

108+
Next.js Pages

Admin, frontend, auth, and plugin-contributed routes

33
API Routes

Clerk webhooks, Convex token bridging, plugin endpoints

The Problem

Building a SaaS platform that can serve multiple tenants with completely different feature sets, UI customizations, and billing requirements — without maintaining separate codebases for each customer. Each tenant needs their own subdomain, plugins, roles, and billing.

The Solution

Created a plugin architecture inspired by WordPress hooks (addAction/addFilter) where 36 plugin packages mount independently. Each tenant gets subdomain routing (including custom domains), org-scoped data via Convex with organizationId-based isolation, plugin-contributed role definitions, and Stripe billing. Convex components encapsulate each domain (CRM, LMS, e-commerce, support, etc.) with their own schemas and access patterns.

System Architecture

Portal system architecture diagram

Technical Decisions

Key architecture decisions and their outcomes

WordPress-style hooks over hard-coded plugin registration

Context

Needed plugins to contribute UI, routes, roles, and settings without modifying core code.

Decision

Built an addAction/addFilter hook system. Plugins register callbacks at install time and contribute menu items, role definitions, and settings pages via hooks.

Outcome

Adding a new plugin is a single package import + hook registration. Zero core code changes.

Convex components for plugin data isolation

Context

36 plugins with distinct schemas would create an unmaintainable single schema file.

Decision

Each plugin mounts as a Convex component with its own schema, queries, and mutations. The app's convex.config.ts composes them.

Outcome

Clean domain boundaries. Plugin schemas are versioned independently. Core schema stays small.

Subdomain + custom domain multi-tenancy

Context

Tenants need branded experiences on their own domains, not just subdomains.

Decision

Middleware extracts tenant from subdomain or custom domain via extractSubdomain/resolveTenantForRequest. Special 'auth' subdomain reserved for auth UI.

Outcome

Tenants can use org.launchthat.app or their own custom domain. DNS verification handles the rest.

Engineering Details

  • Plugin hook system: addAction/addFilter inspired by WordPress — plugins register callbacks for UI, routes, roles, settings
  • 18 Convex components: core-tenant, access, notifications, support, socialfeed, LMS, disclaimers, affiliates, email, ecommerce, discord, CRM, tasks, vimeo, logs, onboarding, puck, migrations
  • Multi-tenant routing: proxy.ts extracts subdomain from *.localhost, Vercel preview URLs, and production domains
  • Plugin-contributed RBAC: plugins register role definitions via ADMIN_SETTINGS_ROLES_DEFINITIONS_FILTER hook
  • Real-time presence: @convex-dev/presence for agent/user presence in support plugin
  • Clerk + Convex auth bridging: TenantConvexProvider wraps protected routes with auth requirement
  • Posts system: org-scoped content with post types, taxonomies, and per-org indexes

Key Highlights

  • 36 plugin packages with WordPress-style hooks system (addAction/addFilter)
  • 18 Convex components mounted for domain isolation
  • Multi-tenant: subdomain + custom domain routing with org-scoped data
  • Plugin-contributed RBAC with role scopes and permission levels
  • Real-time presence via @convex-dev/presence
  • 108+ Next.js pages, 33 API routes, 200+ components
  • Clerk auth with Convex session bridging
  • Stripe billing with entitlements per tenant

Tech Stack

Next.js 16React 19ConvexTailwind CSS 4Clerk AuthStripeTypeScript

Skills & Technologies

Related Articles

Related Projects