Portal
Sole Developer & Architect
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.
CRM, LMS, e-commerce, support, calendar, discord, tasks, and more
Each domain (tenant, access, notifications, etc.) encapsulated as a Convex component
Admin, frontend, auth, and plugin-contributed 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

Technical Decisions
Key architecture decisions and their outcomes
WordPress-style hooks over hard-coded plugin registration
Needed plugins to contribute UI, routes, roles, and settings without modifying core code.
Built an addAction/addFilter hook system. Plugins register callbacks at install time and contribute menu items, role definitions, and settings pages via hooks.
Adding a new plugin is a single package import + hook registration. Zero core code changes.
Convex components for plugin data isolation
36 plugins with distinct schemas would create an unmaintainable single schema file.
Each plugin mounts as a Convex component with its own schema, queries, and mutations. The app's convex.config.ts composes them.
Clean domain boundaries. Plugin schemas are versioned independently. Core schema stays small.
Subdomain + custom domain multi-tenancy
Tenants need branded experiences on their own domains, not just subdomains.
Middleware extracts tenant from subdomain or custom domain via extractSubdomain/resolveTenantForRequest. Special 'auth' subdomain reserved for auth UI.
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
Skills & Technologies
Related Articles
27 Apps, One Monorepo, Zero Regrets
We kept creating new repos for every project. Shared code drifted, configs diverged, and a single bug fix became a multi-day coordination exercise. Here is how a Turborepo monorepo fixed all of it.
Multi-Tenant SaaS: One Codebase, Wildly Different Products
Every customer wanted something different. The CRM customer needed contacts. The LMS customer needed courses. We were shipping bloated software that served nobody well. Here is how plugins fixed it.
From Monolith to 34 Plugins: How We Built an Extensible Platform Without Losing Our Minds
A customer asked for Monday.com integration. We could have hard-coded it into the core. Instead, we built a plugin system — and 18 months later we have 34 plugins serving 27 apps.