Files
servicedesk/README.md
Kacper 90fae0a4de v1.1.0
- 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, 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 FULLTEXT, portable LIKE fallback) across ticket
  subject/body and reply message bodies, now also on the client's own ticket
  list.
- Stats CSV export for the currently filtered ticket set.
- Optional BookStack knowledge-base integration (off by default): suggests
  articles by category/subcategory while creating a ticket and in a separate
  sidebar for operators on an existing ticket (with a copy-link button).
  Configurable connection/SSL bypass/search-type filter, plus two
  independent per-shelf allow-lists so nothing is ever searched until an
  admin opts specific shelves in.
- Closed tickets no longer show in "Moje zgłoszenia"/"Nieprzypisane"/team
  queue tabs, only under "Zamknięte" (matching how "Otwarte" already worked).
- Wired up the Admin > About "Wersja" field to config('app.version')/VERSION
  in .env instead of a stale hardcoded string.
- Fixed: TicketService::setStatus() now checks a status's stage rather than
  the literal key 'closed' to decide whether to fire the "ticket closed"
  notification/stop the timer.
- Updated README/ARCHITECTURE/CHANGELOG/install/SECURITY docs and all three
  wiki/ role guides for the above; documented a root-vs-www-data file
  ownership gotcha in CLAUDE.md (running artisan commands via a plain
  `docker exec` can leave root-owned Blade cache files that later break
  recompilation for the www-data Apache process).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 15:18:09 +02:00

144 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Servicedesk
Helpdesk / ticketing system built with Laravel + Livewire (Polish UI). Clients submit
support tickets, operators triage and resolve them inside team queues, and admins
configure everything else — categories, SLA rules, templates, branding, LDAP/SMTP,
and a REST API for external integrations.
## Roles & areas
The app has three areas, gated by role (a user can hold more than one at once):
| Area | Route prefix | Who | What they do |
|---|---|---|---|
| Client | `/client` | `client` | Submit tickets, track status, reply, see resolution |
| Operator | `/operator` | `operator` | Work the ticket queue, reply/resolve, see team statistics |
| Admin | `/admin` | `admin` | Configure categories, users, teams, SLA, templates, branding, LDAP/SMTP |
Every account gets the `client` role by default (see `AssignDefaultRole` for LDAP-provisioned
accounts), and always lands on `/client` first after login regardless of what other
roles it also holds — staff switch into Operator/Admin via the role switcher in the
header. See **[wiki/client](wiki/client/README.md)**, **[wiki/operator](wiki/operator/README.md)**,
and **[wiki/admin](wiki/admin/README.md)** for role-specific how-to guides.
## Feature overview
- **Tickets** — number, subject, body, category/subcategory, status, priority, team,
assignee, custom fields (per subcategory), attachments, full message thread
(public replies + internal notes), history log, merge, delete.
- **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.
- **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.
- **Teams** — subcategories auto-route to a team; operators only see their own
team's queue (plus unrouted tickets and anything assigned to them) unless they're
an admin.
- **Templates** — canned response snippets for the reply box, admin-configurable
"quick actions" (send + transition status in one click), and HTML e-mail
templates for every ticket lifecycle event (created, status/priority/category/
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.
- **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.
- **LDAP auth** — logins bind against an LDAP/LLDAP directory (`config/auth.php`,
`config/ldap.php`); local accounts (e.g. the emergency `admin` account) fall back
to e-mail + local password when the LDAP bind doesn't match.
- **REST API** (`/api/v1/...`, Sanctum token auth, ability-scoped: `tickets:read`,
`tickets:write`, `dictionaries:read`, `users:read`) for tickets/messages/users/
categories/statuses/priorities/teams — issued via admin-managed API clients.
Interactive docs (L5-Swagger) at `/admin/api-docs`.
- **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).
- **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 15 stars (+ optional
comment) once it's closed; average/response-rate surfaced as a KPI on the
operator stats dashboard, with a link in the "ticket closed" e-mail.
- **Saved queue views** — operators can save their current filter/sort/column
combination in the ticket queue, mark one as default, and switch between them.
- **Full-text search** — MySQL/MariaDB `FULLTEXT` search (with a portable `LIKE`
fallback) across ticket subject/body and reply message bodies, available in
both the operator queue and the client's own ticket list.
- **Stats export** — the operator stats dashboard can export the currently
filtered ticket set as CSV.
- **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).
## 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.
- **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
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.
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,
including which `.env` values to set (there are two separate `.env` files —
Compose-level and Laravel-level) and the LDAP/SMTP gotcha after a fresh seed.
## Local/dev notes
- The app container mounts `./src` directly — editing PHP/Blade/routes takes effect
immediately, no rebuild or restart needed.
- CSS/JS changes under `resources/` **do** need a Vite build. Neither the host nor
the app container has Node installed; rebuild with a throwaway container instead
of rebuilding the app image:
```bash
sudo docker run --rm -v "$(pwd)/src":/app -w /app node:22 npm run build
```
- Fresh install / reset:
```bash
sudo docker exec servicedesk-servicedesk-1 php artisan migrate:fresh --seed
```
Seeds real reference data (categories, custom fields, statuses/priorities/SLA,
teams, quick actions, response/e-mail templates, branding/config with example
SMTP+LDAP placeholders) and a single local fallback account, **`admin@example.com`
/ `admin`** — replace its password and/or the SMTP/LDAP settings before relying on
this in anything but a lab environment.
## Project layout
```
src/ Laravel application
app/Livewire/ Client/Operator/Admin Livewire components
app/Models/ Eloquent models
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/views/ Blade templates
routes/web.php Client/Operator/Admin routes (role-gated)
routes/api.php REST API (Sanctum, ability-gated)
wiki/
client/ How-to guide for the Client role
operator/ How-to guide for the Operator role
admin/ How-to guide for the Admin role
```