DataMagik Documents

Updated Dec 13, 2025
DataMagik Documents

Document Designer Guide

Create, manage, and version professional PDF document templates using HTML, CSS, and Go template syntax.

Table of Contents

  1. Overview
  2. Creating a Template
  3. The Template Editor
  4. Go Template Syntax
  5. Working with Data
  6. Barcodes & QR Codes
  7. ZPL Label Creation & Test Printing
  8. User Defined Tables in Templates
  9. Serial Number Series
  10. Charts & Visualizations
  11. Version Control & Branches
  12. Approval Workflow
  13. Generating Documents
  14. Best Practices

1. Overview

The Document Designer allows you to create professional PDF documents using familiar web technologies (HTML & CSS) combined with Go's powerful templating system. Documents can include:

  • Dynamic data from your ERP, scripts, or APIs
  • Barcodes and QR codes
  • Charts and visualizations
  • Tables with repeating data
  • Conditional content
  • Custom styling and branding

Key Features:

  • Visual Preview — See your template rendered with sample data
  • Version Control — Track changes with branch-based versioning
  • Approval Workflow — Require approval before templates go to production
  • Audit Trail — Full history of who changed what and when

2. Creating a Template

Step 1: Open Document Designer

Navigate to DataMagik → Document Designer in the main menu.

Step 2: Click "New Template"

Click the purple New Template button in the toolbar.

Step 3: Configure Template Settings

FieldDescriptionExampleNameTemplate identifierInvoice - StandardCategoryGrouping for organizationInvoicesDescriptionWhat this template is forStandard customer invoice with line items

Step 4: Start Editing

After creation, click Edit to open the template editor.

3. The Template Editor

The template editor provides a full-featured HTML/CSS editing environment.

Editor Layout

  • Left Panel — Code editor with syntax highlighting
  • Right Panel — Live preview with sample data
  • Top Toolbar — Save, preview, settings, and help

Editor Tabs

  • HTML — Template structure and Go template tags
  • CSS — Styling for your document
  • Sample Data — JSON data for preview

Keyboard Shortcuts

ShortcutActionCtrl+SSave templateCtrl+Shift+PPreview with current dataCtrl+SpaceShow autocompleteCtrl+/Toggle commentCtrl+?Open help modal

4. Go Template Syntax

DataMagik templates use Go's template syntax. Here's a comprehensive reference:

Basic Output

<!-- Output a field value -->
<p>Customer: {{.CustomerName}}</p>

<!-- Access nested fields -->
<p>City: {{.Address.City}}</p>

<!-- Access array elements -->
<p>First Item: {{index .Items 0}}</p>

Variables

<!-- Define a variable -->
{{$total := .OrderTotal}}

<!-- Use the variable -->
<p>Total: ${{$total}}</p>

<!-- Assign from calculation -->
{{$discounted := mul .Price 0.9}}
<p>Discounted: ${{$discounted}}</p>

Conditionals

<!-- Simple if -->
{{if .IsRush}}
<div class="rush-banner">RUSH ORDER</div>
{{end}}

<!-- If-else -->
{{if .IsPaid}}
<span class="status paid">PAID</span>
{{else}}
<span class="status unpaid">UNPAID</span>
{{end}}

<!-- If-else if-else -->
{{if eq .Status "shipped"}}
<span class="shipped">Shipped</span>
{{else if eq .Status "processing"}}
<span class="processing">Processing</span>
{{else}}
<span class="pending">Pending</span>
{{end}}

Comparison Operators

OperatorDescriptionExampleeqEqual{{if eq .Status "active"}}neNot equal{{if ne .Count 0}}ltLess than{{if lt .Quantity 10}}leLess than or equal{{if le .Age 18}}gtGreater than{{if gt .Total 1000}}geGreater than or equal{{if ge .Score 70}}

Logical Operators

<!-- AND -->
{{if and .IsActive .IsVerified}}
<p>User is active and verified</p>
{{end}}

<!-- OR -->
{{if or .IsAdmin .IsModerator}}
<p>User has elevated permissions</p>
{{end}}

<!-- NOT -->
{{if not .IsDeleted}}
<p>Record is active</p>
{{end}}

