Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Escalated Laravel Laravel Package

escalated-dev/escalated-laravel

A full-featured, embeddable support ticket system for Laravel with SLA tracking, escalation rules, agent workflows, and a customer portal. Self-host or sync to cloud with one config change.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Package shape. escalated-dev/escalated-laravel is a full helpdesk (tickets, SLA engine, escalation rules, agent queue, admin panel, customer portal, KB, embeddable widget, inbound email) delivered as an installable Laravel package plus a companion Vue 3 component library published separately as @escalated-dev/escalated. It is not a thin SDK — it is an application shipped inside a package, with its own routes, migrations, config, gates, views, Artisan commands, and frontend build coupling.

Architecture fit. Fit is good but narrow: Laravel 11–13, PHP 8.2+, and — critically — an Inertia.js + Vue 3 + Tailwind host application. The integration model is:

  • composer require → php artisan escalated:install → php artisan migrate
  • Host User model implements Ticketable / HasTickets (installer can auto-patch it)
  • Two authorization gates (escalated-admin, escalated-agent) defined by the host app
  • Frontend requires editing app.ts (Inertia page resolver namespace Escalated/), Tailwind content/@source paths, and optionally EscalatedPlugin for host-layout theming
  • Routes mount under a configurable prefix (/support by default)

If the host app is Blade/Livewire, a React SPA, or API-only, the value proposition largely evaporates — you would be writing your own UI against its controllers. That is the single biggest architectural gate.

Notable design strengths. Genuinely mature for a 28-star package:

  • Automatic user-key type reflection (int/UUID/ULID/string) at migration time, with user_key_type override — removes a common integration failure.
  • Three hosting modes (self-hosted, synced, cloud) behind a driver pattern, with the same controllers/UI across modes; synced degrades to queued retry rather than hard failure.
  • Polymorphic TicketSubject contract for attaching arbitrary host models (Project, Customer, asset) with an explicit allowlist for the agent API — a correct, security-aware default.
  • Email threading via In-Reply-To/References, branded templates, inbound email across Mailgun/Postmark/SES/IMAP.
  • escalated:wake-snoozed-tickets implies scheduler-driven state machine — operationally sane, but a hard runtime dependency.

