Skip to content

Database

The Cloud Backend uses Azure SQL Server with sqlx for all data access. There is no ORM — queries are written as raw SQL with named struct scanning.

Migrations are managed by Flyway and live in Backend/db/migration/. They run automatically on deploy.

MigrationDescription
V1Base schema — all core tables
V10CVE feed catalog
V11Vuln scanner — drop tenant API keys
V12Vuln scanner — drop feed sync enabled
V13Asset registry vendor
V14Disable tenant RLS (RLS policy definition)
V15User settings appearance
V16Refresh tokens table
V17Tenant features table
V18Assets vendor → producer rename
V19CVE scores cache
V20ExploitDB catalog
V21Edge snap updates
V22Edge device control
V23Edge ingest events
V24Onboarding OT completed flag
V25Knowledge article → problem links
V26Zones/VLANs site_id
V27Network hierarchy links
V28Drop diagram-related change_id

Run migrations locally with Flyway CLI or via the CI/CD pipeline post-deploy step.

All database row types are defined in Backend/internal/db/models.go. Domain packages define their own richer types that embed or transform these models.

erDiagram
    tenants {
        uuid id PK
        string name
        string status
        timestamp created_at
    }
    users {
        uuid id PK
        uuid tenant_id FK
        string email
        string password_hash
        bool mfa_enabled
        timestamp created_at
    }
    groups {
        uuid id PK
        uuid tenant_id FK
        string name
    }
    user_groups {
        uuid user_id FK
        uuid group_id FK
    }
    assets {
        uuid id PK
        uuid tenant_id FK
        string name
        string type
        uuid site_id FK
        timestamp created_at
    }
    sites {
        uuid id PK
        uuid tenant_id FK
        string name
    }
    incidents {
        uuid id PK
        uuid tenant_id FK
        string title
        string status
        string severity
        timestamp sla_response_due
        timestamp sla_resolve_due
        timestamp created_at
    }
    problems {
        uuid id PK
        uuid tenant_id FK
        string title
        string status
        string root_cause
    }
    changes {
        uuid id PK
        uuid tenant_id FK
        string title
        string status
        string type
        string risk
    }
    vulnerabilities {
        uuid id PK
        uuid tenant_id FK
        string cve_id
        float cvss_score
        string status
        uuid asset_id FK
    }
    audit_logs {
        uuid id PK
        uuid tenant_id FK
        uuid user_id FK
        string action
        string resource_type
        string resource_id
        timestamp created_at
    }
    tenant_licenses {
        uuid tenant_id FK
        string plan
        timestamp expires_at
    }
    tenant_features {
        uuid tenant_id FK
        string feature
        bool enabled
    }

    tenants ||--o{ users : "has"
    tenants ||--o{ groups : "has"
    tenants ||--o{ assets : "owns"
    tenants ||--o{ incidents : "owns"
    tenants ||--o{ problems : "owns"
    tenants ||--o{ changes : "owns"
    tenants ||--o{ vulnerabilities : "owns"
    tenants ||--o{ audit_logs : "generates"
    tenants ||--|| tenant_licenses : "has"
    tenants ||--o{ tenant_features : "has"
    users }o--o{ groups : "belongs to (user_groups)"
    assets }o--|| sites : "located at"
    vulnerabilities }o--|| assets : "affects"
Env varPurpose
DATABASE_URLLocal/fallback: sqlserver://user:pass@host:port?database=...
SQL_SERVERAzure SQL server hostname (takes precedence over DATABASE_URL)
SQL_DATABASEAzure SQL database name
AZURE_CLIENT_IDUser-assigned Managed Identity client ID (omit for system-assigned)
IS_DEV=trueForces DATABASE_URL (SQL auth) even when SQL_SERVER is set

In production, the backend connects using Azure Managed Identity — no password in environment variables.

For local dev, run SQL Server in Docker:

Terminal window
docker run -e ACCEPT_EULA=Y -e SA_PASSWORD=<password> \
-p 1433:1433 mcr.microsoft.com/mssql/server:2022-latest

Then set DATABASE_URL=sqlserver://sa:<password>@localhost:1433?database=monozu&encrypt=disable in .env.

Flyway applies migrations on first run. On a fresh DB, run Flyway against the local instance:

Terminal window
cd Backend
flyway -url="jdbc:sqlserver://localhost:1433;databaseName=monozu;encrypt=false" \
-user=sa -password=<password> migrate