<!-- Combined -->
{{if and .IsActive (or .IsAdmin .IsModerator)}}
<p>Active user with permissions</p>
{{end}}

Loops

<!-- Simple loop -->
<ul>
  {{range .Items}}
  <li>{{.Name}} - ${{.Price}}</li>
  {{end}}
</ul>

<!-- Loop with index -->
<table>
  {{range $index, $item := .Items}}
  <tr>
    <td>{{add $index 1}}</td>
    <td>{{$item.Name}}</td>
    <td>{{$item.Quantity}}</td>
  </tr>
  {{end}}
</table>

<!-- Loop with else (empty case) -->
{{range .Items}}
<div>{{.Name}}</div>
{{else}}
<div>No items found</div>
{{end}}

Built-in Functions

FunctionDescriptionExamplelenLength of array/string{{len .Items}}indexGet item at index{{index .Items 0}}printfFormatted string{{printf "%.2f" .Price}}upperUppercase{{upper .Code}}lowerLowercase{{lower .Email}}titleTitle case{{title .Name}}trimTrim whitespace{{trim .Input}}

Math Functions

<!-- Addition -->
<p>Subtotal: ${{add .Price .Tax}}</p>

<!-- Subtraction -->
<p>Discount: ${{sub .Total .Discount}}</p>

<!-- Multiplication -->
<p>Extended: ${{mul .Quantity .UnitPrice}}</p>

<!-- Division -->
<p>Average: {{div .Total .Count}}</p>

<!-- Modulo -->
{{if eq (mod $index 2) 0}}
<tr class="even">
  {{else}}
</tr>

<tr class="odd">
  {{end}}
</tr>

Date Formatting

<!-- Format date -->
<p>Date: {{formatDate .OrderDate "January 2, 2006"}}</p>
<p>Date: {{formatDate .OrderDate "2006-01-02"}}</p>
<p>Date: {{formatDate .OrderDate "01/02/2006"}}</p>

<!-- Current date -->
<p>Printed: {{now | formatDate "2006-01-02 15:04:05"}}</p>

Comments

{{/* This is a comment - won't appear in output */}} {{/* Multi-line comment for
documentation */}}

5. Working with Data

Sample Data Structure

Your sample data should mirror the structure of real data that will be passed during generation:

{
  "OrderNumber": "ORD-2025-001234",
  "OrderDate": "2025-12-05",
  "CustomerName": "Acme Corporation",
  "CustomerCode": "ACME001",
  "BillTo": {
    "Name": "Acme Corporation",
    "Address": "123 Main Street",
    "City": "Detroit",
    "State": "MI",
    "Zip": "48201"
  },
  "ShipTo": {
    "Name": "Acme Warehouse",
    "Address": "456 Industrial Blvd",
    "City": "Warren",
    "State": "MI",
    "Zip": "48089"
  },
  "Items": [
    {
      "LineNumber": 1,
      "PartNumber": "WIDGET-001",
      "Description": "Standard Widget",
      "Quantity": 100,
      "UnitPrice": 12.5,
      "ExtendedPrice": 1250.0
    },
    {
      "LineNumber": 2,
      "PartNumber": "GADGET-002",
      "Description": "Premium Gadget",
      "Quantity": 50,
      "UnitPrice": 25.0,
      "ExtendedPrice": 1250.0
    }
  ],
  "Subtotal": 2500.0,
  "TaxRate": 0.06,
  "TaxAmount": 150.0,
  "Total": 2650.0,
  "IsPaid": false,
  "IsRush": true
}

Building a Document

Header Section:

<div class="header">
  <div class="logo">
    <img src="{{.CompanyLogo}}" alt="Logo" />
  </div>
  <div class="document-info">
    <h1>INVOICE</h1>
    <p>Invoice #: {{.OrderNumber}}</p>
    <p>Date: {{formatDate .OrderDate "January 2, 2006"}}</p>
  </div>
</div>

Address Block:

<div class="addresses">
  <div class="bill-to">
    <h3>Bill To:</h3>
    <p>{{.BillTo.Name}}</p>
    <p>{{.BillTo.Address}}</p>
    <p>{{.BillTo.City}}, {{.BillTo.State}} {{.BillTo.Zip}}</p>
  </div>
  <div class="ship-to">
    <h3>Ship To:</h3>
    <p>{{.ShipTo.Name}}</p>
    <p>{{.ShipTo.Address}}</p>
    <p>{{.ShipTo.City}}, {{.ShipTo.State}} {{.ShipTo.Zip}}</p>
  </div>
