feat(form-builder): form_field_configs relational table + non-validation key split + drop validation_rules JSON columns
This commit is contained in:
@@ -1,10 +1,26 @@
|
||||
# Crewli — Core Database Schema
|
||||
|
||||
> Source: Design Document v1.3 — Section 3.5
|
||||
> **Version: 2.3** — Updated April 2026
|
||||
> **Version: 2.4** — Updated April 2026
|
||||
>
|
||||
> **Changelog:**
|
||||
>
|
||||
> - v2.4: WS-5b completion — `form_field_configs` relational table lands
|
||||
> alongside `form_field_validation_rules` (both from WS-5b). Holds
|
||||
> non-validation per-field configuration (`tag_categories`,
|
||||
> `storage_disk`) that would have polluted the validation-rules table
|
||||
> had it stayed there. Same polymorphic-morph pattern (owner aliases
|
||||
> `form_field` / `form_field_library`, reused from WS-5a). The
|
||||
> `validation_rules` JSON columns on `form_fields` and
|
||||
> `form_field_library` are **dropped** by this migration pair — the
|
||||
> entire pre-WS-5b bag now lives relationally across two tables.
|
||||
> Schema snapshots gain a parallel top-level `configs` key on each
|
||||
> field entry; historical snapshots pre-WS-5b remain immutable with
|
||||
> the legacy merged shape. Breaking frontend contract: portal +
|
||||
> organizer SPAs switched from reading `field.validation_rules.min`
|
||||
> etc. to the canonical post-WS-5b keys (`min_value`, `max_length`,
|
||||
> `max_selected`, etc.) per ARCH v1.6 §17.5 and addendum Q3 WS-5b
|
||||
> Uitvoering.
|
||||
> - v2.3: WS-5b (partial) — `form_field_validation_rules` relational table
|
||||
> replaces the `validation_rules` JSON on `form_fields` and
|
||||
> `form_field_library`. Typed `rule_type` column + per-rule `parameters`
|
||||
@@ -1989,7 +2005,7 @@ that aggregates the user's submitted, non-test `form_submissions`.
|
||||
| `is_active` | bool | default: true |
|
||||
| `created_at`, `updated_at` | timestamps | |
|
||||
|
||||
**Relations:** `belongsTo` organisation; `hasMany` form_fields via `library_field_id`; `morphMany` form_field_bindings as `owner`; `morphMany` form_field_validation_rules as `owner`
|
||||
**Relations:** `belongsTo` organisation; `hasMany` form_fields via `library_field_id`; `morphMany` form_field_bindings as `owner`; `morphMany` form_field_validation_rules as `owner`; `morphMany` form_field_configs as `owner`
|
||||
**Indexes:** `(organisation_id, field_type)`, `(organisation_id, is_active)`
|
||||
**Unique constraint:** `UNIQUE(organisation_id, slug)`
|
||||
**Global scope:** `OrganisationScope`
|
||||
@@ -2045,7 +2061,7 @@ that aggregates the user's submitted, non-test `form_submissions`.
|
||||
| `created_at`, `updated_at` | timestamps | |
|
||||
| `deleted_at` | timestamp nullable | Soft delete preserves history |
|
||||
|
||||
**Relations:** `belongsTo` schema, section (nullable), libraryField; `hasMany` form_values; `morphMany` form_field_bindings as `owner`; `morphMany` form_field_validation_rules as `owner`
|
||||
**Relations:** `belongsTo` schema, section (nullable), libraryField; `hasMany` form_values; `morphMany` form_field_bindings as `owner`; `morphMany` form_field_validation_rules as `owner`; `morphMany` form_field_configs as `owner`
|
||||
**Indexes:** `(form_schema_id, sort_order)`, `(form_schema_id, is_filterable)`, `(library_field_id)`, `(form_schema_id, slug)`
|
||||
**Soft delete:** yes
|
||||
|
||||
@@ -2124,6 +2140,32 @@ that aggregates the user's submitted, non-test `form_submissions`.
|
||||
|
||||
---
|
||||
|
||||
### `form_field_configs`
|
||||
|
||||
> Parallel sibling to `form_field_validation_rules` — holds
|
||||
> non-validation per-field configuration (tag-picker category filters,
|
||||
> upload disk selection). Keeps `form_field_validation_rules`
|
||||
> semantically pure (ARCH-FORM-BUILDER.md §17.5; addendum Q3 strict-
|
||||
> enterprise decision). Same polymorphic-morph pattern as the binding
|
||||
> and validation-rules tables.
|
||||
|
||||
| Column | Type | Notes |
|
||||
| -------------- | ----------------- | ---------------------------------------------------------------------- |
|
||||
| `id` | ULID | PK |
|
||||
| `owner_type` | string(40) | morph alias: `form_field` or `form_field_library` |
|
||||
| `owner_id` | ULID | parent row |
|
||||
| `config_type` | string(40) | `FormFieldConfigType` case (`tag_categories`, `storage_disk`) |
|
||||
| `parameters` | JSON | Per-config-type bag (`{"categories":[string]}`, `{"disk":string}`) |
|
||||
| `created_at`, `updated_at` | timestamps | |
|
||||
|
||||
**Relations:** `morphTo` owner (`form_field` or `form_field_library`)
|
||||
**Indexes:** `(config_type)`, `(owner_type, owner_id)`
|
||||
**Unique constraint:** `UNIQUE(owner_type, owner_id, config_type)`
|
||||
**Global scope:** `FormFieldConfigScope` — third sibling in the scope family (after `FormFieldBindingScope` and `FormFieldValidationRuleScope`), same UNION shape. Escape hatch: `withoutGlobalScope(FormFieldConfigScope::class)`.
|
||||
**Soft delete:** no — configs are current state, not audit
|
||||
|
||||
---
|
||||
|
||||
### `form_submissions`
|
||||
|
||||
> One submission per `(schema, subject)` in `single` / `draft_single`
|
||||
|
||||
Reference in New Issue
Block a user