Print Views - protected end-user labels + PWA
The idea
A product label design can have two views: a store view where the employee enters an EAN (typed or via QR/barcode scanner) to get one product label, and a shipping view that prints three labels per order number. End users don't need a designer - they open a URL, fill out the form, see the PDF preview and print to a weblink printer.
Each print view is also its own PWA (Progressive Web App): on a smartphone it can be added to the home screen with its own name and icon and opens in fullscreen (standalone) - like a native app.
URL scheme
- Short URL (canonical):
https://print.zplcloud.com/d/{designName}.{designId}/{viewSlug}- e.g.https://print.zplcloud.com/d/australia-open-rfid.15/store - Shortest URL:
https://print.zplcloud.com/pv/{id}- redirects to the short URL (great for QR codes). - Access: login required; only the creator + granted accounts (
allowedEmails) can open the page - everyone else gets 403.
Creating a print view (platform)
- Sidebar → "Print Views" (platform
/platform/printviews). - Pick a design from your saved designs, set a name and view ID (slug, only
a-z 0-9 -), description optional. - Allowed accounts: email addresses (one per line or separated by
;) - the creator always has access. - Form designer: add fields from the palette (dx-text-box, dx-select-box, dx-check-box, dx-button), configure label/field name (binding), placeholder, required, options, "100 test articles" data source, lookup column and optional QR/barcode scanner.
- Optionally set a default printer (weblink).
- Save → both URLs (short +
/pv/{id}) with copy buttons and a QR code (PNG/PDF/ZPL + printable) appear.
Form fields & data
- dx-text-box - text field with optional 📷 QR/barcode scanner (camera reads codes directly into the field; camera selection with multiple cameras is remembered in localStorage, success beep).
- dx-select-box - dropdown (static options or the 100 test articles as data source).
- dx-check-box - option/flag.
- dx-button - trigger button (preview).
- Lookup: when the end user enters e.g. an EAN, the matching row from the test data is merged into the record - all columns are available to the design as bindings. (The real data layer follows; currently 100 deterministic test articles with EAN-13 checksum.)
- Validation: preview/PDF/print are only enabled when all required fields have valid data; the server otherwise answers 400 instead of 500.
Readable formats (barcode/QR scanner)
The scanner uses ZXing-C++ (WASM, self-hosted) with a fallback to the ZXing-JS port (no CDN) and detects the following formats:
- Linear codes: EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39, Code 93, Codabar, ITF (Interleaved 2 of 5), DataBar (RSS-14), DataBar Expanded
- 2D codes: QR Code, Data Matrix, PDF417, Aztec, Micro QR Code
Tip for small/poorly printed codes: hold the code inside the blue corner frame in the center of the image - in addition to the full frame, it is decoded there at native resolution.
Preview & printing
- Preview as PDF - renders the label (with the form data) as a PDF preview in the browser.
- Print PDF - browser print dialog of the preview.
- Weblink print - sends ZPL to the selected weblink printer (printers are shown de-duplicated, default printer preselected).
PWA - its own app on the home screen
Each print view serves its own web app manifest, a dynamically generated icon (with the view's initial) and a minimal service worker - so the page can be added on Android ("Install app") and iOS ("Add to Home Screen") as its own standalone app:
- Manifest:
/{view}/manifest.json- name = view name,display: standalone, icons 192/512 px. - Icon:
/{view}/icon.png?size=192|512- dark label icon with initial (SkiaSharp). - Service worker:
/sw.js- network passthrough, deliberately no caching of sensitive label/API data. - iOS:
apple-mobile-web-app-capable+apple-touch-icon- opens standalone without browser UI. - After installation the app opens
start_url; without a login the sign-in page appears, then it returns to the view.
Data routes (frontend, no CORS)
Management runs on the same origin (zplcloud.com) so the form designer needs no CORS:
GET /api/printviews/list- views in the user's scope.POST /api/printviews/save- create/update (creator only).POST /api/printviews/delete- delete (creator only).GET /api/printviews/{id}- detail incl. design JSON + 100 test articles.GET /api/printviews/testdata- the 100 test articles.GET /api/weblink/connections/POST /api/weblink/send-zpl- weblink printers (like the batch tab).
Host isolation
On print.zplcloud.com only the print routes (/d/…, /pv/{id},
manifest.json, icon.png, /sw.js), the API (/api/*)
and the account/login pages exist. SPA, marketing and everything else answer with 404 there - all
other hosts remain unchanged.