</div>

Line Items Table:

<table class="line-items">
  <thead>
    <tr>
      <th>Line</th>
      <th>Part #</th>
      <th>Description</th>
      <th>Qty</th>
      <th>Unit Price</th>
      <th>Extended</th>
    </tr>
  </thead>
  <tbody>
    {{range .Items}}
    <tr>
      <td>{{.LineNumber}}</td>
      <td>{{.PartNumber}}</td>
      <td>{{.Description}}</td>
      <td>{{.Quantity}}</td>
      <td>${{printf "%.2f" .UnitPrice}}</td>
      <td>${{printf "%.2f" .ExtendedPrice}}</td>
    </tr>
    {{end}}
  </tbody>
  <tfoot>
    <tr>
      <td colspan="5" class="text-right">Subtotal:</td>
      <td>${{printf "%.2f" .Subtotal}}</td>
    </tr>
    <tr>
      <td colspan="5" class="text-right">Tax ({{mul .TaxRate 100}}%):</td>
      <td>${{printf "%.2f" .TaxAmount}}</td>
    </tr>
    <tr class="total-row">
      <td colspan="5" class="text-right"><strong>Total:</strong></td>
      <td><strong>${{printf "%.2f" .Total}}</strong></td>
    </tr>
  </tfoot>
</table>

6. Barcodes & QR Codes

DataMagik supports generating barcodes directly in your templates.

Supported Barcode Types

1D Barcodes:

  • Code 128 (general purpose)
  • Code 39 (alphanumeric)
  • EAN-13, EAN-8 (retail)
  • UPC-A, UPC-E (US retail)
  • Codabar (libraries, blood banks)

2D Barcodes:

  • QR Code (high capacity, URLs)
  • Data Matrix (compact, industrial)
  • PDF417 (documents, IDs)
  • Aztec (tickets, boarding passes)

Barcode Functions

<!-- Code 128 (most common) -->
<img src="data:image/png;base64,{{barcode128 .OrderNumber}}" alt="Barcode" />

<!-- Code 128 with custom size -->
<img
  src="data:image/png;base64,{{barcode128 .OrderNumber 300 60}}"
  alt="Barcode"
/>

<!-- QR Code -->
<img src="data:image/png;base64,{{qrcode .TrackingURL}}" alt="QR Code" />

<!-- QR Code with size -->
<img src="data:image/png;base64,{{qrcode .TrackingURL 150}}" alt="QR Code" />

<!-- EAN-13 -->
<img src="data:image/png;base64,{{ean13 .ProductEAN}}" alt="EAN" />

<!-- Data Matrix -->
<img
  src="data:image/png;base64,{{datamatrix .SerialNumber}}"
  alt="Data Matrix"
/>

Barcode Best Practices

  • Test scanning — Always test generated barcodes with actual scanners
  • Adequate size — Ensure barcodes are large enough for reliable scanning
  • Quiet zones — Leave white space around barcodes
  • Proper contrast — Use dark barcodes on light backgrounds

7. ZPL Label Creation & Test Printing

DataMagik supports creating ZPL (Zebra Programming Language) labels for thermal printers, with integrated test printing capabilities.

What is ZPL?

ZPL is a command language used by Zebra and compatible thermal label printers. It allows precise control over label layout, barcodes, text, and graphics.

ZPL Template Syntax

ZPL templates use the same Go template syntax as PDF documents:

^XA
^FO50,50^A0N,40,40^FD{{.PartNumber}}^FS
^FO50,100^A0N,30,30^FD{{.Description}}^FS
^FO50,150^BY3^BCN,100,Y,N,N^FD{{.Barcode}}^FS
^FO50,280^A0N,25,25^FDQty: {{.Quantity}}^FS
^FO50,320^A0N,20,20^FD{{formatDate .PrintDate "2006-01-02"}}^FS
^XZ

Common ZPL Commands

