// security & compliance

Security
isn't a feature.
It's the architecture.

Database-level tenant isolation. Composable role-based access. Row- and column-level policies declared as metadata, not buried in application code. Self-hosted by default, anywhere you want.

security posture
●︎ green
tenant isolationdb-level
data at restencrypted
data in transittls 1.3
audit trail100%
self-hostavailable
data residencyyour call
isolation

One database
per tenant.
No exceptions.

The strongest isolation model available. No shared tables. No query filters to forget. If one tenant's database is compromised, other tenants are completely unaffected.

Read: Only You Own Your Data
[separate db]
Separate databases

Each tenant has its own PostgreSQL database. Not a schema, not a row filter — a real database.

[separate creds]
Separate credentials

Unique DB user per tenant. No shared connection. No master role with cross-tenant reach.

[schema iso]
Module schemas

Module schemas (crm, hr, fin, wms) live inside each tenant's own database. Always namespaced.

[auth split]
Auth/data split

User identities live in a separate auth service. Tenant data never touches the auth store.

tenantacme● isolatedpostgresacme_dbcrmhrfintenantglobex● isolatedpostgresglobex_dbcrmhrfintenantinitech● isolatedpostgresinitech_dbcrmhrfinone database per tenant · no shared tables · no cross-tenant queries possible
other platforms · shared db, "tenant_id" filter
risky
postgres · single database
SELECT * FROM accounts WHERE tenant_id = ?
SELECT * FROM contacts WHERE tenant_id = ?
SELECT * FROM invoices WHERE tenant_id = ?
↑ one missed filter = data leak
dforge · one database per tenant
isolated
db · tenant_acmeisolated
db · tenant_globexisolated
db · tenant_initechisolated
no shared rows · no shared roles · no cross-tenant queries possible
data folders

One workspace.
Many boundaries.
Zero code.

Separate organizations get separate workspaces — their own database, walled off completely. Inside one workspace, folders carve the same data into slices: a department, a division, a region, a warehouse. Grant someone a folder and you grant exactly the data its filter defines — nothing more.

[filtered slices]
Folders are filters, not files

A folder is a saved filter over your entities. Records aren't moved into it — they appear when they match, and the same record can live in several folders at once.

[scoped roles]
Same role, scoped per folder

Assign a role inside a folder and it only reaches that slice. Anna manages the East division, Bob the West — one role, two boundaries, no custom code.

[composable]
Folders × views × roles

Row access (folders), column access (views) and operations (roles) are independent blocks. Define each once and combine freely — no role-per-department explosion.

[enforced]
Enforced at the database

Every query carries the folder's filter, and writes can't push a record out of its slice. The boundary holds at the SQL layer, never just the UI.

module · CRMfolder role assignments
CRM
no filter · root
sarah · crm.admin
all divisions
CRM/East Division
division_id = 'east'
anna · crm.manager
east only
CRM/West Division
division_id = 'west'
bob · crm.manager
west only
access control

Four layers.
All declarative.

Every access rule is metadata. Versioned, reviewable, auditable. No security logic scattered across controllers and stored procedures.

[rbac]
Role-based access

Composable, additive roles. Sales Rep + Finance Viewer = full CRM + read-only Finance. Roles never revoke each other.

role  SalesRep        can: read, update.own
role  FinanceViewer   can: read.fin
user  alice
      roles: [SalesRep, FinanceViewer]
[row-level]
Row-level security

Per-record rules gate individual rows by their values, owner, or status — layered on top of folder scope and enforced at the SQL layer, never the UI.

policy  OwnOpenDeals  on Deal
        for SalesRep
        where  owner = $user
[col-level]
Column-level security

Per-role field visibility and editability. Sales sees the contract value but not the margin. Viewers see summary, not internal notes.

field  Contract.margin
       visible: Finance, Exec
       hidden:  Sales, Viewer
[actions]
Action-level rules

Even an enabled action only runs when the user holds the right and the action's own canExecute rule passes for the target record.

action  Approve  on Invoice
        canExecute:  status = 'draft'
audit & compliance

Every change.
Every actor.
Every time.

Read: Audit & access control, built in
100%
Change history

Every data mutation tracked: who, what, when, before, after. Financial modules carry full audit trails.

JWT
Token-based auth

Refresh tokens, short-lived access tokens, secure rotation. No passwords stored in tenant databases.

Yours
Data sovereignty

Self-host in your region, your jurisdiction, your network. Backups, encryption, and policies under your control.

audit log · tenant_acmelive tail
16:42:08
alice@acme.io
update
Lead#3214
stage: qualified → won
16:41:55
bob@acme.io
delete
Account#812
soft delete · recoverable 30d
16:41:32
system
login
alice@acme.io
192.168.1.42 · session+8h
16:40:11
carol@acme.io
export
Invoice
120 rows · csv
16:39:47
dave@acme.io
create
Contact#4501
company: globex
sovereignty

Your infrastructure.
Your rules.

[cloud]
dForge Cloud

Hosted at dforge.app. Managed infra, automatic backups, security patches, SSL/TLS in transit, db-level isolation per tenant.

  • › managed postgres · per-tenant db
  • › automated daily backups
  • › patches applied automatically
  • › eu & us regions
  • › soc 2 · gdpr aligned
[self-hosted]
On-prem & VPC

Run dForge inside your network. Docker, Kubernetes, or bare metal. Bring your own Postgres. Data never leaves your jurisdiction.

  • › docker · k8s · airgapped
  • › bring your own postgres
  • › your own backup & encryption
  • › custom firewall & network policies
  • › regulatory data residency
talk to security

Got compliance
questions?

We're happy to walk through your security and compliance requirements in detail — including DPAs, BAAs, and architecture deep dives.