Skip to content

Database Schema

Melvin PETIT edited this page Jun 22, 2026 · 2 revisions

Database Schema

DataShield uses Prisma 7 with PostgreSQL. The schema lives in prisma/schema.prisma. All identifiers are CUIDs. Every tenant-owned row references a Company, and deletes cascade from the company down.

Entity relationships

erDiagram
  Company ||--o{ User : has
  Company ||--o{ Employee : has
  Company ||--o{ Alert : has
  Company ||--o{ DashboardPreset : has
  Company ||--o{ DirectoryConnection : has
  Company ||--o{ ApiCredential : has
  Company ||--o{ Webhook : has
  Company ||--o{ RemediationAction : logs
  Company ||--o{ ExposureRegisterEntry : records
  Company ||--o{ ReportSchedule : schedules
  User ||--o| DashboardConfig : owns
  User ||--o{ DashboardPreset : authors
  Employee ||--o{ BreachRecord : has
  Employee ||--o{ Alert : triggers
  Breach ||--o{ BreachRecord : appears_in
  Breach ||--o{ Alert : triggers
Loading

Models

Company

Tenant root. domain is unique. Owns every other tenant-scoped entity; all relations cascade on delete. Also holds company-wide settings: riskWeights (JSON override, see Risk Scoring), remediationEnabled (default false, see Remediation), the SIEM pull token (siemTokenEnc / siemTokenHint) and push config (siemPushUrlEnc / siemPushHint / siemPushFormat / siemPushSince, see SIEM Integration), and the auto-scan cadence (scanIntervalMinutes / lastScanAt).

User

email unique, hashedPassword (bcrypt), role (ADMIN | VIEWER, defaults VIEWER). Has one optional DashboardConfig, authors many DashboardPresets, and points to an activePreset (set to null on preset delete).

Employee

@@unique([email, companyId]) so the same address can exist across tenants but is unique within one. Optional department. Optional mfaEnabled (tri-state: true / false / null unknown, see MFA Coverage). Linked to BreachRecords and Alerts.

Breach

name unique (used as the upsert key by the scan engine). source (HIBP | MANUAL | DARK_WEB | STEALER_LOG), breachDate, dataTypes string array.

BreachRecord

Join between an Employee and a Breach with the exposedData for that specific match. @@unique([employeeId, breachId]) prevents duplicate links. Stealer-log matches add artifacts (ArtifactKind[]) and optional infection metadata (machineId, malwareFamily, capturedAt). See Breach Scanning.

Alert

Severity-scored event. severity (CRITICAL | HIGH | MEDIUM | LOW), status (OPEN | ACKNOWLEDGED | RESOLVED, defaults OPEN). Employee and breach references are nullable and set to null on delete so alert history survives.

DirectoryConnection

An identity-provider connection. type (see DirectoryType), encryptedConfig (AES-256-GCM blob), status (ACTIVE | ERROR | PENDING), plus lastSyncAt, lastSyncCount, errorMessage.

ApiCredential

A breach-provider API key. provider (see ApiProvider), encryptedKey, keyHint (display-safe suffix), status, lastUsedAt. @@unique([companyId, provider]), so one key per provider per company.

SyncJob

A retryable background directory-sync job, tied to a DirectoryConnection. status (SyncJobStatus), attempts / maxAttempts (default 3), runAfter for scheduling/backoff, plus startedAt / finishedAt / lastError. See Directory Integrations.

Webhook

Outbound notification target. channel (WEBHOOK | SLACK | TEAMS | EMAIL, defaults WEBHOOK), encryptedUrl (URL or recipient address), urlHint, minSeverity (defaults MEDIUM), enabled. See Notifications.

RemediationAction

Append-only audit of remediation run against the directory. action (RemediationType), status (SUCCESS | FAILED), target, optional detail, performedBy, optional employeeId / alertId. See Remediation.

ExposureRegisterEntry

A GDPR exposure record. title, detectedAt, status (RegisterStatus), affectedCount, dataCategories, optional assessment and notifiedAt. Deadlines are computed, not stored. See Exposure Register.

ReportSchedule

A recurring report emailed to recipients. frequency (ScheduleFrequency), recipients, sections, enabled, lastSentAt. See Reports.

DashboardConfig / DashboardPreset

Per-user live layout (DashboardConfig, one per user) and saved presets (DashboardPreset, scope PERSONAL or COMPANY). Both store layout and widgets as JSON.

Enums

Enum Values
Role ADMIN, VIEWER
Severity CRITICAL, HIGH, MEDIUM, LOW
AlertStatus OPEN, ACKNOWLEDGED, RESOLVED
BreachSource HIBP, MANUAL, DARK_WEB, STEALER_LOG
ArtifactKind PASSWORD, COOKIE, TOKEN, AUTOFILL
DirectoryType AZURE_AD, GOOGLE_WORKSPACE, LDAP, AWS_DIRECTORY, OKTA, SCIM
ApiProvider HIBP, HIBP_STEALER, DEHASHED, LEAKCHECK, INTELX, SNUSBASE
ConnectStatus ACTIVE, ERROR, PENDING
SyncJobStatus PENDING, RUNNING, SUCCEEDED, FAILED
PresetScope PERSONAL, COMPANY
NotificationChannel WEBHOOK, SLACK, TEAMS, EMAIL
RemediationType REVOKE_SESSIONS, FORCE_PASSWORD_RESET
RemediationStatus SUCCESS, FAILED
RegisterStatus ASSESSING, NOTIFIED, NOT_REQUIRED
ScheduleFrequency WEEKLY, MONTHLY

Migrations

Migrations are checked into prisma/migrations/, applied with prisma migrate deploy (npm run db:migrate). The current history:

  1. init
  2. add_dashboard_config
  3. add_preset_scope_and_active_preset
  4. add_directory_connections
  5. add_aws_directory_type
  6. add_okta_scim_directory_types
  7. add_api_credentials
  8. add_webhooks
  9. add_sync_jobs
  10. add_schedule_config
  11. add_stealer_log_artifacts
  12. add_notification_channels
  13. add_company_risk_weights
  14. add_employee_mfa
  15. add_remediation
  16. add_siem_token
  17. add_exposure_register
  18. add_report_schedules
  19. add_siem_push

Clone this wiki locally