- 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>
11 KiB
11 KiB
Changelog
All notable changes to this project are documented in this file. Format loosely follows Keep a Changelog.
[1.1.2] - 2026-07-22
Added
- Real-time updates (Laravel Reverb) — the operator ticket queue now
updates live: new tickets appear, status/priority/team/assignee changes
and new replies re-sort/refresh the affected row, and closed/deleted/
reassigned-away tickets disappear, all without a manual refresh. The
ticket message thread is now "live chat": a reply from either side
appears for the other party instantly. Clients also see status/priority/
team/assignee changes and new history entries on their own ticket live.
Backed by two private channels (
operator.queue,ticket.{id}) and two broadcast events (TicketQueueChanged,TicketMessagePosted), sent synchronously (no queue worker needed, consistent with how e-mail notifications already work in this app). - Periodic fallback refresh — since a websocket connection can drop silently (backgrounded tab, network blip), the operator queue and both ticket-detail views also poll themselves every 30–60 seconds regardless of broadcasting, with a small visible countdown badge so it's clear the page is still refreshing on its own.
- SLA automation rules (Admin > Automatyzacja SLA) — configurable rules
that act on a ticket after N minutes of customer silence (optionally
scoped to a priority/category/team): change priority, status, team, or
assignee. Reuses the same
TicketServicesetters a manual operator action would, so automated changes get the same history entry, notification, and (now) live broadcast as a human doing it. A new scheduled command (automation:run-rules, every 15 minutes) evaluates all enabled rules; each rule only fires once per ticket until a fresh reply or a close/reopen resets it. - New notification: ticket landed in your team — every operator on a team whose subcategories match a newly created ticket now gets notified (enabled by default; toggle like any other trigger in Admin > Szablony e-mail).
- BookStack knowledge-base sidebar on the client's own ticket view — previously only shown to operators; clients now see the same category/subcategory-matched suggestions on their ticket page that they saw while creating it.
- Operator ticket view / client ticket view now show the assigned operator and team in the "Status i priorytet" card (client side).
- Stats dashboard: new breakdowns — tickets by subcategory, CSAT average by team and by operator, top 10 clients by ticket volume (+ one "Goście" bucket for guest submissions), and a client × subcategory cross-tab (top 10 clients × top 5 subcategories, rest folded into "Inne"). The whole dashboard is now organized into labeled sections (Podsumowanie / Rozkład zgłoszeń / Obciążenie / Klienci / Ocena obsługi / Trend) instead of one flat wall of cards.
Changed
- BookStack suggestions (ticket-creation wizards, guest landing page,
operator/client ticket views) now load in a beat after the page's first
paint (
wire:init) instead of blocking the initial render on BookStack's API response. - The notification bell shows unread notifications only — reading one (by clicking it or "mark all as read") now removes it from the list instead of just dimming it.
- The client ticket-view page is now the same width as the operator's (1180px, up from 920px) — the main message-thread column is unaffected.
- Mobile: the theme/notifications/profile-menu dropdowns in the top nav now expand to the full screen width below 640px instead of a fixed narrow width that could overflow off-screen.
Fixed
- Two bugs that silently disabled all real-time updates from the moment
Reverb was first wired in: (1) the Echo client never sent a CSRF token
when authorizing private channels, so every subscription attempt was
rejected by the app's own CSRF middleware; (2) the Echo setup script
(loaded as a deferred ES module) raced against Livewire's own
synchronously-loaded bootstrap script and could miss the
livewire:initevent entirely, silently skipping the operator-queue subscription. - The
mariadbcontainer's healthcheck was failing (Access denied ... using password: NO) because its auto-generated credentials file had world-writable permissions (an artifact of this stack's NFS-backed bind mount) and MariaDB's client refuses to read credentials from a file anyone can modify — the healthcheck now passes. - Several pre-existing test-suite gaps found while working in this area:
User::roles(a virtual attribute backed by theroles/role_userpivot, not a plain column) needs therolestable seeded before assigning a role by key — now seeded automatically for every test inTests\TestCase. A handful of other tests were missingNotificationSetting/ReplyQuickActionseed data, asserting a stale set of default-enabled notification triggers, or using the wrong Notification Fake assertion for a real (non-guest) recipient.
[1.1.0] - 2026-07-22
Added
- In-app notifications — a bell in the top bar backed by Laravel's database notification channel, alongside existing e-mail notifications (same per-trigger toggle drives both; ticket links now correctly point into the recipient's own area instead of always linking to the client view).
- Drag-and-drop attachments on every upload form (ticket creation, replies, internal notes), plus inline image thumbnails in the message thread instead of a plain download link.
- Customer satisfaction (CSAT) rating — clients rate a closed ticket 1–5 stars with an optional comment; shown read-only to operators, surfaced as a KPI on the stats dashboard, and linked from the "ticket closed" e-mail.
- Saved queue views — operators can save/apply/delete named filter+sort+ column presets in the ticket queue and mark one as their default.
- Full-text search — MySQL/MariaDB
FULLTEXTsearch (portableLIKEfallback on sqlite) across ticket subject/body and reply message bodies, now also available on the client's own ticket list (previously operator-only, and previously subject/number/name/email only). - Stats CSV export — exports the currently filtered ticket set from the operator stats dashboard.
- BookStack knowledge-base integration, optional and off by default — suggests relevant articles by category/subcategory while creating a ticket, and in a separate sidebar on an existing ticket for operators (with a copy-link button). Configurable from Admin > Konfiguracja: connection + API token (encrypted), optional SSL-verification bypass for self-signed instances, page/book search-type filter, and two independent per-shelf allow-lists (nothing is ever searched until specific shelves are opted in, separately for ticket-creation suggestions vs. the operator sidebar) with a manual refresh button for the shelf list.
Changed
- Closed tickets are no longer shown in the "Moje zgłoszenia" / "Nieprzypisane" / per-team queue tabs — they now only ever appear under "Zamknięte", matching how the "Otwarte" tab already worked.
- The operator ticket-view sidebar is ~50% wider (to fit the BookStack suggestions panel); the page itself grew to match, so the ticket content/thread column keeps its previous width.
- The "Resetuj" work-timer button sits below the "Zgłoszenie zamknięte — zliczanie wstrzymane" notice instead of beside it.
Fixed
TicketService::setStatus()now checks a status'sstage(viaStatus::stageFor()) rather than the literal key'closed'to decide whether to fire the "ticket closed" notification/stop the timer — correct even if an admin renames or replaces which key maps to the closed stage.
[1.0.2] - 2026-07-22
- Fixed
.gitea/workflows/build.yml: registry login was failing withunauthorizedbecause Gitea's auto-injectedsecrets.GITHUB_TOKENisn't granted push access to its own container registry on this instance. Now uses a dedicatedREGISTRY_TOKENsecret (a Gitea access token withwrite:package/read:packagescope), and the workflow fails fast with a clear::error::message before attempting login if that secret isn't configured, instead of surfacing Docker's opaqueunauthorizederror. - Fixed: opening or manually resuming a closed ticket no longer starts its work timer, and closing a ticket (via the status dropdown, a reply "quick action" transition, the REST API, or merge) now checkpoints and stops any running timer. Time tracking only ever accrues while a ticket is open.
- Fixed: the login form accepted an empty username/password, submitting them
straight to the auth provider. The form fields are now
required(blocks submission client-side) andLogin::submit()also rejects blank/ whitespace-only credentials server-side before attempting authentication, showing "Podaj nazwę użytkownika i hasło." instead. - Fixed: closing a ticket sent two separate notification e-mails
(
status_changedandticket_closed) for the same event. Closing now only firesticket_closed; every other status transition still firesstatus_changedas before.
[1.0.1] - 2026-07-22
Documentation and deployment/CI overhaul — no application behavior changes.
- Added project docs:
TESTING.md,CONTRIBUTING.md,ARCHITECTURE.md,SECURITY.md,CLAUDE.md; removed the unmaintained stock Laravelsrc/README.md. - Added
.gitea/workflows/build.yml: Gitea Actions now builds and pushes theservicedeskimage to the Gitea container registry wheneverDockerfilechanges onmain. compose.yamlnow pullsimage: gitea.kzbikowski.pl/kzbkowski/servicedesk:${IMAGE_TAG:-latest}instead of building locally;mariadbpinned tomariadb:12.3; added amariadbhealthcheck anddepends_on: condition: service_healthyforservicedesk.- Added tracked templates
compose.yaml.exampleand.env.example(root) for the previously-untrackedcompose.yaml/.env. - Documented the new pull-based deploy flow and one-time registry login in
install.md.
[1.0.0] - 2026-07-21
Initial release.
- Ticketing core: categories/subcategories with per-subcategory custom fields, statuses, priorities, teams, attachments, message threads (public replies + internal notes), history log, merge/delete.
- SLA rules per priority with a scheduled breach check (
tickets:check-sla-breaches, every 15 minutes). - Response templates, quick actions, and per-event HTML email templates/ notification toggles.
- Operator statistics dashboard (
/operator/stats) with KPI tiles and breakdowns. - Branding/config panel: company identity, LDAP connection + user sync, SMTP, attachment limits, session lifetime, timezone.
- LDAP authentication (LdapRecord) with local-account fallback.
- REST API (
/api/v1/...) via Sanctum, ability-scoped (tickets:read,tickets:write,dictionaries:read,users:read), with Swagger docs at/admin/api-docs. - Installable PWA manifest/icons for the client-facing area.