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.
Portfolio showcases freelancer work projects; Bookshop lists author titles with multi-platform purchase links. Includes create/edit forms, public assets, and tests.
Public URLs, encoded payloads, slug preview, payment callbacks, and asset paths now use ladl.link instead of ladill.com/q/*.
Co-authored-by: Cursor <cursoragent@cursor.com>
Public landing pages, asset paths, payment callbacks, and redirects now go through QrCode::publicPath() / LadillLink instead of ladill.com/q/* routes.
Co-authored-by: Cursor <cursoragent@cursor.com>
The dashboard 'Create code' / 'Create your first code' links were plain hrefs
to the create page, so a user with insufficient balance only met the top-up
modal after filling the form. Gate them with balanceGate + mount the modal so
they open Add funds directly when the wallet can't cover a QR code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
qr-plus authenticates to the monolith with a billing service key, not an
identity key, so the modal's top-up now goes through BillingClient::topup ->
POST /api/billing/topup. Drops the unused IdentityClient::walletTopup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a user hits an action they can't afford (e.g. creating a QR code with
0/low balance), open an in-app two-step modal instead of bouncing them to the
central wallet page. Step 1 explains pay-as-you-go billing + shows the action
cost and current balance; step 2 takes an amount and starts a Paystack checkout
via the central identity wallet-topup API, returning the user where they were.
- service-topup-modal: rebuilt as two-step (billing explainer -> amount/pay)
- IdentityClient::walletTopup + WalletTopupController + POST /wallet/topup
- balanceGate.openTopup / qrCustomizer.redirectTopup now prefer the modal,
falling back to the wallet page only when no modal is wired
- qr-codes index + create render the modal and open it on insufficient balance
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
InjectBootSplash middleware shows a self-branded loading splash once per session
while the app boots, then fades out.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wallet balance peek rendered as a menu row directly under Billing, backed by
a /wallet/balance endpoint (BillingClient) and guarded by Route::has. Also
opens Afia via a direct window event for reliability.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Users asked to delete codes they no longer need. Add a destroy route +
controller action (authorized via QrCodePolicy::delete) and a danger-zone
delete on the show page behind a confirmation modal that requires typing the
code's label — deliberately not a one-click delete since it permanently
breaks the printed code and removes its scan history.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove interactive OAuth fallback on silent SSO failure and add ladill.marketing_url config so app subdomains open the dashboard when signed in locally.
Co-authored-by: Cursor <cursoragent@cursor.com>
Local-only sign-out: end this app's session but leave the auth.ladill.com
session intact, so the signed-out page's Sign in again re-auths silently via
prompt=none. Full sign-out of all Ladill apps remains on account.ladill.com.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a dedicated /search page, wire the bottom nav and topbar to it, and expose JSON results for live lookup of QR codes.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the shared auth session alive with periodic pings, store OIDC refresh tokens for silent re-login, and route launcher links through SSO connect.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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>
Exposes /api/v1/qr-codes with analytics, team account header support, and qr:read/qr:write token abilities.
Co-authored-by: Cursor <cursoragent@cursor.com>
Enables account collaboration, API tokens, hosted PDF codes, and fixes QR detail 500s by declaring chillerlan/php-qrcode.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>