View/Block System Cleanup (v3)
Unified workspace editor, response-integrated field blocks, container removal, block config schemas, and consistent editing experience across admin and entity detail pages.
Problem
The view/block system has grown organically and is now scattered across multiple disconnected subsystems:
-
The default entity detail view is hardcoded — bento layout, notes, responses, container children, sidebar are all hardcoded JSX, not driven by the view/block system. Custom views exist as separate tabs alongside this hardcoded default, creating two completely separate codepaths.
-
The editor is broken and inconsistent — admin has a basic flat-block editor that doesn't support workspace layouts. The detail page has a ViewEditorSheet that overflows, doesn't scroll, and can't configure blocks. Script-created views can't be edited because the config shape isn't validated. Two different editor UIs, neither works well.
-
Responses are not integrated with views — the ResponsesTab is hardcoded on the default view. The response-form block exists but is standalone. There's no "view as form" pattern where field blocks become editable inputs that create response submissions with provenance tracking.
-
Container is a confusing separate concept — a toggle on entity types that hardcodes a ContainerChildrenSection on the detail page. Containers are just entities with connections — this should be emergent from adding connection-list/child-entity-list blocks to views, not an explicit setting.
-
Block types lack configuration — most blocks have no config UI. Clicking settings does nothing. No typed schemas for block configs, so validation and migration are impossible.
Solution
Mental Model
Three layers, clearly separated:
| Layer | What it is | Editable | Stored |
|---|---|---|---|
| Default view | Auto-generated bento showing all entity data | No | Not in views table — rendered from schema |
| Workspace views | Block-driven layouts designed per entity type | Yes, via workspace editor | views table, page_type: "workspace" |
| Entity overrides | Fork of a workspace view customized for one entity | Yes, via same editor | views table with entity_id set |
The default view is the safety net — always available, shows everything. When workspace views exist, they're shown by default. The default view is accessible via "View All Properties" in the entity dropdown or as a fallback when no custom views exist.
Two Edit Modes
The workspace editor supports two distinct modes with clear visual separation:
Layout mode — rearranging, adding, removing, resizing, and configuring blocks. This changes the view structure. Triggered by "Customize Layout" in the dropdown. Saves affect the view record.
Response mode — filling in field values using the view as a form. This creates response submissions. Triggered by "Edit Values" or a pencil icon on the view. Saves create an entity_response record following the OG amble pattern.
These are separate toolbar states. Layout mode shows block handles and the config panel. Response mode shows editable inputs on field blocks and a "Save Response" button. A user cannot be in both modes simultaneously.
Response Mode Details
When a user enters response mode on a workspace view:
- Field-displaying blocks (field-card, data-table) switch to editable inputs
- Inputs show the current value pre-filled, with response history indicators (who set this, when, confidence)
- User edits values across the view — it looks like a form but follows the view's designed layout
- "Save Response" creates an
entity_responsesubmission — not a direct entity update - The submission uses the entity type's default criteria set (auto-synced from schema via
syncDefaultCriteriaSet()). If no default criteria set exists, one is created on-demand from the entity type schema - The response record is populated as:
criteria_set_id: the default criteria set IDcriteria_snapshot: snapshot of the criteria set dimensions at submission timevalues:{ dimensionKey: newValue, ... }for all edited fields (dimension keys map to field names viaCriteriaSetDimension.fieldName)field_meta:{ fieldName: { confidence: "high" } }for each edited field (user-provided values default to high confidence)source:"manual"submitted_by_user: current user IDweighted_score/normalized_score: computed from numeric dimension values and weights (same as existingsubmitEntityResponse()logic)status:"submitted"(or"promoted"if auto-promotion is enabled)
- Auto-promotion is controlled by a new
promotion_modefield oncriteria_sets(see Migration section). Whenpromotion_mode = "auto"(the column default), response values are immediately promoted toentity.contentvia the existingpromote_field_valueRPC. Whenpromotion_mode = "manual", values appear as pending responses needing explicit promotion - View returns to display mode showing updated current values
This integrates with the existing response system — FieldResponseIndicator, promote_field_value RPC, entity.metadata.field_sources all work as-is.
Design
Architecture
1. Workspace Editor Component
One WorkspaceEditor component replaces both the existing visual-editor/ subsystem and the old ViewEditor/ViewEditorSheet. It is used in both admin and entity detail pages.
The existing features/views/components/visual-editor/ directory (EditModeProvider, EditableBlockGrid, SortableBlockWrapper, BlockPalette, BlockConfigPopover, EditModeToolbar) is replaced by the new workspace-editor. Useful patterns from the existing code (dnd-kit integration, edit mode context) are carried forward, but the components are rebuilt for the new architecture.
features/views/components/workspace-editor/
index.tsx — main editor component (layout mode)
editor-canvas.tsx — block grid with dnd-kit drag/drop (replaces EditableBlockGrid)
block-palette.tsx — categorized, scrollable block picker (replaces visual-editor/block-palette.tsx)
block-config-panel.tsx — right sidebar for selected block config (replaces BlockConfigPopover)
editor-toolbar.tsx — layout preset, add block, save/cancel (replaces EditModeToolbar)
sortable-block.tsx — draggable block wrapper with resize handles (replaces SortableBlockWrapper)
response-mode.tsx — response editing overlay (new)Canvas: shows blocks in their layout positions (matching actual view rendering). Blocks are draggable, resizable (full/half/third), removable. Click to select and open config panel.
Block palette: opens from "Add Block" button. Categorized and scrollable (fixing the current overflow bug):
- Data: field-card, data-table, entity-filter, stat-cards
- Collections: connection-list, child-entity-list
- Charts: chart, radar, bubble-chart, ranking
- Content: rich-text, summary, status-banner, activity, notes (new block type)
- Evaluation: response-form
- Advanced: kanban, form-flow, canvas, entity-graph
Block types not shown in the palette (used programmatically or rarely): entity-card, entity-feed, custom, image, video, excalidraw, react-flow, menu, pdf-viewer, table. These still have config schemas but aren't offered in the visual palette.
Config panel: slides open on the right when a block is selected. Renders a typed config form based on block type. Every block has at minimum: label, size. Block-specific fields are driven by Zod schemas.
Save behavior:
- Admin: saves directly to view record (entity-type template)
- Detail page (no entity override): "Save" = fork-on-write, "Save as Default" = update template
- Detail page (entity override exists): "Save" = update override, "Save as Default" = update template
2. New Block Types
Two new block types are added to BLOCK_TYPES in features/blocks/types.ts:
| New Type | Purpose | Config |
|---|---|---|
notes | Rich text notes editor for entity.description | { placeholder?: string } |
documents | Document list with upload capability | { showUpload?: boolean, filterType?: string } |
These are new entries in the BLOCK_TYPES array and require corresponding renderer components in features/blocks/components/.
Existing block types that already cover needed functionality (no new types needed):
connection-list— already exists, gets config for relation type filter and display modechild-entity-list— already exists, gets config for child type filter and display moderesponse-form— already exists, gets config for criteria set selectorfield-card— already exists, gets config for field selector and display modestat-cards— already exists, can show entity metadata
3. Block Config Schemas
Every block type gets a typed Zod config schema in features/blocks/config-schemas.ts. Config schemas are defined for all 29 existing block types plus the 2 new ones.
// BlockConfig shape (unchanged, but config is now validated per type)
interface BlockConfig {
id: string // auto-generated if missing
type: BlockType // required
label?: string // display name
size?: "full" | "half" | "third"
config: Record<string, unknown> // validated per block type via Zod
}Priority block configs (these get full config panel UIs):
| Block Type | Config Fields |
|---|---|
field-card | fields: string[], displayMode: "value" | "card" | "inline" |
connection-list | relationTypes?: string[], entityTypes?: string[], display: "list" | "grid" | "compact" |
child-entity-list | childTypes?: string[], display: "list" | "table" | "grid", sortBy?: string, sortOrder?: "asc" | "desc" |
response-form | criteriaSetId?: string (defaults to entity type's default) |
notes | placeholder?: string — bound to entity.description, direct entity update (intentional exception to response model; notes are freeform, not structured data) |
documents | showUpload?: boolean, filterType?: string |
chart | chartType: "bar" | "pie" | "line" | "area", dataSourceField?: string, colorThresholds?: object |
data-table | columns?: string[], sortConfig?: object |
rich-text | content?: string |
stat-cards | stats?: StatConfig[] |
radar | dimensions?: string[], showSliders?: boolean |
ranking | field?: string, limit?: number |
Remaining block types (kanban, summary, entity-card, entity-feed, status-banner, activity, custom, image, video, excalidraw, react-flow, bubble-chart, entity-graph, form-flow, canvas, menu, pdf-viewer, entity-filter, table) get a passthrough schema — z.record(z.string(), z.unknown()) — so they validate without blocking. Config panel UIs for these are deferred; the panel shows a JSON editor fallback.
The editor validates and normalizes on load — missing IDs are generated, configs are validated against their type's schema, and a warning badge is shown on blocks that had to be normalized. This fixes the current bug where script-created views can't be edited.
4. Block Data Sources
Each block config explicitly declares where its content comes from:
| Data Source | Blocks | Reads from |
|---|---|---|
| Entity fields | field-card, data-table | entity.content[field] |
| Entity connections | connection-list, child-entity-list | entity_relations table |
| Entity responses | response-form, field-card (response overlay) | entity_responses table |
| Entity metadata | stat-cards, status-banner | entity.metadata |
| Static/configured | rich-text, notes | config.content or entity.description |
| Computed | chart, radar, ranking | Aggregation query |
5. Removals
| What | Action | Reason |
|---|---|---|
| Container tab (admin) | Remove from entity-type-admin-client.tsx | Container is emergent from connections |
ContainerConfig type | Remove from features/entities/types.ts | No longer needed |
isContainerType() helper | Remove from features/entities/types.ts | No longer needed |
getAllowedChildTypes() helper | Remove from features/entities/types.ts | No longer needed |
ContainerChildrenSection | Delete features/entities/components/container-children-section.tsx | Replaced by child-entity-list and connection-list blocks |
ViewEditorSheet | Delete features/views/components/view-editor-sheet.tsx | Replaced by workspace editor |
Old ViewEditor | Delete features/views/components/view-editor.tsx | Replaced by workspace editor |
WorkspaceViewEditor | Delete features/views/components/workspace-view-editor.tsx | Replaced by workspace editor |
visual-editor/ directory | Delete features/views/components/visual-editor/ (all files) | Replaced by workspace-editor/ |
| Container admin tool | Remove manageContainerConfig from features/tools/admin-tools.ts | No longer needed |
| CLAUDE.md reference | Remove manageContainerConfig from admin tools list, reconcile tool count with actual tools in admin-tools.ts | Keep docs accurate |
6. Admin Entity Type Tabs
Simplified from 5 tabs to 4:
| Tab | Content |
|---|---|
| Overview | Name, slug, description, icon, color |
| Fields | Schema editor + field config (extraction, display, connection settings) |
| Criteria Sets | CriteriaSetManager (unchanged) |
| Views | Rebuilt — uses WorkspaceEditor for full workspace view design |
7. Entity Detail Page Flow
No custom views exist:
- Default bento view shown (unchanged)
- "Customize Layout" in dropdown opens workspace editor to create first view
- Save scope based on permissions
Custom views exist:
- First workspace view shown by default
- View tabs if multiple views exist
- "View All Properties" in dropdown shows default bento
- "Customize Layout" enters layout mode on current view (rearrange blocks)
- "Edit Values" enters response mode on current view (fill in field values as a response)
Entity detail hero/dropdown changes:
more-actions-dropdown.tsx: "Customize Layout" always available (creates first view or enters layout mode). "Edit Values" available when a workspace view is active. "View All Properties" shows default bento.entity-detail-hero.tsx: shows mode indicator when in layout or response mode
8. Migration
A new migration adds promotion_mode to criteria_sets:
ALTER TABLE criteria_sets
ADD COLUMN promotion_mode text NOT NULL DEFAULT 'auto'
CHECK (promotion_mode IN ('auto', 'manual'));
COMMENT ON COLUMN criteria_sets.promotion_mode IS
'Controls whether response values are auto-promoted to entity.content on submission';Default is "auto" so that the existing behavior (edit → save → immediately reflected) works out of the box. Teams that want review workflows can set individual criteria sets to "manual".
Container config data migration: No data migration needed. Existing entity types with config.container.enabled = true simply lose the container UI toggle. Their actual connections remain in the entity_relations table and are unaffected. The existing child-entity-list blocks in any views they have continue to work. For entity types that relied on the auto-generated ContainerChildrenSection on the default bento view, the bento already shows connections — no data is lost.
Trade-offs
Chosen: Separate default view from workspace views
- Pro: Safety net always shows all data; custom views can be specialized without data loss risk
- Con: Two rendering paths to maintain
- Alternative considered: Make default view a stored view record. Rejected because the default must always reflect the current schema, and stored views can diverge.
Chosen: Response-based editing (not direct entity update)
- Pro: Full provenance, append-only history, multi-actor collaboration, matches OG amble design
- Con: Extra step for simple edits (submit response then promote)
- Mitigation: Auto-promotion mode on criteria sets (
promotion_mode: "auto"default) eliminates the extra step for simple cases
Chosen: Remove Container as explicit concept
- Pro: Simpler admin, fewer concepts to learn, connections are already the mechanism
- Con: Loses the explicit "this type is a container" signal for non-view contexts
- Mitigation: Any entity type that has connections with child-entity-list or connection-list blocks in its views implicitly acts as a container
Chosen: Single editor component for both admin and detail
- Pro: Consistent experience, one codebase to maintain
- Con: Editor must handle both contexts (type-level vs entity-level saves)
- Mitigation: Save scope is handled by the parent page passing appropriate callbacks
Chosen: Replace existing visual-editor rather than extend
- Pro: Clean architecture, existing visual-editor has debt (broken config popover, overflow issues)
- Con: Throwaway existing code
- Mitigation: Carry forward useful patterns (dnd-kit integration, edit mode context concept)
Acceptance Criteria
Editor
- Workspace editor renders in admin Views tab with full block editing
- Same workspace editor renders on entity detail pages
- Block palette scrolls properly and doesn't overflow
- Priority block types (12 listed above) have typed config panels
- Remaining block types show JSON editor fallback in config panel
- Blocks can be dragged to reorder, resized (full/half/third), and removed
- Script-created and tool-created views are editable (config normalization on load)
- Save on detail page: "Save" = entity override, "Save as Default" = type template
- Save in admin: saves to type-level view
Response Integration
- Response mode on a workspace view turns field blocks into editable inputs
- Saving in response mode creates an entity_response submission using default criteria set
- Response record includes criteria_set_id, criteria_snapshot, field_meta, computed scores
- Field blocks show provenance badges (who set the value, when)
- Auto-promotion works when criteria set promotion_mode is "auto"
- Manual promotion flow works via existing FieldResponseIndicator
- Response history visible on field blocks via existing indicators
New Block Types
-
notesblock renders NotesEditor with configurable placeholder -
documentsblock renders document list with optional upload - Both new types available in block palette
Removals
- Container tab removed from entity type admin
- ContainerConfig, isContainerType, getAllowedChildTypes deleted from types
- ContainerChildrenSection deleted
- manageContainerConfig admin tool removed
- CLAUDE.md updated (admin tool count, manageContainerConfig reference removed)
- ViewEditorSheet, old ViewEditor, WorkspaceViewEditor deleted
- visual-editor/ directory deleted (replaced by workspace-editor/)
- Related test files updated (entities/types.test.ts, admin-tools.test.ts)
Block Configs
- Zod schemas exist for every block type's config (typed for priority, passthrough for rest)
- Config panels render typed forms for priority block types
- Config validation catches invalid shapes and normalizes on load
- connection-list block has relation type filter and display mode config
- child-entity-list block has child type filter and display mode config
- field-card block has field selector and display mode config
- response-form block has criteria set selector
Entity Detail
- When no custom views: default bento shown, "Customize Layout" creates first view
- When custom views exist: first view shown by default
- "View All Properties" shows default bento
- View tabs shown when multiple views exist
- Layout mode and response mode are visually distinct and mutually exclusive
Migration
-
promotion_modecolumn added tocriteria_setswith default "auto" - Existing criteria sets get promotion_mode = "auto"
Files
New files
features/views/components/workspace-editor/index.tsxfeatures/views/components/workspace-editor/editor-canvas.tsxfeatures/views/components/workspace-editor/block-palette.tsxfeatures/views/components/workspace-editor/block-config-panel.tsxfeatures/views/components/workspace-editor/editor-toolbar.tsxfeatures/views/components/workspace-editor/sortable-block.tsxfeatures/views/components/workspace-editor/response-mode.tsxfeatures/blocks/config-schemas.tsfeatures/blocks/config-schemas.test.tsfeatures/blocks/components/notes-block.tsx(new block type)features/blocks/components/documents-block.tsx(new block type)features/blocks/components/block-config-panels/(per-block-type config UIs)supabase/migrations/YYYYMMDD_NNN_criteria_sets_promotion_mode.sql
Modified files
features/blocks/types.ts— addnotesanddocumentsto BLOCK_TYPES, typed config interfacesfeatures/views/types.ts— editor-related typesfeatures/views/hooks/use-view-editor.ts— response-mode save logic, integration with submitEntityResponsefeatures/views/server/actions.ts— normalize/validate on loadfeatures/blocks/components/field-card-block.tsx— edit mode for response inputfeatures/blocks/components/block-renderer.tsx— config normalization, new block type renderingfeatures/responses/types.ts— add promotion_mode to CriteriaSetRecordfeatures/entities/types.ts— remove ContainerConfig, isContainerType, getAllowedChildTypesfeatures/entities/types.test.ts— remove container-related testsfeatures/entities/components/more-actions-dropdown.tsx— add "Edit Values", update "Customize Layout" behavior, add "View All Properties"features/entities/components/entity-detail-hero.tsx— mode indicator for layout/response editingfeatures/tools/admin-tools.ts— remove manageContainerConfig toolfeatures/tools/admin-tools.test.ts— remove manageContainerConfig testsapp/(app)/admin/entity-types/[slug]/entity-type-admin-client.tsx— remove Container tabapp/(app)/admin/entity-types/[slug]/views-tab.tsx— use workspace editorapp/(app)/[typeSlug]/[id]/entity-detail-client.tsx— clean up view switching, remove container logic, add response modeapp/(app)/[typeSlug]/[id]/page.tsx— pass additional props for response modeCLAUDE.md— update admin tool count, remove manageContainerConfig reference
Deleted files
features/views/components/view-editor-sheet.tsxfeatures/views/components/view-editor.tsxfeatures/views/components/workspace-view-editor.tsxfeatures/views/components/visual-editor/(entire directory)features/entities/components/container-children-section.tsx
Relationship to v2 Spec
This spec supersedes view-block-system-v2.mdx. Status of v2 items:
| v2 Item | Status | v3 Treatment |
|---|---|---|
| UnifiedViewRenderer | Done | Kept, modified for response mode |
Standalone /view/[id] route | Done | Kept as-is |
| ViewTabBar | Done | Kept, minor updates |
| useViewRealtime hook | Done | Kept as-is |
| Per-block Suspense | Done | Kept as-is |
| View templates | Not started | Deferred — not in v3 scope |
| Copy/fork API routes | Partially done | fork-on-write is done, copy deferred |
| parent_view_id migration | Done | Kept as-is |
| ViewEditor refactor | Not started | Replaced by workspace-editor in v3 |
| Typed block configs | Not started | Core deliverable of v3 |
The v2 spec should be updated to status: completed for done items and status: superseded overall, with a note pointing to v3.
View and Block System v2
Unified view renderer, standalone view route, per-block Suspense loading, real-time AI iteration, and view management (copy, fork, pin).
Tasks — The Missing Primitive
Introduce Tasks as the 6th platform primitive — a first-class, visible unit of work assignable to agents or humans, with parent/child hierarchy, event triggers, and completion criteria. Consolidates extraction configs, status triggers, field actions, and automation entities into one concept. Provides a unified backlog, per-user/agent workload views, and full auditability.