DataMagik Documents
Document Designer Guide
Create, manage, and version professional PDF document templates using HTML, CSS, and Go template syntax.
Table of Contents
- Overview
- Creating a Template
- The Template Editor
- Go Template Syntax
- Working with Data
- Barcodes & QR Codes
- ZPL Label Creation & Test Printing
- User Defined Tables in Templates
- Serial Number Series
- Charts & Visualizations
- Version Control & Branches
- Approval Workflow
- Generating Documents
- 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 New Template button in the toolbar.
Step 3: Configure Template Settings
| Field | Description | Example |
|---|---|---|
| Name | Template identifier | Invoice - Standard |
| Category | Grouping for organization | Invoices |
| Description | What this template is for | Standard 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
| Shortcut | Action |
|---|---|
Ctrl+S | Save template |
Ctrl+Shift+P | Preview with current data |
Ctrl+Space | Show autocomplete |
Ctrl+/ | Toggle comment |
Ctrl+? | 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}}
<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>Shipped</span>
{{else if eq .Status "processing"}}
<span>Processing</span>
{{else}}
<span>Pending</span>
{{end}}Comparison Operators
| Operator | Description | Example |
|---|---|---|
eq | Equal | {{if eq .Status "active"}} |
ne | Not equal | {{if ne .Count 0}} |
lt | Less than | {{if lt .Quantity 10}} |
le | Less than or equal | {{if le .Age 18}} |
gt | Greater than | {{if gt .Total 1000}} |
ge | Greater 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 -->
{{range $index, $item := .Items}}
<tr>
<td>{{add $index 1}}</td>
<td>{{$item.Name}}</td>
</tr>
{{end}}
<!-- Loop with else (empty case) -->
{{range .Items}}
<div>{{.Name}}</div>
{{else}}
<div>No items found</div>
{{end}}Built-in Functions
| Function | Description | Example |
|---|---|---|
len | Length of array/string | {{len .Items}} |
index | Get item at index | {{index .Items 0}} |
printf | Formatted string | {{printf "%.2f" .Price}} |
upper | Uppercase | {{upper .Code}} |
lower | Lowercase | {{lower .Email}} |
title | Title case | {{title .Name}} |
trim | Trim whitespace | {{trim .Input}} |
Math Functions
<p>Subtotal: ${{add .Price .Tax}}</p>
<p>Discount: ${{sub .Total .Discount}}</p>
<p>Extended: ${{mul .Quantity .UnitPrice}}</p>
<p>Average: {{div .Total .Count}}</p>Date Formatting
<p>Date: {{formatDate .OrderDate "January 2, 2006"}}</p>
<p>Date: {{formatDate .OrderDate "2006-01-02"}}</p>
<p>Printed: {{now | formatDate "2006-01-02 15:04:05"}}</p>Comments
{{/* This is a comment - won't appear in output */}}5. Working with Data
Sample Data Structure
Your sample data should mirror the structure of real data:
{
"OrderNumber": "ORD-2025-001234",
"OrderDate": "2025-12-05",
"CustomerName": "Acme Corporation",
"BillTo": {
"Name": "Acme Corporation",
"Address": "123 Main Street",
"City": "Detroit",
"State": "MI",
"Zip": "48201"
},
"Items": [
{
"LineNumber": 1,
"PartNumber": "WIDGET-001",
"Description": "Standard Widget",
"Quantity": 100,
"UnitPrice": 12.50,
"ExtendedPrice": 1250.00
}
],
"Subtotal": 2500.00,
"TaxRate": 0.06,
"TaxAmount": 150.00,
"Total": 2650.00
}Building a Document
Header Section:
<div class="header">
<h1>INVOICE</h1>
<p>Invoice #: {{.OrderNumber}}</p>
<p>Date: {{formatDate .OrderDate "January 2, 2006"}}</p>
</div>Line Items Table:
<table class="line-items">
<thead>
<tr>
<th>Part #</th>
<th>Description</th>
<th>Qty</th>
<th>Unit Price</th>
<th>Extended</th>
</tr>
</thead>
<tbody>
{{range .Items}}
<tr>
<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="4">Subtotal:</td>
<td>${{printf "%.2f" .Subtotal}}</td>
</tr>
<tr>
<td colspan="4"><strong>Total:</strong></td>
<td><strong>${{printf "%.2f" .Total}}</strong></td>
</tr>
</tfoot>
</table>6. Barcodes & QR Codes
Generate barcodes directly in your templates.
Supported Barcode Types
1D Barcodes: Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, Codabar
2D Barcodes: QR Code, Data Matrix, PDF417, Aztec
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
Create ZPL (Zebra Programming Language) labels for thermal printers with integrated test printing.
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
^XZCommon ZPL Commands
| Command | Description | Example |
|---|---|---|
^XA | Start label format | Always first |
^XZ | End label format | Always last |
^FO | Field origin (x,y position) | ^FO50,100 |
^FD | Field data (text content) | ^FD{{.Text}}^FS |
^FS | Field separator (end field) | Required after data |
^A0 | Font selection | ^A0N,40,40 |
^BC | Code 128 barcode | ^BCN,100,Y,N,N |
^BQ | QR Code | ^BQN,2,5 |
^BY | Barcode defaults | ^BY3 |
^GB | Graphic box (lines/borders) | ^GB400,3,3^FS |
Test Printing
- Open your ZPL template
- Click Test Print in the toolbar
- Select a printer from the dropdown
- Review the preview
- Click Print
Printing from Scripts
function main(context) {
const zplCode = zpl.fromTemplate("PartLabel", {
partNumber: context.partNumber,
description: context.description,
barcode: context.partNumber,
quantity: context.qty
});
manufacturing.printLabel("Warehouse-Zebra-01", zplCode);
return { success: true, script_message: "Label printed" };
}8. User Defined Tables in Templates
Access data from User Defined Tables in your document generation scripts.
Using Table Data in Scripts
function main(context) {
const customer = tables.get("customers", context.customerId);
const shippingOptions = tables.list("shipping_methods");
documents.generate("Order Confirmation", {
orderNumber: context.orderNumber,
customer: customer.value,
shippingOptions: shippingOptions
});
return { success: true };
}Common Table Patterns
// Customer master data for invoices
const customer = tables.get("customers", invoiceData.customerCode);
// Product catalog with pricing
const product = tables.get("products", lineItem.productId);Table Functions Available
| Function | Description |
|---|---|
tables.get(tableName, key) | Get single record by key |
tables.getValue(tableName, key) | Get just the value |
tables.list(tableName) | Get all records |
tables.exists(tableName, key) | Check if record exists |
9. Serial Number Series
Integrate with Traceability serial number series for automatic serial generation in documents.
Generating Serials
function main(context) {
const sn = serial.next("ProductSerials", {
workOrder: context.workOrderNumber,
partNumber: context.partNumber
});
documents.generate("Product Label", {
serialNumber: sn,
partNumber: context.partNumber,
date: new Date().toISOString()
});
return { success: true, data: { serial: sn } };
}Batch Serial Generation
function main(context) {
const serials = serial.batch("ProductSerials", context.quantity, {
workOrder: context.workOrderNumber,
partNumber: context.partNumber
});
for (const sn of serials) {
documents.generate("Product Label", {
serialNumber: sn,
partNumber: context.partNumber
});
}
return {
success: true,
script_message: "Generated " + serials.length + " serial numbers"
};
}Serial Number Format Tokens
| Token | Description | Example |
|---|---|---|
{YYYY} | 4-digit year | 2025 |
{YY} | 2-digit year | 25 |
{MM} | Month | 06 |
{DD} | Day | 15 |
{JJJ} | Julian day | 166 |
{####} | Sequence | 0042 |
Example format: SN-{YYYY}{JJJ}-{####} → SN-2025166-0042
10. Charts & Visualizations
Create dynamic charts using built-in charting functions.
Supported Chart Types
- Line Chart
- Bar Chart
- Pie Chart
- Doughnut Chart
Chart Syntax
<!-- Bar chart -->
{{chart "bar" .SalesData "Month" "Revenue"}}
<!-- Pie chart -->
{{chart "pie" .CategoryBreakdown "Category" "Amount"}}
<!-- Line chart with title -->
{{chart "line" .TrendData "Date" "Value" "title=Sales Trend"}}Chart Data Format
{
"SalesData": [
{ "Month": "Jan", "Revenue": 45000 },
{ "Month": "Feb", "Revenue": 52000 },
{ "Month": "Mar", "Revenue": 48000 }
]
}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
- Make changes in the editor
- Click Commit in the toolbar
- Enter a commit message describing your changes
- Select the branch to commit to
- Click Commit Changes
Viewing Version History
- Select a template
- Click the Versions tab in the preview panel
- View all versions with timestamps and authors
- Click a version to view its content
Comparing Versions
- Select two versions in the history
- Click Compare
- View side-by-side diff of changes
Rolling Back
- Find the version you want to restore
- Click Rollback to this version
- Confirm the rollback
- A new version is created with the restored content
12. Approval Workflow
For production environments, templates can require approval before use.
Requesting Approval
- Commit your changes to a version
- Click Request Approval
- Select the version to approve
- Add any notes for the approver
- Submit the request
Approving a Template
- Go to the Approvals tab
- Review pending approval requests
- Click on a request to see details
- Review the template content and changes
- Click Approve or Reject
- Add approval notes if needed
Approval Status
| Status | Description |
|---|---|
| Pending | Waiting for approval |
| Approved | Template can be used in production |
| Rejected | Changes 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
- Select a template
- Click the Documents tab
- View list of generated documents
- 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 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; }
/* Page numbers */
@page {
@bottom-right { content: "Page " counter(page) " of " counter(pages); }
}