Documentation
cidbee docs
The platform is a generalized ERP / work-management core: tenants define their own data model, automate it, and extend it with safely-sandboxed code. Start here if you are building on top of it.
Every REST route and GraphQL query/mutation, with auth and tenant scoping rules.
ArchitectureSystem topology, multi-tenancy, RLS vs BYODB, deployment model.
Data modelTables, typed fields, relations, unique constraints, expression indexes.
PermissionsThe Permission Engine: org roles, resource ACLs, deny-wins resolution.
AutomationsTrigger → condition → action recipes and safe tenant functions in V8.
SecuritySandbox, broker, secrets, isolation boundaries and the threat model.
The three non-negotiable rules
- Tenant-scoped, always. Every query runs under a resolved tenant scope (Row-Level Security on the shared pool, or a dedicated BYODB connection). There is no trusted bypass path.
- Every record write is validated. All writes — REST, GraphQL, automations, function calls, ingestion — funnel through the metadata engine. No raw JSONB writes.
- User code never runs in-process. Tenant-authored functions execute in V8 isolates inside a dedicated sandbox service, reaching data only through a permission-checking capability broker.
Creating a workspace
Sign up for an account from the home-page popup (or POST /auth/signup against the API directly), then create your first organization via POST /tenants — workspaces live under your account, so one account can own several. The token's tenant claim drives API resolution, so local dev needs no wildcard DNS. A workspace boots with an Owner role; you can create roles, ACLs, tables and functions immediately.
# run the stack locally docker compose -f infra/docker-compose.yml up -d # postgres + redis + minio export DATABASE_URL=postgres://cidbee_admin:cidbee_dev_password@localhost:5432/cidbee export REDIS_URL=redis://localhost:6379 export JWT_SECRET=<64-char random> npm run dev # api :3000 · web-tenant :3100
Architecture
cidbee is a Turborepo monorepo deployed as containerized workloads on AWS. A GraphQL gateway and REST/OpenAPI surface front the core services; Redis backs caching and rate limits; a message bus carries ingestion, quoting, automation and telemetry. See ARCHITECTURE.md for the full blueprint.
| Layer | What lives there |
|---|---|
| Client | Tenant web app (Next.js), field PWA, super-admin control plane |
| Edge | CDN, ALB, WAF — zero-trust perimeter before any code |
| API | GraphQL + REST, tenant resolution, the metadata / formula / automation engines |
| Sandbox | V8 isolate pool reachable only via the capability broker |
| Data | Shared RLS Postgres or per-tenant BYODB, Redis, object storage |
Multi-tenancy
- Standard tenants share a partitioned Postgres cluster behind Row-Level Security.
- Enterprise / sovereign tenants bring their own database (BYODB) — Postgres, MySQL or CockroachDB resolved dynamically at request time.
- Tenant branding is injected server-side at the layout root — never a client-side fetch, never a flash of default chrome.
Dynamic data model
Everything is a record in a tenant-defined table, shaped by typed fields. There is exactly one physical records store per database; all schema diversity lives in metadata.
- Fields: text, markdown long-text, number, currency, checkbox, date/datetime, dropdown, labels, email, url, phone, files, user, rating, progress, location, relationship/FK, lookup, formula and button.
- Relations: any number of relationship fields per table, any cardinality, self-referencing allowed, bidirectional by default.
- Uniqueness: named composite unique constraints — a single-field constraint is the degenerate one-field case.
- Performance: records are JSONB, accelerated by auto-provisioned expression indexes for filterable fields.
Permission engine
One resolution walk serves the whole platform: Discord-style org-wide RBAC (ordered, inheritable roles with bitflag capabilities) layered with ClickUp-style resource ACLs (per-resource allow/deny lists with inheritance).
- Explicit DENY wins at the most specific level — even for org admins.
- Decisions are cached in Redis under a tenant permission epoch; any permission mutation bumps the epoch in O(1).
- A view can only narrow access — its filters compose with the engine, never widen it.
Automations & functions
Automations are trigger → condition → action recipes: record changes, button clicks, schedules, inbound webhooks, form submissions. Conditions use the same expression language as formula fields.
For real code, tenants publish functions in V8 isolates, triggered from anywhere a tenant can wire. The sandbox receives no ambient authority — every SDK call re-resolves the Permission Engine, filters the record snapshot, applies rate limits and mediates secrets.
Security
- Isolation: one isolate per execution, no shared heap; a crashing function can only hurt its own isolate.
- Broker: `function-runtime` holds no database credentials — its only egress is the HMAC-authenticated broker endpoint.
- Secrets: tenant secrets live in object storage / Secrets Manager, readable only via
cidbee.secrets.get, never in logs. - Audit: an append-only audit log records permission and security-relevant actions, mirrored to the platform cluster for BYODB tenants.
public/lottie). Brand icons are from Simple Icons (CC0). Full terms: licenses page.