- Triggers (Admin > Wyzwalacze): event-driven rules that fire immediately on a ticket lifecycle event (created/updated/status/priority/assignee/team/ category changed, new reply), with AND-conditions and ordered actions (set status/priority/team/assignee, send e-mail). Ships its own dedicated, freely add/edit/delete-able e-mail templates, kept separate from the fixed system templates. - Ticket watching: operators can star/"Obserwuj" any ticket to follow it regardless of assignment/team. - Real-time notification bell (private per-user broadcast channel, 30s fallback poll) with an opt-in in-tab browser push notification. - Per-user notification preferences (/settings/notifications): scope (mine/unassigned/watched/all) and e-mail toggle per event category. - Admin > Integracje: new tab for LDAP/AD + BookStack config, split out of Konfiguracja. - Operator queue: Podkategoria/Zespół/Utworzono columns (off by default). - Obserwuj button moved next to the auto-refresh countdown; trigger condition builder shows subcategory/zgłaszający as name dropdowns instead of raw IDs; /settings/notifications got a back link, full-width push card, and a bordered table container; admin panel tab and operator queue view now persist across a plain page refresh. - Docs: README/ARCHITECTURE/wiki updated for all of the above. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
245 lines
13 KiB
Markdown
245 lines
13 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to this project are documented in this file. Format loosely
|
||
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||
|
||
## [1.1.3] - 2026-07-22
|
||
|
||
### Added
|
||
|
||
- **Triggers** (Admin > Wyzwalacze) — event-driven business rules that fire
|
||
immediately on a ticket lifecycle event (created, any field updated, status/
|
||
priority/assignee/team/category changed, new public reply). AND-combined
|
||
conditions gate a sequence of ordered actions (set status/priority/team/
|
||
assignee, or send an e-mail). Ships with its own dedicated, freely
|
||
add/edit/delete-able trigger e-mail templates — kept separate from the
|
||
fixed, per-event system templates, which stay exactly as fixed as before.
|
||
Complements the time-based SLA automation rules rather than replacing them,
|
||
guarded against runaway loops (a depth limit plus a same-value no-op check).
|
||
- **Ticket watching** — operators can star/"Obserwuj" any ticket to follow it
|
||
regardless of assignment or team.
|
||
- **Real-time notification bell** — the bell now updates the instant a
|
||
notification is created (broadcast on a new private per-user channel),
|
||
with the existing 30s poll kept as a fallback for a dropped websocket.
|
||
Optionally also raises a native in-tab browser push notification.
|
||
- **Per-user notification preferences** (`/settings/notifications`) — each
|
||
operator/admin chooses, per event category (new ticket, ticket update,
|
||
escalation), which scope of tickets (mine, unassigned, watched, all)
|
||
notifies them via the bell and whether that also sends an e-mail, plus an
|
||
opt-in toggle for the browser push notifications above.
|
||
- **Admin > Integracje** — new tab hosting LDAP/AD and BookStack
|
||
configuration, split out of Konfiguracja so that tab is just general
|
||
system settings (attachments, session, timezone).
|
||
- Operator queue: three more optional columns (off by default, toggle via
|
||
"Kolumny") — Podkategoria, Zespół, Utworzono.
|
||
|
||
### Changed
|
||
|
||
- The "Obserwuj" button on the operator ticket view moved next to the
|
||
auto-refresh countdown badge, both now grouped on the right.
|
||
- `/settings/notifications`: added a "← Wróć" link back to the operator/admin
|
||
area, the browser-push card now spans the full page width, and the
|
||
preferences table sits in a bordered card like the rest of the app.
|
||
- Trigger conditions on Podkategoria/Zgłaszający now show a name dropdown
|
||
instead of a raw ID field.
|
||
- The admin panel's active tab and the operator queue's active view now
|
||
persist across a plain page refresh (bound to the URL query string), so
|
||
reloading no longer bounces back to the first tab.
|
||
|
||
## [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 `TicketService` setters 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:init`
|
||
event entirely, silently skipping the operator-queue subscription.
|
||
- The `mariadb` container'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 the `roles`/`role_user`
|
||
pivot, not a plain column) needs the `roles` table seeded before
|
||
assigning a role by key — now seeded automatically for every test in
|
||
`Tests\TestCase`. A handful of other tests were missing
|
||
`NotificationSetting`/`ReplyQuickAction` seed 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 `FULLTEXT` search (portable `LIKE`
|
||
fallback 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's `stage` (via
|
||
`Status::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 with
|
||
`unauthorized` because Gitea's auto-injected `secrets.GITHUB_TOKEN` isn't
|
||
granted push access to its own container registry on this instance. Now
|
||
uses a dedicated `REGISTRY_TOKEN` secret (a Gitea access token with
|
||
`write:package`/`read:package` scope), and the workflow fails fast with a
|
||
clear `::error::` message before attempting login if that secret isn't
|
||
configured, instead of surfacing Docker's opaque `unauthorized` error.
|
||
- 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) and `Login::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_changed` and `ticket_closed`) for the same event. Closing now only
|
||
fires `ticket_closed`; every other status transition still fires
|
||
`status_changed` as 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 Laravel
|
||
`src/README.md`.
|
||
- Added `.gitea/workflows/build.yml`: Gitea Actions now builds and pushes the
|
||
`servicedesk` image to the Gitea container registry whenever `Dockerfile`
|
||
changes on `main`.
|
||
- `compose.yaml` now pulls `image: gitea.kzbikowski.pl/kzbkowski/servicedesk:${IMAGE_TAG:-latest}`
|
||
instead of building locally; `mariadb` pinned to `mariadb:12.3`; added a
|
||
`mariadb` healthcheck and `depends_on: condition: service_healthy` for
|
||
`servicedesk`.
|
||
- Added tracked templates `compose.yaml.example` and `.env.example` (root) for
|
||
the previously-untracked `compose.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.
|