Changes in v1.9.4 (assessed). This is a feature release with two security-relevant surface changes and two fixes:

  • Cross-origin widget embedding. An allowlist (escalated.widget.allowed_origins / ESCALATED_WIDGET_ALLOWED_ORIGINS, mirrored as an admin setting widget_allowed_origins) now grants listed origins CORS headers and a CSRF-check exemption, with requests forced to run as guests. Wildcard subdomains (https://*.example.com) are supported. Empty by default.
  • New public route GET {prefix}/widget/embed.js serves a widget bundle built from the npm companion package; disable via escalated.widget.serve_script.
  • Widget metadata capture. Host-supplied parameters (order number, plan, page URL) are persisted on widget tickets and live chats as a flat, sanitised scalar map, plus a server-recorded embedded_on origin. /config advertises accepts_metadata: true — a new client-facing contract.
  • Fixes. Admin settings page now actually persists widget settings it already displayed (the controller dropped them — i.e. widget enablement from the UI was broken); and live-chat metadata now sanitised like ticket metadata (previously unbounded — a prior storage-abuse/PII defect).

Net effect: the package is now a first-class embeddable product rather than a self-contained one, and the widget is a supported public ingress path with a documented configuration contract. The default-empty allowlist means the posture is unchanged until opted into — but the decision to opt in is now a discrete, reviewable risk decision rather than an incidental one.

Technical risk.

Risk Severity Note
Invasive schema ownership High Many host-DB tables created by package migrations, key-typed by reflection at migrate time. Type is chosen once; changing user key type later "requires a manual migration" per README. Treat as a one-way door.
Frontend lock-in High Vue 3 + Inertia + Tailwind coupling, plus a second package (@escalated-dev/escalated) that must be version-locked in step. Two release trains.
Widget ingress (deliberate CSRF exemption) High (raised from Medium) Listed origins skip CSRF and run as guests. Correct for a cross-site embed, but it means the origin allowlist is now a security boundary owned by whoever can edit config or the admin settings page. Wildcard matching must be verified in code, not assumed (https://*.example.com must not match https://evil.com/?x=.example.com or https://*.example.com.attacker.net).
Widget bundle served by the host app Medium (new) widget/embed.js ships a JS bundle built from the npm package and served by PHP. Any widget-side fix now requires a PHP package release, and a PHP-only bump can serve a bundle mismatched to the installed @escalated-dev/escalated. Confirm the shipped artifact is version-stamped and integrity-checkable.
Metadata PII capture Medium (new) metadata + embedded_on record page URL, plan, order number and the embedding origin on customer-visible records. Sanitisation is described as flat/short scalars but size caps, retention, and export/erasure behaviour are unstated.
Adoption signal High 28 stars, 0 dependents, single-vendor. No third-party evidence of production use, no community answers for edge cases.
Release chronology Medium Last release listed as 2026-10-19 — verify this; if it is a data artifact rather than a real tag, re-baseline stability expectations.
Attack surface (broader) Medium–High Guest magic-link tickets, an embeddable <script> widget now explicitly cross-origin, inbound email webhooks, and file uploads all widen exposure. The 1.9.4 notes reference 422/429 answers from widget endpoints, implying rate limiting exists — verify limits, token TTL, and webhook signature checks in code.
Authorization granularity Medium Two boolean-style gates only. No per-department or per-queue scoping described; RBAC depth is likely thinner than enterprise expectations.
Cloud mode data egress Medium synced/cloud ship ticket content (customer PII) to cloud.escalated.dev — now including widget metadata. Requires security/DPA review before any use.

Key questions for the maintainer / spike.

  1. Is there a 1.x stability commitment, semver policy, and documented upgrade path for schema changes across releases?
  2. What is the supported uninstall/rollback procedure — can migrations be cleanly reversed, or is adoption permanent?
  3. Is the product single-tenant per app, or does it support multi-tenant isolation (relevant for SaaS hosts)?
  4. Widget origin allowlist: is matching exact-origin-plus-labelled-wildcard anchored at both ends? Are scheme (http vs https) and port part of the match? Is the stored admin setting validated against the same rules as env config, and who can change it?
  5. CSRF exemption scope: is the bypass strictly limited to the widget endpoints, and is it gated on the allowlist match server-side (not on a client-supplied header)? Does a guest-mode widget request get the same rate limits as the anonymous portal?
  6. Widget rate limiting and abuse: what are the limits behind the 429 path, per-IP or per-origin, and is there a CAPTCHA/challenge escape hatch?
  7. Metadata contract: what are the hard caps (key count, key length, value length), what is dropped vs truncated, how long is it retained, and does it surface in exports/GDPR erasure paths?
  8. Where are guest-token expiry, upload validation, and inbound webhook signature checks enforced?
  9. Does commercial support exist (escalated.dev Cloud), and what is the response SLA?
  10. Do escalated-agent / escalated-admin gates support scoping to departments, or is authorization effectively global once granted?
  11. What is the test matrix — is the CI suite run against Laravel 11/12/13 and multiple DB drivers, and is there a test covering allowlisted vs non-allowlisted origin behaviour (including 422/429 responses)?

Verdict. Feasible and unusually complete for its maturity level; the risk is not technical feasibility but concentration — of stack assumptions, of schema ownership, and of vendor dependency. v1.9.4 raises capability and raises the security-review bar in the same step: the widget is now a supported cross-origin public ingress with a config-managed allowlist, and the release notes confirm a widget-enablement defect existed up to this point, so any prior evaluation of widget behaviour should be re-baselined. Appropriate for a time-boxed spike with a documented exit path, with the embed feature treated as a separate, later go/no-go — not for an unexamined production commitment.

Integration Approach

Stack fit assessment. Score fit before writing code:

Host stack Fit Comment
Laravel 11–13 + Inertia + Vue 3 + Tailwind Strong Designed path; near-drop-in
Laravel + Inertia + React/Svelte Weak Page resolver and component library are Vue-only; you inherit backend, rebuild frontend
Laravel + Livewire/Blade Weak Would need custom views over package controllers; most delivered value lost
Laravel API-only / headless Moderate Viable if you only want the domain layer (tickets, SLA, escalation) — but that is not the advertised product
Non-Laravel marketing site / docs site as embed host New in 1.9.4 A listed origin needs only one <script> tag; the host site's stack is irrelevant

Migration path (recommended, 3-day time-box).

  1. Isolation first. Branch or throwaway app; pin exact versions of both escalated-dev/escalated-laravel and @escalated-dev/escalated. Do not integrate on main.
  2. Schema dry run. Publish config and migrations (--tag=escalated-config, --tag=escalated-migrations) and review the generated SQL before running against any shared database. Confirm the reflected user-key type matches your model. Verify table-name collisions against existing tables. If upgrading an existing install, diff for new columns/tables carrying widget metadata and embedded_on.
  3. Auth wiring. Confirm your User model's admin/agent flags exist and map cleanly to the two gates. If agent status is derived (roles, teams), write the gate closures explicitly rather than bolting booleans onto the users table.
  4. Frontend wiring. Tailwind content/@source (v3 vs v4 paths differ per README), app.ts page resolver, EscalatedPlugin with your AuthenticatedLayout (must accept #header and default slots), theme via CSS custom properties.
  5. Runtime prerequisites. Scheduler entry for escalated:wake-snoozed-tickets and SLA breach detection; queue worker for notifications, sync retries, inbound mail; storage disk config for attachments.
  6. Widget decision — split from core integration. Ship with widget.enabled=false and widget.allowed_origins empty for the first sprint. When you do opt in: enumerate origins explicitly (no wildcards in the first cut), set serve_script intentionally, and confirm the admin-settings path and the env path cannot disagree. Because pre-1.9.4 admin saves silently dropped widget settings, verify persistence after save rather than trusting the UI.
  7. Mode decision. Default to self-hosted for the spike. Treat synced/cloud as a separate, later, security-reviewed decision — cloud egress now includes widget metadata.
  8. Go/no-go. Exit criteria: schema reviewed, gates enforced and tested, one end-to-end ticket lifecycle (create → assign → reply → SLA breach → escalate → resolve) passing in staging, a written uninstall plan, and — if the widget is in scope — an origin-matrix test (allowlisted origin succeeds including on 422/429; non-allowlisted origin unchanged; wildcard does not over-match; CSRF bypass does not extend beyond widget routes).

Compatibility checklist. Laravel constraint vs host; PHP 8.2+; Node 18+; Inertia version; Tailwind major version; Vite; DB driver (verify the user-key reflection behaves on your driver, particularly Postgres UUIDs); mail provider webhook availability for inbound; broadcasting credentials if opting into Reverb/Pusher/Soketi; and — new — CORS behaviour through any reverse proxy/CDN in front of the app, since the widget's cross-origin path is now load-bearing.

Sequencing guidance. Land the backend + schema first and validate it headlessly (routes, policies, ticket lifecycle via artisan/tinker) before touching the frontend build. Frontend issues (Tailwind purging, page resolver paths) are noisy and will mask domain-layer problems if tackled simultaneously. Ship internal-only (agents only, portal disabled, widget not embedded) for one sprint before exposing the customer portal — that isolates auth and SLA correctness from public attack surface. Add the cross-origin widget only after the same-origin portal is stable, so CORS/CSRF failures are not confused with portal bugs.

Rollback posture. Establish before commit: which tables the package owns, whether migrate:rollback is safe, and whether a feature-flag on the route prefix (escalated.prefix) is sufficient to dark-launch. For the widget specifically, confirm that emptying allowed_origins (or setting serve_script=false) fully reverts the exposure — a config-only kill switch is the desired property, but verify it also removes the embed.js route rather than merely 404-ing requests. If uninstall is not clean, that is a decision-changing finding, not a footnote.

Operational Impact

Maintenance. You are adopting a product, not a library. Post-integration you own: schema migrations inside your app's migration history, a Vue component library that upgrades on a separate cadence, a scheduler-driven SLA state machine, queue workers, file storage, outbound email deliverability, and (if enabled) inbound mail webhooks plus a publicly served JS bundle. Two version trains must move in lockstep — a PHP bump without the matching npm bump is a realistic breakage, and after 1.9.4 that mismatch can ship through widget/embed.js to third-party sites you do not deploy to. Treat "upgrade PHP package" as "upgrade PHP package and re-verify the served bundle version." Budget ongoing maintenance; this is not "install and forget."

Support. Single-vendor, low-adoption package. Expect to be the first to hit edge cases: no StackOverflow corpus, no third-party blog posts, no dependents to inspect for patterns. Two newly demonstrated classes of defect reinforce this — widget settings silently not persisting from the admin UI, and unbounded metadata storage — both of which were only corrected in 1.9.4, i.e. they were live for prior adopters without a visible failure signal. The commercial escalated.dev offering is the likely escalation path — confirm support terms before depending on it. Preserve the ability to fork: MIT license makes that viable, but forking a full application (now including a widget bundle) is a large commitment, so treat it as a last resort rather than the plan.

Scaling. Four axes to watch:

  • Data volume — tickets, replies, activity timeline, attachments, and now per-record metadata grow monotonically. Confirm indexes on tickets (requester, assignee, status, SLA due) and plan attachment offload to object storage early. If widget traffic is high-volume, metadata adds a small but non-zero growth multiplier; confirm caps empirically.
  • Polling load — real-time broadcasting is opt-in with an automatic polling fallback. Without Pusher/Reverb/Soketi, agent dashboards generate steady read traffic; size accordingly or enable broadcasting. Cross-origin widget widgets increase the number of concurrent anonymous clients hitting /config and chat endpoints.
  • Queue pressure — notification fan-out, cloud sync retries, and inbound mail parse all land on the queue. A stalled worker degrades silently: tickets update but nobody is emailed.
  • Anonymous write volume — widget tickets and live chats are guest-created by design. Rate limiting exists (429s are handled and CORS-decorated), but capacity planning must assume a public, unauthenticated write path if the widget is enabled.

Failure modes and detection.

Failure Symptom Mitigation
Scheduler not running SLA breaches never fire, snoozed tickets never wake — silent Alert on escalated:wake-snoozed-tickets heartbeat and on overdue-but-unbreached ticket count
Queue worker down Notifications and cloud sync stop; UI still works Queue-depth and failed-job alerts
Cloud unreachable (synced) Local works, unified inbox diverges Monitor sync backlog; document that divergence is expected and self-healing on retry
Inbound email webhook failure Replies lost with no user-visible error Verify signatures, alert on webhook 4xx/5xx, reconcile against provider logs
User-key type mismatch FK/join errors or truncated UUIDs after migration Validate reflected column types in staging before production migrate
Tailwind purge / resolver path errors Unstyled pages or "page not found" in Inertia Add a smoke test hitting each Escalated route in CI
Gate misconfiguration Customers reach agent views Automated authorization test per role, run on every deploy
Origin allowlist misconfiguration (new) Embedded widget silently fails (CORS) or over-permissive wildcard admits unintended sites Load-test the origin matrix in CI; reject wildcards in review; log and alert on widget requests with unmatched Origin
embed.js route disabled or mismatched bundle (new) Third-party embeds break with no host-app error Monitor 404s on {prefix}/widget/embed.js; stamp and assert bundle version at deploy
Admin setting overwritten by config (new) Widget silently disabled after a deploy, or allowlist reverts Decide single source of truth (env vs admin) and treat the admin UI as view-only if env governs
Metadata leakage (new) Page URLs or order numbers appear in exports/logs beyond intended audience Review sanitisation caps in code; include metadata in data-retention and erasure runbooks

Ramp-up. Engineering ramp is fast for anyone fluent in Laravel + Inertia (an afternoon to read the surface, a day to wire it). The real ramp is operational and procedural: agents must learn queue semantics, SLA policy intent, escalation rule precedence, and status-transition constraints. Budget for configuring departments, SLA policies, and escalation rules deliberately — the engine is only as good as the policy data — and for an admin runbook covering stuck queues, missed SLAs, cloud-sync reconciliation, and (new) widget origin management. Support-staff training is a larger cost than developer integration here, and if the widget is exposed, add a documented process for adding/removing embedding sites, since that list is now an access-control artifact rather than a cosmetic setting.

Overall TPM position. High capability per unit of integration effort, offset by concentrated stack coupling, non-trivial schema ownership, and thin adoption evidence. v1.9.4 strengthens the product's differentiation — self-serve embeddable support is a real differentiator — while adding a second public ingress and a config-as-security-boundary surface. Because the feature is default-off, the recommendation is unchanged in shape but needs one extra gate: recommend a scoped, reversible spike with explicit go/no-go criteria (clean schema review, verified authorization, documented uninstall), self-hosted mode only, internal-agent rollout before public portal, and widget embedding as a separately approved phase with an origin-allowlist review, CSRF-exemption scoping verified in code, and a metadata retention decision. Value the optionality: the low adoption that makes this cheap to try also makes it cheap to walk away from — protect that by not letting the package's migrations or frontend coupling become irreversible before the pilot proves out.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc