Choose a tenancy model first
Tenancy is how your customers, called tenants, share your infrastructure. It shapes cost, security and how hard the product is to change later, so decide it before the first table is created.
| Model | How it works | Fits | Trade-off |
|---|---|---|---|
| Shared tables | One database; every row carries a tenant ID | Most early products with many small customers | Cheapest to run, but one missing filter leaks data |
| Schema per tenant | One PostgreSQL database; each tenant has its own schema | A moderate number of customers who need stronger separation | More work for every migration |
| Database per tenant | Each tenant has its own database | A few large customers with strict requirements | Highest cost and the most operational effort |
Many products do best starting with shared tables and enforcing isolation in the database as well as in the code, for example with PostgreSQL row-level security. Keep the option to move one large customer to its own database later by never treating the tenant ID as optional.
Authentication, roles and permissions
- Email and password with strong hashing, plus multi-factor authentication at least for administrators.
- Single sign-on through SAML or OpenID Connect is a common enterprise request. Plan the data model for it, and build it when a customer needs it.
- Roles: start with a small fixed set, such as owner, admin and member, and check them on the server for every action. Custom roles can wait.
- Invitations, session expiry, and the ability to remove a user and end all of their sessions at once.
Authorisation is where most SaaS bugs hide. Check the user, the tenant and the object on every request, not only whether someone is signed in.
Subscription billing through a payment provider
Do not build billing from scratch and do not store card numbers. A payment provider handles cards, invoices and the customer portal; your product keeps a record of what each tenant is entitled to.
- Use the provider's hosted checkout and customer portal, so card data never reaches your servers.
- Model the subscription states you will meet: trial, active, past due and cancelled. Decide what each one means for access.
- Treat the provider's webhooks as the source of truth. Verify the signature, handle each event idempotently, and expect events to arrive late or twice.
- Keep plan limits and features in your own data, as entitlements, so a plan change updates access without a code release.
Tax, invoicing rules and payment-method availability differ by country. Confirm them with your payment provider and an accountant before you set prices.
Tenant data isolation: the biggest security risk
In a multi-tenant product, the worst bug is one customer seeing another's data. It is rarely exotic. It is a missing filter, a guessable identifier, or a shared resource that nobody scoped to a tenant.
Scope every one of these to the tenant, and enforce it in one central place rather than in each query:
- Database queries, through row-level security or a data layer that cannot run without a tenant.
- Background jobs, queues and scheduled tasks, which run without a user request.
- File storage paths and download links.
- Caches and search indexes.
- Exports, reports and analytics.
- Logs and error reports, which can carry customer data.
Test it directly. Create two tenants, sign in as one and try to reach the other's records by changing identifiers in requests. Broken access control is a named category in the OWASP Top 10, and threat modelling of the core flows asks the question at the start: what is the worst thing one tenant could do to another?
Onboarding, admin and support tools
A tenant that does not reach its first useful result in the first session often does not come back. Onboarding should take a new organisation there quickly:
- A short setup that asks only what the product needs, with sensible defaults.
- Easy invitations for teammates, and an import or sample data so screens are never empty.
Behind the product sits an internal admin panel: tenant, plan, usage and users, with actions to suspend, resend an invitation or change a plan. Support staff sometimes need to see what a customer sees. Allow that only with the customer's permission, for a limited time, with a visible banner and a log entry.
These tools are part of the product, not an afterthought, and they are an attack surface. Protect them with multi-factor sign-in, narrow roles and logging.
Audit logs and observability
An audit log records who did what, to which object, when and from where. Write one entry for sign-ins, permission changes, exports, billing changes and deletions. Keep the log append-only, let tenant administrators read their own entries, and decide how long entries are kept.
Observability is how you find out about a problem before the customer does. Use structured logs that never contain passwords, tokens or personal data, error tracking, metrics per tenant, and alerts for failed sign-ins, failed webhooks and growing queues. If you bill by usage, meter it in the same place.
Scope the MVP and defer the rest
A first version should prove that tenants will use the product and pay for it. Some foundations are painful to add later, so build them now. The rest can wait for a real customer request. This is the idea behind an MVP.
| Build in the first version | Defer until a customer needs it |
|---|---|
| Tenant model and isolation tests | Database per tenant |
| Sign-in, multi-factor for admins, a few fixed roles | Single sign-on and custom roles |
| Billing through hosted checkout, with webhooks | Usage-based pricing and complex invoicing |
| An audit log for sensitive actions | Customer-facing log search and export |
| Basic admin and support tools | Public API and integrations |
| An English and Arabic interface | More languages and white-labelling |
| Error tracking and tested backups | Multi-region deployment |
A discovery sprint is a good place to settle this list. It ends with a clickable prototype, a technical approach, a threat model of the core flows and a written roadmap; the pricing page describes how engagements are structured.
A bilingual interface from the first screen
If Arabic-speaking users are in your market, build for both languages from the start. Adding right-to-left to a finished product touches every layout.
- Logical CSS properties and mirrored icons, so layouts flip without a second stylesheet.
- Dates, numbers and currency formatted by locale.
- A language setting per user, with a default per tenant.
- Emails, invoices and notifications in the recipient's language.
- Sorting, search and data entry that handle Arabic and Latin names side by side.
The guide to bilingual Arabic and English products covers these decisions in depth, and Next.js development describes the framework we often use to build the web application.