# Mechanizm planowania spotkań — Iteracja 1

## Status
✅ Gotowe do wdrożenia

---

## Decyzja architektoniczna: Kalendarz vs kafelki

Wybrano **kalendarz FullCalendar** (CDN, wersja 6) dla widoku `admin`, ponieważ:
- Daje natychmiastową orientację w czasie (widok miesięczny, tygodniowy, lista)
- Ułatwia dalszą rozbudowę (np. spotkania cykliczne w iteracji 2)
- Biblioteka jest lekka (CDN), nie wymaga instalacji npm
- Pod kalendarzem dodana jest pomocnicza tabela z akcjami (edytuj, anuluj, Google Calendar)

W `panel` zastosowano **listę** (upcoming + historia), ponieważ:
- Panel to widok read-only dla franczyzobiorcy
- Hierarchia ważności: nadchodzące > historia
- Lista jest czytelniejsza niż kalendarz gdy użytkownik pasywnie przegląda harmonogram

---

## Struktura plików

### Baza danych
- `api/database/franchise_meeting.sql` — DDL tabeli `franchise_meeting`

### API (`api`)
| Plik | Opis |
|------|------|
| `app/Repositories/Communication/MeetingRepository.php` | Bezpośredni dostęp do bazy |
| `app/Services/Communication/MeetingService.php` | Logika biznesowa + walidacja |
| `app/Controllers/Communication/MeetingController.php` | Obsługa HTTP (admin + panel) |
| `v1/Routes/Communication/MeetingRoutes.php` | Rejestracja tras |
| `lang/pl/meeting.json` | Komunikaty PL |
| `lang/en/meeting.json` | Komunikaty EN |
| `core/bootstrap.php` | Rejestracja DI (autowire) |

### Admin (`admin`)
| Plik | Opis |
|------|------|
| `models/Communication/MeetingModel.php` | Model + `getGoogleCalendarLink()` |
| `repositories/Communication/MeetingRepository.php` | Wywołania API |
| `services/Communication/MeetingService.php` | Delegacja + walidacja front-end |
| `controllers/Communication/MeetingController.php` | Kontroler widoku + AJAX |
| `core/Routes/Communication/MeetingRoutes.php` | Trasy FastRoute |
| `views/communication/meeting/overview.twig` | Widok (FullCalendar + tabela + modaly) |
| `public/resources/lang/page/pl/meeting.json` | Tłumaczenia PL |
| `public/resources/lang/page/en/meeting.json` | Tłumaczenia EN |
| `public/resources/lang/page/fr/meeting.json` | Tłumaczenia FR |
| `public/resources/lang/page/nl/meeting.json` | Tłumaczenia NL |
| `public/resources/lang/page/it/meeting.json` | Tłumaczenia IT |
| `core/bootstrap.php` | Rejestracja DI (factory) |

### Panel (`panel`)
| Plik | Opis |
|------|------|
| `models/Communication/MeetingModel.php` | Model + `getGoogleCalendarLink()` |
| `repositories/Communication/MeetingRepository.php` | Wywołania API |
| `services/Communication/MeetingService.php` | Delegacja do repozytorium |
| `controllers/Communication/MeetingController.php` | Kontroler widoku |
| `core/Routes/Communication/MeetingRoutes.php` | Trasy FastRoute |
| `views/communication/meeting_schedule.twig` | Widok harmonogramu |
| `views/communication/_meeting_item.twig` | Partial: element spotkania |
| `public/resources/lang/page/pl/communication.json` | Tłumaczenia (dodane klucze) |
| `public/resources/lang/page/en/communication.json` | Tłumaczenia (dodane klucze) |
| `core/bootstrap.php` | Rejestracja DI (autowire) |

---

## Endpointy API

| Metoda | URL | Opis |
|--------|-----|------|
| GET | `/admin/meetings` | Lista wszystkich spotkań |
| POST | `/admin/meetings` | Nowe spotkanie |
| GET | `/admin/meetings/{id}` | Szczegóły spotkania |
| PATCH | `/admin/meetings/{id}` | Aktualizacja spotkania |
| PATCH | `/admin/meetings/{id}/cancel` | Anulowanie spotkania |
| GET | `/panel/shops/{id}/meetings` | Wszystkie spotkania sklepu |
| GET | `/panel/shops/{id}/meetings/upcoming` | Nadchodzące spotkania |
| GET | `/panel/shops/{id}/meetings/past` | Historyczne spotkania |

Wszystkie endpointy wymagają JWT (`AuthMiddleware::checkAuth()`).

## Trasy admin

| Metoda | URL | Akcja |
|--------|-----|-------|
| GET | `/meetings` | Widok kalendarza |
| GET | `/ajax/meetings/shops` | Lista sklepów (dla modalu) |
| GET | `/ajax/meetings/{id}` | Pobierz spotkanie (edycja) |
| POST | `/ajax/meetings` | Nowe spotkanie |
| PATCH | `/ajax/meetings/{id}` | Aktualizacja |
| PATCH | `/ajax/meetings/{id}/cancel` | Anulowanie |

## Trasy panel

| Metoda | URL | Akcja |
|--------|-----|-------|
| GET | `/meetings/schedule` | Harmonogram franczyzobiorcy |
| GET | `/ajax/meetings` | AJAX — lista (opcjonalnie) |

---

## Walidacja

**Backend (API)**:
- tytuł: wymagany, max 255 znaków
- data: wymagana
- godzina: wymagana
- typ: wymagany, enum(individual, group)
- agenda: wymagana, max 255 znaków
- external_link: opcjonalny, musi być poprawnym URL
- id_shop: wymagany gdy type=individual, zabroniony gdy type=group

**Frontend (admin JS)**:
- identyczne reguły po stronie klienta przed wysłaniem żądania

---

## Google Calendar

Link generowany jest po stronie PHP w metodzie `getGoogleCalendarLink()` w modelu.
Format: `https://www.google.com/calendar/render?action=TEMPLATE&text=...&dates=YYYYMMDDTHHMMSS/YYYYMMDDTHHMMSS&details=...`
Czas trwania: używa `duration_minutes`; gdy brak — domyślnie 60 minut.

---

## Wdrożenie

1. Wykonaj DDL: `api/database/franchise_meeting.sql`
2. Wdróż zmiany w `api`, `admin`, `panel`
3. Dodaj link do `/meetings` w nawigacji admina
4. Dodaj link do `/meetings/schedule` w nawigacji panelu

---

## Kryteria akceptacji (✅ zrealizowane)

1. ✅ Administrator widzi widok kalendarza spotkań w `/meetings`
2. ✅ Lista spotkań z czytelnym statusem aktywne/anulowane
3. ✅ Modal dodawania spotkania (tytuł, data, godzina, typ, agenda, link, sklep)
4. ✅ Edycja spotkania przez modal
5. ✅ Anulowanie spotkania z potwierdzeniem
6. ✅ Spotkanie grupowe widoczne dla wszystkich sklepów
7. ✅ Spotkanie indywidualne widoczne tylko dla przypisanego sklepu
8. ✅ Harmonogram w `/meetings/schedule` z sekcją nadchodzących i historii
9. ✅ Spotkania anulowane z oznaczeniem "Anulowane"
10. ✅ Link „Dodaj do Google Calendar" (generowany po stronie serwera)
11. ✅ Pełne tłumaczenia (PL, EN, FR, NL, IT)
12. ✅ Architektura zgodna z istniejącymi wzorcami projektu

