* feat(events): gallery QR code + printable table-card/poster PDFs (#836)
- GET /api/admin/events/:id/qr — share-link QR as PNG (128-2048px) or
SVG, inline or attachment; adminAuth + events.view + ownership.
- GET /api/admin/events/:id/qr-print — pdfkit-rendered A6 table card /
A4 poster with event name, QR, localized caption (8 locales; Cyrillic
falls back to English — built-in Helvetica has no Cyrillic glyphs) and
the share URL as footer.
- Event detail: QR section in ShareLinkCard with live preview (blob
fetch — Bearer auth) and PNG/SVG/table-card/poster downloads; print
language follows the admin UI language. i18n keys in all 8 locales.
- qrcode + pdfkit were already dependencies (MFA / CRM PDFs).
* fix(events): QR origin fallback, Unicode PDF font, bounded layout, stale-preview guard (codex review of #847)
- QR URLs: prefer the configured public base, but fall back to the admin
browser's origin (passed as ?origin=, validated) when the base is
missing or localhost — mirrors buildShareLinkUrl so the QR encodes the
same URL the card displays instead of an unusable localhost target.
- PDFs render with the bundled IBM Plex Sans TTFs (Latin+Cyrillic+Greek)
instead of WinAnsi-only Helvetica: Cyrillic event names no longer
silently disappear, and the caption's English-fallback hack is gone.
- Fixed vertical layout: title gets a bounded two-line ellipsis region
and all positions derive from constants, so long event names can't
push the QR/caption over the footer; URL footer bounded too.
- ShareLinkCard preview: stale-response guard — a late blob response
after unmount/event-switch is revoked instead of leaking and
overwriting the newer event's QR.
* fix(events): bundle complete IBM Plex Sans for QR PDFs + IPv6 loopback fallback (codex review of #847, round 2)
Round 2 caught that the pre-existing assets/fonts/IBM-Plex-Sans/ files
are 270-glyph Latin SUBSETS — my round-1 font swap didn't actually fix
Cyrillic titles and regressed the ru caption. Now bundling the complete
IBM Plex Sans 400/700 TTFs (1019 glyphs, Latin+Cyrillic+Greek — cmap
verified via fontkit, rendering verified on a generated PDF) under
assets/fonts/IBM-Plex-Sans-Full/ with the OFL license alongside.
~400 KB total; source: IBM/plex release zip @ibm/[email protected].
Also: LOCAL_BASE_RE now recognizes IPv6 loopback ([::1]) so a
FRONTEND_URL of http://[::1]:3000 falls back to the browser origin like
the frontend's own URL logic does.
Note for a follow-up: the CRM invoice/quote PDFs use the same Latin-only
subsets and share the Cyrillic gap.
* fix(events): responsive QR card that survives preview failures (codex review of #847, round 3)
- The QR section keys off share-link availability instead of a loaded
preview: a transient failure of the preview request no longer hides
every download button until reload; a placeholder tile renders in
place of the image.
- Preview + actions stack on phone widths and the button grid drops to
one column below sm, so 'Tischkarte (A6)'-length labels don't
overflow.
* fix(events): QR encodes the stored share_link + spec quiet zone (codex review of #847, confirmation round)
- The QR target is now the STORED share_link — exactly what the card
displays and the admin copies. Rebuilding from current slug/token/
short-URL setting could diverge for legacy absolute links or events
created under a different short-URL setting; a printed QR encoding a
different URL than the card is a permanent mistake. Rebuild remains
only as fallback when no share_link is stored.
- QR margin back to the library's 4-module default for all generated
assets — the spec's quiet zone; margin 2 risks scan failures when the
printout sits against colored surroundings.
* fix(events): bare share_link tokens resolve as /gallery/<token> in QR URLs (codex review of #847, final round)
Quote-/contract-converted events persist share_link as the raw token —
the frontend's buildShareLinkUrl prefixes those with /gallery/, but the
QR path normalization only added a leading slash, encoding
<origin>/<token> into every image/PDF for such events. Now mirrors the
frontend exactly.
* test(events): 30s timeout for the print-PDF cases (CI fix)
The poster PDF now embeds the full IBM Plex Sans TTFs (~200 KB each);
font parsing + subsetting exceeds jest's 5s default on slower CI
runners — the suite went red on exactly that test after the font
commit.