Store templates
Templates live in your database; labelviewer stores nothing. The Editor gives your code everything a row needs on
every save (saveHandler or the save event, see Embed the editor), and load() takes the same fields
back.
Schema#
A table like this covers everything the editor gives you:
CREATE TABLE label_template (
id BIGINT PRIMARY KEY, -- or a UUID
name VARCHAR(200) NOT NULL,
zpl TEXT NOT NULL, -- the template, with {{placeholders}}; up to 1 MiB
sample_data JSON NULL, -- example record(s) for the designer's preview (JSONB / NVARCHAR(MAX))
dpmm SMALLINT NOT NULL DEFAULT 8, -- 6, 8, 12 or 24 (152, 203, 300, 600 dpi)
width_in DECIMAL(5,2) NOT NULL DEFAULT 4, -- label size in inches
height_in DECIMAL(5,2) NOT NULL DEFAULT 6,
version INTEGER NOT NULL DEFAULT 1, -- bumped on every save
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
| Column | From the editor's save | Into load() |
|---|---|---|
zpl | value | zpl |
sample_data | sampleData (undefined when there is none: store NULL) | sampleData |
dpmm | settings.dpmm | dpmm |
width_in, height_in | settings.widthIn, settings.heightIn | width, height |
name | your own form (the editor reports fileName) | fileName (optional) |
Size and density belong to the template. The same ZPL prints differently at 203 and 300 dpi; store dpmm and the
size with it, pass them to load(), and use them again when you print or render it.
Sample data is for designing. Keep it small and free of real customer data: it is shown to everyone who opens the template. Production data comes from your orders at print time.
Concurrent edits: optimistic locking#
Send the version you loaded with every save and update with
UPDATE label_template
SET zpl = ?, sample_data = ?, dpmm = ?, width_in = ?, height_in = ?, version = version + 1, updated_at = CURRENT_TIMESTAMP
WHERE id = ? AND version = ?
Zero rows updated means someone else saved first: answer 409, and let your saveHandler throw. The editor then shows
"Save failed: <your message>" and keeps the user's changes, so nothing is lost.
Versioning#
If printed labels must be reproducible (audits, reprints, customer disputes), keep every saved version:
CREATE TABLE label_template_version (
template_id BIGINT NOT NULL REFERENCES label_template (id),
version INTEGER NOT NULL,
zpl TEXT NOT NULL,
dpmm SMALLINT NOT NULL,
width_in DECIMAL(5,2) NOT NULL,
height_in DECIMAL(5,2) NOT NULL,
saved_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
saved_by VARCHAR(200) NULL,
PRIMARY KEY (template_id, version)
);
- Insert a row in the same transaction as each successful update.
- Record the
template_idandversiona print job used, so a reprint uses the same template even after later edits. - To restore an old version,
load()it into the editor and let the user save it as the next version.
Variables are a contract#
The paths a template uses ({{order.id}}, {{shipTo.name|John Doe}}) must exist in the data your backend sends at
print time, or have a default. The editor's Variables tab lists them. If several teams own the data, document the
fields each template may use, and check new versions with a merge against a real record before you switch production
to them (Print from your backend).
Backups#
Your database is the only place templates exist: include these tables in its backups. labelviewer itself has nothing to back up (Install › Backups).