v1.1.2
- Real-time updates (Laravel Reverb): live operator queue, live ticket chat/detail updates for operator and client, periodic fallback refresh with a visible countdown as a backstop for dropped websocket connections. - SLA automation rules (Admin > Automatyzacja SLA): act on a ticket after N minutes of customer silence (change priority/status/team/assignee), evaluated every 15 minutes, reusing TicketService's own setters so automated changes get the same history/notification/broadcast a manual change would. - New notification: every operator on a matching team gets notified when a new ticket lands in one of their subcategories. - BookStack knowledge-base sidebar now also shown on the client's own ticket view (previously operator-only); suggestions everywhere now load in after first paint instead of blocking it. - Client ticket view: shows assigned operator + team; page widened to match the operator's. - Notification bell shows unread only; read notifications disappear instead of just dimming. - Stats dashboard: sectioned layout, new breakdowns (by subcategory, CSAT by team/operator, top clients, client x subcategory cross-tab). - Mobile: nav dropdowns (theme/notifications/profile) now expand full width instead of overflowing off-screen below 640px. - Fixed two bugs that silently disabled all real-time updates (missing CSRF header on Echo's private-channel auth; a script-load-order race that could miss the livewire:init event) and the mariadb healthcheck (world-writable credentials file on this stack's NFS mount). - Assorted test-suite fixes (roles virtual attribute needs the roles table seeded; a few missing seeds/wrong assertions found along the way). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
61
README.md
61
README.md
@@ -29,6 +29,18 @@ and **[wiki/admin](wiki/admin/README.md)** for role-specific how-to guides.
|
||||
- **SLA** — per-priority response/resolution time targets; a scheduled command
|
||||
(`tickets:check-sla-breaches`, every 15 min) flags overdue tickets and can notify
|
||||
the assigned operator.
|
||||
- **SLA automation rules** (Admin > Automatyzacja SLA) — configurable rules that
|
||||
change a ticket's priority/status/team/assignee after N minutes of customer
|
||||
silence (optionally scoped to a priority/category/team), evaluated every 15
|
||||
minutes (`automation:run-rules`). Reuses the same `TicketService` setters a
|
||||
manual operator action would, so an automated change gets the same history
|
||||
entry, notification, and live broadcast as a human doing it; each rule fires
|
||||
once per ticket until a fresh customer reply or a close/reopen resets it.
|
||||
- **Real-time updates** — the operator ticket queue and both ticket-detail views
|
||||
(operator and client) update live over WebSockets (Laravel Reverb): new
|
||||
tickets, status/priority/team/assignee changes, and new replies ("live chat")
|
||||
all show up without a manual refresh. A periodic fallback refresh (with a
|
||||
visible countdown) covers a dropped websocket connection.
|
||||
- **Categories & custom fields** — admin-defined categories/subcategories, each with
|
||||
its own set of custom fields (text/textarea/select/checkbox/date/number) and an
|
||||
optional default priority.
|
||||
@@ -41,9 +53,12 @@ and **[wiki/admin](wiki/admin/README.md)** for role-specific how-to guides.
|
||||
team changed, closed, operator replied, SLA breached), each independently
|
||||
enable/disable-able.
|
||||
- **Operator statistics** (`/operator/stats`) — filterable dashboard (date range,
|
||||
team, priority, category, assignee) with KPI tiles (volume, SLA breach rate,
|
||||
average first-response/resolution time) and breakdowns by status, priority,
|
||||
category, team and operator workload, plus a daily created-vs-closed trend.
|
||||
team, priority, category, assignee) organized into sections: KPI tiles (volume,
|
||||
SLA breach rate, average first-response/resolution time, CSAT); breakdowns by
|
||||
status, priority, category and subcategory; team/operator workload; top 10
|
||||
clients by ticket volume plus a client × subcategory cross-tab (top 5
|
||||
subcategories, rest folded into "Inne"); CSAT average by team and by operator;
|
||||
and a daily created-vs-closed trend.
|
||||
- **Branding & config** — company name/logo/favicon/accent color, login notice,
|
||||
e-mail layout/footer, LDAP connection + user sync, SMTP connection, attachment
|
||||
limits, session lifetime, timezone — all editable from Admin > Konfiguracja.
|
||||
@@ -57,7 +72,10 @@ and **[wiki/admin](wiki/admin/README.md)** for role-specific how-to guides.
|
||||
- **PWA** — installable manifest + icons for the client-facing area.
|
||||
- **In-app notifications** — a bell in the top bar (client/operator/admin areas)
|
||||
backed by Laravel's database notification channel, alongside the existing
|
||||
e-mail notifications (same per-trigger enable toggle drives both).
|
||||
e-mail notifications (same per-trigger enable toggle drives both); shows
|
||||
unread notifications only — reading one removes it from the list. Includes a
|
||||
dedicated trigger notifying every operator on a team whose subcategories
|
||||
match a newly created ticket.
|
||||
- **Attachments** — drag-and-drop upload (in addition to the file picker) and
|
||||
inline image thumbnails in the message thread instead of a plain download link.
|
||||
- **Customer satisfaction (CSAT)** — clients rate a ticket 1–5 stars (+ optional
|
||||
@@ -73,29 +91,34 @@ and **[wiki/admin](wiki/admin/README.md)** for role-specific how-to guides.
|
||||
- **BookStack knowledge-base integration** *(optional, off by default)* —
|
||||
suggests relevant BookStack articles by category/subcategory while a ticket
|
||||
is being created, and in a separate sidebar panel on an existing ticket for
|
||||
operators (with a copy-link button). Configured entirely from Admin >
|
||||
Konfiguracja: connection + API token, optional SSL-verification bypass for
|
||||
self-signed instances, page/book search-type filter, and two independent
|
||||
per-shelf allow-lists (nothing is searched until an admin opts specific
|
||||
shelves in, separately for ticket-creation suggestions vs. the operator
|
||||
sidebar).
|
||||
both operators and clients (with a copy-link button for operators). Loads in
|
||||
after the page's first paint rather than blocking it. Configured entirely
|
||||
from Admin > Konfiguracja: connection + API token, optional SSL-verification
|
||||
bypass for self-signed instances, page/book search-type filter, and two
|
||||
independent per-shelf allow-lists (nothing is searched until an admin opts
|
||||
specific shelves in, separately for ticket-creation suggestions vs. the
|
||||
operator/client ticket-view sidebar).
|
||||
|
||||
## Tech stack
|
||||
|
||||
- **Backend**: Laravel, Livewire (server-driven UI, no SPA build beyond Tailwind/Vite
|
||||
for CSS), LdapRecord for directory auth, Sanctum for API tokens, L5-Swagger for
|
||||
API docs.
|
||||
API docs, Laravel Reverb for WebSocket broadcasting (real-time queue/chat
|
||||
updates — see [ARCHITECTURE.md](ARCHITECTURE.md)).
|
||||
- **Frontend**: Blade + Livewire + a little Alpine.js for local UI state; Tailwind
|
||||
v4 via Vite for `resources/css/app.css`. No JS charting library — the statistics
|
||||
v4 via Vite for `resources/css/app.css`; Laravel Echo + Pusher-protocol client
|
||||
(`resources/js/echo.js`) for Reverb. No JS charting library — the statistics
|
||||
dashboard is hand-rolled inline-styled bar/column charts, so it needs no client
|
||||
build step beyond the CSS bundle.
|
||||
- **Database**: MariaDB.
|
||||
- **Deployment**: `compose.yaml` — `servicedesk` (source bind-mounted from `./src`,
|
||||
no image rebuild needed for PHP/Blade/route changes) + `mariadb`, fronted by
|
||||
Traefik with a private-CA TLS cert. The `servicedesk` image itself is built and
|
||||
pushed by Gitea Actions (`.gitea/workflows/build.yml`) to the Gitea container
|
||||
registry whenever `Dockerfile` changes — `compose.yaml` just pulls a tag, it
|
||||
never builds locally.
|
||||
no image rebuild needed for PHP/Blade/route changes) + `mariadb` + `reverb`
|
||||
(same image, `php artisan reverb:start`), fronted by Traefik with a private-CA
|
||||
TLS cert (the websocket path is routed to `reverb` by a higher-priority
|
||||
Traefik rule; everything else goes to `servicedesk`). The `servicedesk` image
|
||||
itself is built and pushed by Gitea Actions (`.gitea/workflows/build.yml`) to
|
||||
the Gitea container registry whenever `Dockerfile` changes — `compose.yaml`
|
||||
just pulls a tag, it never builds locally.
|
||||
|
||||
See **[install.md](install.md)** for full step-by-step deployment instructions —
|
||||
both via Docker Compose (this stack) and directly on a server with Apache/Nginx,
|
||||
@@ -128,14 +151,18 @@ Compose-level and Laravel-level) and the LDAP/SMTP gotcha after a fresh seed.
|
||||
src/ Laravel application
|
||||
app/Livewire/ Client/Operator/Admin Livewire components
|
||||
app/Models/ Eloquent models
|
||||
app/Events/ Broadcast events (TicketQueueChanged, TicketMessagePosted)
|
||||
app/Console/Commands/ Scheduled commands (SLA breach check, automation rules)
|
||||
app/Services/ TicketService (ticket lifecycle + notifications), BookStackClient
|
||||
app/Ldap/ LDAP user model + sync handlers
|
||||
database/migrations/ Schema (one file per table group, final shape)
|
||||
database/seeders/ DatabaseSeeder — reference data, no ticket data
|
||||
resources/css/ Tailwind entrypoint (needs `npm run build` after edits)
|
||||
resources/js/echo.js Laravel Echo/Reverb client + broadcast → Livewire event bridge
|
||||
resources/views/ Blade templates
|
||||
routes/web.php Client/Operator/Admin routes (role-gated)
|
||||
routes/api.php REST API (Sanctum, ability-gated)
|
||||
routes/channels.php Broadcasting channel authorization (operator.queue, ticket.{id})
|
||||
wiki/
|
||||
client/ How-to guide for the Client role
|
||||
operator/ How-to guide for the Operator role
|
||||
|
||||
Reference in New Issue
Block a user