act_runner v0.2.x does not expose gitea.run_attempt, so release archive and
workspace paths rendered with a trailing dash. Use gitea.run_id only, matching
the Meet/CRM deploy workflows.
Replace the once-per-session sessionStorage guard (which suppressed the loading
screen after its first appearance) with entry-aware logic: show on app entry
and reloads, suppress on internal link navigations and back/forward.
Add transfer-files S3 disk, config-driven uploads, and an artisan command to migrate existing local blobs to object storage.
Co-authored-by: Cursor <cursoragent@cursor.com>
Sync mobile-header-btn partials, mobile x-btn.create, and update dashboard header actions for consistent mobile FABs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove duplicate Billing header above Home; wallet card follows Billing
in menu order to match the desktop avatar dropdown.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show wallet balance prominently in the mobile profile bottom sheet with refresh
on open; align session lifetime with the platform default.
Co-authored-by: Cursor <cursoragent@cursor.com>
Profile moves to the bottom nav sheet on small screens; optional search tab
support is synced from the Ladill platform template.
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
Ladill Accounting is now live at accounting.ladill.com; add its row + icon to
the shared app launcher (byte-identical across all Ladill apps).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Creating a transfer that the wallet can't cover used to flash a bare error.
Detect the insufficient-balance case and open an in-app two-step modal (billing
explainer -> amount -> Paystack) on the create page instead, with an 'Add funds'
button to top up on demand.
- BillingClient::topup -> POST /api/billing/topup (Transfer already holds its key)
- WalletTopupController + route POST /wallet/topup (user.wallet.topup)
- store() flashes open_topup_modal on TransferWalletErrors::isInsufficientBalance
- service-topup-modal made two-step (uses <x-modal>, plain POST -> checkout)
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>
crm.ladill.com is now live in the suite; add its launcher row + icon
(byte-identical shared launcher config).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Middleware::alias() replaces the alias map rather than merging, so the
second alias() call (platform.session, added in d491130) silently
removed the auth.service alias. Every service-to-service route
(auth.service:transfer) then failed with "Target class [auth.service]
does not exist", returning 500 to webmail/mobile for Transfer file
listing and uploads. Merge both aliases into a single alias() call.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a service API for the Ladill SMS platform to store voice recordings in Transfer and charge monthly storage from the customer wallet.
Co-authored-by: Cursor <cursoragent@cursor.com>