# USTALENIA: MODUŁ ZAMÓWIEŃ ONLINE — SLICEHUB ENTERPRISE
**Data:** 2026-04-16
**Status:** Zatwierdzone przez Product Ownera, oczekuje na start implementacji
---
## 1. ARCHITEKTURA DWUPOZIOMOWA
### Poziom 1: Strona Główna Menu (Przeglądanie)
- Tło: ciemna fotograficzna powierzchnia (uploadowana przez managera w Studio)
- Fallback: gradient ciemny (#1a1a1a) gdy brak zdjęcia
- Akordeon kategorii:
- Wąskie paski (~48px) z nazwą kategorii, strzałką rozwinięcia
- Elementy tekstowe na półprzezroczystym tle (glass-morphism) dla czytelności
- Tylko jedna kategoria otwarta naraz
- Lazy loading miniaturek — ładowane dopiero przy rozwinięciu kategorii
- Każde danie w rozwiniętej liście:
- Miniaturka (~56px kwadrat) po lewej
- Nazwa + krótki opis (1 linia, obcięty) w środku
- Cena po prawej — jeśli warianty rozmiaru: "30cm 29,99 / 37cm 39,99" widoczne od razu inline
- Klik na danie = otwiera Poziom 2
- Opcjonalnie: sekcja "Popularne" nad akordeonem (3-4 wyróżnione dania)
- Opcjonalnie: pasek wyszukiwania na górze
### Poziom 2: Karta Dania ("Surface Card")
- **Mobile**: bottom sheet (wysuwa się od dołu, snap: pół ekranu → pełny ekran)
- **Desktop**: modal lub side panel z backdrop blur
- Tło karty: ta sama ciemna powierzchnia co strona główna (spójność)
- Układ wewnątrz:
- Połowa pizzy po lewej (prawy półkrąg, krawędź cięcia przy lewej ścianie)
- Prawa strona: companions (sos, napój) jako zdjęcia produktów + "DODAJ"
- Pod tym: modyfikatory w zwiniętych kategoriach (np. WARZYWA — 3 widoczne, reszta po "Pokaż więcej")
- Przełącznik **Podgląd / Edycja** u góry nad pizzą
- Tryb Podgląd: pizza statyczna, dodatki quick-add (badge "x1", "x2"), bez zmian warstw
- Tryb Edycja: warstwy ożywają, klik na składnik:
- x1: warstwa (scatter) nakłada się na pizzę + zdjęcie hero produktu pojawia się na powierzchni obok
- x2: brak nowej warstwy, drugie zdjęcie hero materiałuje się obok pierwszego
- x0 (usunięcie): warstwa i zdjęcia hero znikają
- Pizza może opcjonalnie rozszerzyć się na pełny ekran w trybie Edycja
- Pół na pół: widoczna połowa dzieli się horyzontalnie (góra = Pizza A, dół = Pizza B)
---
## 2. KOSZYK — CAŁKOWICIE ODDZIELONY
- Koszyk NIE jest częścią karty dania ani strony menu
- **Mobile**: floating button (prawy dolny róg) z badge'm ilości → klik otwiera drawer od prawej
- **Desktop**: ikona koszyka w nagłówku → dropdown/panel
- Komunikacja: `CustomEvent('pizza-add-to-cart')` — karta dania dispatchuje event, koszyk nasłuchuje
- Walidacja server-side: przed dodaniem → `CartEngine.php` potwierdza cenę (Prawo Zera Zaufania)
---
## 3. SYSTEM DWÓCH ZDJĘĆ NA SKŁADNIK
Każdy modyfikator/składnik wymaga DWÓCH zdjęć:
| Rola | Nazwa kolumny | Opis |
|------|---------------|------|
| **Warstwa (layer/scatter)** | `asset_filename` | Składnik rozsypany jak na pizzy, widok z góry, przezroczyste tło, ~1500x1500px |
| **Produkt (hero)** | `product_filename` (NOWA) | Pojedynczy piękny produkt (pomidorek, listki bazylii), przezroczyste tło, ~600x600px |
Migracja DB: dodanie `product_filename` do `sh_visual_layers` lub `sh_ingredient_assets`.
---
## 4. ZDJĘCIE TŁA POWIERZCHNI (SURFACE)
- Uploadowane przez managera w Studio (`/modules/studio/`)
- Zapisywane w `sh_tenant_settings` pod kluczem `storefront_surface_bg`
- CSS: `--surface-bg: url(...)` na głównym kontenerze
- Wymagania: ciemna powierzchnia (kamień, marmur, drewno), top-down, min. 2560x1600px
- Serwowane jako WebP z srcset dla różnych rozdzielczości
---
## 5. WZORCE Z POS-a (INSPIRACJA, NIE KOPIA)
Bierzemy z POS-a:
- Zwartość elementów (małe paddingi, czytelna hierarchia fontów)
- Akordeonowy układ (kanban click-to-expand → nasze kategorie click-to-expand)
- Modal konfiguracji dania (`dc-card` → nasz bottom sheet)
- Koszyk jako osobny panel (`pos-cart` → nasz floating drawer)
- Color-coded feedback (badge'e, stany aktywne)
NIE bierzemy z POS-a:
- Ciemny motyw systemowy (nasza ciemność pochodzi ze zdjęcia powierzchni, nie z UI)
- Rozmiary fontów POS-owe (7-12px) — online musi być większy dla klientów końcowych
- Tryb operatora (POS to narzędzie pracy, online to doświadczenie klienta)
---
## 6. CO ZACHOWUJEMY Z OBECNEGO KODU
### Backend (bez zmian / minimalne rozszerzenia):
- `api/online/engine.php` — unified storefront engine (action-based) ✅ (zastąpił `product.php` 2026-04-16)
- `api/cart/CartEngine.php` + `calculate.php` — walidacja server-side ✅
- `core/WzEngine.php` — silnik magazynowy, half&half 0.5 multiplier ✅
### Logika biznesowa do odtworzenia w nowym frontend (specyfikacja, nie kod):
- Generowanie payload CartEngine-compatible (`channel`, `order_type`, `lines[]`, `promo_code`)
- Optymistyczny podgląd ceny (half&half: max(A,B) + surcharge z tenant_settings)
- Flatowanie modyfikatorów (group → options → SKU)
- Domyślna selekcja modyfikatorów + rozmiaru
- Half & Half: state machine A/B + ładowanie danych pizzy B
- Komunikacja z backendem przez `online_api.js` (wrapper na `engine.php`)
### Baza danych (zachowane tabele):
- `sh_price_tiers` — macierz cenowa
- `sh_global_assets` — warstwy bazowe (deska, ciasto, sos)
- `sh_visual_layers` — mapowanie modifier → warstwa wizualna
- `sh_board_companions` — cross-sell companions
- `sh_ingredient_assets` — biblioteka składników
- `sh_tenant_settings` — ustawienia tenanta (surcharge, surface_bg)
---
## 7. CO WYMIENIAMY BRUTALNIE
| Plik | Akcja | Powód |
|------|-------|-------|
| `modules/online/index.html` | **TWORZYMY OD ZERA** (stary v4 usunięty 2026-04-16) | Czysty shell zgodny z konwencją POS/Tables |
| `modules/online/css/style.css` | **TWORZYMY OD ZERA** | Surface theme — dark, glass-morphism, mobile-first |
| `modules/online/js/online_api.js` | **TWORZYMY OD ZERA** | Wrapper na `api/online/engine.php` (wzorzec `pos_api.js`) |
| `modules/online/js/online_app.js` | **TWORZYMY OD ZERA** | State machine + glue (init, lifecycle) |
| `modules/online/js/online_ui.js` | **TWORZYMY OD ZERA** | Akordeon kategorii + Surface Card + cart drawer |
---
## 8. ZIDENTYFIKOWANE ZAGROŻENIA
| # | Zagrożenie | Ryzyko | Mitygacja |
|---|-----------|--------|-----------|
| 1 | Wydajność przy 100+ daniach | Wolne ładowanie, lagujący scroll | Akordeon + lazy loading miniaturek (ładowane przy rozwinięciu kategorii) |
| 2 | Bottom sheet + pizza na małym telefonie (375px) | Brak miejsca na dodatki | Pizza max 40% szerokości; na małych ekranach: pizza u góry, dodatki pod spodem |
| 3 | Opóźnienie otwarcia karty dania (API call) | User czeka 1-2s = drop-off | Smart prefetch: ładujemy dane 3 pierwszych dań w tle przy rozwinięciu kategorii |
| 4 | Niespójne zdjęcia od fotografa | Surface effect się rozsypie | Precyzyjny brief fotograficzny (sekcja 9) z przykładami |
| 5 | Czytelność tekstu na ciemnym tle | Accessibility fail (WCAG) | Glass-morphism: elementy UI na półprzezroczystym tle, kontrast min. 4.5:1 |
| 6 | Brak zdjęć na starcie (nowa restauracja) | Pusta strona, zły UX | Graceful fallback: inicjały zamiast miniaturek, brak pizzy wizualnej, czysta lista |
| 7 | Duże zdjęcie tła = wolny LCP | Słabe Core Web Vitals / SEO | WebP + srcset + progressive loading (blur placeholder → full image) |
| 8 | Animacje na starych telefonach | Lagowanie, jank | `prefers-reduced-motion` media query, fallback do prostych przejść |
---
## 9. BRIEF FOTOGRAFICZNY
### Zasady ogólne:
- Kąt kamery: 100% zdjęć z **bezpośrednio nad** (bird's-eye / flat lay)
- Wszystkie składniki i produkty: **.webp/.png z przezroczystym tłem** (alpha)
- Oświetlenie: miękkie, ciepłe, z jednej strony (konsekwentnie ~godz. 10:00), identyczne we wszystkich sesjach
- Kalibracja kolorów: ciepłe tony, karta referencyjna kolorów w każdej sesji
- Rozdzielczość: dostarczać w 2x (retina)
### Na składnik — DWA zdjęcia:
**Zdjęcie A — "Scatter Layer" (warstwa na pizzę):**
- Składnik rozsypany jak na pizzy, widok z góry
- Wypełnia ~60-70% kwadratowej ramki, margines na brzegach
- Naturalny układ (garść oliwek rzuconych na blat, startki mozzarelli organicznie rozłożone)
- Przezroczyste tło, min. 1500x1500px
**Zdjęcie B — "Hero Product" (produkt na powierzchnię + siatka menu):**
- Piękny, kompaktowy pojedynczy obiekt
- Przykłady: JEDEN pomidorek koktajlowy na łodyżce, 3 listki bazylii, mała kupka plastrów salami
- Przezroczyste tło, min. 600x600px
- Ma wyglądać jak "postawiony na ciemnej powierzchni przez food stylistę"
### Zdjęcie tła (Surface):
- Prawdziwa fizyczna powierzchnia z góry (ciemny kamień, stary marmur, ciemne drewno, łupek)
- Subtelna tekstura, bez silnych powtarzających się wzorów
- Min. 2560x1600px, idealnie 3840x2400px
- Jedno zdjęcie per motyw marki
### Companions (sosy, napoje, dodatki):
- Widok z góry (widzimy czubek butelki, wieczko sosu)
- Naturalny cień pod spodem dozwolony
- Przezroczyste tło, .webp
### Miniaturki dań (dla listy menu):
- Kwadrat, danie z góry, pięknie skomponowane
- Min. 400x400px, przezroczyste tło lub na tej samej powierzchni
---
## 10. STUDIO — ROZBUDOWA KOMPOZYTORA WIZUALNEGO (NIE NOWY MODUŁ)
### Stan obecny (`studio_visual.js` / `VisualLayerEditor`):
- Canvas z renderowaniem warstw `.webp` (z-order stacking) ✅
- 3 zakładki: Warstwy, Biblioteka, Cross-sell ✅
- Auto-mapping składników do assetów (`_SUB_TYPE_KEYWORDS`) ✅
- Dodawanie/usuwanie warstw, zmiana ilości (x1/x2/x3) ✅
- Animacje pop-in/pop-out ✅
- Companion CRUD (dodaj/usuń cross-sell) ✅
### Braki do uzupełnienia:
- ❌ Nie zapisuje warstw do bazy (`sh_visual_layers`) — tylko pamięć
- ❌ Brak kalibracji scale/rotate na warstwach
- ❌ Brak uploadu nowych assetów (tylko wybór z biblioteki)
- ❌ Brak systemu dual-photo (hero product)
- ❌ Brak podglądu widoku klienta (Surface preview)
### Plan rozbudowy — okrojony kompozytor z pełnymi możliwościami:
**1. Zapis do bazy (`sh_visual_layers`)**
- Przycisk "ZAPISZ WARSTWY" pod canvasem
- Każda warstwa z canvasa = wiersz w `sh_visual_layers` (item_sku + layer_sku + asset + z_index + kalibracja)
- Endpoint: `api_menu_studio.php` → akcja `save_visual_layers`
- Przy ładowaniu dania (`VisualLayerEditor.load()`) → dane z DB zamiast auto-mapu
**2. Kalibracja na żywo (scale + rotate) — LIVE PREVIEW**
- Przy każdej warstwie w zakładce "Warstwy" → dwa suwaki:
- Scale: `0.80` → `1.20` (krok 0.01)
- Rotate: `-180°` → `180°` (krok 1°)
- Zmiana suwaka = natychmiastowa aktualizacja `transform` na canvasie (bez przeładowania)
- Manager WIDZI NA ŻYWO jak warstwa pasuje do reszty kompozycji
- Wartości zapisywane w `sh_visual_layers.cal_scale` i `sh_visual_layers.cal_rotate`
- CSS canvasa: `transform: scale(var(--cal-scale, 1)) rotate(var(--cal-rotate, 0deg))` (identyczny jak online)
**3. Upload zdjęć (drag & drop)**
- W zakładce "Biblioteka" → sekcja "Wgraj nowy asset" u góry
- Drag & drop zone lub file picker (HTML5 ``)
- DWA SLOTY na upload:
- Slot A: "Warstwa (scatter)" → `asset_filename`
- Slot B: "Hero (produkt)" → `product_filename`
- Walidacja po stronie JS:
- Format: tylko `.webp` lub `.png`
- Wymiary: min 600x600px (hero) / 1000x1000px (layer)
- Rozmiar: max 5MB
- Auto-generowanie `ascii_key` z nazwy pliku (np. `veg_tomato_cherry_a1b2c3`)
- Upload via `api_menu_studio.php` → akcja `upload_visual_asset`
- Pliki zapisywane do `/uploads/global_assets/` (shared) lub `/uploads/visual/{tenant_id}/` (per-tenant)
- Wytyczne fotograficzne jako tooltip/info-box przy uploaderze
**4. Podgląd widoku klienta ("Podgląd Online")**
- CZWARTA zakładka obok Warstwy/Biblioteka/Cross-sell
- Symuluje dokładny widok klienta na stronie online:
- Ciemne tło surface (z `sh_tenant_settings.storefront_surface_bg`)
- Połowa pizzy (prawy półkrąg, lewa krawędź cięcia)
- Hero products materializujące się obok
- Toggle: "Pełna pizza / Połowa / Pół na pół" do testowania różnych widoków
- Używa **dokładnie tego samego CSS** co moduł online (shared stylesheet lub skopiowane reguły)
- Manager widzi 1:1 to co zobaczy klient
**5. Inline wytyczne fotograficzne**
- Małe info-boxy przy uploaderze:
- "📸 Warstwa: widok z góry, przezroczyste tło, min 1500×1500px"
- "📸 Hero: pojedynczy produkt, przezroczyste tło, min 600×600px"
- Link "Pokaż pełny brief" → rozwija szczegółowe wytyczne (z sekcji 9)
### Schemat interakcji managera (flow):
```
1. Otwórz danie w Studio → przewiń do "Konfigurator Wizualny"
2. Canvas pokazuje aktualne warstwy (z sh_visual_layers LUB auto-map jako fallback)
3. Zakładka "Biblioteka" → klik na asset → dodaje do canvasa
4. Zakładka "Warstwy" → suwaki scale/rotate → natychmiastowy efekt na canvasie
5. Zakładka "Podgląd Online" → widzi to samo co klient (połowa pizzy + surface)
6. Potrzeba nowego assetu → "Wgraj nowy" → drag & drop → upload do serwera
7. Klik "ZAPISZ WARSTWY" → persystencja do sh_visual_layers
```
### Zagrożenia rozbudowy Studio:
| # | Zagrożenie | Mitygacja |
|---|-----------|-----------|
| 1 | Upload dużych plików blokuje UI | Async upload z progress barem, limit 5MB per plik |
| 2 | Manager wgra złe zdjęcie (z tłem, źle wykadrowane) | Walidacja: format, wymiary min., ostrzeżenie jeśli brak alpha |
| 3 | Kalibracja transform psuje clip-path | Architektura 3-warstwowa: clip-path na kontenerze, transform na img (już zaprojektowana) |
| 4 | Podgląd rozsynchronizowany z online | Studio preview używa identycznego CSS co frontend online |
| 5 | Manager nie rozumie systemu warstw | Tooltip z instrukcją + automatyczny auto-map jako fallback startowy |
---
## 11. ZASADY ARCHITEKTURY SYSTEMOWEJ
- Moduł online (`/modules/online/`) jest **WYŁĄCZNIE do odczytu** — klient końcowy
- Zero narzędzi edycji wizualnej (drag & drop, uploadery, kalibratory) w module online
- Wszystkie ustawienia wizualne (tło, kalibracja warstw, zdjęcia) zarządzane w **Studio** (`/modules/studio/`)
- Online czyta i aplikuje → Studio pisze i zarządza
- API `product.php` zwraca gotowe URL-e i parametry kalibracji → frontend je tylko renderuje
- `VisualLayerEditor` w Studio to jedyne miejsce w systemie do zarządzania warstwami wizualnymi
---
## 12. MIGRACJA BAZY DANYCH — WYKONANA ✅
**Plik:** `database/migrations/016_visual_compositor_upgrade.sql`
**Status:** UTWORZONY, gotowy do uruchomienia
Migracja jest **idempotentna** (bezpieczna do wielokrotnego uruchomienia) — sprawdza istnienie kolumn przed dodaniem.
### Co dodaje:
| Tabela | Kolumna | Typ | Opis |
|--------|---------|-----|------|
| `sh_visual_layers` | `product_filename` | `VARCHAR(255) NULL` | Hero product photo (standalone, surface/grid) |
| `sh_visual_layers` | `cal_scale` | `DECIMAL(4,2) DEFAULT 1.00` | Kalibracja: współczynnik skali 0.50-2.00 |
| `sh_visual_layers` | `cal_rotate` | `SMALLINT DEFAULT 0` | Kalibracja: rotacja w stopniach -180 do 180 |
| `sh_board_companions` | `product_filename` | `VARCHAR(255) NULL` | Hero product photo dla surface materialization |
| `sh_tenant_settings` | (wiersz) `storefront_surface_bg` | KV | Tło surface uploadowane przez managera |
### SQL idempotentny (fragment):
```sql
-- Sprawdzenie istnienia kolumny przed ALTER TABLE
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'sh_visual_layers'
AND COLUMN_NAME = 'product_filename');
-- IF NOT EXISTS → ALTER TABLE ADD COLUMN
```
---
## 13. KOLEJNOŚĆ IMPLEMENTACJI (ZAKTUALIZOWANA)
### Faza 1: Fundament (DB + API)
1. **Migracja DB** — `product_filename`, `cal_scale`, `cal_rotate`, `storefront_surface_bg`
2. **API rozszerzenie** — `product.php` + nowe endpointy: `save_visual_layers`, `upload_visual_asset`, `get_menu_categories` (dla online)
### Faza 2: Studio — Rozbudowa kompozytora
3. **Studio: zapis warstw** — `VisualLayerEditor` → persystencja do `sh_visual_layers`
4. **Studio: kalibracja** — suwaki scale/rotate z live preview na canvasie
5. **Studio: upload** — drag & drop z walidacją, dual-photo slots
6. **Studio: podgląd online** — 4. zakładka symulująca widok klienta
### Faza 3: Online Frontend
7. **HTML/CSS** — nowa struktura DOM (akordeon + bottom sheet + floating cart)
8. **JS Engine** — przepisanie renderingu, zachowanie logiki biznesowej
9. **Integracja koszyka** — floating cart drawer + CustomEvent bridge
10. **Half & Half** — masking + Pizza B selector w bottom sheet
### Faza 4: Polski i optymalizacja
11. **Animacje** — materializacja na surface, layer-land, przejścia
12. **Fallbacki** — graceful degradation bez zdjęć, bez surface bg
13. **Testy mobile** — responsywność, performance, touch events
14. **Cross-sell step** — krok po dodaniu dania z poleceniami
---
## 14. CO JUŻ MAMY I MOŻEMY WYKORZYSTAĆ
### Pliki gotowe do rozbudowy (nie usuwamy, rozbudowujemy):
| Plik | Stan | Co z nim robimy |
|------|------|-----------------|
| `modules/studio/js/studio_visual.js` | Działa (preview only) | Dodajemy: save, kalibrację, upload, podgląd online |
| `modules/studio/js/studio_item.js` | Działa (formularz dania) | Sekcja `sec-visual` już istnieje — integracja gotowa |
| `modules/studio/index.html` | Działa | Bez zmian — `VisualLayerEditor` renderuje się dynamicznie |
| `api/online/engine.php` | **GOTOWY** (zastąpił `product.php` 2026-04-16) | Akcje: get_storefront_settings, get_menu, get_dish, cart_calculate |
| `api/backoffice/api_menu_studio.php` | Działa | Dodajemy akcje: `save_visual_layers`, `upload_visual_asset` |
| `api/cart/CartEngine.php` | Działa | Bez zmian |
| `core/WzEngine.php` | Działa | Bez zmian |
### Pliki do utworzenia (stary moduł online usunięty 2026-04-16):
| Plik | Powód |
|------|-------|
| `modules/online/index.html` | Nowy shell zgodny z konwencją POS/Tables (czysty HTML) |
| `modules/online/css/style.css` | Surface theme od zera (dark, glass, mobile-first) |
| `modules/online/js/online_api.js` | Wrapper na `engine.php` (wzorzec `pos_api.js`) |
| `modules/online/js/online_app.js` | State machine + glue (lifecycle + init) |
| `modules/online/js/online_ui.js` | Rendering: akordeon + Surface Card + cart drawer |
### Baza danych (istniejące tabele, rozbudowywane):
| Tabela | Stan | Zmiana |
|--------|------|--------|
| `sh_visual_layers` | Istnieje | +`product_filename`, +`cal_scale`, +`cal_rotate` |
| `sh_board_companions` | Istnieje | +`product_filename` |
| `sh_global_assets` | Istnieje | Bez zmian (shared asset library) |
| `sh_price_tiers` | Istnieje | Bez zmian |
| `sh_tenant_settings` | Istnieje | +wiersz `storefront_surface_bg` |
---
## 15. LIMITY UPLOADU I INSTRUKCJA FOTOGRAFICZNA — WYKONANA ✅
**Plik:** `_docs/05_INSTRUKCJA_FOTO_UPLOAD.md`
**Status:** UTWORZONY, gotowy do użycia
### Kluczowe limity (wymuszone na serwerze i kliencie):
| Typ assetu | Max rozmiar | Min wymiary | Max wymiary | Format |
|-----------|-------------|-------------|-------------|--------|
| Warstwa (scatter) | **3 MB** | 1000×1000 | 3000×3000 | `.webp` / `.png` |
| Hero (produkt) | **1.5 MB** | 400×400 | 1200×1200 | `.webp` / `.png` |
| Miniaturka dania | **800 KB** | 300×300 | 800×800 | `.webp` / `.png` |
| Tło surface | **5 MB** | 1920×1080 | 3840×2400 | `.webp` / `.jpg` |
| Companion | **1.5 MB** | 400×400 | 1200×1200 | `.webp` / `.png` |
### Walidacja dwupoziomowa:
1. **JS (pre-upload):** format, rozmiar `File.size`, wymiary `Image.naturalWidth/Height`, preview
2. **PHP (serwer):** MIME type `getimagesize()`, rozszerzenie, rozmiar, wymiary, alpha channel
### ZAKAZANE formaty: `.jpg` (brak alpha), `.gif`, `.bmp`, `.svg`, `.tiff`, `.heic`
Wyjątek: tło surface akceptuje `.jpg` (nie wymaga przezroczystości).
### Komunikaty błędów:
Zdefiniowane po polsku w dokumencie, gotowe do implementacji w JS i PHP.
### Instrukcja zawiera też:
- Kompletny brief fotograficzny (warstwy, hero, surface, companions, miniaturki)
- Checklist managera przed uploadem
- Konwencję nazw plików (auto-generowane `{category}_{sub_type}_{6hex}.{ext}`)
---
## 16. BEZPIECZEŃSTWO UPLOADÓW — WYKONANE ✅
### .htaccess w katalogach uploadów:
| Ścieżka | Stan | Co robi |
|---------|------|---------|
| `uploads/visual/.htaccess` | Istniał ✅ | Blokuje PHP, pozwala tylko .webp/.png |
| `uploads/global_assets/.htaccess` | **DODANY** ✅ | Identyczna ochrona — blokuje PHP, pozwala tylko .webp/.png |
### Reguły bezpieczeństwa uploadów:
- `Options -Indexes -ExecCGI` — brak listowania, brak wykonywania skryptów
- `RemoveHandler .php` — PHP nie wykona się nawet jeśli ktoś wgra `.php`
- `FilesMatch` — tylko `.webp` i `.png` mogą być serwowane, reszta = `403 Forbidden`
- Walidacja server-side (PHP): MIME type, rozszerzenie, rozmiar, wymiary, alpha channel
- Walidacja client-side (JS): format, `File.size`, `Image.naturalWidth/Height`, preview
---
## 17. SETUP_DATABASE.PHP — ZAKTUALIZOWANY ✅
`scripts/setup_database.php` obsługuje teraz:
- Migracje 006, 007, 008 (oryginalne)
- Migracja 012 — `sh_visual_layers` (CREATE TABLE IF NOT EXISTS)
- Migracja 013 — `sh_board_companions` (CREATE TABLE IF NOT EXISTS)
- Migracja 014 — `sh_global_assets` + `sh_ingredient_assets` (CREATE TABLE IF NOT EXISTS)
- Migracja 016 — `product_filename`, `cal_scale`, `cal_rotate`, `storefront_surface_bg` (idempotentne ALTER)
- Weryfikacja: sprawdza istnienie WSZYSTKICH nowych tabel i kolumn
`scripts/setup_enterprise_tables.php` — oddzielny skrypt dla Dine-In (sh_zones, sh_tables, sh_order_logs).
---
## 18. ISTNIEJĄCE ASSETY W UPLOADS ✅
`uploads/global_assets/` zawiera 16 gotowych plików `.webp`:
| Plik | Kategoria |
|------|-----------|
| `base_dough_ac0cae.webp` | base (ciasto) |
| `sauce_tomato_4a8e30.webp` | sauce (sos pomidorowy) |
| `cheese_mozzarella_b4d22d.webp` | cheese (mozzarella) |
| `meat_salami_cc276c.webp` | meat (salami) |
| `meat_bacon_145ef8.webp` | meat (boczek) |
| `veg_tomato_af2636.webp` | veg (pomidor) |
| `veg_corn_282edf.webp` | veg (kukurydza) |
| `veg_olive_b6b164.webp` | veg (oliwki) |
| `veg_mushroom_29cd69.webp` | veg (pieczarki) |
| `veg_onion_45a36f.webp` | veg (cebula) |
| `veg_pepper_f3c612.webp` | veg (papryka) |
| `veg_cucumber_a8c342.webp` | veg (ogórek) |
| `veg_pea_7fc038.webp` | veg (groszek) |
| `herb_basil_acb969.webp` | herb (bazylia) |
| `herb_spiece_4abc7a.webp` | herb (przyprawy) |
| `board_plate_133aed.webp` | board (deska/talerz) |
Te assety używają już konwencji nazw `{category}_{sub_type}_{6hex}.{ext}` — spójne z naszym systemem.
Brakuje: **hero product photos** (drugie zdjęcie per składnik) — do wykonania przez fotografa.
---
## 19. DOKUMENTACJA — ZAKTUALIZOWANA ✅
| Plik | Co zmienione |
|------|-------------|
| `_docs/02_ARCHITEKTURA.md` | Dodano nowy plik 05_INSTRUKCJA, ustalenia.md; zaktualizowana tabela migracji |
| `_docs/04_BAZA_DANYCH.md` | Dodane migracje 009-016 do tabeli |
| `_docs/05_INSTRUKCJA_FOTO_UPLOAD.md` | **NOWY** — kompletna instrukcja limitów, walidacji i brief fotograficzny |
| `database/README.md` | Pełna lista migracji, setup_enterprise_tables.php, zaktualizowane instrukcje |
---
## 20. SPRZĄTANIE MODUŁU ONLINE — WYKONANE ✅
### Znaleziony bałagan:
W `modules/online/` istniały **3 kompletne wersje** modułu jednocześnie:
| # | Pliki | Wersja | Co to było |
|---|-------|--------|-----------|
| **v2** | `index.html` + `css/builder.css` + `js/pizza_builder.js` | Cinematic Pizza Builder | Ciemny 3D tilt, cząsteczki mąki, step wizard |
| **v3** | `css/composer.css` + `js/board_composer.js` | Immersive Pizza Composer | OSIEROCONY — żaden HTML go nie ładował! |
| **v4** | `ordering.html` + `css/ordering.css` + `js/ordering_engine.js` | Subtle Italian SaaS | Parchment jasny, dual-state, half-pizza |
Razem: **~125 KB śmieci** (v2: 63 KB + v3: 62 KB).
### Co zrobione:
1. v2 → skopiowany do `_archive/online_v2/` i **usunięty** z `modules/online/`
2. v3 → skopiowany do `_archive/online_v3/` i **usunięty** z `modules/online/`
3. Zostało TYLKO v4 (ordering.*) — baza do nowej wersji "Surface"
### Po sprzątaniu `modules/online/` zawiera:
```
modules/online/
├── ordering.html (91 linii — do przepisania na Surface)
├── css/ordering.css (1112 linii — do przepisania na Surface)
└── js/ordering_engine.js (978 linii — rendering przepisany, logika zachowana)
```
### Dodatkowe pliki w repo:
- `core/js/neon_pizza_engine.js` — proceduralny SVG neon generator. Fallback kiedy brak zdjęć .webp. ZACHOWANY (nie jest śmieciem, to narzędzie utility).
---
## 21. API UPLOAD — NAPRAWIONY ✅
`api/backoffice/api_visual_studio.php` — kompletnie przepisany:
### Nowe parametry POST:
| Pole | Opis | Przykład |
|------|------|---------|
| `asset` | Plik (multipart) | (file binary) |
| `asset_type` | Typ assetu | `layer` / `hero` / `thumbnail` / `surface` / `companion` |
| `category` | Kategoria składnika | `meat` / `veg` / `herb` / `sauce` / `cheese` / `base` |
| `sub_type` | Pod-typ | `salami` / `tomato` / `basil` |
### Limity per typ (zgodne z 05_INSTRUKCJA_FOTO_UPLOAD.md):
| Typ | Max rozmiar | Min wymiary | Max wymiary |
|-----|-------------|-------------|-------------|
| `layer` | 3 MB | 1000×1000 | 3000×3000 |
| `hero` | 1.5 MB | 400×400 | 1200×1200 |
| `thumbnail` | 800 KB | 300×300 | 800×800 |
| `surface` | 5 MB | 1920×1080 | 3840×2400 |
| `companion` | 1.5 MB | 400×400 | 1200×1200 |
### Wyjątek format dla surface:
`surface` akceptuje `.jpg` / `.jpeg` (nie wymaga alpha channel). Reszta: tylko `.webp` / `.png`.
### Konwencja nazw (automatyczna):
`{category}_{sub_type}_{sha256_6hex}.{ext}` — np. `meat_salami_cc276c.webp`
Hash z zawartości pliku (SHA-256 → 6 znaków). Unikalne bez kolizji.
### Komunikaty błędów po polsku.
### Walidacja: MIME, rozszerzenie, getimagesize, wymiary min/max, rozmiar per typ.
---
## 22. ONLINE — RESET DO ZERA (2026-04-16) ✅
Stary moduł online (v4 "Surface attempt") został **w całości usunięty** decyzją usera: *"po starym module online nie potrzebujemy nic robimy wszystko od nowa ale trzymajac sie koncepcji"*.
### Usunięte pliki (sprzątanie 2026-04-16):
| Ścieżka | Powód |
|---------|-------|
| `modules/online/ordering.html` | Stary shell v4 — nie pasuje do koncepcji nowego modułu |
| `modules/online/css/ordering.css` | Stary Surface theme z błędną logiką masek |
| `modules/online/js/ordering_engine.js` | Stary engine z mieszaną logiką (rendering + biznes) |
| `api/online/product.php` | Zastąpiony przez `api/online/engine.php` (action-based) |
| `_archive/online_v2/*` (3 pliki) | Martwe archiwum — referencje do usuniętego `product.php` |
| `_archive/online_v3/*` (3 pliki) | Martwe archiwum — komozytor v3 |
**Katalogi `modules/online/` i `_archive/online_v2/`, `_archive/online_v3/` nie istnieją fizycznie po sprzątaniu.**
### Co zostaje (gotowe do nowego frontendu):
- ✅ `api/online/engine.php` — unified backend (akcje: get_storefront_settings, get_menu, get_dish, cart_calculate)
- ✅ `api/cart/CartEngine.php` — silnik koszyka (statyczna `::calculate`)
- ✅ `core/WzEngine.php` — dedukcja magazynu (half-half × 0.5)
- ✅ `core/SequenceEngine.php` — atomic numeracja zamówień
- ✅ `database/migrations/016_visual_compositor_upgrade.sql` — `surfaceBg`, `cal_scale/cal_rotate`, `product_filename`
- ✅ `uploads/global_assets/*.webp` — 16 testowych assetów (base, sauce, cheese, mięsa, warzywa, zioła, board)
- ✅ Wytyczne fotograficzne: `_docs/05_INSTRUKCJA_FOTO_UPLOAD.md`
### Następny krok — budowa nowego `modules/online/` od zera
Zgodnie ze wzorcem POS/Tables/Courses (action-based API + modularny JS):
```
modules/online/
├── index.html # Czysty shell (jak modules/pos/index.html)
├── css/style.css # Surface theme — od zera, mobile-first
└── js/
├── online_api.js # Wrapper na engine.php (jak pos_api.js)
├── online_app.js # State machine + glue
└── online_ui.js # Akordeon kategorii + Surface Card + cart drawer
```
**Zasada:** żadnych narzędzi edycji wizualnej w online — tylko storefront dla klienta. Edycja warstw → Studio (zakładka Visual Compositor).
---
## 23. PRZYSZŁE MODUŁY (ŚWIADOMOŚĆ)
Po stabilizacji online ordering + rozbudowie Studio:
- **Moduł Marketingowy** — sezonowe surface'y, promocje, wyróżnione dania
- **Moduł Lojalnościowy** — badge'e, nagrody, streaki na surface
- **Moduł Statystyk** — heatmapa kliknięć, A/B testy zdjęć, konwersja per składnik
- **E-Menu (QR) i Podgląd** — już widoczny w nawigacji Studio jako "WKRÓTCE"
---
## 24. AKCEPT WIZJI MODUŁU ONLINE + MANAGER EDITOR (2026-04-16)
**Dokument wizji:** `_docs/06_WIZJA_MODULU_ONLINE.md` — kompletny, 13 sekcji.
### Zatwierdzone decyzje (user approved):
1. **Dwa moduły zamiast jednego:**
- `modules/online/` — STOREFRONT (klient, public)
- `modules/online_studio/` — MANAGER EDITOR (JWT auth, 5 zakładek)
- Link do composera dodamy *później* z głównego Studio
2. **Migracja 017** — wszystkie 5 zmian:
- `sh_visual_layers.version` (optimistic locking)
- `sh_visual_layers.library_category` + `library_sub_type`
- `sh_checkout_locks` (idempotency tokens, TTL 5min)
- `sh_orders.tracking_token` (guest tracker)
- 5× default `sh_tenant_settings` dla online module
3. **Tenant resolution (storefront):** fallback chain
- 1) subdomain (`mojapizza.slicehub.pl`)
- 2) URL param (`?tenant=1`)
- 3) `` w HTML shell
- Najbardziej elastyczne + production-ready
4. **Apple Pay / Google Pay:** P1 (po MVP — gotówka + przelew wystarczy na start)
### Status implementacji (2026-04-17):
| Komponent | Status |
|-----------|--------|
| `_docs/06_WIZJA_MODULU_ONLINE.md` | ✅ GOTOWE |
| `database/migrations/017_online_module_extensions.sql` | ✅ GOTOWE (idempotentne) |
| `scripts/setup_database.php` — sekcja 017 | ✅ GOTOWE |
| `api/online/engine.php` — akcje podstawowe (4) | ✅ GOTOWE |
| `api/online/engine.php` — akcje rozszerzone (4 nowe) | ✅ GOTOWE |
| `api/online_studio/engine.php` — 12 akcji (JWT/session + role owner/admin/manager) | ✅ GOTOWE — Etap 2 |
| `api/online_studio/*_upload.php` (multipart) | ⏳ Etap 2b (opcjonalnie — jest `api/visual_composer/asset_upload.php`) |
| `modules/online/` — frontend storefront (v1: menu + karta + koszyk) | ✅ szkielet działa |
| `modules/online_studio/` — frontend manager | ⏳ Etap 5-7 |
### Akcje w `api/online/engine.php` (ostateczna lista 8):
1. `get_storefront_settings` — tenant, surfaceBg, halfHalfSurcharge, online flags
2. `get_menu` — kategorie + dania z cenami (akordeon)
3. `get_dish` — item, mods, companions, visual layers, global assets
4. `cart_calculate` — server-authoritative (CartEngine::calculate static)
5. `get_popular` — top SKU ostatnie 30 dni (fallback: display_order)
6. `delivery_zones` — ST_Contains geofencing + ETA + min_order
7. `init_checkout` — lock_token UUID TTL 5min, idempotent po cart_hash
8. `track_order` — status stages + driver GPS (token + phone match security)
### Akcje w `api/online_studio/engine.php` (12 — wymaga `Authorization: Bearer` lub sesji + rola owner/admin/manager):
1. `library_list` — `sh_global_assets` + licznik przypisań (distinct `item_sku` w `sh_visual_layers`)
2. `library_update` — edycja metadanych assetu (nie `tenant_id=0` globalnych)
3. `library_delete` — soft `is_active=0` (opcjonalnie `force` jeśli są przypisania)
4. `composer_load_dish` — item, warstwy, companions, podgląd biblioteki (500), `surfaceBg`, flagi schematu
5. `composer_save_layers` — upsert warstw; `replaceAll` = pełny replace; merge z optimistic lock (`version`)
6. `composer_calibrate` — pojedyncza warstwa `cal_scale` / `cal_rotate`
7. `composer_clone` — kopiuj stos `sourceSku` → `targetSku`
8. `composer_autofit_suggest` — średnia kalibracja dla `sub_type` z biblioteki na danym daniu
9. `companions_list` — lista cross-sell dla `itemSku`
10. `companions_save` — `DELETE` + `INSERT` companions (walidacja SKU w menu)
11. `surface_apply` — `storefront_surface_bg` = bezpieczna nazwa pliku w `global_assets`
12. `preview_url` — URL iframe pod `modules/online/index.html` (gdy shell będzie gotowy)
### Ostatnie kroki:
- Smoke test Studio API: zaloguj się do aplikacji (JWT), `POST` JSON na `/slicehub/api/online_studio/engine.php`
- Następnie: frontend `modules/online_studio/` + ewentualnie dedykowane `*_upload.php` pod ten moduł
---