Skip to main content

Feature deep-dive · SaaSForge Core

B2B SaaS template for Next.js, workspaces, RBAC, audit, SSO

B2B SaaS template for Next.js, workspaces, RBAC, audit, SSO

B2B SaaS templates fall into two camps: pretty marketing shells that lie about tenancy, and serious foundations that handle the unsexy enterprise primitives. The difference shows up the first time a buyer's IT security reviewer asks where row isolation is enforced or whether audit logs are immutable. SaaSForge Core is built for the second camp.

Workspaces, tenancy as a database boundary

Each customer lives in a workspace. Every domain table (projects, documents, comments) carries a `workspace_id` foreign key, and Postgres RLS policies enforce that queries can only see rows where the authenticated user is a member. Application code does not have to remember to add `where workspace_id = ?`, the database refuses to return rows otherwise.

Workspaces have explicit ownership transfer, member invitations via Resend, settings flows, and a switcher in the dashboard. The plumbing is real, not a `team_id` column bolted onto a single-tenant demo.

RBAC, four roles, granular permissions

Owner controls billing and ownership transfer. Admin manages members and settings. Member works on the product. Viewer reads but does not write. The four-role surface is what most B2B SaaS converges on; the boilerplate ships it with explicit permission checks on mutations.

The permission system is granular enough to define new actions (e.g., `documents.delete`, `billing.read`) without rewriting the role table. UI hides what users cannot do; the API rejects what the UI hides. Both layers exist because hide-only UIs leak through API testing tools.

Audit logs and impersonation, the support workflow

Every mutation writes an audit log row: actor, resource, metadata, timestamp. That table is what compliance reviews ask about and what support uses to investigate 'who deleted my thing'. Audit log rows are not editable through normal flows; they are a write-only ledger.

Support impersonation is gated and audited. A support user can assume a customer's context (read-only by default) to debug an issue; every impersonation session shows up in the audit log so the customer can verify after the fact. The combination, impersonation for debugging, audit for accountability, is the table-stakes B2B support workflow.

Audit log row schema
create table audit_logs (
  id uuid primary key default gen_random_uuid(),
  workspace_id uuid not null references workspaces(id),
  actor_user_id uuid not null,
  action text not null,
  resource_type text not null,
  resource_id uuid,
  metadata jsonb,
  ip_address inet,
  created_at timestamptz not null default now()
);

SSO, 2FA, API keys, IP allowlisting, the procurement checklist

IT security reviews ask a predictable list of questions: Is MFA available? Is SSO supported? Are API keys rotated and masked? Is access restrictable by IP? SaaSForge Core ships TOTP 2FA via Supabase Auth, SAML SSO hooks for Okta/Azure AD/Google Workspace, API keys with secret masking after creation, and optional IP allowlisting for workspace access.

None of these are bolted on after the demo, they are first-class patterns in the codebase. The point is that when procurement sends the security questionnaire, your answers are 'yes, and here is the implementation' rather than 'we will add it next quarter'.

Stripe subscriptions wired to workspaces

Subscriptions are workspace-scoped, not user-scoped. The Owner controls billing; member changes do not affect the subscription state. Stripe Checkout handles new purchases; the Customer Portal handles plan changes. The webhook lifecycle (create, update, renew, cancel) is fully wired with idempotency tracking.

Three plan tiers (Starter/Pro/Enterprise) with monthly and yearly options ship as the default; swap price IDs and your billing matches your Stripe products. The webhook handler is documented end-to-end so you know what to extend versus what to leave alone.

Frequently asked

How is this different from a 'tenant_id everywhere' template?
Application-layer tenancy (a `tenant_id` column with manual checks) works until one forgotten `where` clause leaks a row. SaaSForge Core enforces tenancy in Postgres via RLS, so the database returns zero rows on a missing scope rather than leaking. Application checks still exist; the database is the backstop.
Do I need to implement SAML SSO myself?
SaaSForge Core ships the patterns and hooks, invocation points, mapping from SAML claims to workspace membership, but the actual SAML provider is Supabase Auth's SSO product. You configure your Okta/Azure AD/Google Workspace IdP in Supabase, and the template handles the workspace-side wiring.
What is the audit log retention story?
The boilerplate ships an open-ended audit_logs table; retention policy is yours to set based on your compliance posture. For SOC 2-shaped buyers, you would typically keep at least one year; the template's data model supports any retention you want.
Can I add custom roles beyond the four defaults?
Yes. The role surface is data-driven, adding a role means inserting a row and mapping it to a permission set. The UI surfaces new roles in workspace settings without component changes. Most teams stay with the four defaults; the extensibility is there when a vertical needs something custom (e.g., a 'Compliance Officer' role with read-only access to audit logs).
How does it compare to off-the-shelf B2B platforms?
Off-the-shelf platforms (e.g., WorkOS, Auth0 B2B) handle specific layers, SSO, directory sync, but you still own the product surface. SaaSForge Core gives you the product layer plus integration points for those platforms when you graduate. It is a starting boilerplate, not a replacement for a managed identity provider at scale.
Ships in SaaSForge Core

See SaaSForge Core. Skip the deliberation.

Full source code. Lifetime updates. Polar Merchant-of-Record checkout. Private GitHub repo on purchase.