Sprinter Docs

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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:

LayerWhat it isEditableStored
Default viewAuto-generated bento showing all entity dataNoNot in views table — rendered from schema
Workspace viewsBlock-driven layouts designed per entity typeYes, via workspace editorviews table, page_type: "workspace"
Entity overridesFork of a workspace view customized for one entityYes, via same editorviews 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:

  1. Field-displaying blocks (field-card, data-table) switch to editable inputs
  2. Inputs show the current value pre-filled, with response history indicators (who set this, when, confidence)
  3. User edits values across the view — it looks like a form but follows the view's designed layout
  4. "Save Response" creates an entity_response submission — not a direct entity update
  5. 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
  6. The response record is populated as:
    • criteria_set_id: the default criteria set ID
    • criteria_snapshot: snapshot of the criteria set dimensions at submission time
    • values: { dimensionKey: newValue, ... } for all edited fields (dimension keys map to field names via CriteriaSetDimension.fieldName)
    • field_meta: { fieldName: { confidence: "high" } } for each edited field (user-provided values default to high confidence)
    • source: "manual"
    • submitted_by_user: current user ID
    • weighted_score / normalized_score: computed from numeric dimension values and weights (same as existing submitEntityResponse() logic)
    • status: "submitted" (or "promoted" if auto-promotion is enabled)
  7. Auto-promotion is controlled by a new promotion_mode field on criteria_sets (see Migration section). When promotion_mode = "auto" (the column default), response values are immediately promoted to entity.content via the existing promote_field_value RPC. When promotion_mode = "manual", values appear as pending responses needing explicit promotion
  8. 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 TypePurposeConfig
notesRich text notes editor for entity.description{ placeholder?: string }
documentsDocument 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 mode
  • child-entity-list — already exists, gets config for child type filter and display mode
  • response-form — already exists, gets config for criteria set selector
  • field-card — already exists, gets config for field selector and display mode
  • stat-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 TypeConfig Fields
field-cardfields: string[], displayMode: "value" | "card" | "inline"
connection-listrelationTypes?: string[], entityTypes?: string[], display: "list" | "grid" | "compact"
child-entity-listchildTypes?: string[], display: "list" | "table" | "grid", sortBy?: string, sortOrder?: "asc" | "desc"
response-formcriteriaSetId?: string (defaults to entity type's default)
notesplaceholder?: string — bound to entity.description, direct entity update (intentional exception to response model; notes are freeform, not structured data)
documentsshowUpload?: boolean, filterType?: string
chartchartType: "bar" | "pie" | "line" | "area", dataSourceField?: string, colorThresholds?: object
data-tablecolumns?: string[], sortConfig?: object
rich-textcontent?: string
stat-cardsstats?: StatConfig[]
radardimensions?: string[], showSliders?: boolean
rankingfield?: 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 schemaz.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 SourceBlocksReads from
Entity fieldsfield-card, data-tableentity.content[field]
Entity connectionsconnection-list, child-entity-listentity_relations table
Entity responsesresponse-form, field-card (response overlay)entity_responses table
Entity metadatastat-cards, status-bannerentity.metadata
Static/configuredrich-text, notesconfig.content or entity.description
Computedchart, radar, rankingAggregation query

5. Removals

WhatActionReason
Container tab (admin)Remove from entity-type-admin-client.tsxContainer is emergent from connections
ContainerConfig typeRemove from features/entities/types.tsNo longer needed
isContainerType() helperRemove from features/entities/types.tsNo longer needed
getAllowedChildTypes() helperRemove from features/entities/types.tsNo longer needed
ContainerChildrenSectionDelete features/entities/components/container-children-section.tsxReplaced by child-entity-list and connection-list blocks
ViewEditorSheetDelete features/views/components/view-editor-sheet.tsxReplaced by workspace editor
Old ViewEditorDelete features/views/components/view-editor.tsxReplaced by workspace editor
WorkspaceViewEditorDelete features/views/components/workspace-view-editor.tsxReplaced by workspace editor
visual-editor/ directoryDelete features/views/components/visual-editor/ (all files)Replaced by workspace-editor/
Container admin toolRemove manageContainerConfig from features/tools/admin-tools.tsNo longer needed
CLAUDE.md referenceRemove manageContainerConfig from admin tools list, reconcile tool count with actual tools in admin-tools.tsKeep docs accurate

6. Admin Entity Type Tabs

Simplified from 5 tabs to 4:

TabContent
OverviewName, slug, description, icon, color
FieldsSchema editor + field config (extraction, display, connection settings)
Criteria SetsCriteriaSetManager (unchanged)
ViewsRebuilt — 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

  • notes block renders NotesEditor with configurable placeholder
  • documents block 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_mode column added to criteria_sets with default "auto"
  • Existing criteria sets get promotion_mode = "auto"

Files

New files

  • features/views/components/workspace-editor/index.tsx
  • features/views/components/workspace-editor/editor-canvas.tsx
  • features/views/components/workspace-editor/block-palette.tsx
  • features/views/components/workspace-editor/block-config-panel.tsx
  • features/views/components/workspace-editor/editor-toolbar.tsx
  • features/views/components/workspace-editor/sortable-block.tsx
  • features/views/components/workspace-editor/response-mode.tsx
  • features/blocks/config-schemas.ts
  • features/blocks/config-schemas.test.ts
  • features/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 — add notes and documents to BLOCK_TYPES, typed config interfaces
  • features/views/types.ts — editor-related types
  • features/views/hooks/use-view-editor.ts — response-mode save logic, integration with submitEntityResponse
  • features/views/server/actions.ts — normalize/validate on load
  • features/blocks/components/field-card-block.tsx — edit mode for response input
  • features/blocks/components/block-renderer.tsx — config normalization, new block type rendering
  • features/responses/types.ts — add promotion_mode to CriteriaSetRecord
  • features/entities/types.ts — remove ContainerConfig, isContainerType, getAllowedChildTypes
  • features/entities/types.test.ts — remove container-related tests
  • features/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 editing
  • features/tools/admin-tools.ts — remove manageContainerConfig tool
  • features/tools/admin-tools.test.ts — remove manageContainerConfig tests
  • app/(app)/admin/entity-types/[slug]/entity-type-admin-client.tsx — remove Container tab
  • app/(app)/admin/entity-types/[slug]/views-tab.tsx — use workspace editor
  • app/(app)/[typeSlug]/[id]/entity-detail-client.tsx — clean up view switching, remove container logic, add response mode
  • app/(app)/[typeSlug]/[id]/page.tsx — pass additional props for response mode
  • CLAUDE.md — update admin tool count, remove manageContainerConfig reference

Deleted files

  • features/views/components/view-editor-sheet.tsx
  • features/views/components/view-editor.tsx
  • features/views/components/workspace-view-editor.tsx
  • features/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 ItemStatusv3 Treatment
UnifiedViewRendererDoneKept, modified for response mode
Standalone /view/[id] routeDoneKept as-is
ViewTabBarDoneKept, minor updates
useViewRealtime hookDoneKept as-is
Per-block SuspenseDoneKept as-is
View templatesNot startedDeferred — not in v3 scope
Copy/fork API routesPartially donefork-on-write is done, copy deferred
parent_view_id migrationDoneKept as-is
ViewEditor refactorNot startedReplaced by workspace-editor in v3
Typed block configsNot startedCore 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.

On this page