# 05. Moduły funkcjonalne

Opis każdego ekranu: co pokazuje, co robi, jakie ma reguły i czego nie robi. To dokument, z którego powstają widoki.

---

## Dashboard `/panel`

Pierwszy ekran po zalogowaniu. Ma odpowiadać na jedno pytanie: co mnie dzisiaj czeka.

### Układ

```
┌──────────────────────────────────────────────────────────┐
│  Dzień dobry, Aniu            [ + Nowa wizyta ]          │
├──────────────────────────────────────────────────────────┤
│  Dzisiaj: 6 wizyt   Przychód: 980 zł   SMS: 137          │
├────────────────────────────┬─────────────────────────────┤
│  DZISIAJ                   │  JUTRO                      │
│  09:00 Anna Kowalska       │  10:00 Ewa Zielińska        │
│        Rzęsy 1:1, 150 min  │        Brwi, 45 min         │
│  10:30 Julia Nowak         │  12:00 Marta Wiśniewska     │
│  12:00 Marta Wiśniewska    │  ...                        │
│  14:00 Katarzyna Mazur     │                             │
├────────────────────────────┴─────────────────────────────┤
│  Do uzupełnienia: 2 wizyty z wczoraj bez statusu         │
│  Do odzyskania: 5 klientek dawno nie było                │
└──────────────────────────────────────────────────────────┘
```

### Kafelki liczbowe

| Kafelek | Definicja | Uprawnienie |
|---|---|---|
| Wizyty dzisiaj | Liczba wizyt o statusie innym niż `cancelled` w dzisiejszym dniu lokalnym | zawsze |
| Przychód dzisiaj | Suma `total_price` wizyt o statusie `completed` | `finance.view` |
| Klientki | Liczba klientek bez `deleted_at` | `clients.view` |
| Nieobecności w tym miesiącu | Liczba wizyt `no_show` | zawsze |
| Pozostało SMS | `salons.sms_balance` | zawsze |

Pracownica bez `calendar.view_all` widzi wyłącznie swoje wizyty i swoje liczby.

### Lista dzisiaj i jutro

Godzina, imię i nazwisko, usługa, czas trwania, kolor pracownika. Kliknięcie otwiera podgląd wizyty w oknie modalnym. Przy każdej wizycie z przeszłości bez ustawionego statusu widoczne dwa przyciski: "odbyta" i "nieobecność". Jedno kliknięcie, bez przechodzenia do innego ekranu.

### Przypomnienie o uzupełnieniu

Jeśli są wizyty z wczoraj i wcześniej o statusie `scheduled` lub `confirmed`, dashboard pokazuje pasek z ich liczbą i linkiem do szybkiego uzupełnienia. Bez tego statystyki przychodu przestają mieć sens po dwóch tygodniach.

### Czego tu nie ma

Wykresów, porównań rok do roku, list zadań. Dashboard ma się wczytywać natychmiast i mieścić na ekranie telefonu.

---

## Kalendarz `/kalendarz`

Najważniejszy ekran systemu. Tutaj użytkownik spędza większość czasu.

### Widoki

| Widok | Kiedy używany | Co pokazuje |
|---|---|---|
| Dzień | Domyślny na telefonie | Kolumny pracowników, pełna siatka godzin |
| Tydzień | Domyślny na komputerze | 7 kolumn dni, wizyty jako bloki |
| Miesiąc | Planowanie | Liczba wizyt i wolnych godzin w dniu, bez szczegółów |

Przy jednym pracowniku widok dnia ma jedną kolumnę. Przy większej liczbie kolumny są filtrowane paskiem z nazwiskami.

### Siatka

- Zakres godzin z ustawień salonu, domyślnie 8:00 do 20:00, z automatycznym rozszerzeniem, jeśli jakaś wizyta wychodzi poza zakres.
- Podział co 15 minut, konfigurowalny.
- Godziny poza grafikiem pracownika mają szare tło.
- Urlopy i przerwy z `time_off` to zablokowane pasy z etykietą.
- Bieżąca godzina zaznaczona poziomą linią.