CommandDescriptionExample^XAStart label formatAlways first^XZEnd label formatAlways last^FOField origin (x,y position)^FO50,100^FDField data (text content)^FD{{.Text}}^FS^FSField separator (end field)Required after data^A0Font selection^A0N,40,40 (normal, h, w)^BCCode 128 barcode^BCN,100,Y,N,N^BQQR Code^BQN,2,5^BYBarcode defaults^BY3 (module width)^GBGraphic box (lines/borders)^GB400,3,3^FS

Creating a ZPL Template

  1. Create a new template in Document Designer
  2. Set the template type to ZPL Label
  3. Enter your ZPL code with Go template syntax
  4. Configure sample data for preview

Test Printing

Test print labels directly from the Document Designer:

  1. Open your ZPL template
  2. Click Test Print in the toolbar
  3. Select a printer from the dropdown
  4. Review the preview
  5. Click Print

Printer Configuration

Printers are configured in Manufacturing → Printers:

SettingDescriptionNameFriendly printer nameIP AddressPrinter network addressPortUsually 9100 for ZPLProtocolRaw Socket (ZPL/Direct)DPI203 or 300 typicallyZPL CompatibleEnable for ZPL printers

Printing from Scripts

Use the manufacturing and zpl APIs:

function main(context) {
  // Render ZPL template with data
  const zplCode = zpl.fromTemplate("PartLabel", {
    partNumber: context.partNumber,
    description: context.description,
    barcode: context.partNumber,
    quantity: context.qty,
  });

  // Print to specific printer
  manufacturing.printLabel("Warehouse-Zebra-01", zplCode);

  return { success: true, script_message: "Label printed" };
}

Batch Printing

Print multiple labels efficiently:

function main(context) {
  const items = context.items; // Array of items to label

  const batchResult = manufacturing.printBatchLabels(
    "Line1-Zebra",
    "PartLabel",
    items.map((item) => ({
      partNumber: item.pn,
      description: item.desc,
      barcode: item.pn,
      quantity: item.qty,
    }))
  );

  return {
    success: true,
    script_message: `Printed ${batchResult.count} labels`,
  };
}

ZPL Best Practices

  • Test on actual printers — Emulators may render differently
  • Use consistent coordinates — Align elements on a grid
  • Account for label size — Know your label dimensions in dots
  • Include quiet zones — Leave margins around barcodes
  • Test barcode scanning — Verify readability before production

8. User Defined Tables in Templates

Access data from User Defined Tables directly in your document templates.

Querying Tables in Sample Data

Your sample data can include table lookups:

{
  "OrderNumber": "ORD-001",
  "ShippingMethods": "{{tableQuery 'shipping_methods' 'active' true}}",
  "CustomerData": "{{tableGet 'customers' 'CUST001'}}"
}

Using Table Data in Scripts

When generating documents from scripts, query tables and pass data:

function main(context) {
  // Get data from User Defined Tables
  const customer = tables.get("customers", context.customerId);
  const products = tables.query("products", { category: context.category });
  const shippingOptions = tables.list("shipping_methods");

  // Generate document with table data
  documents.generate("Order Confirmation", {
    orderNumber: context.orderNumber,
    customer: customer,
    products: products,
    shippingOptions: shippingOptions,
  });

  return { success: true };
}

Common Table Patterns

Lookup Table for Dropdowns:

// Get list of valid statuses for display
const statuses = tables.list("order_statuses");
const statusName = statuses.find((s) => s.code === order.status)?.name;

Customer Master Data:

// Get customer details for invoice
const customer = tables.get("customers", invoiceData.customerCode);
const billingAddress = tables.get("addresses", customer.billingAddressId);

Product Catalog:

// Get product details with pricing
const product = tables.get("products", lineItem.productId);
const pricing = tables.query("pricing", {
  productId: product.id,
  priceLevel: customer.priceLevel,
});

Table Functions Available in Templates

FunctionDescriptiontables.get(tableName, key)Get single record by primary keytables.query(tableName, filter)Query records matching filtertables.list(tableName)Get all records from tabletables.exists(tableName, key)Check if record exists

Example: Invoice with Customer Lookup

