Print Views - protected end-user labels + PWA

Turn any saved design into a protected print URL under print.zplcloud.com - with an end-user form (form designer), QR/barcode scanner, PDF preview, weblink printing and its own installable PWA for the home screen.

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.
https://print.zplcloud.com/d/australia-open-rfid.15/store
https://print.zplcloud.com/pv/7   # redirects to the /d/ URL

Creating a print view (platform)

  1. Sidebar → "Print Views" (platform /platform/printviews).
  2. Pick a design from your saved designs, set a name and view ID (slug, only a-z 0-9 -), description optional.
  3. Allowed accounts: email addresses (one per line or separated by ;) - the creator always has access.
  4. 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.
  5. Optionally set a default printer (weblink).
  6. 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.