PaperStudio/Diagram Templates
UsuarioSoporteDeveloper

Diagram Templates

Text-defined diagrams rendered as SVG via the Pintora engine. Part of the Data Science module.

Overview

Diagram templates use the existing templates table with source_type = "pintora". They support:

  • 6 diagram types: sequence, activity, ER, class, flowchart, gantt
  • Nunjucks data binding: {{ variable }}, {% for %}, {% if %}
  • $fn: data functions: pull live counts, averages, and lists from the database
  • _form fields in seed_json: auto-generate end-user forms for data input
  • Short references: resolve templates via @code
  • Multiple output formats: SVG, PNG, PDF, JPG, WebP

Architecture

templates table (source_type = "pintora")
├── content: Pintora DSL with {{ nunjucks }} placeholders
├── seed_json: { _form: [...fields], ...defaults, "$fn:count(table)" }
├── template_key: unique per company (e.g., "diag_api_sequence")
└── short_ref: @code auto-generated

Render pipeline: Data Resolve ($fn: + @refs) → Nunjucks Template → Pintora DSL → SVG/PNG/PDF

API Endpoints

All endpoints require JWT authentication.

Render a diagram

POST /v1/render
Content-Type: application/json
Authorization: Bearer <token>

{
  "company_id": "uuid",
  "template_key": "diag_api_sequence",
  "output_format": "svg",
  "data": {
    "client": "Mobile App",
    "endpoint": "/v1/orders"
  },
  "inline": true
}

Returns the SVG directly with Content-Type: image/svg+xml.

Get form metadata

GET /v1/render/form/diag_api_sequence?company_id=uuid
Authorization: Bearer <token>

Returns:

{
  "template_id": "template_01jq5...",
  "template_key": "diag_api_sequence",
  "short_ref": "@k7f2n",
  "description": "API Request Sequence",
  "source_type": "pintora",
  "form_fields": [
    {
      "key": "client",
      "label": "Client Name",
      "type": "text",
      "required": true,
      "default": "Browser"
    },
    {
      "key": "endpoint",
      "label": "Endpoint",
      "type": "text",
      "required": true,
      "default": "/v1/users"
    }
  ],
  "defaults": { "client": "Browser", "endpoint": "/v1/users" },
  "output_formats": ["svg", "png", "pdf", "jpg", "webp"]
}

CRUD (via templates API)

  • GET /v1/templates?source_type=pintora&company_id=uuid — list diagrams
  • POST /v1/templates — create (set source_type: "pintora")
  • PUT /v1/templates/:id — update
  • DELETE /v1/templates/:id — delete

Diagram Types

Sequence Diagram

sequenceDiagram
  participant {{ client }} as Client
  participant {{ server }} as Server
  {{ client }} ->> {{ server }}: {{ method }} {{ endpoint }}
  {{ server }} -->> {{ client }}: 200 OK

Activity Diagram

activityDiagram
  start
  :Receive Order;
  if (Payment valid?) then
    :Process Order;
  else
    :Reject;
  endif
  end

ER Diagram

erDiagram
  Customer {
    uuid id PK
    varchar name
  }
  Order {
    uuid id PK
    uuid customer_id FK
  }
  Customer ||--o{ Order : "places"

Flowchart

flowchart TD
  Start([Start]) --> Check{Valid?}
  Check -->|Yes| Save[Save]
  Check -->|No| Error[Error]

Class Diagram

classDiagram
  class User {
    +String name
    +login()
  }

Gantt Chart

gantt
  title Project
  dateFormat YYYY-MM-DD
  section Phase 1
  Task A: a, 2026-04-01, 7d

Using $fn: Data Functions

Place $fn: directives in seed_json to pull live data from the database:

{
  "total_customers": "$fn:count(customers)",
  "avg_invoice": "$fn:avg(invoices, amount)",
  "total_orders": "$fn:count(orders)",
  "_form": [
    {
      "key": "highlight",
      "label": "Section",
      "type": "select",
      "options": ["all", "crm", "invoicing"]
    }
  ]
}

Then reference in Pintora DSL:

sequenceDiagram
  participant CRM as CRM ({{ total_customers }} customers)
  participant INV as Invoicing (avg ${{ avg_invoice }})

Available functions: count, sum, avg, min, max, list, table, group_count, daily_count, monthly_count.

Form System (_form convention)

The _form array in seed_json defines user-fillable fields for the /render/:key form page:

{
  "_form": [
    { "key": "name", "label": "Name", "type": "text", "required": true },
    {
      "key": "style",
      "label": "Style",
      "type": "select",
      "options": ["default", "dark"]
    },
    {
      "key": "count",
      "label": "Count",
      "type": "number",
      "min": 1,
      "max": 100,
      "default": 10
    },
    {
      "key": "show_labels",
      "label": "Show Labels",
      "type": "checkbox",
      "default": true
    }
  ],
  "name": "Default Name",
  "style": "default"
}

Field types: text, textarea, number, select, checkbox, date, color, email, url, hidden

The _form array is metadata only — stripped before rendering. Remaining keys are default values overridden by user input.

Frontend

  • Data Science tab: /data-science → Diagrams tab (list + detail split panel)
  • Form page: /render/:templateKey — auto-generated form from _form fields
  • API client: dataScienceApi.listDiagrams(), .createDiagram(), .renderDiagram()

Conversion Matrix

Source Output Engine Priority
pintora svg pintora 10
pintora png sharp 5
pintora pdf sharp 3
pintora jpg sharp 3
pintora webp sharp 3

CLI

# Show form fields
docuget render diag_api_sequence --form-info

# Interactive render — prompts for each field
docuget render diag_api_sequence --interactive --out=svg --save=api.svg

# Override fields directly
docuget render diag_api_sequence --out=svg --field client=Mobile --field endpoint=/v1/orders

# Generate shareable URLs (no login required)
docuget share diag_api_sequence --ttl=86400

Debugging

Set DEBUG_RENDER=1 environment variable to enable trace logging across:

  • Template handler (source_type, key, data keys)
  • Render engine (converter selection, cache status)
  • Pintora converter (DSL length, render timing, output size)
  • Render routes (request path, template resolution)