| view_id | string (UUID) | ✅ Yes | gen_random_uuid() default; UNIQUE | any valid UUID | Public stable identifier for this view. Exposed as the JSON:API id. Stable across renames — links to a saved view remain valid as long as the view exists. |
| name | string | ✅ Yes | max length 255 | any non-empty string ≤ 255 chars | Human-readable display name for the view, shown in the view switcher tab and in the views list. |
| root | string | ✅ Yes | max length 100; must match a value in the recordsQuerySchema root enum | see DATA_VIEW_ROOTS (e.g. ‘invoices’, ‘companies’, ‘people’, ‘transactions’) | The record root this view targets. Immutable after creation. A view for ‘invoices’ cannot be reused on ‘companies’. |
| columns | jsonb (ColumnConfig[]) | ⚪ No | default ’[]’; each element: field (string[]), order (number), optional width (px), alias, icon, pinned (‘left’|‘right’) | array of ColumnConfig objects | Ordered list of visible column configurations. Defines which fields appear, their display order, pixel width, optional alias, and pin side. An empty array means the root’s default column set is used. |
| sort | jsonb (SortConfig[]) | ⚪ No | default ’[]’; each element: field (string[]), direction (‘asc’|‘desc’) | array of SortConfig objects | Ordered list of sort rules applied to the query. Multiple entries are applied in array order (primary, secondary, etc.). |
| filters | jsonb (FilterConfig[]) | ⚪ No | default ’[]’; each element: field (string[]), operator (FilterOperator), value, optional conjunction (‘and’|‘or’) | array of FilterConfig objects; operator one of: eq, neq, gt, gte, lt, lte, contains, not_contains, starts_with, ends_with, is_null, is_not_null, in, not_in, between | Active filter conditions persisted with this view. Applied when the view is loaded. The conjunction field chains consecutive filters; defaults to ‘and’. |
| layout_type | string | ⚪ No | max length 20; default ‘table’; CHECK chk_workspace_views_layout_type enforces allowed values | ’table’ | ‘kanban’ | ‘calendar’ | ‘gallery’ | ‘chart’ | ‘list’ | ‘graph’ | The UI layout mode for this view. Determines which renderer and layout_config shape apply. The CHECK constraint is authoritative; the LAYOUT_TYPES constant in @wellapp/shared mirrors it. |
| layout_config | jsonb (LayoutConfig) | ⚪ No | default ’{}’; shape depends on layout_type (TableLayoutConfig | KanbanLayoutConfig | CalendarLayoutConfig | GalleryLayoutConfig | ChartLayoutConfig | ListLayoutConfig | Record<string, never>) | layout-type-specific config object or empty object | Layout-specific presentation settings. Contains ONLY layout rendering preferences (row height, card size, chart type, etc.), NOT field selection — that lives in display_fields. Ignored by the renderer when layout_type changes until explicitly set. |
| display_fields | jsonb (DisplayFieldConfig[]) | ⚪ No | default ’[]’; each element: fieldId (dot-path string), visible (bool), order (number), optional displayType, skillId, skillRenderHint, width, role (LayoutFieldRole) | array of DisplayFieldConfig objects; role one of: title, subtitle, group_by, sub_group, date, end_date, measure, thumbnail, badge, color, assignee, status, detail | Field visibility and rendering configuration for non-table layouts (kanban, calendar, gallery, chart, list, graph). Each entry declares what data appears on a card or tile, in what position, and with what display override. |
| group_by | jsonb (string[] | null) | ⚪ No | nullable; null means no grouping | array of dot-path field strings, or null | Field paths to group records by in the current view. An empty array and null are both treated as ‘no grouping’. Used by the kanban and grouped-table modes. |
| is_default | boolean | ⚪ No | default false; no DB-level unique constraint — enforcement is at the service layer (WorkspaceViewService sets is_default=false on sibling views when one is promoted) | true | false | When true, this view is loaded automatically when a user navigates to the record root within the workspace. Only one view per (workspace, root) should be default at any given time; the service ensures this invariant on every PATCH that sets is_default=true. |
| created_at | 🔒 system (timestamp) | ✅ Yes | set on create via onCreate hook; not nullable | ISO 8601 datetime | Timestamp of view creation. Set once by the MikroORM onCreate lifecycle hook; never updated. |
| updated_at | 🔒 system (timestamp) | ⚪ No | set on create and on every update via onCreate/onUpdate hooks; nullable in schema | ISO 8601 datetime | Timestamp of the last mutation. Refreshed on every PATCH by the MikroORM onUpdate lifecycle hook. Null only if the entity was never flushed after initial creation (should not occur in production). |
| deleted_at | 🔒 system (timestamp | null) | ⚪ No | nullable; null = active row | ISO 8601 datetime or null | Soft-delete timestamp. Set when the user calls DELETE /workspaces/:id/views/:viewId. Active view queries filter deleted_at IS NULL. A soft-deleted view is not accessible via the API but its data is preserved for audit and recovery. |