# Architektura modułu B2B — Panel

## Status: IT-1 / IT-2 / IT-3 (fundament panel) — ZAIMPLEMENTOWANY
## Status: IT-6 (api backend) — ZAIMPLEMENTOWANY

---

## 1. Routing

Wzorzec: FastRoute + auto-discovery `core/Routes/*/*Routes.php`

### Nowe trasy (`core/Routes/B2B/ClientRoutes.php`)

| Metoda | Ścieżka | Akcja |
|--------|---------|-------|
| GET | `/b2b/clients` | Widok HTML listy klientów B2B |
| GET | `/ajax/b2b/clients` | JSON: filtrowana lista klientów |
| GET | `/ajax/b2b/clients/{clientId}/profile` | JSON: profil per-sklep |
| POST | `/ajax/b2b/clients/{clientId}/profile` | JSON: upsert profilu per-sklep |

---

## 2. Kontroler

`controllers/B2B/ClientController.php`
Namespace: `App\User\Controllers\B2B`
Dziedziczy: `App\User\Controllers\Controller`

**Kluczowa zasada izolacji:** shopId jest zawsze odczytywany z sesji zalogowanego użytkownika (`GlobalRegistry::get('user')->getIdShop()`), nigdy z parametrów żądania. Sklep X nie może odczytać ani nadpisać danych sklepu Y.

---

## 3. Warstwa serwisów i repozytoriów

```
controllers/B2B/ClientController
    └── services/B2B/B2BClientService
            └── repositories/B2B/B2BClientRepository
                    └── core/ApiClient → API (panel/shops/{shopId}/b2b/...)
```

---

## 4. Model danych

### Dane globalne klienta (tabela `clients` po stronie `api`)
Pozostają bez zmian. Zawierają: dane adresowe, NIP, PEPPOL, `is_b2b`, `payment_terms`, etc.

### Dane per-sklep (nowa tabela `client_shop_profiles`)

| Pole | Typ | Charakter |
|------|-----|-----------|
| `client_type` | ENUM | konfiguracja per-sklep |
| `service_mode` | ENUM | konfiguracja per-sklep |
| `credit_enabled` | bool | konfiguracja per-sklep |
| `credit_limit` | DECIMAL | konfiguracja per-sklep |
| `cached_score` | ENUM(A/B/C/D) | cache per-sklep |
| `cached_score_value` | DECIMAL | cache per-sklep |
| `cached_recurrence` | DECIMAL | cache per-sklep |
| `cached_orders_12m` | SMALLINT | cache per-sklep |
| `cached_ca_12m` | DECIMAL | cache per-sklep |
| `cached_avg_delay_days` | DECIMAL | cache per-sklep |
| `cached_credit_used` | DECIMAL | cache per-sklep |
| `cached_last_order_at` | DATETIME | cache per-sklep |
| `cached_updated_at` | DATETIME | cache per-sklep |

Migracja: `migrations/2026_04_21_create_client_shop_profiles.sql`

---

## 5. Model PHP

`models/Client/ClientShopProfileModel.php`
Namespace: `App\User\Models\Client`

Zawiera gettery i metodę pomocniczą `getCreditUsagePercent()`.

---

## 6. Rejestracja w ServiceFactory

`core/ServiceFactory.php` — metoda `createB2BClientService()` (dodana).

DI Container (bootstrap.php) rozwiązuje zależności automatycznie przez autowire.

---

## 7. Nawigacja (TODO — IT-5)

Dodać pozycję w sidebarze:
- Sekcja: Klienci
- Link: `/b2b/clients`
- Etykieta: `Zarządzanie B2B` (lub z tłumaczeń)

---

## 8. Kolejne iteracje

| Iteracja | Zakres |
|----------|--------|
| IT-4 | Widok `views/b2b/clients/index.twig` — tabela z filtrami (score, service_mode, client_type, search) |
| IT-4b | Rozwijany panel profilu klienta (drawer/modal z danymi per-sklep + cache scoringowy) |
| IT-5 | Nawigacja + integracja z B2BDashboardService (metryki) |
| IT-6 | Endpointy API po stronie `api` (CRUD profilu per-sklep, obliczanie scoringu) |
| IT-7 | Cache scoringowy — job/cron po stronie `api` odświeżający `cached_*` |

---

## 9. Otwarte pytania / decyzje do podjęcia

1. **Migracja istniejącej trasy `/Client/b2b`** — czy nowy moduł zastępuje stary widok stopniowo (redirect), czy działa równolegle do czasu pełnej gotowości?
2. **Uprawnienia do credit_limit** — operator panelu czy tylko admin może zmieniać limit?
3. **Cache scoring** — czy istnieje już scheduler po stronie `api`, czy trzeba go zaprojektować?
4. **Widok profilu** — drawer (sliding panel) czy osobna strona `/b2b/clients/{id}`?

