App Builder
Create apps, brand them, and attach object navigation by team use case.

Overview
openCRM is an open-source, metadata-driven, multi-tenant CRM learning project for developers. It shows how objects, fields, pages, apps, permissions, and workflows can be shaped through configuration instead of being hardcoded into the product.
Admin Control Surface
Everything below is implemented and available in the current codebase admin + standard surfaces, including the broader capability areas built on top of those configuration tools.
Create apps, brand them, and attach object navigation by team use case.
Configure metric/list/chart widgets with typed filters and owner scopes.
Bulk insert/update/upsert via external IDs with tracked import jobs and row errors.
Grant object-level CRUD, View All, Modify All, and app access by permission set.
Bundle permission sets into assignable groups for cleaner access administration.
Materialize group access to user-owned records using criteria and access level.
Detect likely duplicates on create and edit with multi-field matching plus warn or block actions.
Route new records to a user or queue with ordered, first-match criteria logic.
Organize users for sharing targets and ownership-based access modeling.
Use queue ownership buckets and claim flow for distributed intake and triage.
Record ownership is enforced at row level: user-owned, queue-owned, claim flow, and share-aware access checks.
Configure saved filters, columns, sorting, sharing, pinning, and custom logic expressions per object.
Track field changes and owner transitions with timestamped history for accountability and compliance.
Manage object identity, behavior flags, metadata-level governance, and where-used delete protection.
Define typed fields, options, external IDs, uniqueness, lookup targets, and field where-used checks.
Protect data integrity with per-object condition logic and field constraints.
Assign record page layouts per app and permission context with visibility rules.
Block object/field deletes when metadata still depends on them, with grouped where-used diagnostics.
The same configuration layer powers the broader platform capabilities below, from data modeling and validation to access, automation, collaboration, and productivity UX.
Build your CRM model at runtime
Block bad data before it lands
Enterprise-style permission model
Rule engines and asynchronous processing
Fast navigation and list intelligence
Context and accountability by default
Build object schemas from primitive, relational, and system-generated types.
Tech Stack
openCRM uses a straightforward TypeScript web stack: Next.js and React for the app, Prisma and PostgreSQL for data, NextAuth for authentication, and a small set of supporting libraries for UI, jobs, validation, and state.
The main web app runs on the Next.js App Router with React and TypeScript.
Metadata, records, and access data are stored in PostgreSQL and accessed through Prisma.
User sign-in and session handling are built on NextAuth.
The interface uses Tailwind for styling and Radix plus shadcn/ui primitives for components.
State, validation, and background work use a focused set of supporting libraries.
Unit and component testing run through the Vitest-based test setup.
Architecture Center
Context, boundaries, data model, authorization flow, lifecycle behavior, and async import processing in one place.
openCRM uses two runtime user roles. Both roles are authenticated users inside the same tenant and both are constrained by object permissions and row-level ownership/share logic.
Standard User
Works in the standard app surface (`/app/*`) for daily record operations, list views, dashboards, comments, imports, and queue claim flows based on assigned permissions.
Admin User
Works in the admin surface (`/admin/*`) to manage metadata and policy: apps, objects, fields, permissions, groups, queues, validation, duplicate rules, assignment rules, and sharing rules.
How They Are Similar
Both are tenant-scoped users authenticated through the same session stack. In non-admin record access paths, both still require object grants plus row access (owner, queue, or share) unless global overrides are explicitly granted.
Public users interact with one web runtime. The app coordinates database, worker, and file storage boundaries.
Two cooperating runtimes share one data store: request-time Next.js and background worker execution.
Object and field definitions are metadata. Record values are typed rows in FieldData, with dependency indexing and duplicate-rule metadata alongside safe delete checks.
Record creation layers validation, duplicate detection, assignment evaluation, and share materialization before commit.
Record delete is synchronous and transactional: permission gate, inbound lookup cleanup, hard delete, then storage cleanup.
Imports are staged: synchronous job creation, asynchronous row processing via worker queue.