Multi-tenant CRM — built with StreetJS
Contacts · Deals · Pipeline · RBAC — strict per-tenant isolation.
- Live demo: coming soon (see the demo plan)
- Source:
examples/reference-apps/crm - Deploy:
deploy/cloud-run/service.yaml· Docs: SaaS foundation
Architecture
1
2
3
4
Request (X-Org-Id = tenant, X-User-Id = actor)
├─ RBAC: @streetjs/admin AdminService.can(actor, 'crm:write'|'crm:read')
└─ CrmStore — isolated per-org bucket (cross-tenant access impossible by construction)
└─ companies ─▶ contacts ─▶ deals ─▶ pipeline (lead→qualified→proposal→won/lost) ─▶ activity timeline
Built on the same foundation the SaaS reference app proves — organizations, RBAC, and per-tenant scoping — with a CRM domain on top.
Run it locally
1
2
3
4
npm run build -w packages/core
npm run build -w packages/admin
node examples/reference-apps/crm/server.mjs # :3000
node examples/reference-apps/crm/smoke-test.mjs # 16/16 checks
How it’s proven
The smoke test asserts tenant isolation (each org sees only its own deals; a
cross-tenant deal move is a scoped 404), RBAC (a crm-viewer is denied writes,
a crm-editor is allowed), pipeline transitions, the activity timeline, and
invalid-stage rejection. It runs in CI via reference-apps.yml.
Learning path
- SaaS — orgs, RBAC, multi-tenancy
- CRM — a multi-tenant domain on that foundation
- Persist to PostgreSQL with the repository pattern (
org_idscoping)
A real, CI-tested reference app. Browse all demos in the Showcase.