Backend-first SaaS reference system that demonstrates tenant isolation as an authorization boundary, not a UI convention.
- GraphQL queries and mutations with cursor pagination, status/search filters and a depth limit.
- Organization-scoped PostgreSQL queries with RBAC, monthly quotas and invitations.
- Access tokens plus hashed, revocable refresh tokens.
- Redis-backed login rate limiting.
- DataLoader for batched
createdBymember resolution. - PostgreSQL-backed background jobs with a separate worker, retries and dead-letter state.
- MongoDB history documents with organization indexes and idempotent event IDs.
- Next.js console using the real GraphQL API for organization summary and operation creation.
- Unit tests, Docker Compose, CI and ADRs describing the security and storage boundaries.
Requirements: Node.js 22+, Docker and Docker Compose.
cp .env.example .env
npm install
docker compose up -d postgres redis mongo
npm run dev:apiIn separate terminals:
npm run dev:worker
npm run dev:webOpen http://localhost:3200. The local demo account is admin@operations.local / change-me-now; change it before exposing the stack.
query Dashboard {
organization { name planKey quotaUsed quotaLimit }
operations(first: 20, search: "billing") {
nodes { id name status createdAt createdBy { email role } }
pageInfo { hasNextPage endCursor }
}
}
mutation CreateOperation($name: String!) {
createOperation(name: $name) { id name status createdAt }
}Send the access token from POST /auth/login as Authorization: Bearer <token> to /graphql.
npm run lint
npm run typecheck
npm test
npm run build
docker compose config --quietAfter starting the full Compose stack, the tenant boundary and token rotation integration test can be run with:
$env:RUN_INTEGRATION_TESTS = 'true'
npm --workspace @ops/api run test:integrationThe API and worker are intentionally separate processes. PostgreSQL is authoritative for tenant and quota decisions; MongoDB is used only for organization history, and Redis is used for rate limiting. See the ADRs.