# System targetów — zakres iteracji 2+

**Data:** 2026-04-17  
**Kontekst:** Dokument opisuje wymagania dla kolejnych iteracji systemu targetów/progów oceny metryk,
po wdrożeniu iteracji 1 (3 metryki kosztowe: koszt pracownika, koszt sklepu, koszt surowca).

---

## Iteracja 2 — Targety biznesowe

### Cel
Rozszerzenie systemu targetów o metryki biznesowe i przychodowe, zgodnie z predefiniowaną listą.

### Nowe metryki do obsługi

| Klucz metryki        | Etykieta                    | Jednostka | Kierunek       |
|----------------------|-----------------------------|-----------|----------------|
| `revenue`            | Przychód                    | kwota     | wyższy = lepiej |
| `transactions_count` | Liczba klientów             | ilość     | wyższy = lepiej |
| `avg_ticket`         | Średni koszyk               | kwota     | wyższy = lepiej |
| `b2b_clients_count`  | Liczba klientów B2B per sklep | ilość   | wyższy = lepiej |
| `net_margin_pct`     | Ogólna marża sklepu (netto) | %         | wyższy = lepiej |

### Wymagania szczegółowe

**`api`:**
- Rozszerzyć `MetricDefinitions` o 5 nowych wpisów (klucze, jednostki, `lower_is_better = false`)
- Endpointy CRUD dla targetów admina i konsultanta muszą obsługiwać nowe klucze bez modyfikacji schematu DB (tabela `shop_metric_targets` jest już gotowa)
- Zweryfikować dostępność danych dla `b2b_clients_count` w istniejącym modelu danych — jeśli metryka nie jest jeszcze wyliczana, wymagana jest osobna analiza źródeł danych B2B

**`admin` i `consultant`:**
- Rozszerzyć formularz targetów o sekcję "Targety biznesowe"
- Sekcja pokazuje 5 nowych metryk w tym samym układzie tabeli co metryki kosztowe
- Pole "Marża netto" powinno zawierać podpowiedź: "Dotyczy marży netto: wynik netto / przychód" — dla jasności definicji (decyzja 2.6)

**`panel` — `revenue_dashboard.twig`:**
- Zastąpić hardcoded `marginTarget: 0.15` dynamicznym targetem dla `net_margin_pct`
- Zastąpić hardcoded `marginMin: 0.05` i `marginMax: 0.20` progami odpowiednio `threshold_3` i `threshold_1` z targetu `net_margin_pct`
- Dla KPI "Przychód", "Śr. paragon" i "Śr. transakcje/dzień" — dodać badge oceny oparty o odpowiedni target
- Informacja o definicji marży: dodać statyczny tooltip lub podpis przy wartości marży w KPI "Wynik netto" — np. "marża netto = wynik netto / przychód"

### Weryfikacja przed implementacją
- [ ] Potwierdzić, czy `b2b_clients_count` jest dostępny w danych dashboardu; jeśli nie — zaplanować jako osobny podzadanie

---

## Iteracja 3 — Prezentacja dwóch targetów jednocześnie w `panel`

### Cel
Wyraźne pokazanie użytkownikowi panelu zarówno targetu administratora, jak i konsultanta — gdy oba istnieją — zgodnie z zasadą pierwszeństwa (admin > konsultant).

### Wymagania szczegółowe

**Zasada priorytetyzacji (już wdrożona w iteracji 1):**
- Target aktywny = admin, jeśli istnieje; w przeciwnym razie = konsultant
- Badge oceny zawsze oparty o aktywny target

**Nowe wymagania wizualne:**

Gdy istnieją oba targety (admin i konsultant):
- Badge oceny wyliczany na podstawie targetu admina (aktywny)
- Pod badgem lub w tooltip: widoczny jest również target konsultanta jako pomocniczy
- Target admina: pogrubiony, pełny kontrast
- Target konsultanta: szary, oznaczony etykietą "Konsultant" lub "(K)"

Gdy istnieje tylko jeden target:
- Badge oceny jak dotychczas
- Mały podpis: "wg Admin" lub "wg Konsultant" — wyświetlany subtelnie, np. rozmiar 10px, kolor szary

**Przykładowy wygląd tooltip (on hover na badge):**

```
Koszt pracownika: 32,4%

Admin (aktywny):
  dobry < 25% | średni < 35% | śr. zły < 45% | zły ≥ 45%

Konsultant (pomocniczy):
  dobry < 30% | średni < 40% | śr. zły < 50% | zły ≥ 50%
```

**`api`:**
- Endpoint `GET /panel/shops/{id}/targets` musi zwracać oba zestawy (admin i konsultant) nawet gdy istnieje tylko jeden z nich — `panel` sam decyduje jak renderować
- Pole `active` w odpowiedzi wskazuje który jest aktywny (`"admin"` | `"consultant"` | `null`)

**`panel`:**
- Przy renderowaniu tabeli miesięcznej: jeśli `targets[metric].consultant` istnieje — renderuj dodatkowy wiersz informacyjny lub tooltip
- Nie zmieniać logiki kolorowania — nadal opierać o `active`

---

## Iteracja 4 — Fallback globalny (domyślne wartości gdy brak targetu)

### Cel
Zapewnienie, że użytkownik panelu zawsze widzi jakiś kontekst oceny, nawet jeśli nikt nie zdefiniował targetu dla danego sklepu i miesiąca.

### Wymagania szczegółowe

**Mechanizm:**
- Zdefiniować domyślne wartości progów per metryka w konfiguracji PHP (`MetricDefinitions`)
- Fallback jest aktywowany wyłącznie gdy **brak targetu admina i konsultanta** dla danego sklepu i miesiąca
- Wartości domyślne powinny być rozsądnymi wartościami branżowymi (np. koszt surowca: 30/40/50%)