### Blok wizyty

Zawiera godzinę rozpoczęcia, imię i nazwisko klientki, nazwę usługi (przy krótkich blokach skróconą) i ikonę statusu. Kolor pochodzi od pracownika, a przy filtrze na jednego pracownika od kategorii usługi. Bufor po usłudze rysowany jest jako ukośne paski, żeby było widać, że termin jest zajęty, ale nie jest to czas z klientką.

### Przeciąganie

- Przeciągnięcie bloku zmienia termin, rozciągnięcie krawędzi zmienia czas trwania.
- Przed zapisem sprawdzenie kolizji. Konflikt pokazuje komunikat i cofa blok na miejsce.
- Przeniesienie wizyty, na którą wysłano już przypomnienie, pyta, czy wysłać informację o zmianie terminu.
- Zapis idzie do `/api/wizyty/{id}/przesun`, a każda zmiana trafia do `appointment_history`.
- Na telefonie przeciąganie jest wyłączone, zamiast tego długie przytrzymanie otwiera menu z opcją zmiany terminu.

### Statusy wizyt

| Status | Kiedy | Widok |
|---|---|---|
| `scheduled` | Wizyta utworzona | Kolor pracownika |
| `confirmed` | Klientka potwierdziła, ręcznie albo SMS-em | Kolor pracownika z ramką |
| `completed` | Wizyta się odbyła | Przygaszony |
| `cancelled` | Odwołana | Przekreślony, nie blokuje terminu |
| `no_show` | Klientka nie przyszła | Czerwona ramka, zwiększa licznik w karcie klientki |

### Szybki podgląd

Kliknięcie w blok otwiera panel boczny: dane klientki, telefon z możliwością kliknięcia, usługi, kwota, notatka, historia ostatnich wizyt, przyciski zmiany statusu, "Umów ponownie", "Wyślij SMS", "Edytuj", "Odwołaj".

---

## Wizyty

### Nowa wizyta `/wizyty/nowa`

Cztery kroki na jednym ekranie, bez kreatora wieloetapowego.

```
1. Klientka    [ pole z podpowiedziami ]  albo  [ + nowa klientka ]
2. Usługa      [ lista z czasem i ceną ]  [ + dodaj kolejną ]
3. Pracownik   [ lista, domyślnie zalogowana osoba ]
4. Termin      [ data ] [ godzina ]  albo  [ pokaż wolne terminy ]
                                     Podsumowanie: 150 min, 220 zł
                                     [ Zapisz i wyślij potwierdzenie ]
```

Reguły:

- Pole klientki szuka po imieniu, nazwisku i numerze telefonu, od trzeciego znaku, przez `/api/klientki/szukaj`. Jeśli wpisany ciąg wygląda na numer telefonu i nie ma dopasowania, system proponuje utworzenie klientki z tym numerem.
- Dodanie usługi wydłuża wizytę o czas usługi plus bufor. Przy kilku usługach bufor liczy się tylko po ostatniej.
- Zmiana pracownika filtruje listę usług do tych, które on wykonuje.
- "Pokaż wolne terminy" korzysta z tego samego silnika co rezerwacje online, opisanego w `08-rezerwacje-online.md`.
- Cena podpowiada się z cennika i da się ją nadpisać, jeśli użytkownik ma `appointments.change_price`.
- Przy zapisie wizyta dostaje status `scheduled` i jeśli przypomnienia są włączone, do kolejki trafia SMS z wyliczoną godziną wysyłki.

### Kilka usług w jednej wizycie

Wizyta trzyma pozycje w `appointment_services`. Każda pozycja ma własny czas i cenę skopiowane z cennika. Suma czasów wyznacza `ends_at`, suma cen minus rabat wyznacza `total_price`.

### Odwoływanie

Odwołanie wymaga wskazania powodu z listy: klientka odwołała, salon odwołał, klientka nie przyszła, inny. Wizyta zostaje w bazie ze statusem `cancelled`, przestaje blokować termin i znika z przychodu. Jeśli SMS przypominający czeka jeszcze w kolejce, jest anulowany.

