Skip to content

System Schema

SIMPLICITY-ADMIN stores its internal state in a dedicated PostgreSQL schema, separate from your application tables. This page documents every system table, database role, and default seed data.

The system schema is created during bootstrap(), which runs automatically on:

  • First dev startup (npx simplicity-admin dev)
  • Running migrate apply

Bootstrap is idempotent — it is safe to run multiple times without side effects.

The default schema name is _simplicity. You can change it via the systemSchema config option:

import { defineConfig } from '@mabulu-inc/simplicity-admin-core';
export default defineConfig({
database: process.env.DATABASE_URL,
systemSchema: 'my_admin_schema',
});

Your application tables in public (or any other schema) are never modified by SIMPLICITY-ADMIN.

User accounts for authentication and identity.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
emailtextUnique email address
password_hashtextBcrypt-hashed password
display_nametextOptional display name
super_adminbooleanWhether this user is a super admin (default: false)
activebooleanWhether the account is active (default: true)
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivilegesColumn restrictions
app_viewerSELECTid, email, display_name, active only
app_editorSELECTid, email, display_name, active only
app_adminSELECT, INSERT, UPDATE, DELETEAll columns

Workspace/organization isolation for multi-tenancy.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
nametextTenant display name
slugtextUnique URL-safe identifier (must match ^[a-z0-9][a-z0-9-]*$)
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivilegesColumn restrictions
app_viewerSELECTid, name, slug only
app_editorSELECTid, name, slug only
app_adminSELECT, INSERT, UPDATE, DELETEAll columns

Links users to tenants with a functional role assignment.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
user_iduuidReferences users.id (CASCADE on delete)
tenant_iduuidReferences tenants.id (CASCADE on delete)
roletextFunctional database role (app_viewer, app_editor, or app_admin)
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT
app_adminSELECT, INSERT, UPDATE, DELETE

JWT blocklist that persists across server restarts.

ColumnTypeDescription
token_hashtextPrimary key — SHA-256 hash of the revoked token
revoked_attimestamptzWhen the token was revoked (default: now())
expires_attimestamptzWhen the token naturally expires (used for cleanup)

Access:

RolePrivileges
authenticatorSELECT, INSERT, DELETE

Workflow state machine definitions — one per table/column combination.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
table_nametextTable this state machine governs
column_nametextColumn that holds the state value
statesjsonbArray of state definition objects
transitionsjsonbArray of transition objects with roles, guards, and hooks
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT
app_adminSELECT, INSERT, UPDATE, DELETE

Audit trail for state machine transitions.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
table_nametextTable where the transition occurred
record_idtextID of the record that transitioned
from_statetextState before the transition
to_statetextState after the transition
user_iduuidReferences users.id (SET NULL on delete) — who performed the transition
commenttextOptional comment provided during transition
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT, INSERT
app_adminSELECT, INSERT

Dashboard definitions with widget layouts.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
nametextDashboard display name
slugtextUnique URL-safe identifier
rolestext[]Which roles can see this dashboard (default: {})
is_defaultbooleanWhether this is the default dashboard (default: false)
layoutjsonbWidget layout configuration (default: [])
created_bytextWho created this dashboard
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT
app_adminSELECT, INSERT, UPDATE, DELETE

Data-driven UI components for dashboards.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
typetextWidget type identifier
titletextWidget display title
configjsonbWidget configuration (default: {})
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT
app_adminSELECT, INSERT, UPDATE, DELETE

Notification trigger rules with conditions, templates, and delivery channels.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
nametextRule display name
enabledbooleanWhether this rule is active (default: true)
triggertextEvent type: record.created, record.updated, record.deleted, field.changed, or schedule
tabletextWhich table triggers this rule (for record events)
fieldtextWhich field (for field.changed trigger)
conditiontextSimple condition expression, e.g. status = 'urgent'
channelsjsonbDelivery channels: in_app, email (default: ["in_app"])
templatejsonbTemplate with subject and body supporting {{field}} interpolation (default: {})
recipientsjsonbRecipient config: `{ type: roles
scheduletextCron expression for schedule trigger
created_bytextWho created this rule
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_viewerSELECT
app_editorSELECT
app_adminSELECT, INSERT, UPDATE, DELETE

Delivered notification records for in-app and email channels.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
user_iduuidReferences users.id (CASCADE on delete) — notification recipient
channeltextDelivery channel: in_app or email
subjecttextNotification subject line
bodytextNotification body content
readbooleanWhether the notification has been read (default: false)
rule_iduuidReferences simplicity_notification_rules.id (SET NULL on delete)
record_idtextID of the record that triggered this notification
table_nametextTable name of the triggering record
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivilegesColumn restrictions
app_viewerSELECT, UPDATEid, user_id, read only
app_editorSELECT, INSERT, UPDATEAll columns
app_adminSELECT, INSERT, UPDATE, DELETEAll columns

UI-defined permission overrides — can only DENY access, never exceed the code ceiling.

ColumnTypeDescription
iduuidPrimary key (auto-generated)
roletextTarget role name
table_nametextTarget table
column_nametextTarget column (nullable — null means table-level)
operationtextOperation being denied
deniedbooleanWhether access is denied (default: true)
created_bytextWho created this override
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast update timestamp

Access:

RolePrivileges
app_adminSELECT, INSERT, UPDATE, DELETE

On first bootstrap, SIMPLICITY-ADMIN creates the following seed data:

EntityDetails
Default tenantName: Default, slug: default
Admin userEmail: admin@localhost, password: changeme, super_admin: true
Admin membershipLinks admin@localhost to the Default tenant with role app_admin

Bootstrap creates five PostgreSQL roles used for access control:

RoleLoginInheritPurpose
authenticatorYesYesConnection role — switches to functional roles via SET LOCAL role
anonNoNoUnauthenticated requests — minimal or no access
app_viewerNoYesRead-only application access
app_editorNoYesRead and write application access
app_adminNoYesFull application access including delete and system administration

The authenticator role is a member of all four functional roles (anon, app_viewer, app_editor, app_admin) and switches between them based on the authenticated user’s membership role for the current tenant.