**Prezentacja w `panel`:**
- Badge oceny wyświetlany jak przy normalnym targecie, ale oznaczony ikoną lub podpisem "wartości domyślne"
- Tooltip: "Brak zdefiniowanych targetów. Wyświetlane są wartości domyślne systemu."
- Możliwość wyłączenia fallbacku przez admina (opcjonalne — do decyzji)

**`api`:**
- Endpoint `GET /panel/shops/{id}/targets` zwraca dodatkowe pole `source: "admin" | "consultant" | "default" | null`
- Gdy `source = "default"` — panel wyświetla odpowiednie oznaczenie

---

## Iteracja 5 — Informowanie użytkownika o kontekście czasowym targetu

### Cel
Jasne poinformowanie użytkownika panelu, który target jest aktualnie stosowany, gdy zakres widoku jest szerszy niż jeden miesiąc.

### Kontekst
Dashboard obsługuje widoki roczne i wielomiesięczne. W takim przypadku — zgodnie z decyzją 2.4 — dla KPI zbiorczych używany jest **ostatni znany target** (ostatni miesiąc, dla którego zdefiniowano target).

### Wymagania szczegółowe

**`api`:**
- Endpoint `GET /panel/shops/{id}/targets?year={year}` (bez parametru `month`) powinien zwrócić:
  - listę targetów per miesiąc dla całego roku (do użycia w tabeli miesięcznej)
  - wskazanie "ostatniego aktywnego targetu" (ostatni miesiąc z zdefiniowanym targetem) — do użycia w KPI zbiorczych

**`panel`:**
- W sekcji KPI zbiorczych (góra dashboardu): jeśli zakres > 1 miesiąc, wyświetlić pod badge'm:
  - "Target z [miesiąc roku, np. Marzec 2026]"
  - Jeśli brak jakiegokolwiek targetu w danym roku — brak badge'a, bez kolorowania
- W tabeli miesięcznej: każdy wiersz używa targetu właściwego dla swojego miesiąca; jeśli brak targetu dla danego miesiąca — brak kolorowania w tym wierszu (bez fallbacku między wierszami)

**UX — sposób informowania:**
- Etykieta przy badge KPI: mały szary tekst "(wg [Marzec 2026])"
- Tooltip po najechaniu: "Ocena bazuje na targetach zdefiniowanych dla marca 2026 — ostatniego miesiąca z dostępnymi targetami w wybranym zakresie."

---

## Iteracja 6 — Historia zmian targetów (audit log)

### Cel
Możliwość śledzenia kto i kiedy zmienił wartości targetów — przydatne przy rozliczaniu realizacji celów.

### Wymagania szczegółowe

**`api`:**
- Tabela `shop_metric_targets_history`:
  - Kolumny: `id`, `id_target` (FK do `shop_metric_targets`), `changed_by`, `changed_at`, `old_threshold_1/2/3`, `new_threshold_1/2/3`, `change_reason` (opcjonalne)
- Trigger lub logika serwisowa: przed każdym `UPDATE` w `shop_metric_targets` — zapis do tabeli historii
- Endpoint: `GET /admin/shops/{id}/targets/history?metric_key=&year=&month=` — zwraca listę zmian

**`admin` i `consultant`:**
- Opcjonalne pole "Powód zmiany" przy zapisie (textarea, nieobowiązkowe)
- Link/przycisk "Historia zmian" w widoku targetów — otwiera modal z listą zmian dla wybranej metryki / sklepu / miesiąca

---

## Iteracja 7 — Widok porównawczy target vs. realizacja

### Cel
Umożliwienie użytkownikowi panelu przeglądu wszystkich metryk na osi: target → realizacja → ocena — w widoku zbiorczym, nie tylko per miesiąc w tabeli.

### Wymagania szczegółowe

**Nowy widok lub sekcja w `panel`:**
- Karta per metryka z:
  - wartością targetu (dobry / średni / śr. zły / zły — progi)
  - wartością zrealizowaną (z danych dashboardu)
  - badge'em oceny
  - strzałką trendu (realizacja vs. poprzedni miesiąc)
- Możliwość filtrowania po miesiącu i roku
- Możliwość eksportu do CSV lub PDF (opcjonalne)

**`api`:**
- Endpoint `GET /panel/shops/{id}/targets/evaluation?year=&month=` — zwraca dla każdej metryki:
  - target (progi, aktywny autor)
  - wartość zrealizowaną
  - obliczony poziom oceny (`good` | `medium` | `medium_bad` | `bad` | `no_target`)

---

## Podsumowanie kolejności iteracji

| Iteracja | Zakres | Priorytet |
|---|---|---|
| **1** (gotowa) | 3 metryki kosztowe, CRUD, dashboard | ✅ Wdrożona |
| **2** | 5 metryk biznesowych + rozszerzenie UI | 🔴 Wysoki |
| **3** | Prezentacja dwóch targetów jednocześnie | 🟡 Średni |
| **4** | Fallback globalny (wartości domyślne) | 🟡 Średni |
| **5** | Informowanie o kontekście czasowym targetu | 🟡 Średni |
| **6** | Historia zmian (audit log) | 🟢 Niski |
| **7** | Widok porównawczy target vs. realizacja | 🟢 Niski |

---

## Zależności między iteracjami

```
Iteracja 1 (baza)
    └── Iteracja 2 (nowe metryki) ← wymagana przed 3, 4, 5
            ├── Iteracja 3 (dwa targety jednocześnie)
            ├── Iteracja 4 (fallback globalny)
            └── Iteracja 5 (kontekst czasowy)
                    └── Iteracja 7 (widok porównawczy)

Iteracja 6 (historia) ← niezależna, można wdrożyć po iteracji 1
```