---

## Klientki `/klientki`

### Lista

Tabela: nazwisko i imię, telefon, ostatnia wizyta, następna wizyta, liczba wizyt, suma wydatków (przy `finance.view`). Wyszukiwarka u góry działa po nazwisku, imieniu, telefonie i e-mailu. Filtry: nowe w tym miesiącu, z nadchodzącą wizytą, bez wizyty od X dni, z urodzinami w tym miesiącu, zablokowane. Sortowanie po nazwisku i po dacie ostatniej wizyty. Stronicowanie po 50.

### Karta klientki `/klientki/{id}`

```
┌───────────────────────────────────────────────────────────┐
│  Anna Kowalska                    [ Umów ponownie ]       │
│  +48 500 600 700   anna@example.com   ur. 14 marca        │
│  Zgody: SMS tak, marketing tak                            │
├───────────────────────────────────────────────────────────┤
│  Wizyt: 12    Wydała: 2 340 zł    Średnio co 35 dni       │
│  Ostatnia: 12.08.2026    Następna: 24.09.2026             │
├───────────────────────────────────────────────────────────┤
│  Notatka                                                  │
│  Alergia na klej z lateksem. Woli ciemniejszy odcień.     │
├───────────────────────────────────────────────────────────┤
│  Historia wizyt                                           │
│  12.08.2026  Rzęsy 1:1          220 zł   odbyta           │
│  08.07.2026  Uzupełnienie       180 zł   odbyta           │
│  02.06.2026  Uzupełnienie       180 zł   nieobecność      │
├───────────────────────────────────────────────────────────┤
│  SMS wysłane do klientki                                  │
└───────────────────────────────────────────────────────────┘
```

Przycisk "Umów ponownie" otwiera formularz nowej wizyty z wypełnioną klientką i podpowiedzianą usługą z ostatniej wizyty oraz terminem oddalonym o `avg_interval_days`.

### Zgody

Dwie osobne zgody, obie z datą wyrażenia:

- **SMS transakcyjne**: przypomnienia o wizycie, potwierdzenia, informacje o zmianie terminu. Bez tej zgody system nie wyśle żadnego SMS do tej klientki.
- **Marketing**: SMS urodzinowe, wiadomości do klientek, które dawno nie były, promocje. Sprawdzane osobno przy każdej wysyłce nietransakcyjnej.

Przy dodawaniu klientki w panelu zgody są domyślnie niezaznaczone. Odpowiedzialność za ich zebranie jest po stronie salonu i tak to jest opisane w regulaminie.

### Duplikaty

Numer telefonu jest unikalny w salonie. Przy próbie dodania klientki z istniejącym numerem system pokazuje istniejącą kartę i pyta, czy otworzyć ją zamiast tworzyć nową. Scalanie duplikatów wchodzi w etapie 10.

---

## Usługi `/uslugi`

Lista pogrupowana w kategorie, przeciąganie zmienia kolejność. Wiersz usługi: nazwa, czas, cena, przypisani pracownicy, przełącznik aktywności, przełącznik widoczności w rezerwacjach online.

Formularz usługi: nazwa, kategoria, opis, czas trwania w minutach, bufor po usłudze, cena, cena "od", kolor, aktywna, dostępna online, pracownicy.

Reguły:

- Zmiana ceny działa na przyszłość. Wizyty już utworzone mają cenę skopiowaną i nie zmieniają się.
- Usługa użyta w wizytach nie da się usunąć, da się tylko wyłączyć. Przycisk usuwania prowadzi do dezaktywacji z wyjaśnieniem dlaczego.
- Przy pierwszym uruchomieniu salon dostaje przykładowe kategorie i usługi, gotowe do edycji, żeby nie startować z pustym ekranem.

---

## Pracownicy `/pracownicy`

Lista: imię i nazwisko, stanowisko, rola, kolor, status, ostatnie logowanie.

Karta pracownika ma trzy zakładki:

