Skip to main content

Database Structure

This guide documents the complete database schema used by Muonroi across the control plane, rule engine, and supporting systems. All tables are created via Entity Framework Core migrations and are organized by functional area.

Overview

The Muonroi ecosystem uses PostgreSQL as the primary database (supporting multiple schemas for tenant isolation). Tables fall into these categories:

  1. Identity & Permission — User authentication, roles, permissions
  2. Rule Engine — Ruleset definitions, versions, approval workflows
  3. Decision Tables — Decision table models, versions, cell data
  4. Workflows — BPMN process definitions, execution tracking
  5. Multi-Tenancy — Tenant configuration, quotas, isolation modes
  6. Canary Deployments — Version rollout tracking
  7. Authorization — Rule-driven auth rules
  8. Audit Trail — System audit logs
  9. License Server — (separate database) License keys, activations, heartbeats

Identity and Permission Tables

TableSchemaPurposeOptional
MUsersdboUser account information, email, status
MRolesdboRole definitions (Admin, Approver, Viewer)
MPermissionsdboPermission definitions mapped to enum values
MRolePermissionsdboN:N mapping between roles and permissions
MUserRolesdboN:N mapping between users and roles
MRefreshTokensdboRefresh token storage with validity keys
MUserTokensdboExternal login tokens (OAuth, SAML, etc.)✔️
MUserLoginAttemptsdboFailed login attempt tracking for rate limiting✔️
MLanguagesdboSupported locale codes for localization
MPermissionGroupsdboLogical groups of related permissions
MPermissionAuditLogsdboAudit trail of permission changes✔️

Rule Engine Tables

RuleSets

