Customers can connect their own domain to a merchant page (storefront/event):
add a domain, point an A record (apex + www) to the app server, click Verify —
DNS is checked, then Ladill Domains' central SSL service issues + installs the
Let's Encrypt cert and calls back to flip it live. The custom domain then serves
the mapped page (host resolution on /). Feature-gated: only active when a Domains
SSL API key is set, so this deploy is inert until wired.
- custom_domains table + CustomDomain model
- CustomDomainService (DNS verify, request cert), DomainsSslClient, DnsResolver
- settings UI panel, signed SSL callback receiver, host resolution on /
- feature tests (DNS verify/fail, signed callback, ownership)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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>
When a menu (food) storefront order is paid, best-effort POST it to the
merchant's Ladill POS kitchen ingest (config/kitchen.php → KITCHEN_API_URL/KEY)
so it lands on their Kitchen Display alongside dine-in tabs. Failures are logged,
never surfaced — order completion is unaffected; POS ignores orders for accounts
that don't run a POS kitchen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New Products page (merchant.products.*) with full CRUD proxied to the Ladill
CRM products API via a new CrmClient + config/crm.php (owner-scoped, type=product).
- Sidebar gains a Products entry.
- The new storefront form loads the merchant's catalog: each shop/menu section
gets an "Add from products…" picker that drops a CRM product in as an item
(name, price, description). Catalog fetch is resilient — empty if CRM is down.
Wires CRM_API_URL + CRM_API_KEY_MERCHANT on the merchant env (matches CRM).
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>
Correct localhost marketing_url default and stop redirecting guests through
/sso/connect on visit; SSO starts only via explicit sign-in.
Co-authored-by: Cursor <cursoragent@cursor.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>
One-time importer that copies legacy menu/shop storefronts (and their
products, stored inline in qr_codes.payload.content.sections) from the
shared platform DB into this app's database, so owners who created them
before the Merchant extraction can see/manage them again.
- Maps platform owners to local users by public_id (SSO sub), creating a
local user stub when missing
- Copies product images from a new read-only `platform_qr` disk
(PLATFORM_QR_ROOT) to the local `qr` disk
- Idempotent (skips existing short_codes unless --refresh); supports
--user, --dry-run, --skip-images
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>