Architecture
ADR 0008 — Multi-tier platform, module marketplace & AI onboarding
- Status: Accepted
- Date: 2026-06-13
- Supersedes: the flat single-tenant assumption in earlier ADRs (the agency→client intent from the original brief is now made explicit).
Context
Feedback OS is evolving from a single-tenant CRM into a multi-tier SaaS platform sold GHL-style: Feedback Studios runs the platform, sells it to agencies, and each agency serves its own clients (sub-accounts).
Requirements that emerged:
- A master/platform account (Feedback Studios) that can see and manage every account in the system.
- Agency accounts that configure things once and deploy to their sub-accounts (all or some).
- A marketplace of installable modules (AI, Channels, Payments, Calendar, …) — "the batches of extra modules we keep building".
- Configuration is per account, not per user.
- An AI onboarding concierge: the first thing a new account sees is an AI that offers to set everything up, installing + configuring each entitled module conversationally until 100% live.
- The whole thing must be easier to use than GHL.
Decision
1. Three-tier tenancy
The tenants collection becomes hierarchical:
| Field | Meaning |
|---|---|
type | platform | agency | subaccount |
parent | relationship → tenants (an agency's parent is the platform; a sub-account's parent is its agency) |
status | active | suspended |
- Platform (Master) — one tenant (Feedback Studios). Super-admin: sees all accounts, curates the marketplace catalog, owns platform billing, can impersonate any account for support (audited).
- Agency — a customer. Owns its users, branding, billing, installed modules, and its sub-accounts.
- Sub-account — an agency's client. Fully isolated data (contacts, inbox, pipelines, appointments…).
2. Access, RLS & account switcher
- A user belongs to a home tenant with a role. Roles per tier:
platform_admin,agency_admin,agency_member,subaccount_admin,subaccount_member. - RLS: a request is scoped to the active tenant. A user may switch the active tenant to any descendant they're allowed into (master → any; agency → its sub-accounts). Queries filter by
tenant = active OR tenant IN descendants(active)per the user's grant. - Account switcher: a breadcrumb in the top bar —
Platform › Agency › Sub-account— sets the active tenant (a cookie + server-validated against the user's grants). This single switcher replaces GHL's nested menus.
3. Marketplace & modules
- Catalog lives in code (
apps/crm/lib/marketplace.ts): each module declares its metadata + install requirements (a field schema) + whether it's configurable. Example: the AI module declares it needs anapiKey; the WhatsApp channel declaresphoneNumberId,accessToken, … - Install state + credentials live per account in the tenant-scoped
integrationscollection (secrets write-only to the browser). - AI agent contexts live per account in the tenant-scoped
agentscollection (name, system prompt, model, scope, isDefault) — one or many. - The same server actions (
saveIntegration,saveAgent, …) are used by both the manual marketplace UI and the AI onboarding agent — built once, driven two ways.
4. Entitlements
What an account "paid for / enabled" = its entitlements (the set of module slugs it may install). Owned by billing / set by the agency-or-platform. Stored on the account (tenant) as entitlements: string[] (or a future subscriptions collection). The marketplace shows entitled modules as installable; non-entitled as upsell.
5. Hybrid sub-account deployment (agency-decided)
Per module, the agency chooses at deploy time (stored in integrations.deployment, already a forward-compatible JSON field):
deployTo:account|all|selected(+subAccounts: number[])credentialMode:shared(sub-accounts use the agency's credential/config) |byo(each sub-account connects its own)allowCustomize: boolean — may the sub-account override model/agents?
"Configure once → deploy to many in one click" is the agency superpower GHL makes painful.
6. AI onboarding concierge
On first run (and re-runnable later), an AI tool-using agent offers: "Want me to set everything up, or do it yourself?" If AI:
listEntitlements()→ the modules this account paid for / enabled.- For each not-yet-
Connectedmodule, in order:- explain it in one line,
- read its declared install requirements and ask the user for exactly those values,
installModule(slug, creds)→configureModule(slug, config)(for AI: pick model + create agent context(s)),checkModuleStatus(slug)→ confirm it's live; surface + retry on error,
- continue until every entitled module is 100% live, then hand off to the workspace.
Why it scales ("block by block"): because every module declares its own requirements, the agent is generic — any future module is auto-onboardable with zero agent changes. The agent simply walks the entitled modules; each one tells it what it needs.
Tooling: a constrained Claude agent (function-calling) whose tools are the same install/configure/verify actions the UI uses, scoped to the active account.
Consequences
- Tenancy is the critical-path foundation — everything sits on it; getting it wrong means rework. It is Phase A and must land first.
- The marketplace's declarative catalog + shared actions are what make both the manual UI and the AI concierge cheap to extend.
- More to build, but it is the platform's moat: an AI-native, self-installing, multi-tier CRM that an agency can white-label and deploy to clients.
- Migrations:
tenantsgainstype/parent/status/entitlements; newintegrations+agentscollections (some already built); RLS policies updated for descendant scoping.
Phased roadmap
| Phase | Scope |
|---|---|
| A — Platform tenancy | tenant type/parent/status, roles, RLS descendant scoping, account switcher, master "all accounts" view, impersonation (audited) |
| B — Marketplace (account level) | catalog, install (gather declared creds), configure (AI: model + agent contexts). AI engine already built — it plugs in here. |
| C — Sub-account deployment | entitlements, hybrid credential mode, per-module allow-customize, "deploy to all/some" |
| D — AI onboarding concierge | tool-using agent that installs+configures entitled modules conversationally until 100% live |
| E — Premium inbox | 360° context panel, power workflow (slash/snooze/notes/assign), visual redesign (AI assistant already built) |
"Easier than GHL" — the design principles this enables
- One clear account switcher, not nested menus.
- AI does the setup (the concierge) instead of manual clicking.
- Unified marketplace vs scattered settings.
- Configure once → deploy to many in one click.
- Modern, fast, opinionated UI with smart defaults.