1. **Dane**: imię, nazwisko, e-mail, telefon, stanowisko, kolor w kalendarzu, aktywny, umawialny.
2. **Uprawnienia**: przełączniki z katalogu z `04-uprawnienia-i-role.md`, z zaznaczonymi wartościami domyślnymi roli. Zmiana względem domyślnej jest oznaczona.
3. **Grafik**: godziny pracy na każdy dzień tygodnia plus lista urlopów i przerw.

Reguły:

- Nowe konto dostaje e-mail z linkiem do ustawienia hasła, ważnym 7 dni. Właścicielka nie ustawia haseł za pracowników.
- Pracownika z wizytami w historii nie da się usunąć, tylko dezaktywować. Dezaktywacja odbiera dostęp i ukrywa go przy umawianiu, ale zostawia historię.
- Plan BASIC pozwala na jedno konto. Próba dodania drugiego prowadzi do ekranu z informacją o planie PRO.

---

## Statystyki `/statystyki`

Zakres dat u góry z gotowymi ustawieniami: ten miesiąc, poprzedni miesiąc, ostatnie 30 dni, ten rok, własny zakres.

### Sześć liczb

| Liczba | Definicja |
|---|---|
| Wizyty | Liczba wizyt `completed` w zakresie |
| Przychód | Suma `total_price` wizyt `completed` |
| Nowe klientki | Liczba klientek z `created_at` w zakresie |
| Odwołane | Liczba wizyt `cancelled` |
| Nieobecności | Liczba wizyt `no_show` |
| Średnia wartość wizyty | Przychód podzielony przez liczbę wizyt `completed` |

Każda liczba pokazuje zmianę względem poprzedniego okresu o tej samej długości.

### Najpopularniejsze usługi

Pozycje z `appointment_services` dla wizyt `completed`, zliczone i posortowane malejąco. Lista dziesięciu pozycji z liczbą wykonań i przychodem.

### Wyniki pracowników

Dla każdego pracownika: liczba wizyt, przychód, średnia wartość wizyty, liczba nieobecności. Widoczne przy `stats.view_all`. Przy `stats.view_own` pracownica widzi wyłącznie swój wiersz.

### Zasady liczenia

- Do przychodu wchodzą wyłącznie wizyty `completed`. Wizyty zaplanowane to nie przychód.
- Przychód liczy się z `total_price`, czyli po rabacie.
- Zakres dat działa na `starts_at` wizyty w czasie lokalnym salonu, nie na `created_at`.
- Wykresy w etapie 4 są jedne: słupki przychodu w dniach zakresu. Reszta to liczby.

---

## Ustawienia `/ustawienia`

Jeden ekran z zakładkami:

| Zakładka | Zawartość |
|---|---|
| Salon | Nazwa, adres, telefon, e-mail, NIP, logo, strefa czasowa |
| Godziny otwarcia | Siedem wierszy, godziny od i do, dzień zamknięty |
| Kalendarz | Zakres godzin, długość podziału, pierwszy dzień tygodnia |
| Przypomnienia SMS | Włączone, ile godzin przed, o której godzinie wysyłać |
| Rezerwacje online | Opisane w `08-rezerwacje-online.md` |
| Konto | Zmiana hasła, aktywne sesje, usunięcie konta |

Ustawień ma być mało i mają być zrozumiałe bez dokumentacji. Każda nowa opcja wymaga odpowiedzi na pytanie, co się stanie, jeśli jej nie będzie.

---

## Wersja mobilna

Panel jest używany w telefonie w trakcie pracy, często jedną ręką, czasem w rękawiczkach.

- Układ jednokolumnowy poniżej 768 pikseli.
- Kalendarz domyślnie w widoku dnia.
- Dolny pasek nawigacji: Kalendarz, Klientki, Nowa wizyta, Więcej.
- Przycisk nowej wizyty zawsze dostępny, jako duży okrągły przycisk w prawym dolnym rogu.
- Pola dotykowe co najmniej 44 na 44 piksele.
- Numery telefonów jako linki `tel:`, adresy jako linki do map.
