isaaccladandCursor 3d79dfad10
Deploy Ladill Queue / deploy (push) Successful in 39s
Fit public display to viewport and use Ladill Queue logo in footer.
Lock layout to 100dvh without scroll, scale ticket cards with clamp(), and replace powered-by text with the dark wordmark.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 23:05:40 +00:00

Ladill CRM

The Ladill sales CRM at crm.ladill.com — a full SSO web app for managing contacts, leads, deals, activities and productsand the shared Customers/Leads/Products service consumed over HTTP by Ladill Invoice, Merchant, Mini and future apps, so contact + catalog data is owned in one place and reused everywhere.

Every record is scoped to one platform account via owner_ref (the user's public_id / OIDC sub).

App (web UI — Sign in with Ladill)

Authenticates against auth.ladill.com (OIDC Authorization Code + PKCE; see Auth\SsoLoginController). Local session is subordinate to the platform session (platform.session middleware) and joins Single Logout via /sso/logout-frontchannel.

  • Dashboard — KPIs (contacts, open leads, open deals, pipeline value), tasks due, recent activity.
  • Contacts — the contact book, with a per-contact timeline (notes, tasks, logged calls/meetings, sent email + SMS) and cross-product events (invoices, payments, orders) pushed from sibling apps.
  • Leads — list + kanban board (new → contacted → qualified), convert to a contact.
  • Deals — drag-free pipeline kanban across configurable stages (config/crm.pipeline_stages), won/lost tracking.
  • Activities — notes, tasks (with due dates / completion), calls, meetings.
  • Products & services — reusable catalog items.
  • Comms — email contacts (via the app mailer / Ladill Bird SMTP) and SMS (Termii); each send is logged on the timeline.
  • Reports — pipeline by stage, win rate, won value over time, leads by status, activity mix.

Service API (first-party, service-key auth)

Authenticate with a per-consumer service key: Authorization: Bearer <CRM_API_KEY_*> (see config/crm.php, App\Http\Middleware\AuthenticateService, alias auth.service:crm). Every request must pass owner (query or body) to scope data to the end user.

GET    /api/customers?owner=<sub>&search=
POST   /api/customers            {owner,name,email,phone,company,...}
... (show/update/destroy)

GET    /api/leads?owner=<sub>&status=
POST   /api/leads                {owner,name,status,estimated_value_minor,...}
POST   /api/leads/{id}/convert   {owner}        -> creates/links a customer

GET    /api/products?owner=<sub>&type=&active=
POST   /api/products             {owner,name,type,unit_price_minor,currency,tax_rate}

POST   /api/timeline             {owner,event,title,external_id,amount_minor,
                                  currency,url,customer_id|customer_email,...}

POST /api/timeline is how sibling products push "what happened" events onto a contact's timeline (invoice.sent, payment.received, order.paid). The source is derived from the service key (never client-supplied) and the write is idempotent per (owner, source, external_id, event). Reference consumer: ladill-invoice App\Services\Crm\CrmClient::pushTimeline().

No key → 401; missing owner → 422; cross-owner access → 404.

Local dev

composer install
cp .env.example .env && php artisan key:generate
# sqlite for local: set DB_CONNECTION=sqlite and `touch database/database.sqlite`
php artisan migrate
npm install && npm run build   # or `npm run dev`
php artisan serve
php artisan test

See DEPLOY.md for production cutover.

S
Description
No description provided
Readme
1.7 MiB
Languages
PHP 67.6%
Blade 26.9%
JavaScript 2.2%
CSS 1.7%
Shell 1.6%