Validation
Sovrium validates data at two layers: config-time (the schema is decoded with Effect Schema when the app boots, catching invalid definitions) and runtime (records are checked against field rules, constraints, and permissions on every write). This page summarizes the validation surface for tables.
Field-Level Validation
Many field types carry built-in validation derived from their properties:
| Rule | Applies to | Effect |
|---|---|---|
required |
All fields | Value must be present on every record. |
unique |
All fields | No two records may share the value. |
min / max |
integer, decimal, currency, percentage |
Value must fall within the inclusive range. |
precision |
decimal (1–10), currency/percentage (0–10) |
Restricts decimal places. |
currency (ISO 4217) |
currency |
Must be a valid three-letter code. |
maxLength |
rich-text |
Caps character length. |
maxSelections |
multi-select |
Caps choices; cannot exceed the number of options. |
options |
single-select, multi-select, status |
Values must come from the declared option list. |
| format validation | email, url |
Must match RFC 5322 / a valid absolute URL. |
targetLanguage |
ai-translate |
Must be an ISO 639-1 code (optionally region-suffixed). |
categories / tags |
ai-categorize / ai-tag |
Minimum 2 entries, no duplicates. |
Table-Level Validation (Config Time)
When the schema is decoded, Sovrium enforces structural rules and rejects invalid configurations with descriptive errors:
- Field names and IDs must be unique within a table.
- Field & table names must match
^[a-z][a-z0-9_]*(after sanitization) and stay within 63 characters. - Index names and constraint names must be unique within the table and match the identifier pattern.
- Primary key fields must reference real fields.
- Indexes, permissions, views, webhooks are checked so their field references name actual table fields.
count/rollup/lookupfields must reference an existingrelationshipfield in the same table.- Formula fields are validated for correct field references.
- Webhook names must be unique, and
payloadfield selectors must name real fields (the implicitidis always valid).
CHECK Constraints
Use CHECK constraints for cross-field and conditional rules that field-level validation cannot express:
constraints:
- { name: chk_end_after_start, check: 'end_date > start_date' }
- { name: chk_active_members_have_email, check: '(is_active = false) OR (email IS NOT NULL)' }
Uniqueness & Integrity
- Single-field uniqueness:
field.unique: trueor a top-levelunique: [{ fields: [x] }]. - Composite uniqueness: top-level
unique: [{ fields: [a, b] }](becomes a unique index) or a unique index. - Partial uniqueness: a unique index with a
whereclause (e.g. unique slug only among non-deleted rows). - Relational integrity:
relationshipfields create foreign keys withonDelete/onUpdateactions; composite references useforeignKeys.
Fail fast at boot. Because configuration is decoded with Effect Schema, a malformed table definition (duplicate field name, dangling relationship reference, invalid currency code, out-of-range precision) fails when the app starts — not silently at runtime. Run sovrium validate app.yaml to check a config before deploying.