function main(context) {
  // Get customer from UDT
  const customer = tables.get("customers", context.customerId);

  // Get line items with product details
  const lineItems = context.orderLines.map((line) => {
    const product = tables.get("products", line.productId);
    return {
      ...line,
      productName: product.name,
      productDescription: product.description,
      unitOfMeasure: product.uom,
    };
  });

  // Get company info from settings table
  const companyInfo = tables.get("settings", "company_info");

  documents.generate("Invoice - Standard", {
    invoiceNumber: context.invoiceNumber,
    customer: customer,
    lineItems: lineItems,
    company: companyInfo,
    total: context.total,
  });

  return { success: true };
}

9. Serial Number Series

Integrate with Traceability serial number series for automatic serial generation in documents.

Generating Serials in Templates

Use the manufacturing API to generate serial numbers:

function main(context) {
  // Generate serial for this document
  const serialNumber = manufacturing.generateSerial("ProductSerials", {
    workOrder: context.workOrderNumber,
    partNumber: context.partNumber,
  });

  documents.generate("Product Label", {
    serialNumber: serialNumber,
    partNumber: context.partNumber,
    date: new Date().toISOString(),
  });

  return { success: true, data: { serial: serialNumber } };
}

Batch Serial Generation

Generate multiple serials for batch labels:

function main(context) {
  const quantity = context.quantity;

  // Generate batch of serials
  const serials = manufacturing.generateSerials("ProductSerials", quantity, {
    workOrder: context.workOrderNumber,
    partNumber: context.partNumber,
  });

  // Generate a label for each serial
  for (const serial of serials) {
    documents.generate("Product Label", {
      serialNumber: serial,
      partNumber: context.partNumber,
      workOrder: context.workOrderNumber,
    });
  }

  return {
    success: true,
    script_message: `Generated ${serials.length} serial numbers`,
    data: { serials: serials },
  };
}

Serial Number Formats

Serial numbers are formatted according to the series configuration:

TokenDescriptionExample{YYYY}4-digit year2025{YY}2-digit year25{MM}Month06{DD}Day15{JJJ}Julian day166{####}Sequence0042{SEQUENCE}Sequence (alias)0042

Example format: SN-{YYYY}{JJJ}-{####} → SN-2025166-0042

Using Serials in ZPL Labels

function main(context) {
  // Generate serial
  const serial = manufacturing.generateSerial("PartSerials");

  // Create ZPL label with serial
  const zplCode = zpl.fromTemplate("SerialLabel", {
    serialNumber: serial,
    partNumber: context.partNumber,
    barcode: serial,
  });

  // Print the label
  manufacturing.printLabel(context.printer, zplCode);

  return { success: true, data: { serial: serial } };
}

Serial + UDT Integration

Combine serial generation with table lookups:

function main(context) {
  // Get product info from UDT
  const product = tables.get("products", context.productId);

  // Get the correct serial series for this product
  const seriesName = product.serialSeries || "DefaultSerials";

  // Generate serial
  const serial = manufacturing.generateSerial(seriesName, {
    partNumber: product.partNumber,
    workOrder: context.workOrder,
  });

  // Generate label with all data
  documents.generate("Product Certificate", {
    serialNumber: serial,
    product: product,
    manufactureDate: new Date().toISOString(),
    workOrder: context.workOrder,
  });

  return { success: true };
}

10. Charts & Visualizations

Create dynamic charts using the built-in charting functions.

Supported Chart Types

  • Line Chart
  • Bar Chart
  • Pie Chart
  • Doughnut Chart

Chart Syntax

<!-- Bar chart from data -->
{{chart "bar" .SalesData "Month" "Revenue"}}

<!-- Pie chart -->
{{chart "pie" .CategoryBreakdown "Category" "Amount"}}

<!-- Line chart with options -->
{{chart "line" .TrendData "Date" "Value" "title=Sales Trend"}}

Chart Data Format

Your data should be an array of objects:

{
  "SalesData": [
    { "Month": "Jan", "Revenue": 45000 },
    { "Month": "Feb", "Revenue": 52000 },
    { "Month": "Mar", "Revenue": 48000 }
  ]
}

📸 Screenshot Needed: A document preview showing a chart rendered in the template.

11. Version Control & Branches

Document Designer includes Git-like version control for templates.

Branches

  • main — Production-ready templates
  • draft — Work-in-progress changes
  • Custom branches — Feature development or customer-specific versions

Creating a Version

  1. Make changes in the editor
  2. Click Commit in the toolbar
  3. Enter a commit message describing your changes
  4. Select the branch to commit to
  5. Click Commit Changes

Viewing Version History

  1. Select a template
  2. Click the Versions tab in the preview panel
  3. View list of all versions with timestamps and authors
  4. Click a version to view its content

Comparing Versions

  1. Select two versions in the history
  2. Click Compare
  3. View side-by-side diff of changes

Rolling Back

  1. Find the version you want to restore
  2. Click Rollback to this version
  3. Confirm the rollback
  4. A new version is created with the restored content

12. Approval Workflow

For production environments, templates can require approval before use.

Requesting Approval

  1. Commit your changes to a version
  2. Click Request Approval
  3. Select the version to approve
  4. Add any notes for the approver
  5. Submit the request

Approving a Template

  1. Go to the Approvals tab
  2. Review pending approval requests
  3. Click on a request to see details
  4. Review the template content and changes
  5. Click Approve or Reject
  6. Add approval notes if needed

📸 Screenshot Needed: The Approvals tab showing pending approval requests.

Approval Status

StatusDescriptionPendingWaiting for approvalApprovedTemplate can be used in productionRejectedChanges needed before approval

13. Generating Documents

From Scripts

function main(context) {
  documents.generate("Invoice - Standard", {
    OrderNumber: context.orderNumber,
    CustomerName: context.customerName,
    Items: context.lineItems,
    Total: context.total,
  });

  return { success: true };
}

From Automations

Documents can be triggered from:

  • Webhook automations
  • Scheduled tasks
  • Browser extension actions
  • n8n workflows

Generation Options

// Async generation (fire and forget)
const requestId = documents.generate("Template Name", data);

// Sync generation (wait for result)
const result = documents.generateSync("Template Name", data, {
  returnType: "url", // "url" or "binary"
  timeout: 60000, // milliseconds
});

// Check status
const status = documents.getStatus(requestId);

Viewing Generated Documents

  1. Select a template
  2. Click the Documents tab
  3. View list of generated documents
  4. Click to download or preview

14. Best Practices

Template Organization

  • Use categories — Group related templates (Invoices, Packing Slips, Labels)
  • Descriptive names — Invoice - Standard not inv1
  • Document in description — Explain when/how template is used

Code Quality

  • Keep it simple — Break complex templates into sections
  • Use variables — Store calculated values in variables for reuse
  • Comment your code — Use {{/* comments */}} to explain complex logic
  • Consistent styling — Use CSS classes, not inline styles

Testing

  • Test with edge cases — Empty arrays, null values, long text
  • Test printing — PDF rendering may differ from screen preview
  • Test barcodes — Verify they scan correctly

Performance

  • Optimize images — Use appropriate sizes, compress when possible
  • Limit complexity — Very complex templates may be slow to render
  • Test with real data volume — Large tables may need pagination

CSS Tips for PDF

/* Force page breaks */
.page-break {
  page-break-before: always;
}

/* Prevent element from breaking across pages */
.keep-together {
  page-break-inside: avoid;
}

/* Set page size and margins */
@page {
  size: letter;
  margin: 0.5in;
}

/* Header on every page */
@page {
  @top-center {
    content: "Company Name";
  }
}

/* Page numbers */
@page {
  @bottom-right {
    content: "Page " counter(page) " of " counter(pages);
  }
}

Screenshots Summary

Please capture the following screenshots to complete this documentation:

  1. Document Designer main interface - Template list and preview panel
  2. New Template button - In the toolbar
  3. Template Editor - Code editor and live preview
  4. Barcode example - Document with barcode/QR code rendered
  5. ZPL template editor - ZPL code and label preview
  6. Test Print dialog - Printer selection for test printing
  7. Serial number in document - Generated serial number preview
  8. Chart example - Document with chart rendered
  9. Branch selector - Dropdown showing branches
  10. Versions tab - Version history with commits
  11. Request Approval - Button and modal
  12. Approvals tab - Pending requests
  13. Documents tab - List of generated documents
Was this page helpful?