Reklamacje i skargi (Complaint) Ostatnia aktualizacja dokumentacji: 26 lutego 2026 Stan synchronizacji z kodem: ✅ Zsynchronizowany
1. Opis ogólny Domena Reklamacji zarządza zgłoszeniami problemów od klientów — od złożenia reklamacji, przez wymianę wiadomości, aż po rozwiązanie sprawy. To jak cyfrowa książka skarg i wniosków z pełnym workflow, historią korespondencji i możliwością dołączania zdjęć czy dokumentów.
Klienci mogą składać reklamacje bez logowania — wystarczy kod dostępu z rezerwacji. System automatycznie generuje unikalny numer zgłoszenia i kod dostępu, umożliwiając śledzenie statusu sprawy i wymianę wiadomości z obsługą.
2. Architektura domeny 2.1 Modele danych Complaint (Reklamacja) Ścieżka: app/Domain/Complaint/Model/Complaint.php Tabela: complaints Klucz: UUID (string, HasUuids) Interfejsy: HasMedia (Spatie MediaLibrary) Traity: HasUuids, InteractsWithMedia Observery: StatusLogObserver, ComplaintObserver Hidden fields: access_code (ukryty w serializacji, ale zwracany w Resource) Relacje:
Metoda Typ Model docelowy Opis organization() BelongsTo Organization Organizacja powiązana z reklamacją reservation() BelongsTo Reservation Rezerwacja, której dotyczy reklamacja messages() HasMany ComplaintMessage Wątek wiadomości supervisor() BelongsTo User (via supervisor_id) Opiekun sprawy solver() BelongsTo User (via resolved_by) Osoba, która rozwiązała sprawę notes() MorphMany Note Wewnętrzne notatki (polimorficzne) media MediaLibrary Media Załączniki (kolekcja attachments)
Kolekcje mediów:
Kolekcja attachments akceptuje: image/jpeg, image/png, image/gif, image/webp, video/mp4, video/quicktime, video/x-msvideo, application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document.
ComplaintMessage (Wiadomość reklamacji) Ścieżka: app/Domain/Complaint/Model/ComplaintMessage.php Tabela: complaint_messages Klucz: UUID (string, HasUuids) Observer: ComplaintMessageObserver Relacje:
Metoda Typ Model docelowy Opis complaint() BelongsTo Complaint Reklamacja nadrzędna
2.2 Diagram relacji erDiagram
Complaint ||--o{ ComplaintMessage : "messages()"
Complaint }o--|| Organization : "organization()"
Complaint }o--o| Reservation : "reservation()"
Complaint }o--o| User : "supervisor()"
Complaint }o--o| User : "solver()"
Complaint ||--o{ Note : "notes() [morph]"
Complaint ||--o{ Media : "media [attachments]"
Complaint {
uuid id PK
uuid uuid
string access_code
uuid organization_id FK
uuid reservation_id FK
string first_name
string last_name
string email
string mobile_phone
enum type
text message
enum status
enum priority
uuid supervisor_id FK
uuid resolved_by FK
datetime resolved_at
datetime created_at
datetime updated_at
}
ComplaintMessage {
uuid id PK
uuid complaint_id FK
enum author_type
string author_name
string author_email
text message
datetime created_at
datetime updated_at
} 2.3 Struktura tabel w bazie danych Migracja: database/migrations/0001_01_01_000020_create_complaints.php
Tabela complaints Kolumna Typ Nullable Default Indeks Opis id uuid Nie — PK Identyfikator (klucz główny) uuid uuid Nie — INDEX Publiczny identyfikator UUID access_code string Nie — INDEX Kod dostępu (10 znaków, wielkie litery) organization_id uuid Tak null INDEX, FK → organizations.id (CASCADE) Organizacja reservation_id uuid Tak null INDEX, FK → reservations.id (CASCADE) Rezerwacja resolved_by uuid Tak null INDEX, FK → users.id (CASCADE) Kto rozwiązał first_name string Nie — — Imię zgłaszającego last_name string Nie — — Nazwisko zgłaszającego email string Nie — — Email zgłaszającego mobile_phone string Nie — — Telefon zgłaszającego type enum Nie — — Typ: issue, refund, suggestion, other message text Nie — — Treść zgłoszenia status enum Nie — — Status: new, in_progress, resolved, closed priority enum Nie — — Priorytet: low, medium, high supervisor_id uuid Tak null INDEX, FK → users.id (SET NULL) Opiekun sprawy resolved_at datetime Tak null — Data rozwiązania created_at timestamp Tak — — Data utworzenia updated_at timestamp Tak — — Data aktualizacji
Tabela complaint_messages Kolumna Typ Nullable Default Indeks Opis id uuid Nie — PK Identyfikator (klucz główny) complaint_id uuid Nie — FK → complaints.id (CASCADE), COMPOSITE INDEX Reklamacja nadrzędna author_type enum Nie — COMPOSITE INDEX Typ autora: resident, staff, system author_name string Tak null — Nazwa autora author_email string Tak null — Email autora message text Nie — — Treść wiadomości created_at timestamp Tak — COMPOSITE INDEX Data utworzenia updated_at timestamp Tak — — Data aktualizacji
Indeksy złożone: (complaint_id, created_at), (author_type, created_at)
3. Endpointy API 3.1 Endpointy uwierzytelnione (auth) Middleware bazowe: auth:api, user_is_active, throttle:api, to_user_access, user_accepted_agreements.
Middleware roli ADMIN|SUPERVISOR|EMPLOYEE na: index, show, update, changeStatus, assignSupervisor.
GET /api/complaints Opis: Lista reklamacji z filtrami i paginacją Autoryzacja: Rola ADMIN, SUPERVISOR lub EMPLOYEE Query Parameters: Paginacja (standardowa z TraitSupport) filter[id] — dokładne dopasowanie UUID filter[type] — typ reklamacji (issue, refund, suggestion, other) filter[status] — status (new, in_progress, resolved, closed) filter[priority] — priorytet (low, medium, high) filter[supervisor.name] — częściowe dopasowanie nazwy opiekuna filter[solver.name] — częściowe dopasowanie nazwy osoby rozwiązującej Response (sukces): Paginowana kolekcja ComplaintResource z relacjami: reservation, organization, supervisor, solver GET /api/complaints/{complaintId} Opis: Szczegóły pojedynczej reklamacji Autoryzacja: Rola ADMIN, SUPERVISOR lub EMPLOYEE Parametry URL: complaintId (UUID) Response (sukces): ComplaintResource z relacjami Response (błędy): 404 — reklamacja nie znaleziona (NotFoundModelException) POST /api/complaints Opis: Tworzenie nowej reklamacji (dostępne dla wszystkich zalogowanych, bez wymogu roli ) Body (Request): StoreComplaintControllerRequest — patrz sekcja 4.3 Response (sukces): 200 — "The Complaint has been successfully added" PATCH /api/complaints/{complaintId} Opis: Aktualizacja reklamacji Autoryzacja: Rola ADMIN|SUPERVISOR|EMPLOYEE + Policy update (musi należeć do organizacji) Parametry URL: complaintId (UUID) Body (Request): UpdateComplaintControllerRequest — patrz sekcja 4.3 Response (sukces): 200 — "The Complaint has been successfully updated" PATCH /api/complaints/{complaintId}/change-status Opis: Zmiana statusu reklamacji Autoryzacja: Rola ADMIN|SUPERVISOR|EMPLOYEE + Policy update Parametry URL: complaintId (UUID) Body (Request): ChangeStatusComplaintControllerRequest {
"status" : "in_progress"
}
Response (sukces): 200 — standardowa odpowiedź z changeStatusXController Reguły biznesowe: Używa generycznej metody changeStatusXController z TraitControllerSupport PATCH /api/complaints/{complaintId}/assign-supervisor Opis: Przypisanie opiekuna do reklamacji Autoryzacja: Rola ADMIN|SUPERVISOR|EMPLOYEE + Policy update Parametry URL: complaintId (UUID) Body (Request): AssignSupervisorComplaintControllerRequest {
"supervisor_id" : "uuid-of-user"
}
Response (sukces): 200 — "Supervisor has been successfully assigned to the complaint" Reguły biznesowe: Opiekun musi być pracownikiem organizacji powiązanej z reklamacją (VerifySupervisorIsInOrganizationRule) GET /api/complaint-messages Opis: Lista wiadomości dla danej reklamacji Autoryzacja: Brak wymogu roli (weryfikacja przez complaint_id + complaint_uuid + complaint_access_code) Query Parameters: Paginacja + complaint_id (required), complaint_uuid (required), complaint_access_code (required) Response (sukces): Paginowana kolekcja ComplaintMessageResource POST /api/complaint-messages Opis: Dodanie wiadomości do reklamacji Autoryzacja: Brak wymogu roli Body (Request): StoreComplaintMessageControllerRequest — patrz sekcja 4.3 Response (sukces): 200 — "The Complaint message has been successfully added" GET /api/complaint-attachments Opis: Lista załączników reklamacji Autoryzacja: Brak wymogu roli (weryfikacja przez complaint_id + complaint_uuid + complaint_access_code) Response (sukces): Kolekcja ComplaintAttachmentResource POST /api/complaint-attachments Opis: Dodanie załączników do reklamacji Autoryzacja: Brak wymogu roli (weryfikacja przez dane reklamacji) Body (Request): StoreComplaintAttachmentControllerRequest — patrz sekcja 4.3 Response (sukces): 201 — kolekcja ComplaintAttachmentResource DELETE /api/complaint-attachments/{attachmentId} Opis: Usunięcie załącznika Autoryzacja: Brak wymogu roli (weryfikacja przez dane reklamacji) Parametry URL: attachmentId (UUID) Body (Request): DeleteComplaintAttachmentControllerRequest (wymaga complaint_id, complaint_uuid, complaint_access_code) Response (sukces): 200 — "Attachment deleted successfully" 3.2 Endpointy publiczne (noAuth) Middleware bazowe: require_app_client, global_database_transaction, app_mode, check_site_enable, set_locale, security_headers, throttle:api.
Metoda Endpoint Opis Throttle POST /api/no-auth/complaints Złożenie reklamacji public-store GET /api/no-auth/complaints/{complaintId}/find Podgląd reklamacji po UUID+kod public-find GET /api/no-auth/complaint-messages Lista wiadomości — POST /api/no-auth/complaint-messages Dodanie wiadomości public-store GET /api/no-auth/complaint-attachments Lista załączników — POST /api/no-auth/complaint-attachments Dodanie załączników public-store DELETE /api/no-auth/complaint-attachments/{attachmentId} Usunięcie załącznika public-store
Route names (noAuth): no-auth-complaints.store, no-auth-complaints.find, no-auth-complaint-messages.index, no-auth-complaint-messages.store, no-auth-complaint-attachments.index, no-auth-complaint-attachments.store, no-auth-complaint-attachments.delete.
Dostęp do wiadomości i załączników
Endpointy wiadomości i załączników wymagają podania complaint_id, complaint_uuid i complaint_access_code — weryfikowanych przez VerifyComplaintCorrectDataRule.
4. Logika biznesowa 4.1 Główne procesy Proces tworzenia reklamacji sequenceDiagram
participant K as Klient
participant S as System
participant A as Administrator
participant E as Email
K->>S: Składa reklamację (po rezerwacji)
S->>S: Generuje UUID i kod dostępu
S->>S: Kopiuje dane z rezerwacji (imię, email, telefon)
S->>E: Wysyła potwierdzenie z kodem
E-->>K: Email z kodem i linkiem
S->>A: Nowa reklamacja w panelu
A->>S: Przypisuje opiekuna
S->>E: Powiadomienie dla opiekuna
A->>S: Odpowiada klientowi
S->>E: Email do klienta
E-->>K: Odpowiedź od obsługi Klient po rezerwacji składa reklamację podając reservation_id, reservation_uuid i reservation_access_code CreatingComplaintObserver generuje unikalny uuid (UUID v4) i access_code (10 znaków, wielkie litery via Str::random(10)) Dane kontaktowe (first_name, last_name, email, mobile_phone) są automatycznie kopiowane z rezerwacji, jeśli nie zostały podane organization_id jest automatycznie ustawiany z rezerwacji Domyślny status: new CreatedComplaintObserver wysyła ComplaintCreatedNotification do klienta (email) Jeśli przypisano opiekuna — ComplaintNewSupervisorNotification do opiekuna Proces wymiany wiadomości flowchart TD
A[Nowa wiadomość] --> B{Kto pisze?}
B -->|Zalogowany użytkownik| C[author_type = staff]
C --> D[Ustaw author_name z user.name]
B -->|Niezalogowany klient| E[author_type = resident]
E --> F[Ustaw author_name z complaint.first_name + last_name]
D --> G{Czy poprzednia wiadomość<br>od tego samego autora?}
F --> G
G -->|Tak| H[Nie wysyłaj powiadomienia]
G -->|Nie| I{Kto jest odbiorcą?}
I -->|Klient pisał| J[Email do opiekuna]
I -->|Opiekun pisał| K[Email do klienta] Logika powiadomień (SendComplaintMessageCreatedNotification):
Sprawdza czy poprzednia wiadomość w wątku (last by created_at) ma inny author_email niż bieżąca Jeśli ten sam email — powiadomienie nie jest wysyłane (zapobiega podwójnym powiadomieniom) Jeśli autor to resident → email do supervisor.email Jeśli autor to staff → email do complaint.email (klient) Proces śledzenia statusu (dostęp publiczny) Klient otwiera link z emaila Endpoint GET /api/no-auth/complaints/{complaintId}/find wymaga uuid i access_code FindComplaintUUIDAccessCode szuka reklamacji po uuid, access_code i id ExceptionFindComplaintUUIDAccessCode sprawdza rate limiting (checkAccessLockout, rateLimitAccessAttempt) Przy niepowodzeniu — rzuca FindComplaintUUIDAccessCodeException (409) 4.2 Reguły biznesowe Rezerwacja musi być potwierdzona — status rezerwacji musi być confirmed (ReservationStillToComplaintRule) Rezerwacja musi być zakończona — end_at musi być w przeszłości Termin złożenia — maksymalnie MAX_DAY_TO_ADD_COMPLAINT dni od zakończenia rezerwacji (konfigurowalny) Weryfikacja rezerwacji — wymagane reservation_id, reservation_uuid i reservation_access_code (VerifyReservationCorrectDataRule) Opiekun musi być pracownikiem organizacji — walidacja VerifySupervisorIsInOrganizationRule sprawdza existOrganizationEmployee() Niezalogowani nie mogą przypisać opiekuna — CreatingComplaintObserver ustawia supervisor_id = null jeśli !auth()->check() Automatyczne kopiowanie danych z rezerwacji — organization_id zawsze, first_name, last_name, email, mobile_phone tylko jeśli puste Automatyczne zarządzanie rozwiązaniem — UpdatingComplaintObserver: status resolved → ustawia resolved_at + resolved_by; inny status → czyści te pola Powiadomienia o istotnych zmianach — UpdatedComplaintObserver wysyła ComplaintUpdatedNotification tylko gdy zmienione pola to nie supervisor_id i nie updated_at Rate limiting dostępu publicznego — ExceptionFindComplaintUUIDAccessCode używa checkAccessLockout i rateLimitAccessAttempt dla resource type RATE_LIMIT_RESOURCE_COMPLAINT Honeypot antyspamowy — przy tworzeniu przez niezalogowanego: pola website, company_website, fax_number muszą być puste (max:0) Filtr wulgaryzmów — pola author_name, author_email i message w wiadomościach walidowane regułą blasp_check 4.3 Walidacje StoreComplaintControllerRequest (Tworzenie reklamacji) Pole Reguły Uwagi reservation_id required\|uuid\|exists:reservations,id + ReservationStillToComplaintRule Weryfikuje termin i status rezerwacji reservation_uuid required\|uuid\|max:255 + VerifyReservationCorrectDataRule reservation_access_code required\|string\|min:1\|max:20 + VerifyReservationCorrectDataRule first_name required_without:reservation_id\|string\|max:255 Wymagane gdy brak reservation_id last_name required_without:reservation_id\|string\|max:255 email required_without:reservation_id\|email\|max:255 mobile_phone nullable\|string\|max:32 type required\|string\|in:issue,refund,suggestion,other message required\|string\|max:5000 priority required\|string\|in:low,medium,high files sometimes\|array\|min:1\|max:10 Opcjonalnie files.* sometimes\|file\|max:30480\|mimetypes:... ~29.8 MB na plik supervisor_id sometimes\|uuid\|exists:users,id + VerifySupervisorIsInOrganizationRule Tylko dla zalogowanych website sometimes\|max:0 Honeypot — tylko dla niezalogowanych company_website sometimes\|max:0 Honeypot fax_number sometimes\|max:0 Honeypot
UpdateComplaintControllerRequest (Aktualizacja reklamacji) Pole Reguły type required\|string\|in:issue,refund,suggestion,other priority required\|string\|in:low,medium,high first_name sometimes\|string\|max:255 last_name sometimes\|string\|max:255 email sometimes\|email\|max:255 mobile_phone nullable\|string\|max:32 supervisor_id sometimes\|nullable\|uuid\|exists:users,id + VerifySupervisorIsInOrganizationRule
ChangeStatusComplaintControllerRequest (Zmiana statusu) Pole Reguły status required\|string\|in:new,in_progress,resolved,closed
AssignSupervisorComplaintControllerRequest (Przypisanie opiekuna) Pole Reguły supervisor_id sometimes\|nullable\|uuid\|exists:users,id + VerifySupervisorIsInOrganizationRule
FindComplaintControllerRequest (Podgląd reklamacji) Pole Reguły uuid required\|uuid\|max:255 access_code required\|string\|min:1\|max:20
StoreComplaintMessageControllerRequest (Dodanie wiadomości) Pole Reguły Uwagi complaint_id required\|uuid\|max:255\|exists:complaints,id complaint_uuid required\|uuid\|max:255\|exists:complaints,uuid complaint_access_code required\|string\|min:1\|max:20\|exists:complaints,access_code author_name RequiredWhenNotAuthenticatedRule\|string\|max:255\|blasp_check Wymagane gdy niezalogowany author_email RequiredWhenNotAuthenticatedRule\|email\|max:255\|blasp_check Wymagane gdy niezalogowany message required\|string\|min:3\|max:5000\|blasp_check Filtr wulgaryzmów
IndexComplaintMessageControllerRequest (Lista wiadomości) Pole Reguły (paginacja) Standardowe reguły paginacji complaint_id required\|uuid\|max:255\|exists:complaints,id + VerifyComplaintCorrectDataRule complaint_uuid required\|uuid\|max:255\|exists:complaints,uuid + VerifyComplaintCorrectDataRule complaint_access_code required\|string\|min:1\|max:20\|exists:complaints,access_code + VerifyComplaintCorrectDataRule
StoreComplaintAttachmentControllerRequest (Dodanie załączników) Pole Reguły complaint_id required\|uuid\|max:255\|exists:complaints,id + VerifyComplaintCorrectDataRule complaint_uuid required\|uuid\|max:255\|exists:complaints,uuid + VerifyComplaintCorrectDataRule complaint_access_code required\|string\|min:1\|max:20\|exists:complaints,access_code + VerifyComplaintCorrectDataRule files required\|array\|min:1\|max:10 files.* required\|file\|max:20480\|mimetypes:...
IndexComplaintAttachmentControllerRequest (Lista załączników) Pole Reguły complaint_id required\|uuid\|max:255\|exists:complaints,id + VerifyComplaintCorrectDataRule complaint_uuid required\|uuid\|max:255\|exists:complaints,uuid + VerifyComplaintCorrectDataRule complaint_access_code required\|string\|min:1\|max:20\|exists:complaints,access_code + VerifyComplaintCorrectDataRule
DeleteComplaintAttachmentControllerRequest (Usunięcie załącznika) Pole Reguły complaint_id required\|uuid\|max:255\|exists:complaints,id + VerifyComplaintCorrectDataRule complaint_uuid required\|uuid\|max:255\|exists:complaints,uuid + VerifyComplaintCorrectDataRule complaint_access_code required\|string\|min:1\|max:20\|exists:complaints,access_code + VerifyComplaintCorrectDataRule
5. Autoryzacja i uprawnienia Middleware roli Kontroler ComplaintController stosuje middleware role:ADMIN|SUPERVISOR|EMPLOYEE na metodach: index, show, update, changeStatus, assignSupervisor.
Metoda store jest dostępna bez roli — zarówno dla zalogowanych jak i niezalogowanych użytkowników.
Kontrolery ComplaintMessageController i ComplaintAttachmentController nie mają middleware roli — dostęp jest kontrolowany przez weryfikację complaint_id + complaint_uuid + complaint_access_code.
Laravel Policies ComplaintPolicy (app/Domain/Complaint/Policy/ComplaintPolicy.php) Metoda Logika Opis view belongsToOrganization($user, $complaint->organization_id) Użytkownik musi należeć do organizacji reklamacji create return false Tworzenie zawsze dozwolone (zarządzane przez middleware/route) update belongsToOrganization($user, $complaint->organization_id) Użytkownik musi należeć do organizacji reklamacji
ComplaintMessagePolicy (app/Domain/Complaint/Policy/ComplaintMessagePolicy.php) Metoda Logika Opis view belongsToOrganization($user, $complaint->organization_id) Przez complaint nadrzędny create return false Zawsze false update return false Zawsze false
Matryca uprawnień Rola Podgląd listy Szczegóły Tworzenie Edycja Zmiana statusu Przypisanie opiekuna Wiadomości Załączniki Administrator Supervisor Employee Klient (z kodem) (swoje)
6. Eventy i efekty uboczne ComplaintObserver Zdarzenie Klasa akcji Efekt creating CreatingComplaintObserver Generuje uuid i access_code; kopiuje dane z rezerwacji; ustawia domyślny status new; ustawia resolved_at/resolved_by jeśli status = resolved; czyści supervisor_id jeśli niezalogowany created CreatedComplaintObserver Wysyła ComplaintCreatedNotification do klienta; opcjonalnie ComplaintNewSupervisorNotification do opiekuna updating UpdatingComplaintObserver Przy zmianie statusu na resolved → ustawia resolved_at i resolved_by; przy innym statusie → czyści te pola. Pomija jeśli status nie został zmieniony (isDirty) updated UpdatedComplaintObserver Wysyła ComplaintUpdatedNotification do klienta (jeśli istotne zmiany, tj. nie supervisor_id/updated_at); ComplaintNewSupervisorNotification przy zmianie opiekuna
Dodatkowy observer
Model Complaint ma również StatusLogObserver z domeny StatusLog — loguje wszystkie zmiany statusów do dziennika.
ComplaintMessageObserver Zdarzenie Klasa akcji Efekt creating CreatingComplaintMessageObserver Automatycznie ustawia author_type, author_name, author_email na podstawie stanu uwierzytelnienia (zalogowany → staff z danych usera; niezalogowany → resident z danych reklamacji) created CreatedComplaintMessageObserver Wywołuje sendComplaintMessageCreatedNotification — wysyła powiadomienie email z inteligentnym filtrowaniem (nie wysyła jeśli poprzednia wiadomość od tego samego autora)
7. Powiadomienia Wszystkie powiadomienia są wysyłane asynchronicznie przez SimpleSendNotificationJob (kolejka) kanałem mail.
Powiadomienie Klasa Kiedy Odbiorca Treść Reklamacja utworzona ComplaintCreatedNotification Po złożeniu reklamacji Klient (complaint.email) Numer UUID, kod dostępu, data, status, wiadomość, link do panelu Nowy opiekun ComplaintNewSupervisorNotification Po przypisaniu/zmianie opiekuna Opiekun (supervisor.email) Numer UUID, kod dostępu, data, status, wiadomość, link do panelu admin Reklamacja zaktualizowana ComplaintUpdatedNotification Po istotnej zmianie (nie supervisor_id, nie updated_at) Klient (complaint.email) Numer UUID, kod dostępu, data, aktualny status, link Nowa wiadomość ComplaintMessageCreatedNotification Po dodaniu wiadomości (warunkowo) Opiekun lub klient (zależnie od autora) Numer UUID, kod dostępu, aktualny status, treść oryginalnego zgłoszenia, treść nowej wiadomości, link
Inteligentne powiadomienia wiadomości
System nie wysyła powiadomienia , jeśli ostatnia wiadomość w wątku pochodzi od tego samego autora (adres email). Zapobiega to podwójnym powiadomieniom, gdy ta sama osoba pisze kilka wiadomości pod rząd.
URL w powiadomieniach
Klient: {frontend_url}/reklamacje/{id}?uuid={uuid}&access_code= Staff/supervisor: {frontend_url}/panel/reklamacje/{id}?uuid={uuid}&access_code= Wiadomości: URL zależy od author_type — staff dostaje URL panelu, resident URL publiczny 8. Powiązania z innymi domenami 9. Konfiguracja Parametr Źródło Opis MAX_DAY_TO_ADD_COMPLAINT Domena Configuration (getConfigurationBySlug) Maksymalna liczba dni od zakończenia rezerwacji, w ciągu których można złożyć reklamację app.frontend_url config('app.frontend_url') Bazowy URL frontendu — używany do generowania linków w powiadomieniach RATE_LIMIT_RESOURCE_COMPLAINT SupportEnumService Typ zasobu do rate limitingu przy publicznym dostępie
10. Znane ograniczenia i TODO Ograniczenie Opis ComplaintPolicy::create() zwraca false Tworzenie obsługiwane poza Policy (przez routing) access_code w $hidden Kod jest ukryty w serializacji modelu, ale jawnie zwracany w ComplaintResource Brak weryfikacji tożsamości klienta Endpoint find wymaga UUID + access_code, ale nie weryfikuje czy osoba to faktyczny klient Brak limitu wiadomości Nie ma ograniczenia na liczbę wiadomości w wątku Brak soft delete Reklamacje i wiadomości nie mają miękkiego usuwania
Struktura domeny app/Domain/Complaint/
├── Action/
│ ├── Controller/
│ │ ├── AssignSupervisorComplaintController.php # Przypisanie opiekuna
│ │ ├── DeleteComplaintAttachmentController.php # Usuwanie załącznika
│ │ ├── FindComplaintController.php # Znajdź reklamację (publiczny)
│ │ ├── IndexComplaintAttachmentController.php # Lista załączników
│ │ ├── IndexComplaintController.php # Lista reklamacji
│ │ ├── IndexComplaintMessageController.php # Lista wiadomości
│ │ ├── ShowComplaintController.php # Szczegóły reklamacji
│ │ ├── StoreComplaintAttachmentController.php # Dodawanie załączników
│ │ ├── StoreComplaintController.php # Tworzenie reklamacji
│ │ ├── StoreComplaintMessageController.php # Dodawanie wiadomości
│ │ └── UpdateComplaintController.php # Aktualizacja reklamacji
│ └── Other/
│ ├── CreateComplaint.php # Tworzenie + załączniki
│ ├── CreateComplaintAttachments.php # Upload plików (Spatie Media)
│ ├── CreateComplaintMessage.php # Tworzenie wiadomości
│ ├── CreatedComplaintMessageObserver.php # Powiadomienie po wiadomości
│ ├── CreatedComplaintObserver.php # Powiadomienie po utworzeniu
│ ├── CreatingComplaintMessageObserver.php # Auto-uzupełnianie autora
│ ├── CreatingComplaintObserver.php # UUID, kod, dane z rezerwacji
│ ├── ExceptionFindComplaintUUIDAccessCode.php # Rate limiting dostępu
│ ├── FindComplaintUUIDAccessCode.php # Wyszukiwanie po UUID+kod
│ ├── SendComplaintMessageCreatedNotification.php # Logika powiadomień wiadomości
│ ├── UpdateComplaint.php # Aktualizacja danych
│ ├── UpdatedComplaintObserver.php # Powiadomienia po aktualizacji
│ └── UpdatingComplaintObserver.php # resolved_at/resolved_by
├── Controller/
│ ├── ComplaintAttachmentController.php # Kontroler załączników
│ ├── ComplaintController.php # Główny kontroler
│ └── ComplaintMessageController.php # Kontroler wiadomości
├── Model/
│ ├── Complaint.php # Model reklamacji
│ └── ComplaintMessage.php # Model wiadomości
├── Notification/
│ ├── ComplaintCreatedNotification.php # Email: reklamacja utworzona
│ ├── ComplaintMessageCreatedNotification.php # Email: nowa wiadomość
│ ├── ComplaintNewSupervisorNotification.php # Email: nowy opiekun
│ └── ComplaintUpdatedNotification.php # Email: aktualizacja
├── Observer/
│ ├── ComplaintMessageObserver.php # Observer wiadomości (creating, created)
│ └── ComplaintObserver.php # Observer reklamacji (creating, created, updating, updated)
├── Policy/
│ ├── ComplaintMessagePolicy.php # Polityka wiadomości
│ └── ComplaintPolicy.php # Polityka reklamacji
├── Request/
│ ├── AssignSupervisorComplaintControllerRequest.php
│ ├── ChangeStatusComplaintControllerRequest.php
│ ├── DeleteComplaintAttachmentControllerRequest.php
│ ├── FindComplaintControllerRequest.php
│ ├── IndexComplaintAttachmentControllerRequest.php
│ ├── IndexComplaintControllerRequest.php
│ ├── IndexComplaintMessageControllerRequest.php
│ ├── Rule/
│ │ ├── RequiredWhenNotAuthenticatedRule.php # Pole wymagane gdy niezalogowany
│ │ ├── ReservationStillToComplaintRule.php # Warunki złożenia reklamacji
│ │ ├── VerifyComplaintCorrectDataRule.php # Weryfikacja UUID+kod
│ │ └── VerifySupervisorIsInOrganizationRule.php # Opiekun z organizacji
│ ├── StoreComplaintAttachmentControllerRequest.php
│ ├── StoreComplaintControllerRequest.php
│ ├── StoreComplaintMessageControllerRequest.php
│ └── UpdateComplaintControllerRequest.php
├── Resource/
│ ├── ComplaintAttachmentResource.php # JSON załącznika
│ ├── ComplaintMessageResource.php # JSON wiadomości
│ └── ComplaintResource.php # JSON reklamacji
└── Service/
├── ComplaintEnumService.php # Statusy, typy, priorytety, typy autorów
├── TraitComplaint.php # Metody domenowe
└── TraitControllerComplaint.php # Metody kontrolera
Enumy (ComplaintEnumService) Statusy reklamacji Enum Wartość Etykieta COMPLAINT_STATUS_NEW new Nowa COMPLAINT_STATUS_IN_PROGRESS in_progress W trakcie COMPLAINT_STATUS_RESOLVED resolved Rozwiązana COMPLAINT_STATUS_CLOSED closed Zamknięta
Typy reklamacji Enum Wartość Etykieta COMPLAINT_TYPE_ISSUE issue Zgłoszenie problemu COMPLAINT_TYPE_REFUND refund Reklamacja / Zwrot COMPLAINT_TYPE_SUGGESTION suggestion Sugestia / propozycja COMPLAINT_TYPE_OTHER other Inne
Priorytety Enum Wartość Etykieta COMPLAINT_PRIORITY_LOW low Niski COMPLAINT_PRIORITY_MEDIUM medium Średni COMPLAINT_PRIORITY_HIGH high Wysoki
Typy autorów wiadomości Enum Wartość Etykieta COMPLAINT_AUTHOR_TYPE_STAFF staff Pracownik COMPLAINT_AUTHOR_TYPE_RESIDENT resident Mieszkaniec COMPLAINT_AUTHOR_TYPE_SYSTEM system System
Workflow reklamacji stateDiagram-v2
[*] --> new: Złożenie reklamacji
new --> in_progress: Podjęcie sprawy
in_progress --> resolved: Rozwiązanie problemu
resolved --> closed: Zamknięcie sprawy
in_progress --> new: Ponowne otwarcie
resolved --> in_progress: Ponowne otwarcie Status Kod Opis Akcje obserwera Nowa new Nowa reklamacja, oczekuje na podjęcie Domyślny status przy tworzeniu W trakcie in_progress W trakcie rozpatrywania Czyści resolved_at i resolved_by Rozwiązana resolved Problem rozwiązany Ustawia resolved_at i resolved_by Zamknięta closed Sprawa zamknięta Czyści resolved_at i resolved_by
Odpowiedź API (Resource) ComplaintResource Automatycznie ładowane relacje: reservation, organization, supervisor, solver.
Pola niedostępne dla niezalogowanych: can.
Pole Typ Opis id string (UUID) Identyfikator reklamacji uuid string (UUID) Publiczny identyfikator access_code string Kod dostępu (10 znaków) organization_id string\|null ID organizacji reservation_id string\|null ID rezerwacji first_name string Imię zgłaszającego last_name string Nazwisko zgłaszającego email string Email zgłaszającego mobile_phone string Telefon zgłaszającego type string Kod typu reklamacji type_lang string Przetłumaczona nazwa typu message string Treść zgłoszenia status string Kod statusu status_lang string Przetłumaczona nazwa statusu priority string Kod priorytetu priority_lang string Przetłumaczona nazwa priorytetu can_be_edit boolean Czy reklamacja może być edytowana resolved_by string\|null ID użytkownika który rozwiązał resolved_at string\|null Data rozwiązania (Y-m-d H:i:s) supervisor_id string\|null ID opiekuna created_at string\|null Data utworzenia (Y-m-d H:i:s) updated_at string\|null Data aktualizacji (Y-m-d H:i:s) can object Uprawnienia (tylko dla zalogowanych)
ComplaintMessageResource Pola niedostępne dla niezalogowanych: can.
Pole Typ Opis id string (UUID) Identyfikator wiadomości complaint_id string\|null ID reklamacji author_type string Typ autora (staff, resident, system) author_type_lang string Przetłumaczona nazwa typu autora author_name string Nazwa autora author_email string Email autora message string Treść wiadomości created_at string\|null Data utworzenia (Y-m-d H:i:s) updated_at string\|null Data aktualizacji (Y-m-d H:i:s) can object Uprawnienia (tylko dla zalogowanych)
ComplaintAttachmentResource Pole Typ Opis id string ID załącznika uuid string UUID media model_type string Typ modelu nadrzędnego model_id string ID modelu nadrzędnego collection_name string Nazwa kolekcji (attachments) name string Nazwa pliku file_name string Nazwa pliku na dysku mime_type string Typ MIME disk string Dysk przechowywania size integer Rozmiar w bajtach size_human string Rozmiar czytelny (np. 2.5 MB) url string URL do pobrania type string Typ mediów (image, video, document) custom_properties object Właściwości niestandardowe created_at string\|null Data utworzenia (Y-m-d H:i:s) updated_at string\|null Data aktualizacji (Y-m-d H:i:s)