Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

CanvasView stores a user-customised investor-report canvas layout for a workspace. One active row exists per (workspace, template_id) pair, enforced by a partial unique index on deleted_at IS NULL. The entity is REST-only and is not tracked in Hasura; the financial-overview page fetches one row by template via PUT /v1/workspaces/:id/canvas-views/:template_id (upsert). It belongs to a Workspace and optionally records the People who created it.
NamingValue
ObjectCanvasView
Resource type (JSON:API type)canvas_view
Collection / records root(not a records root)
REST base/v1/canvas-views
Entity classCanvasView
Internal object. Not currently exposed on the public REST API. The operations below describe the intended contract.

API operations

OperationMethod & pathStatus
ListGET /v1/canvas-views🟡 Planned
RetrieveGET /v1/canvas-views/{id}🟡 Planned
CreatePOST /v1/canvas-views🟡 Planned
UpdatePATCH /v1/canvas-views/{id}🟡 Planned
DeleteDELETE /v1/canvas-views/{id}🟡 Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
canvas_view_idstring (UUID) — 🔒 system✅ YesUNIQUE; DEFAULT gen_random_uuid()Public-facing UUID for JSON:API addressing. System-assigned at creation; never client-provided.
template_idstring (varchar 50)✅ Yesmax 50 chars; partial unique with workspace on deleted_at IS NULL (idx_canvas_views_workspace_template_active); validated at service layer against CANVAS_TEMPLATESService-layer validated against CANVAS_TEMPLATES enum from @wellapp/shared (e.g. ‘investor-report-v1’). Stored as varchar — no DB enum.Identifies which canvas template this layout belongs to. Used as the natural write key; the FE addresses the row as PUT …/canvas-views/:template_id.
namestring (varchar 255) | null⚪ Nomax 255 chars; nullableOptional human label for the layout. Reserved for future multi-named-layout support per workspace/template pair. Null = the implicit default layout.
blocksCanvasBlockConfig[] (jsonb)✅ YesNOT NULL jsonb; service enforces: 1-7 entries, unique slot_id values, valid width enum (‘one_third’|‘two_thirds’), positions form a permutation of [0, length)Array of { slot_id: ‘header’|‘kpi-1’|‘kpi-2’|‘kpi-3’|‘body-left’|‘body-right’|‘footer’, width: ‘one_third’|‘two_thirds’, position: number }Ordered list of selected blocks defining the canvas layout. The read formatter drops unknown slot_id values (forward-compat); the write path strictly validates against CANVAS_SLOT_IDS.
created_atdatetime — 🔒 system✅ YesNOT NULL timestamptz; set once via onCreate hookTimestamp when the canvas view was first created. Set automatically by the MikroORM onCreate lifecycle hook.
updated_atdatetime — 🔒 system⚪ Nonullable timestamptz; set by onCreate and onUpdate hooksTimestamp of the last upsert. Updated automatically via the MikroORM onUpdate lifecycle hook on every write.
deleted_atdatetime | null — 🔒 system⚪ Nonullable timestamptz; null = active rowSoft-delete timestamp. Null for active rows. The partial unique index exempts soft-deleted rows so delete + re-create preserves history. Set by the service on logical deletion.

Relationships

NameTypeRequiredDescription
workspaceto-one (ManyToOne)Yes — NOT NULL FK with ON DELETE CASCADEThe workspace that owns this canvas layout. Workspace deletion cascades and removes all associated canvas_views. All queries are workspace-scoped via this FK.
created_byto-one (ManyToOne)No — nullable FK with ON DELETE SET NULLThe People (user) who created this canvas view. Nullable; set to null if the creating user is deleted. References the peoples table.

System-computed

  • canvas_view_id: auto-assigned via gen_random_uuid() default at row creation — never client-provided
  • created_at: set once by MikroORM onCreate hook (new Date())
  • updated_at: set by onCreate and onUpdate hooks on every write
  • deleted_at: set by the service layer on soft deletion; null for active rows
  • pk: internal auto-increment serial primary key — never exposed in the API
  • Partial unique index idx_canvas_views_workspace_template_active enforces at most one active row per (workspace_pk, template_id) while allowing soft-deleted history rows to coexist
  • The write path is an upsert keyed on (workspace, template_id) — the service resolves or creates the row rather than requiring the caller to supply canvas_view_id
  • blocks validation is fully service-layer enforced (1-7 entries, unique slot_ids, valid widths, position permutation) — no DB-level CHECK constraint on the JSONB column
  • The read formatter (canvas-view.formatter.ts) drops unknown slot_id entries rather than throwing — forward-compat for future slot registry expansions

Example

{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "type": "canvas_view",
    "attributes": {
      "template_id": "investor-report-v1",
      "name": null,
      "blocks": [
        { "slot_id": "kpi-1", "width": "one_third", "position": 0 },
        { "slot_id": "kpi-2", "width": "one_third", "position": 1 },
        { "slot_id": "kpi-3", "width": "one_third", "position": 2 },
        { "slot_id": "body-left", "width": "one_third", "position": 3 },
        { "slot_id": "body-right", "width": "two_thirds", "position": 4 }
      ],
      "created_at": "2026-05-16T17:00:00.000Z",
      "updated_at": "2026-05-20T09:30:00.000Z",
      "deleted_at": null
    },
    "relationships": {
      "workspace": { "data": { "id": "wsp_uuid_here", "type": "workspace" } },
      "created_by": { "data": { "id": "ppl_uuid_here", "type": "people" } }
    }
  }
}
Source: apps/api/src/database/entities/CanvasView.ts · domain: workspace · tier: Infrastructure