Asteriq Unified SaaS Platform
Multi-tenant SaaSA multi-tenant SaaS product with a tenant workspace, a separate operator console, and Stripe-backed subscriptions on one API.
Problem
A small team still needs the shape of a commercial SaaS: more than one organisation on one codebase, a way for the operator to see across tenants, and billing that does not trust the browser for whether a plan is paid.
Constraints
- Tenant identity must come from the server, never from a client-supplied field.
- Paid state follows the billing provider. The UI is not a source of truth.
- Platform operators and tenant users share an API surface with different guards, not two backends.
Responsibilities
- Built an end-to-end multi-tenant SaaS platform: a tenant workspace, a separate platform operator console, and a modular backend API.
- Tenant identity is taken from the signed session, not from the client. Org data is scoped in the data layer; only the operator console may cross tenants.
- Authentication covers email verification, access and refresh tokens with rotation, logout, and multi-factor sign-in with TOTP enrolment and backup codes.
- Stripe is the source of truth for paid state: plan catalogue, checkout, customer portal, cancellation, refunds, and signed webhooks — the UI is not trusted for payment status.
- In-app notifications and transactional email follow domain events. Plan-gated tenant chat is entitlement-checked on the server.
Resume wording. Engineering detail behind these is pending verification.
Architecture
- One NestJS API, MongoDB persistence, a tenant React app, and a separate operator console.
- Org-scoped queries carry a tenant key from the authenticated session. Cross-tenant reads exist only on operator routes.
- Access and refresh tokens, with rotation and logout. Multi-factor enrolment is optional on the account.
- Stripe checkout, customer portal, and signed webhooks update subscription state. In-app notifications and mail follow domain events in-process — no message broker in this deployment.
- Tenant chat is gated by plan entitlements checked on the server.
Technical decisions
- Shared database with a tenant key, rather than a database per organisation, so operator oversight stays one query path.
- Webhooks, not the checkout return URL, decide whether a subscription is active.
- Domain events stay in-process so notifications and mail do not require a queue for the current scale.
Implementation
- Public registration creates a tenant and its first user. Operators are not created through that path.
- The API is documented publicly. Live tenant and operator apps are linked from the project record.
Difficult problems
The hard line is tenancy: every tenant-user path must stay inside one organisation, while the operator console is allowed to cross that line — and those two paths must not share a handler that optionally skips the filter.
Trade-offs
- In-process events keep operations simple and avoid a broker. They will not survive multiple API instances without a later move to a queue.
- Workspace and file modules exist as structure only; they are not claimed as a shipped task or storage product.