Commit Graph
13 Commits
Author SHA1 Message Date
isaaccladandClaude 9ead4573d6 qr: downscale uploaded images before storing them
Uploads were written to the qr disk byte-for-byte. A bookshop cover arrived as a
9000x6600 print-resolution JPEG — 18MB — and was then served in full to every
visitor of a public bio page. During a launch that one file accounted for roughly
1.6GB of 1.9GB of image traffic, and because these assets are proxied through the
app rather than served statically, PHP streamed every byte of it and held a worker
for the duration.

Nothing the QR/bio pages display needs more than a couple of thousand pixels, so
UploadedImageOptimizer caps the long edge at 2000px and re-encodes on the way in.
The incident file becomes ~350KB. Configurable via qr.image.*.

Deliberately conservative, because a broken upload is worse than a large one:

- Format is preserved. A PNG stays a PNG so transparency survives; converting to
  JPEG would put black boxes behind logos.
- GIF is excluded — GD would silently drop animation frames.
- SVG and any file GD cannot read is stored untouched.
- Small files are passed through rather than lossily re-encoded for no gain.
- Output is discarded if it came out larger than the original.
- Any failure logs and falls back to storing the original.

Applied to the seven image paths only. Books (PDF/EPUB) and documents keep the
plain store — the optimiser would have fallen through for them anyway, but routing
non-images through something called an image optimiser invites the wrong change
later.

This is the source-level counterpart to the nginx cache: caching stops the bytes
being regenerated, this stops them existing.

Tests: 6 new, including the real 9000x6600 shape, PNG alpha survival, format
preservation and non-image passthrough. Pre-existing suite failures unchanged at 8.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-25 12:23:08 +00:00
isaacclad 90aef0c3f4 Stop Paystack pre-modal flash on customer checkout.
Deploy Ladill QR Plus / deploy (push) Successful in 46s
Use the shared Inline sheet, hold busy until payment UI opens, and avoid locking page scroll during the handoff.
2026-07-24 10:14:41 +00:00
isaacclad e30c9dada5 Restore Paystack Inline in-page sheet/modal; stop separate-browser checkout.
Deploy Ladill QR Plus / deploy (push) Successful in 1m9s
Pass access_code through pay responses and launch PaystackPop from the shared sheet instead of window.open.
2026-07-21 19:12:24 +00:00
isaacclad f88d50f24c Open Paystack from the Pay click gesture, not after fetch.
Deploy Ladill QR Plus / deploy (push) Successful in 47s
Paystack blocks iframes, so checkout uses a popup beside the sheet/modal chrome. Opening about:blank on the user tap keeps that window from being blocked after the async initiate response.
2026-07-21 18:14:04 +00:00
isaacclad 6b81644c32 Fix Paystack sheet: stop iframe embeds that Paystack blocks.
Deploy Ladill QR Plus / deploy (push) Successful in 52s
Paystack checkout.paystack.com returns X-Frame-Options: SAMEORIGIN, so the shared sheet opened empty. Keep mobile sheet/desktop modal chrome, launch checkout in a named window with a Continue CTA fallback, and escape payment-return via window.opener or top.
2026-07-21 17:35:31 +00:00
isaacclad 02e6778ccf Speed up QR create/update by cutting billing round-trips.
Deploy Ladill QR Plus / deploy (push) Successful in 2m2s
Create was making three sequential public HTTPS billing calls (~400ms each)
while holding a DB transaction open for image generation. Use loopback DNS
forcing, cache balances briefly, return balance from debit, regenerate images
only when style changes, and keep remote work outside the DB transaction.
2026-07-16 21:25:16 +00:00
isaacclad d83a314bee Add Portfolio and Bookshop QR types with tailored landing pages.
Deploy Ladill QR Plus / deploy (push) Successful in 58s
Portfolio showcases freelancer work projects; Bookshop lists author titles with multi-platform purchase links. Includes create/edit forms, public assets, and tests.
2026-07-16 20:56:52 +00:00
isaacclad 95d73d1367 Add Campaigns module for grouping QR codes.
Deploy Ladill QR Plus / deploy (push) Successful in 1m6s
Let accounts organise codes by promo or launch, attach or detach codes, and view combined scan totals from the sidebar.
2026-07-16 20:43:02 +00:00
isaaccladandCursor 03fffa04be Add account-level Analytics page to QR Plus.
Deploy Ladill QR Plus / deploy (push) Successful in 39s
Aggregates scan metrics across all codes with charts, breakdowns, and a sidebar nav item.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 00:57:08 +00:00
isaaccladandCursor a7090e9c30 Add QR-specific settings for notifications and new-code defaults.
Deploy Ladill QR Plus / deploy (push) Successful in 1m15s
Store per-account preferences in qr_settings and pre-fill the create flow with saved type and brand styling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 09:14:16 +00:00
isaaccladandCursor 9ddda21ea3 Add Afia AI assistant to the QR Plus header.
Deploy Ladill QR Plus / deploy (push) Successful in 1m33s
Wire in-app chat scoped to QR codes, billing, and scans so users get product-specific help without leaving qrplus.ladill.com.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 08:56:29 +00:00
isaaccladandCursor 6a5e26315e Import PDF documents when migrating QR codes from the platform.
Deploy Ladill QR Plus / deploy (push) Successful in 28s
Links qr_documents to imported codes and copies PDF files when --storage-source is provided.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 07:49:53 +00:00
isaaccladandCursor cd6571f199 Extract Ladill QR Plus as standalone app at qr.ladill.com.
Deploy Ladill QR Plus / deploy (push) Failing after 1s
Utility QR types only (URL, WiFi, link list, business, app download) with
SSO, Billing API integration, public /q resolver, and qr-plus:import for
platform migration. vCard and commerce types stay on the platform.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 21:31:24 +00:00