Co nowego: - Wsparcie Active Directory dla LDAP (obok LLDAP/OpenLDAP), przełącznik typu katalogu w Admin > Integracje. - Wyszukiwarka klientów dla operatora (Operator > Klienci). - Stronicowanie kolejki operatora (50/stronę) i dashboardu klienta (20/stronę). - Globalna wyszukiwarka zgłoszeń (Ctrl+K/Cmd+K) z operatorami w stylu Gmaila (od:, temat:, treść:, numer:), plus przycisk "Szukaj" w panelu bocznym. - Ostatnio przeglądane zgłoszenia w panelu bocznym operatora. - Przeprojektowany pasek nawigacji: suwak Klient/Operator/Administrator zamiast rozwijanego menu, bogatsze menu profilu (nazwa/e-mail/role), dynamiczne tytuły kart przeglądarki na każdej podstronie. - Narzędzie do jednorazowego importu historii zgłoszeń z Heska 3.x (scripts/hesk-import/). - Poprawka: paginacja pokazywała surowe klucze tłumaczeń zamiast tekstu (brakujący lang/pl/pagination.php). Zaktualizowana dokumentacja: README, CLAUDE.md, install.md, ARCHITECTURE.md, CHANGELOG.md, wiki/*. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
21 KiB
Instalacja / wdrożenie
Dwa sposoby uruchomienia Servicedesk: przez Docker Compose (tak jak działa ten projekt obecnie) albo bezpośrednio na serwerze z Apache/Nginx + PHP-FPM, bez kontenerów.
Zanim zaczniesz, ważne rozróżnienie — w projekcie są dwa różne pliki .env:
| Plik | Do czego służy |
|---|---|
.env (w katalogu głównym repo, obok compose.yaml) |
Zmienne dla Docker Compose — hasła do MariaDB, nazwa hosta dla Traefika. Czyta go compose.yaml, nie czyta go Laravel. |
src/.env (w katalogu aplikacji Laravel) |
Cała konfiguracja aplikacji — połączenie z bazą, adres URL, klucz szyfrowania, LDAP, SMTP, itd. Czyta go wyłącznie Laravel. |
Oba istnieją niezależnie od siebie (nawet w wersji Docker) — wartości DB_* w
src/.env muszą odpowiadać wartościom MYSQL_* z głównego .env, ale to dwa
osobne pliki, w dwóch różnych miejscach.
1. Wdrożenie przez Docker Compose
Wymagania
- Docker + wtyczka
docker compose. - Zewnętrzna sieć Docker
traefik_public, jeśli używasz Traefika tak jak wcompose.yaml(docker network create traefik_public, jeśli jeszcze nie istnieje). Bez Traefika trzeba samodzielnie zmapować porty serwisuappna hosta (ports: ["8080:80"]) i obsłużyć TLS inaczej (patrz sekcja 2 niżej, w razie potrzeby reverse-proxy przed kontenerem).
1.1. Pliki compose.yaml i .env w katalogu głównym
Oba są celowo .gitignore'owane (podobnie jak src/.env) — kopiujesz je z
szablonów przy pierwszym wdrożeniu, a potem edytujesz lokalnie:
cp compose.yaml.example compose.yaml
cp .env.example .env
.env:
HOSTNAME=servicedesk.twoja-domena.pl
MYSQL_ROOT_PASSWORD=wygeneruj-silne-haslo
MYSQL_DATABASE=servicedesk
MYSQL_USER=servicedesk
MYSQL_PASSWORD=wygeneruj-inne-silne-haslo
# IMAGE_TAG=latest
HOSTNAME— domena, pod którą Traefik wystawi aplikację (trafia do regułyHost(...)w etykietachservicedesk).MYSQL_*— dane bazy dla konteneramariadb;MYSQL_USER/MYSQL_PASSWORDto te same wartości, które za chwilę wpiszesz dosrc/.envjakoDB_USERNAME/DB_PASSWORD.IMAGE_TAG— który tag obrazuservicedeskwdrożyć (patrz sekcja 1.3a); domyślnielatest, jeśli zmienna nie jest ustawiona.
1.2. Plik src/.env (Laravel)
cp src/.env.example src/.env
Kluczowe wartości do zmiany względem .env.example:
APP_NAME=Servicedesk
APP_ENV=production
APP_DEBUG=false
APP_URL=https://servicedesk.twoja-domena.pl # to samo co HOSTNAME wyżej, z https://
APP_LOCALE=pl
APP_FALLBACK_LOCALE=pl
AUTHOR_CONTACT=helpdesk@twoja-domena.pl # widoczne w Admin > O aplikacji
VERSION=1.3.0 # widoczne w Admin > O aplikacji
DB_CONNECTION=mysql
DB_HOST=mariadb # nazwa serwisu z compose.yaml, NIE 127.0.0.1
DB_PORT=3306
DB_DATABASE=servicedesk # = MYSQL_DATABASE z głównego .env
DB_USERNAME=servicedesk # = MYSQL_USER
DB_PASSWORD=wygeneruj-inne-silne-haslo # = MYSQL_PASSWORD
SESSION_DRIVER=database
QUEUE_CONNECTION=database
APP_KEY wygenerujesz komendą artisan (krok 1.4) — zostaw puste w pliku.
LDAP_* i MAIL_* w src/.env są tylko wartościami startowymi/awaryjnymi.
Docelowo LDAP konfiguruje się wygodniej z poziomu Admin > Integracje, a SMTP
z Admin > Poczta (patrz ramka ostrzegawcza w kroku 1.6) — ale jeśli chcesz mieć
sensowny fallback zanim ktokolwiek się zaloguje do panelu admina, warto je od razu
uzupełnić:
LDAP_HOST=ldap.twoja-domena.pl
LDAP_USERNAME=cn=admin,dc=twoja-domena,dc=pl
LDAP_PASSWORD=haslo-bind-ldap
LDAP_BASE_DN=dc=twoja-domena,dc=pl
LDAP_PORT=389
MAIL_MAILER=smtp
MAIL_HOST=smtp.twoja-domena.pl
MAIL_PORT=587
MAIL_USERNAME=noreply@twoja-domena.pl
MAIL_PASSWORD=haslo-smtp
MAIL_FROM_ADDRESS=noreply@twoja-domena.pl
MAIL_FROM_NAME="${APP_NAME}"
1.3. Start kontenerów
Obraz servicedesk nie jest budowany lokalnie — compose.yaml odwołuje się
do obrazu zbudowanego przez CI i wypchniętego do rejestru kontenerów Gitea (patrz
1.3a). Uruchomienie stacka to więc zawsze:
docker compose pull
docker compose up -d
Przy zwykłych zmianach w kodzie PHP/Blade nic więcej nie trzeba robić — źródło
jest zamontowane z ./src, Laravel odświeża się natychmiast. docker compose pull uruchamiaj ponownie tylko wtedy, gdy chcesz podnieść nowszy tag obrazu
(np. po zmianie w Dockerfile i przebudowie przez CI).
1.3a. Automatyczne budowanie obrazu (CI, Gitea Actions)
.gitea/workflows/build.yml buduje i wypycha obraz do wbudowanego rejestru
kontenerów Gitea (gitea.kzbikowski.pl/kzbkowski/servicedesk) po każdym pushu na
main, który zmienia Dockerfile (celowo nie odpala się na zwykłe zmiany w
src/ — obraz nie zawiera kodu aplikacji, tylko PHP/Apache/rozszerzenia, więc
przebudowa dla samego kodu byłaby marnowaniem czasu CI). Wypycha dwa tagi:
latest i <sha commita>.
Zanim to zadziała, workflow potrzebuje sekretu REGISTRY_TOKEN — Gitei nie
ufaj domyślnemu secrets.GITHUB_TOKEN do logowania w jej własnym rejestrze
kontenerów, w praktyce kończy się to błędem unauthorized przy
docker login. Zamiast tego:
- Wygeneruj token: Ustawienia użytkownika > Aplikacje > Generate New Token,
z uprawnieniami co najmniej
write:packageiread:package. - Dodaj go jako sekret repo: Ustawienia repo > Actions > Secrets →
nazwa
REGISTRY_TOKEN, wartość = wygenerowany token.
Jeśli ten sekret nie jest ustawiony, workflow celowo przerywa się przed
próbą logowania z czytelnym komunikatem błędu (::error::), zamiast wysyłać
puste/nieautoryzowane dane do rejestru i kończyć na niejasnym unauthorized z
demona Dockera.
To tylko build + push — świadomie bez auto-deployu na produkcję. Po tym jak CI skończy, wdrożenie nowego obrazu na serwerze wciąż jest ręcznym krokiem:
cd /ścieżka/do/repo
docker compose pull
docker compose up -d
Zanim to zadziała po raz pierwszy, potrzebne jest jednorazowe zalogowanie hosta
produkcyjnego do rejestru Gitea (żeby docker compose pull miał czym
autoryzować pobranie obrazu, jeśli repozytorium/paczka nie są publiczne):
docker login gitea.kzbikowski.pl -u <twoja-nazwa-uzytkownika>
Jeśli to zupełnie pierwsze wdrożenie (rejestr jeszcze nie ma żadnego wypchniętego
obrazu servicedesk) — poczekaj, aż workflow CI przejdzie choć raz (np. przez
push/PR zmieniający Dockerfile, albo ręczne odpalenie z zakładki Actions w
Gitea), zanim spróbujesz docker compose pull na serwerze.
1.3b. Real-time (Laravel Reverb)
Realtime (kolejka operatora, czat na żywo) wymaga trzeciej usługi w
compose.yaml, reverb — tego samego obrazu servicedesk, tylko z innym
command: php artisan reverb:start --host=0.0.0.0 --port=8080. Obraz musi
mieć rozszerzenia PHP pcntl/posix (potrzebne serwerowi Reverb do obsługi
sygnałów) — jeśli Dockerfile ich nie instaluje, reverb będzie się zapętlać
w restartach z błędem Undefined constant "...SIGINT"; dodaj pcntl posix do
listy w docker-php-ext-install i poczekaj na przebudowanie obrazu przez CI.
Traefik musi kierować ścieżkę websocketu (/app*) do reverb, a resztę do
app — na tej samej domenie, więc bez dodatkowego wpisu DNS/certyfikatu:
reverb:
image: gitea.kzbikowski.pl/kzbkowski/servicedesk:${IMAGE_TAG:-latest}
command: php artisan reverb:start --host=0.0.0.0 --port=8080
volumes:
- ./src:/var/www/html
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
networks:
- internal
- traefik_public
labels:
- traefik.enable=true
- traefik.docker.network=traefik_public
- traefik.http.routers.reverb.rule=Host(`${HOSTNAME}`) && PathPrefix(`/app`)
- traefik.http.routers.reverb.priority=1000
- traefik.http.routers.reverb.entrypoints=websecure
- traefik.http.routers.reverb.tls=true
- traefik.http.services.reverb.loadbalancer.server.port=8080
priority=1000 jest ważne — Traefik domyślnie liczy priorytet reguły na
podstawie długości jej zapisu, co może dać samemu Host(...) z servicedesk
wyższy priorytet niż oczekiwano, przez co ścieżkowa reguła reverb przegrywa i
nic nie działa mimo poprawnej konfiguracji.
W src/.env — BROADCAST_CONNECTION=reverb plus:
REVERB_APP_ID=wygeneruj-losowy-id
REVERB_APP_KEY=wygeneruj-losowy-klucz
REVERB_APP_SECRET=wygeneruj-losowy-sekret
REVERB_HOST=reverb # nazwa usługi compose — ruch serwer-serwer po sieci internal
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST=servicedesk.twoja-domena.pl # publiczna domena — to, z czym łączy się przeglądarka
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https
REVERB_HOST (serwer→serwer, wewnętrzna sieć Docker) i VITE_REVERB_HOST
(przeglądarka→Traefik, publiczna domena) to celowo dwie różne wartości —
pomylenie ich to najczęstszy błąd przy pierwszym wdrożeniu tej funkcji.
Po zmianie zmiennych VITE_REVERB_* trzeba przebudować front-end (krok 1.5) —
te wartości są wypiekane w zbudowany bundle JS, nie czytane w runtime.
1.4. Instalacja aplikacji wewnątrz kontenera
docker compose exec app composer install --no-dev --optimize-autoloader
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate --seed
docker compose exec app php artisan storage:link
migrate --seed (bez --fresh) na pustej bazie utworzy wszystkie tabele i
wypełni dane referencyjne: kategorie/podkategorie, pola dodatkowe, statusy,
priorytety/SLA, zespoły, szybkie akcje, szablony odpowiedzi/e-mail, branding oraz
jedno konto lokalne admin@example.com / admin — zmień jego hasło od razu
po pierwszym zalogowaniu (Admin > Użytkownicy).
1.5. Zbudowanie zasobów front-endowych (CSS/Tailwind)
Ani host, ani kontener app nie mają zainstalowanego Node.js — buduj
przez jednorazowy kontener node:22 zamiast dorzucać Node do obrazu aplikacji:
cd /ścieżka/do/repo
docker run --rm -v "$(pwd)/src":/app -w /app node:22 npm ci
docker run --rm -v "$(pwd)/src":/app -w /app node:22 npm run build
Powtarzaj drugi krok po każdej zmianie w resources/css/ lub resources/js/.
1.6. Zadanie cykliczne (SLA, automatyzacje, poczta IMAP, AI) i kolejka
routes/console.php planuje tickets:check-sla-breaches i automation:run-rules
co 15 minut, oraz emails:fetch-imap (odbieranie zgłoszeń/odpowiedzi e-mailem —
patrz Admin > Poczta) i ai:run-ticket-automation (opcjonalna automatyczna
kategoryzacja/podsumowania AI zgłoszeń — patrz Admin > Integracje) co 5 minut,
ale obraz Dockera nie ma wbudowanego cron/supervisora — bez dodatkowego
kroku żadne z tych zadań nigdy się nie uruchomi (poczta IMAP nadal da się
sprawdzić ręcznie przyciskiem „Pobierz teraz”, ale bez tego nic nie dzieje się
samo). Wszystkie cztery interwały są też konfigurowalne z poziomu Admin >
Konfiguracja (bez potrzeby edycji kodu czy restartu — nowa wartość obowiązuje
od najbliższego tyknięcia harmonogramu).
compose.yaml rozwiązuje to czwartą usługą, cron — tego samego obrazu
servicedesk, tylko z innym poleceniem:
cron:
image: gitea.kzbikowski.pl/kzbkowski/servicedesk:${IMAGE_TAG:-latest}
command: php artisan schedule:work
volumes:
- ./src:/var/www/html
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
networks:
- internal
schedule:work to własna, pierwszoplanowa pętla harmonogramu Laravela —
odpowiednik odpalania schedule:run co minutę, ale bez potrzeby zewnętrznego
triggera. Ten kontener nie musi być widoczny w Traefiku (nie obsługuje ruchu
HTTP), stąd tylko sieć internal. Sprawdź, że działa: docker compose ps cron
oraz docker compose logs -f cron (loguje każde odpalenie zaplanowanego
zadania).
Powiadomienia e-mail wysyłają się synchronicznie (nie trafiają do kolejki), więc
php artisan queue:work nie jest obowiązkowy — QUEUE_CONNECTION=database w
.env wystarcza jako bezpieczny domyślny driver, gdyby coś w przyszłości zaczęło
kolejkować zadania.
⚠️ Ważne: LDAP/SMTP z panelu Admina nadpisują .env w locie
AppServiceProvider na starcie żądania sprawdza tabelę settings — jeśli w
Admin > Integracje pole host LDAP albo w Admin > Poczta SMTP włączony +
host jest ustawione, te wartości wygrywają z .env, bez potrzeby
restartu czy redeployu.
Po świeżym migrate --seed te pola zawierają przykładowe placeholdery
(ldap.example.com, smtp.example.com, changeme-*-password) — to znaczy, że
zaraz po instalacji LDAP/SMTP faktycznie próbują łączyć się z tymi fałszywymi
adresami, nawet jeśli w .env wpisałeś prawdziwe dane! Zanim oddasz system do
użytku:
- Zaloguj się lokalnym kontem
admin@example.com/admin. - Wejdź w Admin > Integracje i wpisz prawdziwe dane LDAP (wybierz też
właściwy Typ katalogu — LLDAP/OpenLDAP albo Active Directory — jeśli
katalog to nie LLDAP; albo wyczyść pole hosta LDAP, żeby wrócić do
wartości z
.env), a w Admin > Poczta dane SMTP. - Użyj przycisku „Testuj połączenie” w Integracje i „Wyślij testową wiadomość” w Poczta, zanim zaczniesz polegać na logowaniu przez katalog albo na powiadomieniach e-mail.
Integracje opcjonalne (BookStack, AI)
Podpowiedzi artykułów z bazy wiedzy BookStack (przy tworzeniu zgłoszenia i w
panelu operatora) są domyślnie wyłączone i nie wymagają żadnej zmiennej w
.env — całość konfiguruje się w Admin > Integracje: adres instancji,
Token ID/Secret (rola/użytkownik właściciela tokenu musi mieć w BookStacku
uprawnienie „Access System API”), filtr typu treści (książki/strony/rozdziały,
niezależne checkboxy), tryb wyszukiwania (po nazwie / po tagach / oba), oraz
osobne listy dozwolonych półek dla podpowiedzi przy tworzeniu zgłoszenia i dla
panelu operatora — dopóki żadna półka nie jest zaznaczona, wyszukiwanie nic
nie zwraca.
Integracja AI (Admin > Integracje > „Integracja AI”) jest domyślnie
wyłączona i tak samo nie wymaga żadnej zmiennej w .env — adres API
(dowolny dostawca kompatybilny z OpenAI: Groq, OpenAI, lokalny Ollama),
opcjonalny klucz API, nazwa modelu i przełącznik weryfikacji SSL. Sama w
sobie nic nie robi — dopiero po jej włączeniu można włączyć automatyczne
tagowanie treści BookStack (przyciski przy integracji BookStack) oraz
automatyczną kategoryzację/podsumowania AI zgłoszeń (Admin > Integracje >
„Automatyzacja AI dla zgłoszeń”, wymaga też wpisu crona z kroku 1.6/2.6
powyżej — to ten sam harmonogram co SLA/automatyzacje/IMAP).
Import historycznych zgłoszeń z Heska (opcjonalnie)
Jeśli migrujesz z helpdesku Hesk 3.x, scripts/hesk-import/ zawiera
jednorazowe (nie ciągłe) narzędzie migracyjne — importuje zgłoszenia wraz z
pełną historią odpowiedzi/notatek, ograniczone do jednej domeny e-mail, w
trybie dry-run domyślnie. Nie dotyka bazy Heska poza odczytem. Zobacz
scripts/hesk-import/README.md po pełną instrukcję.
2. Wdrożenie bezpośrednio na serwerze (Apache/Nginx, bez Dockera)
Wymagania
- PHP 8.3+ z rozszerzeniami:
curl,mysqli,pdo_mysql,ldap,zip,mbstring,openssl,tokenizer,xml,ctype,bcmath,fileinfo. - Composer 2.
- MariaDB/MySQL (osobny serwer lub lokalny).
- Node.js 20+ — tylko do jednorazowej (lub przy update'ach) budowy zasobów Tailwind/Vite; niepotrzebny w runtime.
- Apache z
mod_rewrite(+mod_ssl) lub Nginx + PHP-FPM.
2.1. Pobranie kodu i zależności
cd /var/www
git clone <adres-repo> servicedesk
cd servicedesk/src
composer install --no-dev --optimize-autoloader
2.2. Konfiguracja .env
cp .env.example .env
Te same zmienne co w sekcji 1.2, z jedną różnicą — DB_HOST wskazuje na
prawdziwy adres serwera bazy, nie na nazwę serwisu Compose:
APP_NAME=Servicedesk
APP_ENV=production
APP_DEBUG=false
APP_URL=https://servicedesk.twoja-domena.pl
APP_LOCALE=pl
APP_FALLBACK_LOCALE=pl
AUTHOR_CONTACT=helpdesk@twoja-domena.pl
VERSION=1.3.0
DB_CONNECTION=mysql
DB_HOST=127.0.0.1 # albo adres IP/hostname prawdziwego serwera DB
DB_PORT=3306
DB_DATABASE=servicedesk
DB_USERNAME=servicedesk
DB_PASSWORD=wygeneruj-silne-haslo
SESSION_DRIVER=database
QUEUE_CONNECTION=database
Uzupełnij też LDAP_*/MAIL_* jak w sekcji 1.2 (to samo ostrzeżenie o
Admin > Integracje/Poczta nadpisującym te wartości w locie dotyczy tu identycznie).
php artisan key:generate
php artisan migrate --seed
php artisan storage:link
2.3. Budowa zasobów
npm ci
npm run build
(Na maszynie bez Node.js zbuduj public/build/ gdzie indziej i skopiuj cały
katalog — to jedyne, co Vite generuje poza źródłem.)
2.4. Uprawnienia plików
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
(Zmień www-data na użytkownika, pod którym faktycznie działa Apache/PHP-FPM w
Twojej dystrybucji, np. apache na RHEL/CentOS.)
2.5. Konfiguracja serwera WWW
DocumentRoot musi wskazywać na public/, nigdy na katalog główny aplikacji.
Apache (/etc/apache2/sites-available/servicedesk.conf):
<VirtualHost *:443>
ServerName servicedesk.twoja-domena.pl
DocumentRoot /var/www/servicedesk/src/public
<Directory /var/www/servicedesk/src/public>
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile /etc/ssl/certs/servicedesk.crt
SSLCertificateKeyFile /etc/ssl/private/servicedesk.key
ErrorLog ${APACHE_LOG_DIR}/servicedesk-error.log
CustomLog ${APACHE_LOG_DIR}/servicedesk-access.log combined
</VirtualHost>
a2enmod rewrite ssl
a2ensite servicedesk
systemctl reload apache2
Jeśli kiedykolwiek dodasz własny katalog
public/icons/— nie rób tego. Stockowy modułmod_aliasApache definiujeAlias /icons/ "/usr/share/apache2/icons/"(FancyIndexing), który po cichu przechwytuje/icons/*przed dotarciem do Laravela. Ten projekt celowo używapublic/pwa-icons/z tego właśnie powodu.
Nginx (+ PHP-FPM):
server {
listen 443 ssl http2;
server_name servicedesk.twoja-domena.pl;
root /var/www/servicedesk/src/public;
ssl_certificate /etc/ssl/certs/servicedesk.crt;
ssl_certificate_key /etc/ssl/private/servicedesk.key;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
2.6. Zadanie cykliczne (SLA, automatyzacje, poczta IMAP, AI) i kolejka
Crontab użytkownika, pod którym stoi aplikacja (np. www-data) — obsługuje też
automation:run-rules, emails:fetch-imap i ai:run-ticket-automation
(patrz 1.6 wyżej, w tym konfigurowalne interwały w Admin > Konfiguracja):
* * * * * cd /var/www/servicedesk/src && php artisan schedule:run >> /dev/null 2>&1
Jak w wersji Docker — kolejka (php artisan queue:work) nie jest obowiązkowa,
skoro powiadomienia wysyłają się synchronicznie; zostaw QUEUE_CONNECTION=database
jako bezpieczny domyślny driver na przyszłość.
Realtime (patrz 1.3b) potrzebuje tu długo działającego procesu
php artisan reverb:start — PHP musi mieć rozszerzenia pcntl/posix
(standardowo dostępne, ale sprawdź php -m). Najprościej pod systemd:
# /etc/systemd/system/servicedesk-reverb.service
[Unit]
Description=Servicedesk Reverb websocket server
After=network.target
[Service]
User=www-data
WorkingDirectory=/var/www/servicedesk/src
ExecStart=/usr/bin/php artisan reverb:start --host=0.0.0.0 --port=8080
Restart=always
[Install]
WantedBy=multi-user.target
systemctl enable --now servicedesk-reverb
Ustaw też te same zmienne .env co w 1.3b (BROADCAST_CONNECTION=reverb,
REVERB_*, VITE_REVERB_* — tu REVERB_HOST to po prostu 127.0.0.1, nie
nazwa usługi compose) i skieruj serwer WWW tak, by ścieżka /app* trafiała do
portu 8080 zamiast do PHP-FPM/Apache (osobny location/VirtualHost dla tej
jednej ścieżki, analogicznie do reguły Traefika w 1.3b).
2.7. Pierwsze logowanie i dalsza konfiguracja
Identycznie jak w kroku 1.6 — zaloguj się admin@example.com / admin, zmień
hasło, uzupełnij prawdziwe LDAP w Admin > Integracje i SMTP w Admin > Poczta
(placeholdery z seeda inaczej realnie próbują łączyć się z fałszywymi
adresami), przetestuj oba połączenia.
2.8. Aktualizacje (bez przestoju)
cd /var/www/servicedesk/src
git pull
composer install --no-dev --optimize-autoloader
php artisan migrate --force
npm ci && npm run build
php artisan config:clear # tylko jeśli wcześniej użyto config:cache
Nie ma potrzeby restartu Apache/PHP-FPM dla samych zmian w PHP/Blade — restart
przyda się tylko po zmianie w .env lub konfiguracji samego serwera WWW.