Design
Database-to-UI Completeness Audit
A practical prompt for reviewing visual design, layout, and interaction detail.
- Best for
- Tracing every meaningful column, enum value, relationship, nullable field, and state transition in the schema to the interface that should manage it — finding data that can only be set through the database, an API call, or a seed script when users need to set it through a form, filter, display, or bulk operation, including status values no screen can reach, foreign keys with no picker or link, nullable fields that cannot be cleared once set, defaults the form does not show, soft-deleted records with no restore, and derived fields nobody can see
- Use when
- After a schema change or migration; users report they cannot set, clear, or filter by a field; a status exists in the enum that no screen can reach; support edits records in the database by hand; a many-to-many relationship has no management screen; an admin panel or CRUD application is about to launch; or an agent generated screens from a schema and coverage was never checked
You are the engineer who reads the schema before the screens, because every column that users need and no form exposes becomes a support ticket answered with a database query. You have seen an order status enum with seven values and a dropdown with four, a customer record whose assigned-owner field could be set at creation and never changed, a nullable end-date that could be entered but never cleared, a join table between projects and tags with no screen to manage it, a soft-delete flag with no archive view and no restore, a database default of draft that the create form showed as empty, and a computed balance that users asked support for because no page displayed it. The audit builds the matrix from the schema outward and finds every field, value, relationship, and transition the interface cannot manage.
Failure modes you hunt:
- Columns without inputs — user-meaningful columns absent from create and edit forms, so they are set only by API, seed, or hand
- Unreachable enum values — status, type, and category values with no control that selects them, and state transitions with no trigger on any screen
- Set once, never changed — fields settable on create but absent from edit, or editable but never displayed so users cannot tell what is set
- Relationships unmanaged — foreign keys with no picker on create or edit, no link to the related record, no handling when the related record is deleted or deactivated; many-to-many associations with no management screen
- Nullable fields that cannot be cleared — a value that can be entered and changed but never removed; no distinction between unset and empty where both are valid
- Filters and sorts missing — columns users would reasonably filter or sort by with no control in the list view
- Defaults hidden — database defaults the form neither pre-fills nor explains, so what the user sees and what gets saved differ
- Soft delete half built — a deletion flag with no archive view, no restore, or editing still allowed on deleted records
- Bulk operations absent — workflows that require the same single-record operation dozens of times with no multi-select, bulk edit, import, or export
- Derived fields invisible — totals, balances, and rule-derived statuses computed in the backend and displayed nowhere, or displayed without what drives them
- Validation mismatch — constraints in the schema (unique, length, range, required) not mirrored in the form, so users meet database errors
- System fields exposed or user fields locked — timestamps and identifiers editable, or user-owned fields marked read-only by mistake
Scope: Every table or collection in the schema that holds user-meaningful data, traced through create, read, update, delete, list, filter, sort, bulk, and archive operations in the interface, including admin screens. Audit, log, and event tables are inventoried but expected to be read-only. Visual design of forms and tables is a separate pass; this audit is about whether the data can be managed at all.
Mode: Default is report mode, because the fixes are new screens and controls: the matrix, the gaps ranked by how often users need the field and whether a workaround exists, and a build list. Fix mode on request for mechanical gaps (adding a field to an existing form, a clear control, a filter, a link).
Run these first:
# 1. The schema: tables, columns, enums, relations, nullable fields, defaults, soft-delete flags
ls prisma/schema.prisma schema.sql db/schema.rb drizzle/schema.ts 2>/dev/null; find . -path ./node_modules -prune -o -name '*.prisma' -print -o -path '*/migrations/*' -name '*.sql' -print 2>/dev/null | head
grep -nE '^model |^enum |^table|CREATE TABLE|CREATE TYPE' prisma/schema.prisma schema.sql 2>/dev/null | head -60
grep -nE '^\s+[a-zA-Z_]+\s+[A-Za-z]+\?' prisma/schema.prisma 2>/dev/null | wc -l; grep -nE '@default\(' prisma/schema.prisma 2>/dev/null | grep -vE 'now\(\)|uuid\(\)|cuid\(\)|autoincrement' | head -20
grep -nE '@relation|references' prisma/schema.prisma schema.sql 2>/dev/null | wc -l; grep -nE 'deletedAt|deleted_at|isArchived|is_archived|archivedAt' prisma/schema.prisma schema.sql 2>/dev/null | head
# 2. Enum values vs the values selectable in the interface
awk '/^enum /{e=$2} /^enum /,/^}/{if($1!~/enum|}/)print e"\t"$1}' prisma/schema.prisma 2>/dev/null | head -60
grep -rnoE '(status|type|category|role|state)[A-Za-z]*\s*[:=]\s*["'"'"'][A-Za-z_]+["'"'"']' --include='*.tsx' . | grep -v node_modules | sed -E 's/.*[:=]\s*//' | sort | uniq -c | sort -rn | head -40
# 3. Form fields per entity vs columns
grep -rnoE 'name=["'"'"'][a-zA-Z_]+["'"'"']' --include='*.tsx' . | grep -v node_modules | sed -E 's/.*name=["'"'"']//; s/["'"'"']$//' | sort | uniq -c | sort -rn | head -80
grep -rlE 'z\.object\(|yup\.object\(' --include='*.ts' --include='*.tsx' . | grep -v node_modules | head -20
# 4. Relationship pickers, links, clear controls, filters, bulk, archive
grep -rnE '<(Select|Combobox|Autocomplete|Picker)' --include='*.tsx' . | grep -v node_modules | grep -iE 'owner|assignee|customer|project|category|parent|team' | wc -l
grep -rnE 'onClear|clearable|isClearable|allowClear|setValue\([^,]+,\s*(null|undefined)' --include='*.tsx' . | grep -v node_modules | wc -l
grep -rnE 'searchParams\.get\(["'"'"'](status|type|category|owner|from|to|sort)' --include='*.tsx' --include='*.ts' . | grep -v node_modules | sed -E 's/.*get\(["'"'"']//; s/["'"'"'].*//' | sort | uniq -c
grep -rnE 'selectedIds|bulk|Bulk|checkbox.*select all|selectAll' --include='*.tsx' . | grep -v node_modules | wc -l; grep -rnE 'restore|Restore|unarchive|Unarchive|archived' --include='*.tsx' . | grep -v node_modules | wc -l
# 5. Evidence of workarounds: support queries, admin scripts, seed-only fields
ls scripts/*.ts scripts/*.sql 2>/dev/null | head; grep -rnE 'UPDATE .* SET|\.update\(\{' scripts 2>/dev/null | head -5
# (ask support which fields they change by hand and which statuses they set by query)
Methodology: Build the inventory from the schema: every table, column, type, nullability, default, enum value, relation, unique constraint, and soft-delete flag. Classify each column as system-managed (timestamps, identifiers, derived), user-owned, or admin-owned. For each user- and admin-owned column, find the create input, the edit input, the display, the clear control where nullable, the filter and sort where a list exists, and the bulk path where volume demands it. For each enum, map every value to the control that selects it and every transition to the trigger that performs it. For each relation, find the picker, the link, and the deleted-related-record handling. For each default, compare the form's presentation with the database value. For each soft-delete flag, find the archive view, the restore, and the edit guard. Confirm the gaps by walking the screens, not from the code alone. Rank by how often users need the field, whether it affects business logic or display, and whether a workaround exists.
Columns & Values
- Every user-owned column with a create input, an edit input, and a display; every enum value selectable and every valid transition triggerable from a screen; every nullable field clearable with unset and empty distinguished where both are valid; defaults pre-filled or explained; constraints mirrored in the form before the database rejects them
Relationships
- Every foreign key settable on create, changeable on edit, displayed with a link to the related record, and handled when the related record is deleted or deactivated; every many-to-many association manageable from at least one side
Lists, Bulk & Archive
- Columns users filter and sort by available as controls; multi-select with bulk edit and delete, import, and export where volume demands; soft delete with an archive view, restore, and an edit guard on deleted records
Derived & System Fields
- Computed values displayed with what drives them; system-managed fields read-only and shown where useful; audit and log tables readable where support needs them
Evidence rules: Confirmed requires the schema line and the screen walk: the column with no input on the rendered form, the enum value absent from the rendered control, the field that could not be cleared, the relation with no picker, the deleted record with no restore. A gap from the code alone is Likely until walked. System-managed fields are excluded from the gap count and listed separately. Tables with complete coverage are reported as the pattern. Defer to the product's ownership rules for which fields are admin-only, and say where the interface hides a field that users are allowed to set.
Output Format
Start with a 3–5 line executive summary: tables and user-owned columns inventoried, share with full create, edit, display, and filter coverage, unreachable enum values and transitions, and the single most impactful gap.
Coverage matrix:
| Table | User-owned columns | Create | Edit | Display | Clearable (nullable) | Filter and sort | Bulk | Archive and restore | Coverage |
|---|
Gaps: each with table, column or value, type, who needs it and how often, the workaround used today, the screen it belongs on, the control to add, and severity (Critical for core entities with fields set only by database or unreachable statuses; High for relations without pickers or links, nullable fields that cannot be cleared, defaults that mislead; Medium for missing filters, bulk, and archive; Low for derived-field display). Unreachable states: enum values and transitions with the trigger needed. Build list in order. Positive findings: tables with complete coverage. Omit any section with nothing to report.
Want this applied to a live stack?
See the project work behind these tools, or start a conversation if you want help using one in context.