ColumnTypeKeyDescription
RuleSetIdGUIDPKUnique ruleset identifier
TenantIdVARCHAR(256)FKMulti-tenant owner (ITenantScoped)
WorkflowNameVARCHAR(256)Unique workflow name (e.g., "loan-approval")
SourceTypeVARCHAR(50)Kind: CodeBased, FlowGraph, DecisionTable, JsonWorkflow
SourceCodeTEXTRule source (C# class name, DMN XML, JSON flow)
DescriptionTEXTHuman-readable description
CreatedAtDATETIMEUTC timestamp of creation
UpdatedAtDATETIMEUTC timestamp of last modification
CreatorUserIdGUIDFKUser who created (audit trail)
VersionINTCurrent active version number

Relationships:

  • 1:N to RuleSetVersions (all versions of this ruleset)
  • 1:N to RuleSetApprovals (approval workflow records)
  • 1:N to RuleSetAudit (change audit trail)
  • FK to MUsers (CreatorUserId)
  • FK to Tenants (TenantId, if multi-tenant enabled)

Indexes: (TenantId, WorkflowName), (CreatedAt DESC), (UpdatedAt DESC)

RuleSetVersions

ColumnTypeKeyDescription
VersionIdGUIDPKUnique version identifier
RuleSetIdGUIDFKParent ruleset
VersionNumberINTIncremental version (1, 2, 3...)
RuleSetJsonTEXTComplete ruleset JSON (source code snapshot)
DescriptionVARCHAR(500)Version notes / change summary
StatusVARCHAR(50)Draft, PendingApproval, Active, Superseded
CreatedAtDATETIMETimestamp of creation
CreatedByGUIDFKUser who created this version
ActivatedAtDATETIMENULL until activated, then UTC timestamp
ActivatedByGUIDFKUser who activated this version
SignedHashVARCHAR(256)SHA256 of RuleSetJson for integrity verification
SignatureTEXTHMAC-SHA256 signature for approval chain

Relationships:

  • FK to RuleSets (RuleSetId)
  • FK to MUsers (CreatedBy, ActivatedBy)
  • 1:N to RuleSetApprovals (approval records for this version)

Indexes: (RuleSetId, VersionNumber), (Status, CreatedAt), (ActivatedAt DESC)

RuleSetApprovals

ColumnTypeKeyDescription
ApprovalIdGUIDPKUnique approval record ID
VersionIdGUIDFKVersion being approved
TenantIdVARCHAR(256)FKMulti-tenant owner
ApprovalStatusVARCHAR(50)Pending, Approved, Rejected
SubmittedAtDATETIMESubmission timestamp
SubmittedByGUIDFKUser who submitted
ApprovedAtDATETIMENULL until approved
ApprovedByGUIDFKApprover user (maker ≠ checker rule)
RejectionReasonTEXTReason if rejected
ApprovalCommentTEXTComments from approver

Relationships:

  • FK to RuleSetVersions (VersionId)
  • FK to MUsers (SubmittedBy, ApprovedBy)
  • FK to Tenants (TenantId)

Indexes: (VersionId, ApprovalStatus), (SubmittedAt DESC), (ApprovedBy, ApprovedAt)

RuleSetAudit

ColumnTypeKeyDescription
AuditIdGUIDPKUnique audit log entry
RuleSetIdGUIDFKRuleset being audited
TenantIdVARCHAR(256)FKMulti-tenant owner
ActionTypeVARCHAR(50)Created, Modified, Activated, Approved, Rejected, Executed
ActionDetailTEXTJSON context (version, previous values)
PerformedByGUIDFKUser who performed action
PerformedAtDATETIMETimestamp of action
CorrelationIdVARCHAR(256)Trace correlation ID
IpAddressVARCHAR(50)IP of requesting client

Relationships:

  • FK to RuleSets (RuleSetId)
  • FK to MUsers (PerformedBy)
  • FK to Tenants (TenantId)

Indexes: (RuleSetId, PerformedAt DESC), (PerformedBy, PerformedAt), (CorrelationId)


Decision Table Tables

DecisionTables

ColumnTypeKeyDescription
TableIdGUIDPKUnique decision table identifier
TenantIdVARCHAR(256)FKMulti-tenant owner (ITenantScoped)
NameVARCHAR(256)Readable table name (e.g., "Loan Approval Rules")
DescriptionTEXTPurpose and business rules
HitPolicyVARCHAR(50)First, Unique, Collect, Priority
CreatedAtDATETIMEUTC creation timestamp
UpdatedAtDATETIMEUTC last modification timestamp
CreatorUserIdGUIDFKUser who created
VersionINTCurrent active version

Relationships:

  • 1:N to DecisionTableVersions
  • FK to MUsers (CreatorUserId)
  • FK to Tenants (TenantId)

Indexes: (TenantId, Name), (CreatedAt DESC)

DecisionTableVersions

ColumnTypeKeyDescription
VersionIdGUIDPKUnique version ID
TableIdGUIDFKParent decision table
VersionNumberINTIncremental version (1, 2, 3...)
HitPolicyVARCHAR(50)First, Unique, Collect, or Priority
InputColumnsTEXTJSON array of input column definitions
OutputColumnsTEXTJSON array of output column definitions
CreatedAtDATETIMETimestamp
CreatedByGUIDFKUser who created
ActivatedAtDATETIMENULL until activated
ActivatedByGUIDFKUser who activated
DescriptionVARCHAR(500)Version notes
SignedHashVARCHAR(256)SHA256 of table structure

Relationships:

  • FK to DecisionTables (TableId)
  • FK to MUsers (CreatedBy, ActivatedBy)
  • 1:N to DecisionTableCells

Indexes: (TableId, VersionNumber), (ActivatedAt DESC)

DecisionTableCells

ColumnTypeKeyDescription
CellIdGUIDPKUnique cell identifier
VersionIdGUIDFKDecision table version
RowIndexINTRow number (0-based)
ColumnNameVARCHAR(256)Column identifier (input or output)
CellValueTEXTFEEL expression or literal value
CellTypeVARCHAR(50)Input, Output
IsDisabledBITRow disabled (skipped during evaluation)
DisplayOrderINTVisual row ordering

Relationships:

  • FK to DecisionTableVersions (VersionId)

Indexes: (VersionId, RowIndex), (VersionId, ColumnName)


Workflow Execution Tables

MJsonWorkflows

ColumnTypeKeyDescription
WorkflowIdGUIDPKUnique workflow identifier
TenantIdVARCHAR(256)FKMulti-tenant owner
NameVARCHAR(256)Workflow name
DefinitionTEXTBPMN 2.0 XML definition
VersionINTCurrent version
CreatedAtDATETIMECreation timestamp
CreatorUserIdGUIDFKCreator user

Relationships:

  • FK to Tenants (TenantId)
  • FK to MUsers (CreatorUserId)
  • 1:N to MJsonWorkflowExecutions

MJsonWorkflowExecutions

ColumnTypeKeyDescription
ExecutionIdGUIDPKUnique execution record
WorkflowIdGUIDFKParent workflow
TenantIdVARCHAR(256)FKMulti-tenant context
StatusVARCHAR(50)Running, Completed, Failed, Compensated
StartedAtDATETIMEExecution start timestamp
CompletedAtDATETIMECompletion timestamp (if finished)
ContextDataTEXTJSON FactBag state at execution end
ErrorMessageTEXTError details if failed
ExecutionModeVARCHAR(50)AllOrNothing, BestEffort, CompensateOnFailure

Relationships:

  • FK to MJsonWorkflows (WorkflowId)
  • FK to Tenants (TenantId)

Indexes: (WorkflowId, StartedAt DESC), (Status, CompletedAt)


Multi-Tenancy Tables

Tenants

ColumnTypeKeyDescription
TenantIdVARCHAR(256)PKUnique tenant identifier (e.g., "acme-corp")
DisplayNameVARCHAR(256)Human-readable tenant name
StatusVARCHAR(50)Active, Suspended, Deleted
IsolationModeVARCHAR(50)SharedSchema, SeparateSchema, SeparateDatabase
SchemaNameVARCHAR(256)For SeparateSchema: PostgreSQL schema name (e.g., "acme_corp")
DatabaseConnectionStringTEXTFor SeparateDatabase: full connection string
CreatedAtDATETIMERegistration timestamp
CreatedByGUIDFKAdmin user who created
TierVARCHAR(50)Free, Starter, Professional, Enterprise

Relationships:

  • 1:N to TenantQuotas
  • 1:N to TenantIsolationModes (audit trail of mode changes)
  • FK to MUsers (CreatedBy)

Indexes: (Status, CreatedAt), (Tier, CreatedAt)

TenantQuotas

ColumnTypeKeyDescription
QuotaIdGUIDPKUnique quota record
TenantIdVARCHAR(256)FKTenant owner
QuotaTypeVARCHAR(50)RuleExecutionsPerDay, ConcurrentExecutions, ApiRequestsPerMinute, etc.
LimitINTMaximum allowed (-1 = unlimited)
CurrentUsageINTCurrent usage in period (cache value)
PeriodKeyVARCHAR(50)Time period (yyyyMMddHHmmss, yyyyMMddHHmm, etc.)
ResetAtDATETIMENext reset timestamp
UpdatedAtDATETIMELast update timestamp

Quota Types (13 total):

  • MaxRulesPerTenant
  • MaxRuleExecutionsPerDay
  • MaxConcurrentExecutions
  • MaxDecisionTables
  • MaxJsonWorkflows
  • MaxStorageMB
  • MaxApiRequestsPerMinute
  • MaxRuleEvaluationsPerSecond
  • MaxWorkflowExecutionsPerHour
  • MaxRuleComplexity
  • MaxWorkflowSizeKB
  • MaxExecutionTimeMs
  • MaxMessagesPerDay

Relationships:

  • FK to Tenants (TenantId)

Indexes: (TenantId, QuotaType), (PeriodKey, ResetAt)

TenantIsolationModes

ColumnTypeKeyDescription
RecordIdGUIDPKUnique record
TenantIdVARCHAR(256)FKTenant being changed
OldModeVARCHAR(50)Previous isolation mode
NewModeVARCHAR(50)New isolation mode
ReasonTEXTChange reason
RequestedAtDATETIMETimestamp of request
RequestedByGUIDFKAdmin user
ApprovedAtDATETIMEApproval timestamp (if approved)
ApprovedByGUIDFKApprover user
StatusVARCHAR(50)Requested, Approved, Applied, Failed

Relationships:

  • FK to Tenants (TenantId)
  • FK to MUsers (RequestedBy, ApprovedBy)

Indexes: (TenantId, RequestedAt DESC), (Status, ApprovedAt)


Canary Deployment Tables

CanaryRollouts

ColumnTypeKeyDescription
RolloutIdGUIDPKUnique canary rollout ID
RuleSetIdGUIDFKRuleset being rolled out
TenantIdVARCHAR(256)FKTenant context
VersionNumberINTVersion being canary'd
StatusVARCHAR(50)Active, Promoted, RolledBack
TargetPercentageINTPercentage of traffic (1-100)
TargetTenantIdsTEXTJSON array of specific tenants (null = all tenants)
StartedAtDATETIMERollout start timestamp
StartedByGUIDFKUser who initiated
PromotedAtDATETIMEPromotion timestamp (if promoted)
PromotedByGUIDFKUser who promoted
RolledBackAtDATETIMERollback timestamp (if rolled back)
RolledBackByGUIDFKUser who rolled back
RollbackReasonTEXTReason for rollback
MetricsJsonTEXTEvaluation metrics (error rate, latency)
CreatedAtDATETIMERecord creation timestamp

Relationships:

  • FK to RuleSets (RuleSetId)
  • FK to Tenants (TenantId)
  • FK to MUsers (StartedBy, PromotedBy, RolledBackBy)

Indexes: (RuleSetId, Status, StartedAt DESC), (TargetPercentage), (PromotedAt DESC)


Authorization Tables

AuthRules

ColumnTypeKeyDescription
RuleSetIdGUIDPKUnique auth rule ID
TenantIdVARCHAR(256)FKMulti-tenant owner
NameVARCHAR(256)Auth rule name (normalized to auth/{name})
SourceCodeTEXTRule source (C# or FEEL expression)
VersionINTCurrent version number
ActiveVersionIdGUIDFKCurrently active version
CreatedAtDATETIMECreation timestamp
CreatedByGUIDFKCreator user
UpdatedAtDATETIMELast modification timestamp
UpdatedByGUIDFKUser who last modified

Relationships:

  • 1:N to RuleSetVersions (reuses same version table)
  • FK to Tenants (TenantId)
  • FK to MUsers (CreatedBy, UpdatedBy)

Indexes: (TenantId, Name), (ActiveVersionId), (CreatedAt DESC)


Audit Trail Tables

GlobalAuditLog

ColumnTypeKeyDescription
AuditIdGUIDPKUnique audit entry
TenantIdVARCHAR(256)FKMulti-tenant owner
EntityTypeVARCHAR(256)Entity being audited (RuleSet, DecisionTable, Tenant, etc.)
EntityIdGUIDFKID of entity
ActionTypeVARCHAR(50)Create, Read, Update, Delete, Activate, Execute
ActionDetailTEXTJSON with old/new values (for Update)
PerformedByGUIDFKUser who performed action
PerformedAtDATETIMEAction timestamp
CorrelationIdVARCHAR(256)Request correlation ID
IpAddressVARCHAR(50)Client IP address
UserAgentTEXTHTTP User-Agent header

Relationships:

  • FK to Tenants (TenantId)
  • FK to MUsers (PerformedBy)

Indexes: (TenantId, PerformedAt DESC), (EntityType, EntityId, PerformedAt), (CorrelationId), (PerformedBy, PerformedAt)


License Server Database (Separate Instance)

The license-server maintains its own PostgreSQL database (muonroi_licenses) for license key and activation management.

LicenseKeys

ColumnTypeKeyDescription
LicenseKeyIdGUIDPKLicense key record ID
LicenseKeyVARCHAR(256)Key format: MRR-{24-byte base64url} (unique, indexed)
LicenseIdVARCHAR(256)Internal ID: lic_{GUID}
OrganizationIdVARCHAR(256)Customer organization identifier
OrganizationNameVARCHAR(256)Human-readable org name
TierVARCHAR(50)Free, Licensed, Enterprise
FeaturesTEXTJSON array of enabled features
ValidFromDATETIMEValidity start date
ValidUntilDATETIMEExpiration date
MaxActivationsINTMaximum allowed activations (-1 = unlimited)
CurrentActivationsINTCurrent active count
StatusVARCHAR(50)Active, Suspended, Revoked, Expired
CreatedAtDATETIMEIssue timestamp
CreatedByVARCHAR(256)Admin who issued
RevokedAtDATETIMERevocation timestamp (if revoked)
RevokedByVARCHAR(256)Admin who revoked
RevocationReasonTEXTReason for revocation
SignedHashVARCHAR(256)SHA256 signature for integrity

Feature Values (by Tier):

  • Free: [api.validate]
  • Licensed: [vsix.publish, vsix.watch, vsix.explorer, api.validate, cp.publish]
  • Enterprise: [*] (all features enabled)

Indexes: (LicenseKey), (Status, ValidUntil), (CreatedAt DESC), (RevokedAt DESC)

Activations

ColumnTypeKeyDescription
ActivationIdGUIDPKUnique activation record
LicenseKeyIdGUIDFKParent license key
ProofIdGUIDActivation proof identifier (sent in heartbeats)
MachineFingerprintVARCHAR(256)SHA256(machine name + OS + app name)
HardwareIdVARCHAR(256)Hardware identifier for offline mode
ActivatedAtDATETIMEActivation timestamp
LastHeartbeatAtDATETIMEMost recent heartbeat
ExpiresAtDATETIMEProof expiration (if not renewed)
CurrentNonceVARCHAR(256)Server-side nonce for heartbeat chain
StatusVARCHAR(50)Active, Revoked, Expired

Relationships:

  • FK to LicenseKeys (LicenseKeyId)

Indexes: (LicenseKeyId, Status), (MachineFingerprint), (LastHeartbeatAt DESC)

HeartbeatRecords

ColumnTypeKeyDescription
HeartbeatIdGUIDPKUnique heartbeat record
ActivationIdGUIDFKActivation being heartbeat'd
LicenseIdVARCHAR(256)FKLicense identifier
ProofIdGUIDProof being renewed
TimestampDATETIMEHeartbeat timestamp
NonceUsedVARCHAR(256)Nonce from request
NonceNewVARCHAR(256)New nonce issued
IsRevokedBITWhether revocation detected
GraceUntilUtcDATETIMERevocation grace period end
ClientVersionVARCHAR(50)Client app version
StatusVARCHAR(50)Success, RejectedRevoked, RejectedExpired

Relationships:

  • FK to Activations (ActivationId)

Indexes: (ActivationId, Timestamp DESC), (Timestamp DESC), (IsRevoked, GraceUntilUtc)


Key Design Patterns

Multi-Tenancy Pattern

  • All user-defined tables implement ITenantScoped (TenantId column)
  • EF Core query filters automatically add: e => e.TenantId == TenantContext.CurrentTenantId || TenantContext.CurrentTenantId == null
  • Tenant isolation via:
    • SharedSchema: row-level filtering (dbo schema)
    • SeparateSchema: PostgreSQL SearchPath per tenant (tenant-specific schema)
    • SeparateDatabase: separate connection string and database

Versioning Pattern

  • RuleSetVersions, DecisionTableVersions store all historical versions
  • Active version tracked via parent table's Version column and ActivatedAt timestamp
  • Immutable version records enable audit trail and rollback

Approval Workflow Pattern

  • RuleSetApprovals tracks submission → approval → activation chain
  • Maker-Checker rule: SubmittedBy ≠ ApprovedBy enforced at application layer
  • Signatures (SignedHash, Signature) prevent tampering during approval

Audit Trail Pattern

  • RuleSetAudit and GlobalAuditLog track all changes by action type and user
  • CorrelationId links related operations across distributed requests
  • Immutable design: audit records are never deleted or modified