Vancetope Application — app: canvasbook

Folder container for multiple kind: canvas pages — a “book” of Canvases, built on the doc-kind-application foundation. Intentionally named differently from the Kind (workbookworkpage as a model) to avoid confusing the app and the Kind. See also: doc-kind-canvas, app-workbook (model pattern), documents-channel (live update). Implementation track: planning/canvas.md.


1. Purpose

kind: canvas alone is sufficient for a single surface. As soon as multiple related boards need to be managed and switched between, a Canvasbook bundles them: a folder with _app.yaml (kind: application, app: canvasbook), containing multiple *.canvas.* pages and an auto-generated _index.md. For a single surface, create kind: canvas directly.

CanvasbookApplication is the only authoring interface for Canvases.


2. Folder Layout & Manifest

design-sketches/
├── _app.yaml                  ← kind: application, app: canvasbook
├── _index.md                  ← auto-generated (page list), only refresh() writes
├── ideas.canvas.yaml          ← kind: canvas
├── architecture.canvas.yaml
└── assets/                    ← files imported via Drag&Drop
$meta:
  kind: application
  app: canvasbook
title: "Design Sketches"
description: "Whiteboard Collection"
canvasbook:
  landingPage: "ideas.canvas.yaml"   # optional — default page on open
  index:
    outputPath: "_index.md"

Discovery: listByKind(..., "application") + Header app == "canvasbook". The manifest is written via ApplicationDocument + ApplicationCodec (not manually). For the web create dialog, the addon provides a bundled Document Template canvasbook (resource under vance-defaults/_vance/templates/, name: { mode: fixed, value: _app.yaml }) — it only writes the manifest; pages are added afterwards via the editor / canvasbook_page_create. Generated artifact: _index.md (kind: workpage, link list of all Canvas pages), deterministically from the sources, only CanvasbookApplication.refresh writes.


3. Tools

Tool Purpose
canvasbook_app_create(folder, title?, description?, landingPage?, pages?) One-shot: Manifest + optional initial pages + index rebuild. Instead of manual _app.yaml.
canvasbook_page_create(folder, title?, slug?) New Canvas page in Canvasbook + index refresh.
app_rebuild(folder) Regenerates _index.md.

The pages themselves are populated using the canvas_* tools (see doc-kind-canvas §4) and validated with canvas_validate. promptInject displays a short hint block with the tools as long as a Canvasbook is open in Cortex.


4. Web UI

Kind registration application:canvasbookCanvasbookAppKind.vue (immersive app view). A single menu button at the top switches between the *.canvas.* pages (intentionally no sidebar tree navigation); landing page leads. The active Canvas is edited in the VueFlow editor, debounced auto-saved (status indicator: saved/not saved/saving), plus “+ Canvas” and “↻ Index”.

Live Document Update: the app view subscribes to the documents channel via folder prefix; an external save of the active page reloads it. Own echoes are suppressed via a self-write window, and local unsaved changes are not overwritten. No CRDT — for true simultaneous editing, Last-Writer-Wins applies; awareness comes via the live cursors of the pointers channel.


5. REST API

Under /brain/{tenant}/addon/canvas/... (permission-scoped, no direct MongoTemplate access from the controller):

Endpoint Purpose
GET /scan?projectId=&folder= Manifest title, landing, page list.
POST /page?projectId=&folder= New Canvas page.
POST /rebuild?projectId=&folder= Regenerate _index.md.
GET /graph?projectId=&path= Parsed graph as JSON (server codec).
PUT /graph?projectId=&path= Graph JSON → serialized + saved.
GET /documents/search?projectId=&query= Project document search (Doc Picker).
GET /document?projectId=&path= Doc meta (Embed Resolution).

The client does not parse YAML — the Java CanvasCodec remains the Single Source of Truth; graph GET/PUT transport typed JSON.


6. Anti-Patterns

  • Manual edits to _app.yaml → use canvasbook_app_create.
  • Canvasbook with a single page → bare kind: canvas is sufficient.
  • Manual edits to _index.md → will be overwritten by app_rebuild.
  • Sub-Canvasbook in a section folder → one Canvasbook per tree root.