Application reference. This is an illustrative architecture and scope checklist, not a verified customer project or measured deployment. Technologies, integration scope and delivery items are agreed for the actual brief.
Scenario and Constraints
A product serving many customer organisations from one deployment. The decision that shapes everything is the isolation model: shared tables with a tenant column, a schema per tenant, or a database per tenant. Choosing by default rather than deliberately is the most expensive mistake in this category, because changing it later means migrating live customer data.
Architecture
Layers and responsibilities
| Layer | Technology | What it is responsible for |
|---|---|---|
| Web | Next.js (SSR for marketing and SEO, SPA behind login) | Public pages get server rendering for search visibility; the authenticated product does not need it and stays a client app. |
| API | Go + Gin, tenant resolved per request | Tenant context resolved from subdomain or token before any handler runs, then carried through every query. |
| Storage | PostgreSQL, shared schema with row-level tenant scoping | One database with a tenant_id on every tenant-owned table, enforced at the repository layer and, where supported, by row-level security as a second line of defence. |
| Cache | Redis, tenant-prefixed keys | Sessions, rate limits and hot config. Key prefixing prevents the classic cache-key collision that leaks one tenant's data to another. |
| Billing | Stripe or a regional gateway | Subscription state mirrored locally so entitlement checks never depend on a live call to the payment provider. |
| Jobs | Queue workers with tenant context | Scheduled and async work; tenant context travels with the job payload rather than being inferred at execution time. |
Data Model
The tables below carry the rules that everything else depends on. Getting these wrong is what turns a working demo into a system that cannot be extended.
Core entities
| Entity | Key fields, relations and rules |
|---|---|
| tenant | Organisation record with plan, status, region and feature flags. Every tenant-owned table carries tenant_id, and no query is allowed to omit it. |
| user / membership | A user may belong to several tenants with a different role in each, so identity is global while permission is per membership. Modelling user and membership as one table is what makes multi-org support impossible later. |
| role / permission | Permissions granted to roles, roles assigned per membership, and every check performed in the backend. Frontend hiding is presentation, never enforcement. |
| subscription / entitlement | Plan, seats, period and derived entitlements. Feature access reads the local entitlement, so a payment provider outage does not lock customers out of the product. |
| audit_log | Actor, tenant, action, target and before/after payload. Supports security review and incident analysis; agree retention, access and audit requirements before implementation. |
| tenant_config | Per-tenant settings, branding and feature overrides, resolved with a documented precedence over plan defaults. |
Key Interfaces
Endpoints that carry the business rules
| Endpoint | Purpose and concurrency notes |
|---|---|
| POST /api/v1/auth/login | Authenticates identity, then returns the tenant memberships available; the tenant is selected explicitly rather than guessed from the last session. |
| GET /api/v1/{resource} | Every tenant-scoped read goes through a repository that injects tenant_id. The scoping lives in one place so no handler can forget it — the single most common source of cross-tenant leaks. |
| POST /api/v1/webhooks/billing | Payment provider webhook, idempotent on the event id, updating local subscription and entitlement state. |
| POST /api/v1/tenants/{id}/invite | Invitation flow creating a membership with a role, rate limited per tenant to prevent invitation abuse. |
| GET /api/v1/audit | Tenant-scoped audit query with pagination, exposed to tenant admins as a self-service compliance answer. |
Technical Decisions
- Shared schema with tenant_id, chosen deliberately. It is the cheapest to operate and migrate, and fits most products. Where a customer contractually requires physical separation, the same codebase can run a dedicated deployment — that path is designed for from the start rather than discovered during a sales negotiation.
- Tenant scoping enforced in one repository layer. Relying on every developer to remember a WHERE clause is how cross-tenant leaks happen. Centralising it means the unsafe query is hard to write by accident.
- Entitlements mirrored locally. Checking the payment provider on every request adds latency and a hard dependency. Local mirroring means a provider outage degrades billing operations, not the product itself.
- Audit log from the first release. Backfilling audit history is impossible. Confirm the buyer's audit requirements and retain the agreed history from the first release.
- SSR only for public pages. Marketing and documentation pages need search visibility; the authenticated product does not, and forcing SSR on it adds cost with no return.
Hypothetical Design Targets
The figures below are hypothetical capacity-planning examples, not measured client results, a validated sizing recommendation or an SLA. Set project-specific acceptance targets after defining the workload, devices, data, hardware and third-party dependencies; verify them through a pilot and load tests before committing to a production target.
Capacity and performance targets
| Target | Value and assumption |
|---|---|
| API latency | p95 under 250 ms for tenant-scoped reads with correct composite indexes leading on tenant_id. |
| Tenant isolation | Require an automated suite that attempts cross-tenant access on every endpoint and fails the build on unauthorized access. The implementation must pass these checks; this reference is not evidence of a completed security test. |
| Onboarding | New tenant provisioned in seconds, since it is a row and a configuration record rather than infrastructure work. |
| Scale | Sized for the low thousands of tenants on one PostgreSQL instance; beyond that the path is read replicas then sharding by tenant, planned but not built prematurely. |
What Delivery Includes
- Next.js frontend source, Go backend source and admin panel source in your repository
- Database schema with tenant scoping, indexes and audit tables documented, plus migration history
- Cross-tenant isolation test suite runnable in your CI
- Billing integration, webhook handling and entitlement documentation
- Deployment notes for Docker and Nginx, environment configuration, backup and restore procedure
Planning This for Your Business
The modules above are a starting point, not a fixed package. We normally cut the first release to one core workflow plus one admin workflow, then extend once real usage shows where the load and the edge cases actually are. Send a scoped brief and we will map it against this architecture and tell you which parts you do not need yet.
