# Changelog shopPRO

Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.

---

## ver. 0.309 (2026-02-23) - ApiloLogger + cache-busting CSS/JS + poprawki UI

- **NEW**: `ApiloLogger` — logowanie operacji Apilo do tabeli `pp_log` z kontekstem JSON (send_order, resend_order, payment_sync, status_sync, status_poll)
- **NEW**: Migracja `pp_log` — kolumny `action`, `order_id`, `context` + indeksy
- **NEW**: Cache-busting dla CSS i JS w admin panelu — `?ver=filemtime()` przy wszystkich lokalnych zasobach w `main-layout.php`
- **FIX**: Przeniesienie inicjalizacji `$mdb` przed `SettingsRepository` w `admin/index.php`
- **FIX**: Rzutowanie na `(string)` w `ShopProductController::escapeHtml()` — zapobiega warningom
- **ZMIANA**: Skrocone kategorie produktow na liscie — `text-overflow: ellipsis` z `title` tooltip
- **ZMIANA**: `copyToClipboard()` — uzywa `navigator.clipboard` API z fallbackiem na `<textarea>`
- **ZMIANA**: Uproszczenie CSS `.site-content` — usuniety zbedny `.with-menu`, menu widoczne zawsze na desktop

---

## ver. 0.308 (2026-02-22) - Kolory statusow zamowien + poprawki bezpieczenstwa

- **NEW**: Kolorowe badge statusow na liscie zamowien w admin panelu — kolory pobierane z `pp_shop_statuses.color`, kontrast tekstu obliczany automatycznie
- **FIX**: Walidacja formatu hex koloru z bazy (`/^#[0-9a-fA-F]{3,6}$/`) — odrzucanie nieprawidlowych wartosci
- **FIX**: Sanityzacja HTML w kolumnie "Dostawa" — `strip_tags()` + regex usuwajacy atrybuty z dozwolonych tagow (zapobieganie XSS via `onclick` itp.)
- **OPTYMALIZACJA**: Polaczenie dwoch zapytan SQL do `pp_shop_statuses` (nazwy + kolory) w jedno `orderStatusData()`
- **ZMIANA**: Path-based form submit w `table-list.php` — formularze filtrow i per-page uzywaja JS interceptora z `data-path-submit` zamiast natywnego GET, kompatybilne z admin URL routing
- **NEW**: 11 nowych testow jednostkowych (750 total, 2114 assertions)

---

## ver. 0.307 (2026-02-22) - Przycisk sprawdzania aktualizacji + auto-changelog

- **NEW**: Przycisk "Sprawdz aktualizacje" w panelu admina — ikona odswiezenia obok numeru wersji, klik odpytuje serwer AJAX-em i pokazuje/ukrywa badge "aktualizacja" bez przeladowania strony
- **NEW**: `UpdateController::checkUpdate()` — nowa akcja AJAX czyszczaca sesje `new-version` i sprawdzajaca wersje z serwera
- **NEW**: `updates/changelog.php` — auto-generowany z manifestow JSON (`_manifest.json`) + `changelog-legacy.json`, zamiast recznej edycji HTML
- **NEW**: `updates/changelog-legacy.json` — migracja 295 wpisow changelogu (wersje 0.300-0.001) do formatu JSON
- **ZMIANA**: Workflow KONIEC PRACY — usuniety krok recznej edycji `changelog.php` (teraz automatyczny)

---

## ver. 0.306 (2026-02-22) - Ukrywanie form dostawy bez dostepnych platnosci

- **FIX**: Formy dostawy, dla ktorych nie ma zadnej dostepnej formy platnosci (np. wszystkie odfiltrowane przez `min_order_amount`/`max_order_amount`), sa teraz ukrywane z listy w koszyku
- **ZMIANA**: `TransportRepository::transportMethodsFront()` — po filtrze wagowym i korekcie darmowej dostawy, dodano filtr sprawdzajacy dostepnosc form platnosci per transport (z wykorzystaniem `PaymentMethodRepository::paymentMethodsByTransport()` z cache Redis)
- **NEW**: 5 nowych testow jednostkowych (739 total, 2089 assertions)

---

## ver. 0.305 (2026-02-22) - Sortowanie permutacji + pasek darmowej dostawy

- **FIX**: Naprawa kolejnosci atrybutow permutacji — sortowanie po ID atrybutu (`usort` wg pierwszego segmentu przed `-`) we wszystkich miejscach: koszyk, kombinacje AJAX, `getPermutation()`, `BasketCalculator`. Zapewnia zgodnosc z `permutation_hash` generowanym przez `ksort`.
- **NEW**: Pasek postepu darmowej dostawy w koszyku — progress bar z ikona, tekstem i animacja. Pokazuje ile brakuje do progu `free_delivery` z ustawien sklepu.
- **FIX**: icheck CSS/JS przeniesione z szablonu `product-combination` do globalnego layoutu admina (`main-layout.php`)
- **FIX**: `Tpl::__isset()` — obsluga `isset()` na zmiennych szablonu
- **.updateignore** — lokalne style frontendowe dodane do listy ignorowania

---

## ver. 0.304 (2026-02-22) - Konfigurowalne limity kwotowe metod platnosci

- **NEW**: Kolumny `min_order_amount` i `max_order_amount` w `pp_shop_payment_methods` — konfigurowalne limity kwotowe per metoda platnosci
- **NEW**: Pola min/max kwoty zamowienia w formularzu edycji metody platnosci (admin)
- **FIX**: Zastapiono hardcoded warunek PayPo (id=6, 40-1000 PLN) generycznym filtrowaniem na froncie (basket checkout)
- **NEW**: Cache invalidation po zapisie metody platnosci
- **NEW**: 4 nowe testy jednostkowe (734 total, 2080 assertions)
- **MIGRATION**: `migrations/0.304.sql` — ALTER TABLE pp_shop_payment_methods ADD min/max_order_amount

---

## ver. 0.303 (2026-02-22) - Fix: wyswietlanie atrybutow produktu na froncie + podglad produktu w adminie

- **FIX**: Naprawiono wyswietlanie atrybutow produktu na froncie — gdy dwa atrybuty mialy te sama wartosc kolejnosci (`o`), jeden nadpisywal drugi (kolizja kluczy tablicy). Teraz atrybuty sortowane przez `usort()` z unikalnymi kluczami sekwencyjnymi.
- **NEW**: Przycisk "Podglad" w formularzu edycji produktu — otwiera strone produktu w nowej karcie
- **NEW**: `FormAction::preview()` — nowy typ akcji formularza z `target="_blank"`

---

## ver. 0.302 (2026-02-22) - REST API: warianty produktow, atrybuty, filtrowanie

- **NEW**: API wariantow produktow — CRUD: `variants`, `create_variant`, `update_variant`, `delete_variant`
- **NEW**: API slownik atrybutow — `dictionaries/attributes` z wielojezycznymi nazwami i wartosciami
- **NEW**: Filtrowanie produktow po atrybutach w `products/list` — parametry `attribute_{id}={value_id}`
- **NEW**: Wzbogacone atrybuty w `products/get` — nazwy atrybutow i wartosci z tlumaczeniami
- **NEW**: Warianty w odpowiedzi `products/get` — lista wariantow z atrybutami dla produktow nadrzednych
- **NEW**: Walidacja `price_brutto` przy tworzeniu produktu (musi byc nieujemna liczba)
- **NEW**: Batch-loading atrybutow i wartosci (4 zapytania zamiast N+1) w `AttributeRepository::listForApi()`
- **NEW**: 43 nowe testy jednostkowe (730 total, 2066 assertions)

---

## ver. 0.301 (2026-02-22) - Mobile responsive: filtry tabel i szczegoly zamowienia

- **NEW**: Filtry w tabelach admina domyslnie ukryte — przycisk toggle z ikona filtra, badge z liczba aktywnych filtrow
- **NEW**: Stan filtrow zapamietywany w `localStorage` per widok; auto-show gdy filtry aktywne
- **NEW**: Mobilna wersja szczegolow zamowienia — responsywny layout (CSS-only, breakpoint 767px)
- **NEW**: Pasek akcji zamowienia — ikony-only na mobile, flex row bez zawijania
- **NEW**: Tabela produktow zamowienia — kompaktowa lista na mobile (obraz + nazwa + linia `qty x cena = suma`)
- **NEW**: Sekcje informacyjne zamowienia — full-width stacking na mobile
- **NEW**: Dropdown integracji jako bottom-sheet na mobile

---

## ver. 0.300 (2026-02-21) - System aktualizacji oparty na manifestach JSON

- **NEW**: Manifest JSON per wersja — zastępuje osobne pliki `_sql.txt` i `_files.txt`
- **NEW**: Weryfikacja checksum SHA256 pobranych paczek ZIP
- **NEW**: Automatyczny backup plików przed nadpisaniem (`backups/` directory)
- **NEW**: `build-update.ps1` — automatyczne budowanie paczek z `git diff` między tagami
- **NEW**: `.updateignore` — wzorce plików wykluczonych z paczek aktualizacji
- **NEW**: `migrations/` — folder na wersjonowane pliki SQL
- **NEW**: Panel "Log ostatniej aktualizacji" w widoku aktualizacji admina
- **UPDATE**: `UpdateRepository` — dual-mode dispatcher (manifest + legacy fallback)

---

## ver. 0.299 (2026-02-21) - Widoczność kolumn w tabelach

- **NEW**: Toggle widoczności kolumn w komponentach `table-list` — przycisk z ikoną kolumn, dropdown z toggle switchami
- **NEW**: Stan widoczności kolumn zapisywany w `localStorage` per tabela (klucz na bazie `basePath`)
- **NEW**: Przycisk "Pokaż wszystkie" resetujący widoczność
- **UPDATE**: Style z `table-list.php` wyekstrahowane do osobnego pliku `admin/layout/style-css/table-list.css`
- **UPDATE**: `admin/templates/site/main-layout.php` — podłączenie `table-list.css`

---

## ver. 0.297 (2026-02-19) - REST API produktów

- **NEW**: Endpoint `products` w REST API — lista, szczegóły, tworzenie, aktualizacja produktów
- **NEW**: `\api\Controllers\ProductsApiController` — 4 akcje (list, get, create, update)
- **NEW**: `ProductRepository::listForApi()` — lista produktów z filtrowaniem (search/status/promoted), sortowaniem i paginacją
- **NEW**: `ProductRepository::findForApi()` — szczegóły produktu z językami, zdjęciami, kategoriami i atrybutami
- **NEW**: Partial update — `update` merguje przesłane pola z istniejącymi danymi produktu
- **NEW**: Mapowanie API → format formularza (`mapApiToFormData`) — status/promoted jako checkboxy, languages jako mapy
- **UPDATE**: `ApiRouter` — rejestracja endpointu `products`
- **UPDATE**: `docs/API.md` — dokumentacja 4 akcji produktowych z przykładami
- **Tests**: 21 nowych testów (`ProductsApiControllerTest`)

---

## ver. 0.296 (2026-02-19) - REST API zamówień dla ordersPRO

- **NEW**: REST API do zarządzania zamówieniami — lista, szczegóły, zmiana statusu, oznaczanie płatności
- **NEW**: Endpointy słownikowe — statusy zamówień, metody transportu, metody płatności
- **NEW**: Autentykacja API przez header `X-Api-Key` (klucz w `pp_settings`)
- **NEW**: `\api\ApiRouter` — router API z autentykacją, routingiem i helperami odpowiedzi
- **NEW**: `\api\Controllers\OrdersApiController` — 5 akcji (list, get, change_status, set_paid, set_unpaid)
- **NEW**: `\api\Controllers\DictionariesApiController` — 3 akcje (statuses, transports, payment_methods)
- **NEW**: `OrderRepository::listForApi()` — lista zamówień z filtrowaniem i paginacją (z `updated_since` do pollingu)
- **NEW**: `OrderRepository::findForApi()` — szczegóły zamówienia z produktami i historią statusów
- **NEW**: `OrderRepository::touchUpdatedAt()` — aktualizacja `updated_at` przy modyfikacji zamówienia
- **NEW**: Kolumna `pp_shop_orders.updated_at` — data ostatniej modyfikacji (polling API)
- **NEW**: Setting `api_key` w `pp_settings` — klucz autentykacji API
- **UPDATE**: `api.php` — skip sesji dla requestów API, routing do `ApiRouter`
- **UPDATE**: Metody `updateOrderStatus`, `setAsPaid`, `setAsUnpaid`, `saveOrderByAdmin`, `saveNotes`, `createFromBasket` wywołują `touchUpdatedAt()`
- **NEW**: `docs/API.md` — dokumentacja REST API
- **Tests**: 30 nowych testów API (ApiRouter, OrdersApiController, DictionariesApiController)

---

## ver. 0.295 (2026-02-19) - Admin: edycja produktów w zamówieniu + wyszukiwanie AJAX + korekta stanów magazynowych

- **NEW**: Edycja produktów w zamówieniu z panelu admina (dodawanie, usuwanie, zmiana ilości/cen)
- **NEW**: Wyszukiwarka produktów AJAX w formularzu edycji zamówienia (`search_products_ajax`)
- **NEW**: Automatyczna korekta stanów magazynowych przy edycji produktów zamówienia
- **NEW**: Automatyczne przeliczanie kosztu dostawy (próg darmowej dostawy) po zmianie produktów
- **NEW**: `OrderRepository` — CRUD: `addOrderProduct()`, `updateOrderProduct()`, `deleteOrderProduct()`, `getOrderProduct()`, `updateTransportCost()`
- **NEW**: `OrderAdminService` — `searchProducts()`, `saveOrderProducts()`, `getFreeDeliveryThreshold()`, `adjustStock()`, `recalculateTransportCost()`
- **NEW**: `ShopOrderController` — endpoint `search_products_ajax`, rozszerzony `order_save` o zapis produktów
- **UPDATE**: `admin\App` — rozszerzone DI wiring (ProductRepository, SettingsRepository, TransportRepository)
- **FIX**: `OrderRepository::createOrder()` — promo price = 0 gdy taka sama jak cena bazowa (brak realnej promocji)
- **NEW**: Template `order-edit-custom-script.php` — interaktywny JS do zarządzania produktami zamówienia
- **UPDATE**: Template `order-edit.php` — sekcja edycji produktów z dynamicznym formularzem
- **Tests**: `OrderAdminServiceTest` (nowy), rozszerzony `OrderRepositoryTest` (+132 linii), zaktualizowany `ShopOrderControllerTest`

---

## ver. 0.294 (2026-02-19) - Code review: full codebase review complete (96/96 classes), 27 fixes across all layers

**Code review zakończony — 96 klas, ~1144 metody przejrzane.**

- **Domain layer (16 fixes):**
  - FIX: `CategoryRepository` — usunięto martwy kod `updateCategoryDefaultLayoutId()`, `allCategoriesForCacheRefresh()`
  - FIX: `ClientRepository` — null guard na `query()->fetchAll()`
  - FIX: `DictionariesRepository` — null guard na `query()->fetchAll()` (2 metody)
  - FIX: `IntegrationsRepository` — null guard na `query()->fetchAll()` (3 metody)
  - FIX: `LanguagesRepository` — null guard na `query()->fetchAll()` (2 metody)
  - FIX: `LayoutsRepository` — null guard na `query()->fetchAll()` (4 metody)
  - FIX: `OrderAdminService` — null safety `find()` + redundancja DI
  - FIX: `OrderRepository` — null guard na `query()->fetchAll()`
  - FIX: `ProductRepository` — null guard na `query()->fetchAll()` (8 metod), redundancja DI
  - FIX: `PromotionRepository` — redundancja `new ProductRepository` w pętlach (3 metody)
- **Admin layer (11 fixes):**
  - FIX: `admin\App` — null guard po `details()` w logowaniu i 2FA
  - FIX: `BannerController`, `ScontainersController`, `ShopProducerController` — null guard `find() ?: []` + `save()` null guard
  - FIX: `PagesController` — null guard `menuDetails() ?: []`, `pageDetails() ?: []`
  - FIX: `ProductArchiveController` — `$this->repository` → `$this->productRepository`
  - FIX: `ShopAttributeController` — null guard `findAttribute() ?: []`
  - FIX: `ShopCouponController` — null guard `find() ?: []`
  - FIX: `ShopProductSetsController`, `ShopPromotionController` — null guard `find() ?: []`
  - FIX: `ShopProductController` — null safety `findForAdmin() ?: []` + 3x redundancja DI
- **Front layer (3 fixes):**
  - FIX: `LayoutEngine` — undefined `$level` → `null`; `$_GET['permutation_hash']` → `?? null`
  - FIX: `ShopBasketController` — brakujące `global $lang_id` w `basketAddProduct()`
- **Shared layer (2 fixes):**
  - FIX: `Helpers::generate_webp_image()` — `$_GET['c_w']`/`$_GET['c_h']` → `?? null`
  - FIX: `Helpers::generate_webp_image()` — **bug**: `'png'` → `'image/png'` (Imagick lossless WebP nigdy się nie aktywował)
- **CLASS_CATALOG.md** — kompletny katalog z ✅/🔧 przy wszystkich 1144 metodach
- Testy: 614 OK, 1821 asercji

---

## ver. 0.293 (2026-02-19) - Code review: fixes ArticleRepository, AttributeRepository, BannerRepository, BasketCalculator, CategoryRepository, PromotionRepository

- **ArticleRepository** (7 fixes):
  - FIX: `articlesByDateAdd()` — SQL injection (addslashes→parameterized queries), dodano parametr `$langId`
  - FIX: `articleDetailsFrontend()` — uproszczono select()+foreach→get()
  - FIX: `articlesIds()`, `pageArticlesCount()` — parametryzacja `$langId`
  - FIX: `topArticles()`, `newsListArticles()` — DRY refactor via `fetchArticlesByPage()`, parametryzacja
- **AttributeRepository** (1 fix):
  - FIX: `clearTempAndCache()` — martwy `class_exists('\S')` blokował czyszczenie cache/temp
- **CategoryRepository** (2 fixes):
  - FIX: `refreshCategoryArtifacts()` — martwy `class_exists('\S')` blokował czyszczenie htaccess/temp
  - FIX: `normalizeSeoLink()` — **krytyczny bug** — linki SEO kategorii nigdy nie były generowane od usunięcia `\S`
- **BannerRepository** (2 fixes):
  - FIX: `banners()`, `mainBanner()` — parametryzacja `$today` w SQL + null guard na `query()`
- **BasketCalculator** (3 fixes):
  - FIX: `checkProductQuantityInStock()` — dodano `is_array()` guard (foreach na null→fatal)
  - FIX: `summaryPrice()` — dodano opcjonalne DI params `$langId`, `$productRepo` z fallbackiem do globals
  - FIX: `calculateBasketProductPrice()` — dodano opcjonalny `$productRepo` z fallbackiem do globals
- **PromotionRepository** (1 fix):
  - FIX: `findPromotion()` — null guard na `$basket` (produkcyjny fatal error)
- **OrderRepository** — zaktualizowano callery BasketCalculator (jawne DI zamiast globals), usunięto redundantne tworzenie ProductRepository w pętli
- **ShopBasketController**, **ajax.php** — zaktualizowano callery summaryPrice (jawne `$lang_id`)
- **CLASS_CATALOG.md** — zaktualizowano katalog dla 5 klas (rzeczywiste metody + znaczniki przeglądu)
- Testy: 614 OK, 1821 asercji (+4 nowe testy BasketCalculator)

---

## ver. 0.292 (2026-02-18) - Usuniecie autoload/shop/ — 12 legacy klas

- **Faza 5.1: class.Order.php (~562 linii) USUNIETA**
  - Logika Apilo sync przeniesiona do `OrderAdminService::processApiloSyncQueue()`
  - Email zmiany statusu zintegrowany w `OrderAdminService::changeStatus()`
  - `cron.php` przepiety na `OrderAdminService`
  - `front\Controllers\ShopOrderController` — dodano `OrderAdminService` jako drugie DI
  - `\shop\Order::order_statuses()` → `OrderRepository::orderStatuses()` (3 lokalizacje)
- **Faza 5.2: class.Product.php (~952 linii) USUNIETA — NAJWIEKSZA KLASA**
  - ~20 metod przeniesionych do `ProductRepository`: `findCached()`, `isProductOnPromotion()`, `productSetsWhenAddToBasket()`, `addVisit()`, `getProductImg()`, `getProductUrl()`, `searchProductsByName()`, `searchProductByNameAjax()`, `searchProductsByNameCount()`, `isStock0Buy()`, `getProductPermutationQuantityOptions()`, `getProductIdByAttributes()`, `getProductPermutationHash()`, `getProductAttributes()`, `generateSkuCode()`, `productMeta()`, `generateSubtitleFromAttributes()`, `getDefaultCombinationPrices()`, `getProductDataBySelectedAttributes()`, `productCategories()`, `arrayCartesian()`
  - `calculate_basket_product_price()` przeniesione do `BasketCalculator::calculateBasketProductPrice()`
  - `BasketCalculator` przepisany: `summaryPrice()`, `checkProductQuantityInStock()` uzywaja `ProductRepository`
  - XML generation (4 metody) — konwersja object→array access
  - ~60+ callsite'ow zamienionych w kontrolerach, szablonach, repozytoriach i entry-pointach
  - Cache key strings zaktualizowane z `\shop\Product::` na `ProductRepository::`
- **Cleanup:**
  - Usunieto dead `\shop\` routing z `front\App::route()`
  - Cache key `\shop\Promotion::get_active_promotions` → `PromotionRepository::getActivePromotions`
  - Katalog `autoload/shop/` jest teraz pusty
- **Production hotfixes:**
  - FIX: `findCached()` — stale Redis cache z obiektami `\shop\Product` powodowal ceny 0,00 zl (obiekty `__PHP_Incomplete_Class` po `(array)` cast maja zmanglowane klucze). Teraz invaliduje stary cache i re-fetchuje z DB
  - FIX: `LayoutEngine.php` — 4 niekwalifikowane `Product::getFromCache()` resolwaly do `\front\Product` po usunieciu `use shop\Product`
  - FIX: szablony (product-mini, product-search, product, product-warehouse-message, alert-product-sets, basket-details, main-view, promoted-products) — konwersja object access (`$product->field`) na array access (`$product['field']`)
  - UPDATE: `AttributeRepository::getAttributeValueById()` — dodano Redis cache (zgodnosc ze starym `\shop\ProductAttribute::get_value_name()`)
- **PODSUMOWANIE CALEJ MIGRACJI:** 12 legacy klas, ~2363 linii kodu usunieto. Zero referencji `\shop\` w aktywnym kodzie.
- Testy: 610 OK, 1817 asercji

---

## ver. 0.293 (2026-02-17) - front\controls\Site + front\view\Site → front\App + front\LayoutEngine

- **front\controls\Site → front\App** — migracja routera na nowy namespace
  - Port 1:1 z camelCase: `check_url_params()` → `checkUrlParams()`, `page_title()` → `pageTitle()`
  - Wewnętrzna zmiana: `\front\view\Site::contact()` → `\front\LayoutEngine::contact()`
  - USUNIETA: `autoload/front/controls/class.Site.php`
- **front\view\Site → front\LayoutEngine** — migracja layout engine na nowy namespace
  - Port 1:1 z camelCase: `cookie_information()` → `cookieInformation()`
  - Wewnętrzne zmiany: `\front\controls\Site::route()` → `\front\App::route()`, self-referencje na `self::`
  - 13 stałych regex i ~30 tag replacements przeniesione 1:1
  - USUNIETA: `autoload/front/view/class.Site.php`
- **Call sites** — 4 miejsca przepięte:
  - `index.php:62` — `\front\App::checkUrlParams()`
  - `index.php:157` — `\front\LayoutEngine::show()`
  - `index.php:160` — `\front\LayoutEngine::cookieInformation()`
  - `ajax.php:51` — `\front\App::checkUrlParams()`
- USUNIETE puste foldery: `autoload/front/controls/`, `autoload/front/view/`
- **Pelna migracja frontendu zakonczona** — `autoload/front/` zawiera: `App.php`, `LayoutEngine.php`, `Controllers/`, `Views/`
- Testy: 610 OK, 1816 asercji (bez zmian — czysty rename/restructure)

---

## ver. 0.292 (2026-02-17) - ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend migration

- **Pelna migracja front\factory\** — USUNIETY caly folder `autoload/front/factory/` (wszystkie 20 klas zmigrowane do Domain)
- **ShopProduct (frontend Stage 1)** — migracja factory + controls na Domain
  - NOWE METODY w `ProductRepository`: ~20 metod frontendowych (getSkuWithFallback, getEanWithFallback, isProductActiveCached, productCategoriesFront, getWarehouseMessageZero/Nonzero, topProductIds, newProductIds, promotedProductIdsCached, getMinimalPrice, productImageCached, productNameCached, productUrlCached, randomProductIds, productWp)
  - USUNIETA: `front\factory\class.ShopProduct.php` (~410 linii) — logika przeniesiona do `ProductRepository`
  - USUNIETA: `front\controls\class.ShopProduct.php` — logika w `ProductRepository` + szablony
  - UPDATE: callerzy w szablonach, kontrolerach, index.php, cron.php przepieci na repo
- **ShopPaymentMethod (frontend)** — migracja factory + view + shop facade na Domain
  - NOWE METODY w `PaymentMethodRepository`: metody frontendowe z Redis cache (paymentMethodsCached, paymentMethodCached, paymentMethodsByTransportCached)
  - USUNIETA: `front\factory\class.ShopPaymentMethod.php`, `front\view\class.ShopPaymentMethod.php`, `shop\class.PaymentMethod.php`
  - UPDATE: callerzy w szablonach i kontrolerach przepieci na `PaymentMethodRepository`
- **ShopPromotion (frontend)** — migracja factory na Domain
  - NOWE METODY w `PromotionRepository`: 5 metod aplikowania promocji (applyTypeWholeBasket, applyTypeCheapestProduct, applyTypeCategoriesOr, applyTypeCategoriesAnd, applyTypeCategoryCondition)
  - USUNIETA: `front\factory\class.ShopPromotion.php` — logika przeniesiona do `PromotionRepository`
  - UPDATE: `shop\Promotion::find_promotion()` — 5 wywolan przepietych na repo
- **ShopStatuses (frontend)** — rewiring callerow
  - USUNIETA: `front\factory\class.ShopStatuses.php` — 4 callerzy przepieci bezposrednio na `ShopStatusRepository`
- **ShopTransport (frontend)** — migracja factory + view na Domain
  - NOWE METODY w `TransportRepository`: 4 metody frontendowe (transportMethodsFront, transportCostCached, findActiveByIdCached, forPaymentMethod)
  - USUNIETA: `front\factory\class.ShopTransport.php`, `front\view\class.ShopTransport.php`
  - UPDATE: 8 callerow przepietych na `TransportRepository`
  - FIX: broken `transports_list()` w ajax.php — nowa metoda `forPaymentMethod()`
- NOWY: `tests/stubs/ShopProduct.php` — stub `shop\Product` dla testow
- Testy: 610 OK, 1816 asercji (+37: 20 ProductRepository, 5 PaymentMethodRepository, 7 PromotionRepository, 5 TransportRepository)

---

## ver. 0.291 (2026-02-17) - ShopProducer frontend migration

- **ShopProducer (frontend)** — migracja controls + shop facade na Domain + Controllers
  - NOWA METODA w `ProducerRepository`: `allActiveProducers()` — pełne dane aktywnych producentów (id, name, img)
  - NOWY: `front\Controllers\ShopProducerController` — instancyjny kontroler z DI (`products()`, `list()`)
  - USUNIETA: `front\controls\class.ShopProducer.php` — logika przeniesiona do kontrolera + repozytorium
  - USUNIETA: `autoload\shop\class.Producer.php` — fasada niepotrzebna, callery przepięte na repo
  - UPDATE: `front\view\Site::show()` — `new \shop\Producer(...)` zamienione na `$producerRepo->findForFrontend()`
  - UPDATE: `front\controls\Site::getControllerFactories()` — zarejestrowany `'ShopProducer'`
  - FIX: bug `shop\Producer::__get()` referował nieistniejące `$this->data` (usunięty z kodem klasy)
- Testy: 573 OK, 1738 asercji (+8: 5 ProducerRepository frontend, 3 ShopProducerController)

---

## ver. 0.290 (2026-02-17) - ShopCoupon + ShopOrder frontend migration

- **ShopCoupon (frontend)** — migracja controls + factory na Domain + Controllers
  - NOWE METODY w `CouponRepository`: 4 metody frontendowe (findByName, isAvailable, markAsUsed, incrementUsedCount)
  - NOWY: `front\Controllers\ShopCouponController` — instancyjny kontroler z DI (useCoupon, deleteCoupon)
  - KONWERSJA: `shop\Coupon` na fasade z dzialajacymi metodami (is_one_time, set_as_used)
  - FIX: kupony jednorazowe nigdy nie byly oznaczane jako uzyte (is_one_time zwracalo null)
  - USUNIETA: `front\controls\class.ShopCoupon.php`, `front\factory\class.ShopCoupon.php`
- **ShopOrder (frontend)** — migracja controls + factory + view na Domain + Controllers
  - NOWE METODY w `OrderRepository`: 5 metod frontendowych (findIdByHash, findHashById, orderDetailsFrontend, generateOrderNumber, createFromBasket ~180 linii)
  - NOWY: `front\Controllers\ShopOrderController` — instancyjny kontroler z DI (paymentConfirmation, paymentStatusTpay, paymentStatusPrzelewy24pl, paymentStatusHotpay, orderDetails)
  - POPRAWA: webhooks przelewy24/hotpay — zamiana recznych $mdb->update/insert na \shop\Order::set_as_paid() + update_status() (spójnosc z tpay, poprawna obsluga Apilo sync)
  - UPDATE: `ShopBasketController` — DI OrderRepository (createFromBasket, findHashById)
  - UPDATE: `ClientRepository::clientOrders()` — OrderRepository::orderDetailsFrontend()
  - UPDATE: `shop\Order::order_resend_confirmation_email()` — OrderRepository::orderDetailsFrontend()
  - UPDATE: `cron-turstmate.php` — OrderRepository::orderDetailsFrontend()
  - USUNIETA: `front\controls\class.ShopOrder.php`, `front\factory\class.ShopOrder.php`, `front\view\class.ShopOrder.php`
- Testy: 565 OK, 1716 asercji (+28: 12 CouponRepository frontend, 3 ShopCouponController, 10 OrderRepository frontend, 3 ShopOrderController)

---

## ver. 0.289 (2026-02-17) - ShopCategory + ShopClient frontend migration

- **ShopCategory (frontend)** — migracja factory + view na Domain + Views
  - NOWE METODY w `CategoryRepository`: 9 metod frontendowych + 3 stale (SORT_ORDER_SQL, PRODUCTS_PER_PAGE, LANGUAGE_FALLBACK_NAME_SQL)
  - NOWY: `front\Views\ShopCategory` — czysty VIEW (categoryDescription, categoryView, categories)
  - USUNIETA: `front\factory\class.ShopCategory.php` — logika przeniesiona do `CategoryRepository`
  - USUNIETA: `front\view\class.ShopCategory.php` — zastapiona przez `front\Views\ShopCategory`
  - UPDATE: `index.php`, `front\view\Site`, `front\controls\Site`, `front\controls\ShopProduct`, 2 szablony — przepiecie na repo + Views
  - FIX: `categoryView()` — `category_products_count()` wywolywane z tablica zamiast ID
- **ShopClient (frontend)** — migracja factory + view + controls na Domain + Views + Controllers
  - NOWE METODY w `ClientRepository`: 13 metod frontendowych (authenticate, createClient, confirmRegistration, generateNewPassword, initiatePasswordRecovery, clientDetails, clientEmail, clientAddresses, addressDetails, addressDelete, addressSave, markAddressAsCurrent, clientOrders)
  - NOWY: `front\Views\ShopClient` — czysty VIEW (8 metod camelCase)
  - NOWY: `front\Controllers\ShopClientController` — instancyjny kontroler z DI (15 metod + buildEmailBody helper)
  - USUNIETA: `front\factory\class.ShopClient.php`, `front\view\class.ShopClient.php`, `front\controls\class.ShopClient.php`
  - UPDATE: 7 callerow + rejestracja w getControllerFactories()
  - SECURITY FIX: usuniety hardcoded password bypass 'Legia1916'
  - OPTYMALIZACJA: buildEmailBody() deduplikuje 4x powtorzony wzorzec emaili
  - OPTYMALIZACJA: addressSave() przyjmuje array $data zamiast 6 parametrow
- Testy: 537 OK, 1648 asercji (+53: 17 CategoryRepository frontend, 36 ClientRepository frontend)

---

## ver. 0.288 (2026-02-17) - BasketCalculator + ShopBasketController + cms\Layout removal

- **ShopBasket (factory → Domain)** — migracja na Domain
  - NOWY: `Domain\Basket\BasketCalculator` — 4 statyczne metody (`summaryWp`, `countProductsText`, `summaryPrice`, `countProducts`)
  - USUNIETA: `front\factory\class.ShopBasket.php` — logika przeniesiona do `BasketCalculator`
  - UPDATE: 18 callerow w 7 plikach przepietych na `\Domain\Basket\BasketCalculator::`
- **ShopBasket (controls → Controllers)** — migracja kontrolera
  - NOWY: `front\Controllers\ShopBasketController` — instancyjny kontroler z camelCase metodami
  - Wyekstrahowano `jsonBasketResponse()` — wspolna odpowiedz JSON dla 4 metod koszyka
  - Zainicjalizowano zmienne `$values`, `$attributes`, `$custom_fields` w `basketAddProduct()`
  - USUNIETA: `front\controls\class.ShopBasket.php` — zastapiona przez `ShopBasketController`
  - UPDATE: `front\controls\Site::route()` — konwersja `snake_case → camelCase` w dispatch dla nowych kontrolerow
  - UPDATE: `front\controls\Site::title()` / `page_title()` — sprawdzanie `front\Controllers\*Controller` przed fallback
  - Zarejestrowany `'ShopBasket'` w `getControllerFactories()`
- **cms\Layout removal**
  - USUNIETA: `autoload/cms/class.Layout.php` — caly folder `autoload/cms/` (1 klasa, bug w `__get()`)
  - UPDATE: `front\view\Site::show()` — `new \cms\Layout(...)` → `$layoutsRepo->find(...)`
- Testy: 484 OK, 1528 asercji (+8 testow: BasketCalculatorTest)

---

## ver. 0.287 (2026-02-17) - Scontainers + ShopAttribute frontend migration

- **Scontainers (frontend)** — migracja na Domain
  - NOWA METODA w `ScontainersRepository`: `frontScontainerDetails()` — z Redis cache + fallback
  - UPDATE: `clearFrontCache()` — klucz cache dopasowany do nowego wzorca
  - NOWY: `front\Views\Scontainers` — czysty VIEW (`scontainer()`)
  - USUNIETA: `front\factory\class.Scontainers.php` — logika przeniesiona do `ScontainersRepository`
  - USUNIETA: `front\view\class.Scontainers.php` — zastapiona przez `front\Views\Scontainers`
  - UPDATE: `front\view\Site::show()` — przepiecie na `$scontainersRepo->frontScontainerDetails()` + `\front\Views\Scontainers::`
- **ShopAttribute (frontend)** — migracja na Domain
  - NOWE METODY w `AttributeRepository`: `frontAttributeDetails()`, `frontValueDetails()` — z Redis cache + fallback
  - NOWA: `clearFrontCache()` — czyszczenie cache frontowego per atrybut/wartość i język
  - UPDATE: `saveAttribute()`, `deleteAttribute()`, `saveValues()` — wpiete czyszczenie cache frontowego
  - USUNIETA: `front\factory\class.ShopAttribute.php` — logika przeniesiona do `AttributeRepository`
  - UPDATE: `front\factory\ShopOrder` — przepiecie na `$attributeRepo->frontAttributeDetails()` / `frontValueDetails()`
  - UPDATE: 3 szablony (`product-attribute.php`, `summary-view.php`, `basket-details.php`) — przepiecie na `AttributeRepository`
- Testy: 476 OK, 1512 asercji (+6 testow: 2 ScontainersRepository frontend, 4 AttributeRepository frontend)

---

## ver. 0.286 (2026-02-17) - Layouts, Menu, Pages frontend migration

- **Layouts (frontend)** — migracja na Domain
  - NOWE METODY w `LayoutsRepository`: `categoryDefaultLayoutId()`, `getDefaultLayout()`, `getProductLayout()`, `getArticleLayout()`, `getCategoryLayout()`, `getActiveLayout()` — z Redis cache, 3-level fallback (product→category→default)
  - USUNIETA: `front\factory\class.Layouts.php` — logika przeniesiona do `LayoutsRepository`
  - UPDATE: `front\view\Site::show()` — przepiecie na `$layoutsRepo`
  - UPDATE: `Shared\Helpers\Helpers::htacces()` — optymalizacja z 3 wywolan `category_default_layout()` do jednej zmiennej
- **Menu + Pages (frontend)** — migracja na Domain + Views
  - NOWE METODY w `PagesRepository`: `frontPageDetails()`, `frontPageSort()`, `frontMainPageId()`, `frontLangUrl()`, `frontMenuDetails()`, `frontMenuPages()` — z Redis cache, rekurencja stron
  - NOWY: `front\Views\Menu` — czysty VIEW (`pages()`, `menu()`)
  - USUNIETA: `front\factory\class.Menu.php` — logika przeniesiona do `PagesRepository`
  - USUNIETA: `front\factory\class.Pages.php` — logika przeniesiona do `PagesRepository`
  - USUNIETA: `front\view\class.Menu.php` — zastapiona przez `front\Views\Menu`
  - USUNIETA: `templates\menu\submenu.php` — martwy kod (wola nieistniejaca metode `Menu::submenu()`)
  - UPDATE: `front\controls\Site::check_url_params()` — przepiecie na `$pagesRepo->frontPageDetails()`
  - UPDATE: `index.php` — przepiecie na `$pagesRepo->frontPageDetails()`
  - UPDATE: `templates/site/languages.php` — przepiecie na `$pagesRepo->frontLangUrl()`
  - UPDATE: `templates/menu/menu.php`, `pages.php`, `main-menu.php` — przepiecie na `\front\Views\Menu::`
  - FIX: `frontPageDetails()` — usuniety type hint `string` z `$langId` + cast `(string)` (null $lang_id przy wczesnym wywolaniu `check_url_params()`)
  - FIX: `front\controls\class.Site.php` — dodano `$lang_id ?? ''` przy przekazywaniu do `frontPageDetails()`
- Testy: 470 OK, 1484 asercji (+16 testow: 8 LayoutsRepository frontend, 8 PagesRepository frontend)

---

## ver. 0.285 (2026-02-17) - Tpl namespace, CurlServer removal, thumb.php fix

- **Shared\Tpl\Tpl** — migracja silnika szablonow do namespace Shared
  - NOWY: `autoload/Shared/Tpl/Tpl.php` (namespace `Shared\Tpl`)
  - USUNIETA: `autoload/class.Tpl.php` — zastapiona przez `Shared\Tpl\Tpl`
  - ZAMIENIONE: ~135 plikow — `\Tpl::` / `new \Tpl` → `\Shared\Tpl\Tpl::` / `new \Shared\Tpl\Tpl`
  - DRY: wyciagnieto powtorzony `ob_start/include/ob_get_contents/ob_end_clean` do prywatnej metody `renderFile()`
  - FIX: bug w `render()` branch 3 — sprawdzal `../templates_user/` ale ladowal `../templates/`
  - CLEANUP: usunieta nieuzywana property `$dir` i konstruktor `__construct($dir)`
- **CurlServer** — usuniecie nieuzywanej klasy
  - USUNIETA: `autoload/curl.class.php` — klasa `CurlServer` bez referencji w projekcie (0 uzyc)
- **thumb.php** — naprawa require po migracji Image
  - FIX: `libraries/thumb.php` — zmiana `require_once '../autoload/class.Image.php'` na `../autoload/Shared/Image/ImageManipulator.php` + `use`
  - FIX: poprawiony short open tag `<?` na `<?php`
- Testy: 454 OK, 1449 asercji

---

## ver. 0.284 (2026-02-16) - DbModel elimination

- **DbModel** — usunięcie klasy base ORM
  - USUNIETA: `autoload/class.DbModel.php` — jedyny konsument (`shop\Promotion`) ma teraz wbudowany konstruktor + `__get()`
  - UPDATE: `autoload/shop/class.Promotion.php` — usunięto `extends DbModel` + `use DbModel`, wbudowano minimalny konstruktor z `$mdb->get()` i `__get()`
  - Testy: 454 OK, 1449 asercji

---

## ver. 0.283 (2026-02-16) - Legacy class cleanup — S, Html, Email, Image, Log, Mobile_Detect → Shared namespace

- **class.S.php → Shared\Helpers\Helpers**
  - PRZENIESIONA: `class.S.php` → `autoload/Shared/Helpers/Helpers.php` (namespace `Shared\Helpers`, klasa `Helpers`)
  - ZAMIENIONE: ~140 plików — `\S::` → `\Shared\Helpers\Helpers::`
  - CLEANUP: usunięto 12 nieużywanych metod (set_array_value, parse_name, clear_redis_cache, get_domain, pre_dump, escape, chmod_r, rrmdir, rcopy, pre, json_to_array, is_empty_dir)
  - FIX: `array_cartesian_product()` — iteracja po niezdefiniowanej zmiennej `$array` zamiast parametru `$input`
  - NOWY: `tests/stubs/Helpers.php` — stub klasy Helpers dla testów
  - USUNIETA: `autoload/class.S.php`
- **Shared\Html\Html** — `autoload/class.Html.php` → `autoload/Shared/Html/Html.php`
- **Shared\Email\Email** — `autoload/class.Email.php` → `autoload/Shared/Email/Email.php`
- **Shared\Image\Image** — `autoload/class.Image.php` → `autoload/Shared/Image/Image.php`
- **Shared\Log\Log** — `autoload/class.Log.php` → `autoload/Shared/Log/Log.php`
- **Mobile_Detect** — USUNIETA: przestarzała detekcja UA (v2.8.16), zastąpiona responsive design
  - USUNIETA: metoda `S::is_mobile()` i 3 warunki mobilne w `front\view\Site`
  - USUNIETE z `LayoutsRepository`: pola `m_html`, `m_css`, `m_js`
- Testy: 454 OK, 1449 asercji

---

## ver. 0.282 (2026-02-16) - Cache cleanup, Shared namespace

- **Shared\Cache namespace** — przeniesienie CacheHandler i RedisConnection do `Shared\Cache\`
  - NOWY: `autoload/Shared/Cache/CacheHandler.php` — glowna implementacja
  - NOWY: `autoload/Shared/Cache/RedisConnection.php` — glowna implementacja singleton
  - USUNIETA: `autoload/class.CacheHandler.php` — wrapper usuniety, 60 odwolan przepietych na `\Shared\Cache\CacheHandler`
  - USUNIETA: `autoload/class.RedisConnection.php` — wrapper usuniety, 12 odwolan przepietych na `\Shared\Cache\RedisConnection`
- **Eliminacja legacy Cache** — usuniecie plikowego cache `class.Cache.php`
  - USUNIETA: `autoload/class.Cache.php` — legacy file-based cache (store/fetch z base64+serialize)
  - UPDATE: `front\factory\ShopProduct` — 5 metod przepietych z `\Cache::` na `CacheHandler` (get_minimal_price, product_name, product_image, random_products, promoted_products)
  - UPDATE: `front\factory\ShopPaymentMethod` — 3 metody przepiete (payment_methods_by_transport, payment_method, payment_methods)
  - UPDATE: `front\factory\ShopCategory` — 2 metody przepiete (get_category_sort, category_name)
  - UPDATE: `front\factory\ShopTransport` — 2 metody przepiete (transport_cost, transport)
  - UPDATE: `front\factory\ShopAttribute` — 1 metoda przepieta (attribute_details)
  - UPDATE: `Domain\Dictionaries\DictionariesRepository` — prywatne wrappery cacheFetch/cacheStore przepiete na CacheHandler
  - FIX: naprawione rozbieznosci kluczy cache (random_products, category_name) — fetch i store uzywaly roznych kluczy
  - Testy: 454 OK, 1449 asercji

---

## ver. 0.281 (2026-02-16) - Banners frontend migration

- **Banners (frontend)** — migracja na Domain + Views
  - NOWE METODY w `BannerRepository`: `banners(string $langId)`, `mainBanner(string $langId)` — z Redis cache, filtrowanie dat, plaski format `$banner['languages']` (zgodny z szablonami)
  - NOWY: `front\Views\Banners` — czysty VIEW (`banners()`, `mainBanner()`)
  - USUNIETA: `front\factory\Banners` — logika przeniesiona do `BannerRepository`
  - USUNIETA: `front\view\Banners` — zastapiona przez `front\Views\Banners`
  - UPDATE: `front\view\Site::show()` — przepiecie linii 62-63 na repo + Views (bezposrednio `$bannerRepo->banners()` / `$bannerRepo->mainBanner()`)
  - Testy: 454 OK, 1449 asercji (+4 nowe testy w BannerRepositoryTest)

---

## ver. 0.280 (2026-02-16) - Articles frontend migration

- **Articles (frontend)** — pelna migracja na Domain + Views
  - NOWE METODY w `ArticleRepository`: `articleDetailsFrontend()`, `articlesIds()`, `pageArticlesCount()`, `pageArticles()`, `news()`, `articleNoindex()`, `topArticles()`, `newsListArticles()`
  - NOWY: `front\Views\Articles` — czysty VIEW + utility (renderowanie, generateTableOfContents, generateHeadersIds, getImage)
  - UPDATE: `front\view\Site::show()` — przepiecie 5 sekcji na repo + Views (BOX aktualnosci, article meta, noindex, news list, top articles)
  - UPDATE: `front\controls\Site::route()` — przepiecie single article + page_type switch (4 typy) na repo + Views
  - UPDATE: 5 szablonow `templates/articles/*` — przepiecie na `\front\Views\Articles::`
  - FASADA: `front\factory\Articles` — 10 metod delegujacych do repo + Views
  - FASADA: `front\view\Articles` — 5 metod delegujacych do repo + Views
  - USUNIETA: `class.Article` — encja + metody statyczne; logika przeniesiona do `ArticleRepository` + `front\Views\Articles`
  - FIX: eliminacja `global $lang` z `articleNoindex()` — zamiana na jawny parametr `$langId`
  - FIX: eliminacja zaleznosci od `\front\factory\Pages::page_sort()` w `news()` — inline query
  - FIX: naprawione kolizje nazw zmiennych w `front\view\Site::show()` ($news_list → $news_list_matches, $top_news_matches)
  - Testy: 450 OK, 1431 asercji (+13 nowych testow w ArticleRepositoryTest)
  - UPDATE: `tests/bootstrap.php` — dodany stub `S::is_array_fix()`

---

## ver. 0.279 (2026-02-16) - Newsletter + Languages frontend migration, front\Controllers, front\Views

- **Languages (view)** — migracja do nowego namespace
  - USUNIĘTA: `front\factory\Languages` — fasada niepotrzebna, wszystkie zależności przepięte na `Domain\Languages\LanguagesRepository`
  - USUNIĘTA: `front\view\Languages` → przeniesiona do `front\Views\Languages` (nowy namespace, bez `class.` prefix)
  - UPDATE: 26 plików przepiętych z fasady na repozytorium (kontrolery DI, entry points, szablony, shop classes)
  - UPDATE: `admin\App` — DI factory dla `ShopProductController` rozszerzona o `LanguagesRepository`

- **Newsletter (frontend)** — pełna migracja na Domain
  - NOWE METODY w `NewsletterRepository`: `unsubscribe()`, `confirmSubscription()`, `getHashByEmail()`, `removeByEmail()`, `signup()`, `sendQueued()`
  - NOWY: `front\Controllers\NewsletterController` — pierwszy frontowy kontroler z DI (nowy namespace `front\Controllers\`)
  - NOWY: `front\Views\Newsletter` — czysty VIEW (nowy namespace `front\Views\`)
  - USUNIĘTA: `front\factory\Newsletter` — logika przeniesiona do `NewsletterRepository`
  - USUNIĘTA: `front\view\Newsletter` → zastąpiona przez `front\Views\Newsletter`
  - USUNIĘTA: `front\controls\Newsletter` → zastąpiona przez `front\Controllers\NewsletterController`
  - UPDATE: `front\controls\Site::route()` — nowy routing: `getControllerFactories()` (DI) → fallback stare `front\controls\`
  - UPDATE: `front\factory\ShopClient` — 4x `get_template()` przepięte na `NewsletterRepository::templateByName()`
  - UPDATE: `index.php` — `newsletter_send()` przepięte na `$repo->sendQueued()`
  - FIX: `newsletter_unsubscribe()` — błędna składnia medoo `delete()` (3 argumenty zamiast 2)
  - UPDATE: `tests/bootstrap.php` — dodane stuby: `S::email_check()`, `S::get_session()`, `S::set_session()`
  - Testy: 437 OK, 1398 asercji (+10 nowych testów w NewsletterRepositoryTest)

---

## ver. 0.278 (2026-02-16) - Settings + Languages frontend migration

- **Settings + Languages (frontend)** — pierwszy etap refaktoringu frontendu
  - NOWE METODY: `SettingsRepository::allSettings($skipCache)` — pobranie ustawien z cache Redis
  - NOWE METODY: `SettingsRepository::getSingleValue($param)` — pobranie pojedynczej wartosci ustawienia
  - NOWE METODY: `LanguagesRepository::defaultLanguage()` — domyslny jezyk z cache Redis
  - NOWE METODY: `LanguagesRepository::activeLanguages()` — lista aktywnych jezykow z cache Redis
  - NOWE METODY: `LanguagesRepository::translations($lang)` — tlumaczenia z cache Redis
  - UPDATE: `front\factory\Settings` → fasada delegujaca do `SettingsRepository`
  - UPDATE: `front\factory\Languages` → fasada delegujaca do `LanguagesRepository`
  - FIX: `get_single_settings_value()` — parametr `$param` poprawnie uzywany (wczesniej hardcoded `'firm_name'`)
  - Testy: 427 OK, 1378 asercji (+13 nowych)

---

## ver. 0.277 (2026-02-16) - ShopProduct factory, Dashboard, Update, legacy cleanup, admin\App

- **ShopProduct (factory)** - pelna migracja modulu #29 na Domain + DI
  - NOWE: `ProductRepository` rozszerzony o ~40 metod: CRUD (countProducts, listForAdmin, findForAdmin, allProductsList, productCategoriesText, getParentId, productDefaultName), zapis (saveProduct + 9 prywatnych helperow), operacje (delete, duplicate, toggleStatus, updatePriceBrutto/Promo, updateCustomLabel), kombinacje (getPermutations, generateCombinations, deleteCombination, countCombinations, saveCombination*), zdjecia/pliki (deleteImage, updateImageAlt, saveImagesOrder, deleteFile, updateFileName, deleteNonassigned*), Google Feed XML (generateGoogleFeedXml, generateEAN), custom labels (customLabelSuggestions, saveCustomLabel, saveXmlName), updateCombinationPricesFromBase
  - NOWE: `ShopProductController` rozszerzony o ~30 akcji: view_list, product_edit, save, duplicate_product, product_archive/unarchive, product_delete, change_product_status, product_change_price_brutto/promo, product_change_custom_label, product_custom_label_suggestions/save, ajax_product_url, generate_sku_code, product_combination, generate_combination, delete_combination, product_combination_*_save, image_delete, images_order_save, image_alt_change, product_file_delete, product_file_name_change, product_image_delete
  - UPDATE: przepiecie zaleznosci zewnetrznych: `ProductArchiveController`, `order-details.php`, `cron.php`, `cron-xml.php`, `product-edit.php`, `mass-edit-custom-script.php`
  - CLEANUP: usuniete `autoload/admin/controls/class.ShopProduct.php`, `autoload/admin/factory/class.ShopProduct.php`, `admin/ajax/shop.php` + require z `admin/ajax.php`
- **ShopOrder (stabilizacja po migracji)**
  - FIX: `Domain\Order\OrderRepository::listForAdmin()` - poprawa zapytan SQL (count/list), bezpieczne fallbacki i poprawne zwracanie listy zamowien w `/admin/shop_order/list/`
  - FIX: wyrównanie wysokości komórek w `components/table-list` (`vertical-align` + lokalny override dla `.text-right` w tabeli)
- **Integrations (cleanup)**
  - CLEANUP: usunieta fasada `autoload/admin/factory/class.Integrations.php`
  - UPDATE: przepięcie wywołań na `Domain\Integrations\IntegrationsRepository` w: `cron.php`, `shop\Order`, `admin\Controllers\ShopPaymentMethodController`, `admin\Controllers\ShopStatusesController`, `admin\Controllers\ShopTransportController`
- **Admin UX**
  - NOWE: globalna wyszukiwarka w top-barze (obok "Wyczysc cache") dla produktow i zamowien
  - NOWE: endpoint `/admin/settings/globalSearchAjax/` (`SettingsController::globalSearchAjax`)
  - FIX: wsparcie wyszukiwania po pełnym imieniu i nazwisku (np. "Jan Kowalski") + poprawka escapingu SQL w `CONCAT_WS`
- **Dashboard** - migracja modulu #30 na Domain + DI
  - NOWE: `Domain\Dashboard\DashboardRepository` (summaryOrders, summarySales, salesGrid, mostViewedProducts, bestSalesProducts, last24MonthsSales, lastOrders, Redis caching)
  - NOWE: `admin\Controllers\DashboardController` (DI z DashboardRepository + ShopStatusRepository)
  - CLEANUP: usuniete `autoload/admin/controls/class.Dashboard.php`, `autoload/shop/class.Dashboard.php`
- **Update** - migracja modulu #31 na Domain + DI
  - NOWE: `Domain\Update\UpdateRepository` (update, runPendingMigrations, downloadAndApply, executeSql, deleteFiles, extractZip, saveLog)
  - NOWE: `admin\Controllers\UpdateController` (DI z UpdateRepository)
  - UPDATE: template `update/main-view.php` - usunieto `gridEdit` i `$.prompt()`, zastapiono panelami + `$.confirm()`/`$.alert()`
  - CLEANUP: usuniete `autoload/admin/controls/class.Update.php`, `autoload/admin/factory/class.Update.php`, `autoload/admin/view/class.Update.php`
- **Legacy cleanup**
  - CLEANUP: usunieto `autoload/admin/factory/class.Articles.php` (martwy kod, `articles_by_date_add` przeniesione do `ArticleRepository`)
  - UPDATE: `front\factory\Newsletter` przepieta na `Domain\Article\ArticleRepository::articlesByDateAdd()`
  - CLEANUP: usunieto `autoload/admin/view/class.Page.php`, logika przeniesiona do `admin\App::render()`
  - CLEANUP: usuniete puste foldery `autoload/admin/controls/`, `autoload/admin/factory/`, `autoload/admin/view/`
- **admin\Site -> admin\App**
  - UPDATE: klasa `admin\Site` przemianowana na `admin\App` (plik `App.php` bez przedrostka `class.`)
  - UPDATE: refaktoring `App` — usunieto martwy fallback na `\admin\controls\`, uproszczono routing, ujednolicony code style
- TEST:
  - NOWE: `DashboardControllerTest` (4), `DashboardRepositoryTest` (6), `UpdateControllerTest` (6), `UpdateRepositoryTest` (6)
  - Pelny suite: **OK (414 tests, 1335 assertions)**

---

## ver. 0.276 (2026-02-15) - ShopOrder

- **ShopOrder** - migracja `/admin/shop_order/*` na Domain + DI + nowe widoki
  - NOWE: `Domain\Order\OrderRepository` (lista admin z filtrowaniem/sortowaniem, szczegóły, historia statusów, notes, save admin, summary, trustmate, delete)
  - NOWE: `Domain\Order\OrderAdminService` (operacje aplikacyjne admin: status/paid/unpaid/resend email/send to apilo/delete)
  - NOWE: `admin\Controllers\ShopOrderController` (DI) z akcjami `list/view_list`, `details/order_details`, `edit/order_edit`, `save/order_save`, `notes_save`, `order_status_change`, `order_resend_confirmation_email`, `set_order_as_paid`, `set_order_as_unpaid`, `send_order_to_apilo`, `toggle_trustmate_send`, `delete/order_delete`
  - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopOrder`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_order/list/`
  - UPDATE: lista zamówień przepięta z legacy grid na `components/table-list` (`shop-order/orders-list`)
  - UPDATE: `shop-order/order-details` i `shop-order/order-edit` przebudowane bez `gridEdit` + wydzielenie JS do `*-custom-script.php`
  - UPDATE: `shop\Order::order_statuses()` przepiete na `Domain\ShopStatus\ShopStatusRepository`
  - UPDATE: `admin\controls\Dashboard` pobiera statusy przez `Domain\ShopStatus\ShopStatusRepository`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopOrder.php`, `autoload/admin/factory/class.ShopOrder.php`, `admin/templates/shop-order/view-list.php`
- TEST:
  - NOWE: `tests/Unit/Domain/Order/OrderRepositoryTest.php`
  - NOWE: `tests/Unit/admin/Controllers/ShopOrderControllerTest.php`
  - Testy punktowe: **OK (8 tests, 49 assertions)**

---

## ver. 0.275 (2026-02-15) - ShopCategory

- **ShopCategory** - migracja `/admin/shop_category/*` na Domain + DI + nowe endpointy AJAX
  - NOWE: `Domain\Category\CategoryRepository` (`sortTypes`, `subcategories`, `categoryDetails`, `categoryProducts`, `save`, `categoryDelete`, `saveCategoriesOrder`, `saveProductOrder`, `categoryTitle`)
  - NOWE: `admin\Controllers\ShopCategoryController` (DI) z akcjami `list/view_list`, `edit/category_edit`, `save`, `delete/category_delete`, `products/category_products`, `category_url_browser`, `save_categories_order`, `save_products_order`, `cookie_categories`
  - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopCategory`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_category/list/`
  - UPDATE: widoki `shop-category/*` - wydzielenie skryptow do `*-custom-script.php`, ujednolicone strzalki drzewa (`button + caret + aria-expanded`)
  - UPDATE: AJAX drzewek przepiety z `/admin/ajax.php?a=*` na `/admin/shop_category/*`
  - UPDATE: zaleznosci `ShopProduct` przepiete z `admin\factory\ShopCategory` na `Domain\Category\CategoryRepository`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopCategory.php`, `autoload/admin/factory/class.ShopCategory.php`, `autoload/admin/view/class.ShopCategory.php`
  - CLEANUP: usuniety preload `class.ShopCategory.php` z `libraries/grid/config.php`
- TEST:
  - NOWE: `tests/Unit/Domain/Category/CategoryRepositoryTest.php`
  - NOWE: `tests/Unit/admin/Controllers/ShopCategoryControllerTest.php`
  - Testy punktowe: **OK (16 tests, 72 assertions)**
  - Pelny suite: **OK (377 tests, 1197 assertions)**

---

## ver. 0.274 (2026-02-15) - ShopProduct mass_edit + UI trees

- **ShopProduct (mass_edit)** - migracja akcji masowej edycji na Domain + DI
  - NOWE: `admin\Controllers\ShopProductController` (DI) z akcjami `mass_edit`, `mass_edit_save`, `get_products_by_category`
  - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopProduct`
  - UPDATE: `Domain\Product\ProductRepository` rozszerzone o metody `allProductsForMassEdit`, `getProductsByCategory`, `applyDiscountPercent` (+ aktualizacja cen kombinacji)
  - CLEANUP: usuniete legacy akcje `mass_edit`, `mass_edit_save`, `get_products_by_category` z `admin\controls\ShopProduct`
- **ShopProduct mass_edit UI** - przebudowa widoku i skryptu
  - UPDATE: `admin/templates/shop-product/mass-edit.php` przepiety na nowy partial JS `mass-edit-custom-script`
  - NOWE: `admin/templates/shop-product/mass-edit-custom-script.php` (nestedSortable + iCheck + stabilizacja drzewka)
  - UPDATE: `admin/templates/shop-product/subcategories-list.php` ujednolicone strzalki (button + caret)
  - FIX: zaznaczenie kategorii w drzewku nie zaznacza automatycznie produktow na liscie
- **Pages / Articles UI** - ujednolicenie drzewek
  - UPDATE: `/admin/pages/list/` - nowe strzalki drzewa + `aria-expanded` + odswiezanie stanu branch/leaf
  - UPDATE: `/admin/articles/edit/*` (zakladka wyswietlania) - nowe strzalki i checkboxy (iCheck) dla drzewka stron
- **ShopClients** - migracja `/admin/shop_clients` na Domain + DI + nowe widoki
  - NOWE: `Domain\Client\ClientRepository` (`listForAdmin`, `ordersForClient`, `totalsForClient`)
  - NOWE: `admin\Controllers\ShopClientsController` (DI) z akcjami `list`, `details` + aliasy legacy `view_list`, `clients_details`
  - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopClients`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_clients/list/`
  - UPDATE: widoki `shop-clients/view-list` i `shop-clients/clients-details` przepiete na `components/table-list`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopClients.php`, `autoload/admin/factory/class.ShopClients.php`
- TEST:
  - NOWE: `tests/Unit/admin/Controllers/ShopProductControllerTest.php`
  - NOWE: `tests/Unit/Domain/Client/ClientRepositoryTest.php`, `tests/Unit/admin/Controllers/ShopClientsControllerTest.php`
  - UPDATE: `tests/Unit/Domain/Product/ProductRepositoryTest.php` (nowe przypadki dla mass_edit)
  - UPDATE: `tests/bootstrap.php` (stub `S::normalize_decimal()`)
- Testy: **OK (361 tests, 1125 assertions)**

---

## ver. 0.273 (2026-02-15) - ShopProducer

- **ShopProducer** - migracja `/admin/shop_producer` na Domain + DI + nowe widoki
  - NOWE: `Domain\Producer\ProducerRepository` (`listForAdmin`, `find`, `save`, `delete`, `allProducers`, `findForFrontend`, `producerProducts`, `allActiveIds`)
  - NOWE: `admin\Controllers\ShopProducerController` (DI) z akcjami `list`, `edit`, `save`, `delete`
  - UPDATE: modul `/admin/shop_producer/*` dziala na `components/table-list` i `components/form-edit` z zakladkami jezykowymi (Opis + SEO)
  - UPDATE: routing i menu admin na kanoniczny URL `/admin/shop_producer/list/`
  - UPDATE: `shop\Producer` przepiety na fasade do `Domain\Producer\ProducerRepository`
  - UPDATE: `admin\factory\ShopProduct` - 2 wywolania `admin\factory\ShopTransport` przepiete na `Domain\Transport\TransportRepository`
  - UPDATE: `admin\controls\ShopProduct` - usuniety fallback do `admin\factory\Layouts`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopProducer.php`, `admin/templates/shop-producer/list.php`, `admin/templates/shop-producer/edit.php`
  - CLEANUP: usuniete 6 pustych factory facades: `admin\factory\Languages`, `admin\factory\Newsletter`, `admin\factory\Scontainers`, `admin\factory\ShopProducer`, `admin\factory\ShopTransport`, `admin\factory\Layouts`
  - TEST: dodane `tests/Unit/Domain/Producer/ProducerRepositoryTest.php` i `tests/Unit/admin/Controllers/ShopProducerControllerTest.php`
- Testy: **OK (338 tests, 1063 assertions)**

---

## ver. 0.272 (2026-02-15) - ShopProductSets

- **ShopProductSets** - migracja `/admin/shop_product_sets` na Domain + DI + nowe widoki
  - NOWE: `Domain\ProductSet\ProductSetRepository` (`listForAdmin`, `find`, `save`, `delete`, `allSets`, `allProductsMap`)
  - NOWE: `admin\Controllers\ShopProductSetsController` (DI) z akcjami `list`, `edit`, `save`, `delete`
  - UPDATE: modul `/admin/shop_product_sets/*` dziala na `components/table-list` i `components/form-edit` + Selectize multi-select produktow
  - UPDATE: routing i menu admin na kanoniczny URL `/admin/shop_product_sets/list/`
  - UPDATE: `shop\ProductSet` przepiety na fasade do `Domain\ProductSet\ProductSetRepository`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopProductSets.php`, `autoload/admin/factory/class.ShopProductSet.php`, `admin/templates/shop-product-sets/view-list.php`, `admin/templates/shop-product-sets/set-edit.php`
  - TEST: dodane `tests/Unit/Domain/ProductSet/ProductSetRepositoryTest.php` i `tests/Unit/admin/Controllers/ShopProductSetsControllerTest.php`
- Testy: **OK (324 tests, 1000 assertions)**

---

## ver. 0.271 (2026-02-14) - ShopAttribute

- **ShopAttribute** - migracja `/admin/shop_attribute` na Domain + DI + nowe widoki
  - NOWE: `Domain\Attribute\AttributeRepository` (`listForAdmin`, `findAttribute`, `saveAttribute`, `deleteAttribute`, `findValues`, `saveValues`, `saveLegacyValues`, `valueDetails`)
  - NOWE: `admin\Controllers\ShopAttributeController` (DI) z akcjami `list`, `edit`, `save`, `delete`, `values`, `values_save`, `value_row_tpl`
  - UPDATE: modul `/admin/shop_attribute/*` dziala na `components/table-list` i `components/form-edit`
  - UPDATE: nowy edytor wartosci cechy (`values-edit`) z walidacja serwerowa i stabilnym `row_key` (bez indeksow do wyboru domyslnej wartosci)
  - UPDATE: routing i menu admin na kanoniczny URL `/admin/shop_attribute/list/` (bez aliasow legacy)
  - UPDATE: przepiecie zaleznosci kombinacji produktu (`admin\controls\ShopProduct`, `admin\factory\ShopProduct`, `admin/templates/shop-product/product-combination.php`) na `Domain\Attribute\AttributeRepository` i `shop\ProductAttribute`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopAttribute.php`, `autoload/admin/factory/class.ShopAttribute.php`, `autoload/admin/view/class.ShopAttribute.php`, `admin/templates/shop-attribute/_partials/value.php`
  - TEST: dodane `tests/Unit/Domain/Attribute/AttributeRepositoryTest.php` i `tests/Unit/admin/Controllers/ShopAttributeControllerTest.php`
- Testy: **OK (312 tests, 948 assertions)**

---

## ver. 0.270 (2026-02-14) - Apilo payment/status sync hardening

- **Shop/Order + Apilo** - utwardzenie synchronizacji platnosci i statusow zamowien
  - FIX: `shop\Order::set_as_paid()` wysyla do Apilo mapowany typ platnosci (`payment_method_id` -> `apilo_payment_type_id`) zamiast stalego `type = 1`
  - NOWE: retry queue dla chwilowej niedostepnosci Apilo (`temp/apilo-sync-queue.json`) dla sync platnosci i statusu
  - NOWE: `shop\Order::process_apilo_sync_queue()` przetwarza zalegle syncy
  - UPDATE: `cron.php` uruchamia przetwarzanie kolejki sync Apilo przy aktywnej integracji
  - UPDATE: rozszerzone logowanie debug (`logs/apilo.txt`) o HTTP code i bledy cURL dla sync platnosci/statusu
- Testy: **OK (300 tests, 895 assertions)**

---

## ver. 0.269 (2026-02-14) - ShopTransport

- **ShopTransport** - migracja `/admin/shop_transport` na Domain + DI + nowe widoki
  - NOWE: `Domain\Transport\TransportRepository` (`listForAdmin`, `find`, `save`, `allActive`, `allForAdmin`, `findActiveById`, `getTransportCost`, `lowestTransportPrice`, `getApiloCarrierAccountId`)
  - NOWE: `admin\Controllers\ShopTransportController` (DI) z akcjami `list`, `edit`, `save`
  - NOWE: widoki `shop-transport/transports-list.php` i `shop-transport/transport-edit.php` + `transport-edit-custom-script.php`
  - UPDATE: routing i menu admin na kanoniczny URL `/admin/shop_transport/list/`
  - UPDATE: `admin\factory\ShopTransport`, `front\factory\ShopTransport` przepiete na nowe repozytorium
  - FIX: `save()` return type `?int` zamiast `int|bool` (spojnosc z PaymentMethod)
  - FIX: `toSwitchValue()` helper zamiast `=== 'on'` (obsluga '1', 'on', 'true', 'yes')
  - FIX: `\S::delete_dir()` przeniesione z repozytorium do kontrolera (DDD)
  - FIX: Medoo `select()` syntax - ORDER w WHERE zamiast 4-arg form
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopTransport.php`, `autoload/admin/view/class.ShopTransport.php`, `admin/templates/shop-transport/view-list.php`
  - FIX: `transports-list.php` - zmienna `'viewModel'` zmieniona na `'list'` (zgodnie z `table-list.php` komponentem)
- Testy: **OK (300 tests, 895 assertions)**

---

## ver. 0.268 (2026-02-14) - ShopPaymentMethod + Apilo token keepalive

- **ShopPaymentMethod** - migracja `/admin/shop_payment_method` na Domain + DI + nowe widoki
  - NOWE: `Domain\PaymentMethod\PaymentMethodRepository` (`listForAdmin`, `find`, `save`, `allActive`, `allForAdmin`, `findActiveById`, `isActive`, `getApiloPaymentTypeId`, `forTransport`)
  - NOWE: `admin\Controllers\ShopPaymentMethodController` (DI) z akcjami `list`, `edit`, `save`
  - NOWE: widoki `shop-payment-method/payment-methods-list.php` i `shop-payment-method/payment-method-edit.php`
  - UPDATE: routing i menu admin na kanoniczny URL `/admin/shop_payment_method/list/`
  - UPDATE: `admin\controls\ShopTransport`, `front\factory\ShopPaymentMethod`, `shop\PaymentMethod` przepiete na nowe repozytorium
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopPaymentMethod.php`, `autoload/admin/factory/class.ShopPaymentMethod.php`, `autoload/admin/view/class.ShopPaymentMethod.php`, `admin/templates/shop-payment-method/view-list.php`
- **Integrations/Apilo** - stabilizacja tokenu i lepszy feedback
  - NOWE: automatyczne odswiezanie tokenu Apilo przed wygasnieciem (`apiloKeepalive`, refresh lead time)
  - UPDATE: cron uruchamia keepalive i odswieza konfiguracje Apilo
  - UPDATE: bardziej szczegolowe komunikaty bledow dla przyciskow integracji Apilo (co zrobic dalej)
- Testy: **OK (280 tests, 828 assertions)**

---

## ver. 0.267 (2026-02-14) - ShopStatuses

- **ShopStatuses** - migracja `/admin/shop_statuses` na Domain + DI + nowe widoki
  - NOWE: `Domain\ShopStatus\ShopStatusRepository` (`listForAdmin`, `find`, `save`, `getApiloStatusId`, `getByIntegrationStatusId`, `allStatuses`)
  - NOWE: `admin\Controllers\ShopStatusesController` (DI) z akcjami `list`, `edit`, `save` (bez aliasow legacy)
  - NOWE: typ pola `FormFieldType::COLOR` + `FormField::color()` + `FormFieldRenderer::renderColor()` (color picker HTML5 zsynchronizowany z polem tekstowym)
  - UPDATE: modul `/admin/shop_statuses/*` dziala na `components/table-list` i `components/form-edit`
  - UPDATE: `front\factory\ShopStatuses` jako fasada delegujaca do `Domain\ShopStatus\ShopStatusRepository`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_statuses/list/`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopStatuses.php`, `autoload/admin/factory/class.ShopStatuses.php`
  - UWAGA: statusy maja ID od 0 - kluczowe dla walidacji (find/save uzywaja `$id < 0`)
- Testy: **OK (254 tests, 736 assertions)**

---

## ver. 0.266 (2026-02-13) - ShopCoupon

- **ShopCoupon** - migracja `/admin/shop_coupon` na Domain + DI + nowe widoki
  - NOWE: `Domain\Coupon\CouponRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`)
  - NOWE: `admin\Controllers\ShopCouponController` (DI) z akcjami `list`, `edit`, `save`, `delete`
  - UPDATE: kompatybilnosc aliasow legacy (`view_list`, `coupon_edit`, `coupon_save`, `coupon_delete`) obslugiwana przez nowy kontroler
  - UPDATE: modul `/admin/shop_coupon/*` dziala na `components/table-list` i `components/form-edit`
  - NOWE: widoki/partiale `shop-coupon/coupons-list`, `shop-coupon/coupon-edit-new`, `shop-coupon/coupon-categories-selector`, `shop-coupon/coupon-categories-tree`, `shop-coupon/coupon-edit-custom-script`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopCoupon.php`, `autoload/admin/factory/class.ShopCoupon.php`, `admin/templates/shop-coupon/view-list.php`, `admin/templates/shop-coupon/coupon-edit.php`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_coupon/list/`
  - FIX: ujednolicone UI drzewek i checkboxow miedzy kuponami i layoutami
- Testy: **OK (235 tests, 682 assertions)**

---

## ver. 0.265 (2026-02-13) - ShopPromotion poprawki

- **ShopPromotion** - stabilizacja po migracji
  - UPDATE: dodane `date_from` w `Domain\Promotion\PromotionRepository` (save/find/list/sort)
  - UPDATE: `admin\Controllers\ShopPromotionController` rozszerzony o pole `Data od` na formularzu i kolumne `Data od` na liscie
  - UPDATE: `shop\Promotion::get_active_promotions()` filtruje aktywnosc po `date_from` i `date_to`
  - FIX: zapis edycji promocji nie tworzy nowego rekordu (hidden `id` + fallback `id` z URL)
  - TEST: rozszerzono `PromotionRepositoryTest` o asercje `date_from`
- Testy: **OK (222 tests, 614 assertions)**

---

## ver. 0.264 (2026-02-13) - ShopPromotion

- **ShopPromotion** - migracja `/admin/shop_promotion` na Domain + DI + nowe widoki
  - NOWE: `Domain\Promotion\PromotionRepository` (`listForAdmin`, `find`, `save`, `delete`, `categoriesTree`, invalidacja cache aktywnych promocji)
  - NOWE: `admin\Controllers\ShopPromotionController` (DI) z akcjami `list`, `edit`, `save`, `delete`
  - UPDATE: routing DI (`admin\Site`) rozszerzony o modul `ShopPromotion`
  - UPDATE: modul `/admin/shop_promotion/*` dziala na `components/table-list` i `components/form-edit`
  - NOWE: widoki/partiale `shop-promotion/promotions-list`, `shop-promotion/promotion-edit`, `shop-promotion/promotion-categories-selector`, `shop-promotion/promotion-categories-tree`, `shop-promotion/promotion-edit-custom-script`
  - CLEANUP: usuniete legacy `autoload/admin/controls/class.ShopPromotion.php`, `autoload/admin/factory/class.ShopPromotion.php`, `admin/templates/shop-promotion/view-list.php`
  - UPDATE: menu admin przepiete na kanoniczny URL `/admin/shop_promotion/list/`
- Testy: **OK (222 tests, 609 assertions)**

---

## ver. 0.263 (2026-02-13) - Integrations + cleanup Sellasist/Baselinker

- NOWE: `Domain\Integrations\IntegrationsRepository` (settings Apilo/ShopPRO, OAuth, product linking, API fetch)
- NOWE: `admin\Controllers\IntegrationsController` (DI) dla akcji Apilo i ShopPRO
- UPDATE: `admin\factory\Integrations` jako fasada delegujaca do repozytorium
- **CLEANUP: usunieto integracje Sellasist i Baselinker z calego projektu:**
  - Usuniete klasy: `admin\controls\Integrations`, `admin\controls\Baselinker`, `admin\factory\Baselinker`, `front\factory\Shop`, `shop\ShopStatus`
  - Usuniete szablony: `integrations/sellasist-settings.php`, `integrations/baselinker-settings.php`, `admin/templates/baselinker/`
  - Wyczyszczone referencje w: `cron.php`, `cron/cron-xml.php`, `shop\Order`, kontrolery/factory/front Shop*
- Testy: **OK (212 tests, 577 assertions)**

---

## ver. 0.262 (2026-02-13) - Pages

- NOWE: `Domain\Pages\PagesRepository` (CRUD menu/stron, drzewo stron, sortowanie, SEO)
- NOWE: `admin\Controllers\PagesController` (DI) dla akcji menu/page/AJAX
- UPDATE: widoki `admin/templates/pages/*` przepiete na dane z kontrolera/repozytorium
- UPDATE: endpointy AJAX przepiete z `admin/ajax.php?a=*` na `/admin/pages/*`
- CLEANUP: usuniete legacy `controls/Pages`, `view/Pages`, `factory/Pages`, `ajax/pages.php`
- Testy: **OK (186 tests, 478 assertions)**

---

## ver. 0.261 (2026-02-13) - Articles (dalsza refaktoryzacja)

- UPDATE: `Domain\Article\ArticleRepository` rozszerzone o metody UI/admin i `saveFilesOrder()`
- UPDATE: `admin\Controllers\ArticlesController` obsluguje AJAX: `article_image_alt_change`, `article_file_name_change`, `article_image_delete`, `article_file_delete`, `filesOrderSave`
- UPDATE: lista artykulow nie korzysta juz z `admin\factory\Articles::article_pages()`
- UPDATE: widok edycji przepiety z `/admin/ajax.php` na `/admin/articles/*`
- UPDATE: drag&drop sortowania listy zalacznikow
- CLEANUP: usuniete `autoload/admin/view/class.Articles.php` i `admin/ajax/articles.php`
- Testy: **OK (178 tests, 443 assertions)**

---

## ver. 0.260 (2026-02-12) - ArticlesArchive

- NOWE: `admin\Controllers\ArticlesArchiveController` (DI)
- UPDATE: `Domain\Article\ArticleRepository` rozszerzone o `listArchivedForAdmin()`, `restore()`, `deletePermanently()`
- UPDATE: `/admin/articles_archive/view_list/` migrowane na `components/table-list`
- CLEANUP: usuniete legacy `controls/ArticlesArchive`, `factory/ArticlesArchive`, `view/ArticlesArchive`
- Testy: **OK (165 tests, 424 assertions)**

---

## ver. 0.259 (2026-02-12) - Scontainers

- NOWE: `Domain\Scontainers\ScontainersRepository` (listForAdmin, find, save, delete, detailsForLanguage)
- NOWE: `admin\Controllers\ScontainersController` (DI)
- UPDATE: `/admin/scontainers/*` migrowane na `components/table-list` i `components/form-edit`
- UPDATE: `admin\factory\Scontainers` i `front\factory\Scontainers` jako fasady
- CLEANUP: usuniete `controls/Scontainers`, `view/Scontainers`
- Testy: **OK (158 tests, 397 assertions)**

---

## ver. 0.258 (2026-02-12) - Newsletter (stabilizacja)

- UPDATE: tymczasowo wylaczono flow `prepare/send/preview` (wymaga przebudowy)
- UPDATE: tymczasowo wylaczono modul `Szablony uzytkownika`
- UPDATE: aktywna obsluga tylko szablonow administracyjnych (`is_admin = 1`)
- CLEANUP: usuniete nieuzywane widoki `prepare.php`, `preview.php`, `email-templates-user.php`

---

## ver. 0.257 (2026-02-12) - Newsletter

- NOWE: `Domain\Newsletter\NewsletterRepository` (subskrybenci, szablony, ustawienia, kolejka wysylki)
- NOWE: `Domain\Newsletter\NewsletterPreviewRenderer` (render podgladu)
- NOWE: `admin\Controllers\NewsletterController` (DI)
- UPDATE: `/admin/newsletter/*` migrowane na `components/table-list` i `components/form-edit`
- UPDATE: `admin\factory\Newsletter` jako fasada; `front\factory\Newsletter` bez `admin\view\Newsletter`
- CLEANUP: usuniete `controls/Newsletter`, `view/Newsletter`
- Testy: **OK (150 tests, 372 assertions)**

---

## ver. 0.256 (2026-02-12) - Layouts

- NOWE: `Domain\Layouts\LayoutsRepository` (find, save, delete, listForAdmin, menusWithPages, categoriesTree)
- NOWE: `admin\Controllers\LayoutsController` (DI)
- UPDATE: lista `/admin/layouts/view_list/` migrowana na `components/table-list`
- UPDATE: widok `layouts/layout-edit` korzysta z danych z repozytorium
- NOWE: partial `admin/templates/layouts/subcategories-list.php`
- UPDATE: `Domain\Languages\LanguagesRepository::defaultLanguageId()` jako wspolna metoda
- UPDATE: `ArticlesController` korzysta z `LayoutsRepository` (DI)
- CLEANUP: usuniete `controls/Layouts`, `view/Layouts`; `factory/Layouts` jako fasada
- Testy: **OK (141 tests, 336 assertions)**

---

## ver. 0.255 (2026-02-12) - Languages DI cleanup

- UPDATE: SettingsController, BannerController, DictionariesController, ArticlesController pobieraja liste jezykow przez `Domain/Languages/LanguagesRepository` (DI)
- UPDATE: router DI przekazuje `LanguagesRepository` do kontrolerow
- UPDATE: legacy `admin/controls`, `admin/factory/Shop*` przepiete na `LanguagesRepository`
- FIX: `admin/factory/class.Languages.php` poprawione na `<?php` (short_open_tag=Off)
- Testy: **OK (130 tests, 303 assertions)**

---

## ver. 0.254 (2026-02-12) - Languages

- NOWE: `Domain\Languages\LanguagesRepository` (languages + translations CRUD/list)
- NOWE: `admin\Controllers\LanguagesController` (DI)
- UPDATE: widoki `languages/*` migrowane na `components/table-list` i `components/form-edit`
- CLEANUP: usuniete `controls/Languages`, `view/Languages`; `factory/Languages` jako fasada
- Testy: **OK (130 tests, 301 assertions)**

---

## ver. 0.253 (2026-02-12) - Users

- NOWE: `Domain\User\UserRepository` (CRUD, logon, 2FA, checkLogin)
- NOWE: `admin\Controllers\UsersController` (DI: view_list, user_edit, user_save, user_delete, login_form, twofa)
- UPDATE: `admin\factory\Users` jako fasada; `admin/ajax/users.php` oparty o `UserRepository`
- UPDATE: widoki users migrowane na `components/table-list` i `components/form-edit`
- UPDATE: walidacja warunkowa: `twofa_email` wymagany gdy `twofa_enabled = 1`
- CLEANUP: usuniete `controls/Users`, `factory/Users`, `view/Users`
- Testy: **OK (119 tests, 256 assertions)**

---

## ver. 0.252 (2026-02-10) - ProductArchive + Filemanager

- UPDATE: `ProductArchiveController` i szablony przepiete na `components/table-list`
- UPDATE: CSS/JS dla list wydzielone do osobnych widoków `*-custom-script.php`
- NOWE: `admin\Controllers\FilemanagerController` - przepieto filemanager na nowy routing
- FIX: naprawiono błąd `Invalid Key` w filemanagerze
- CLEANUP: usunieto legacy `controls/Archive`, `controls/Filemanager`, `view/FileManager`, stare szablony
- RENAME: `admin/templates/product_archive/` → `admin/templates/product-archive/`
- Testy: **OK (82 tests, 181 assertions)**

---

## ver. 0.251 (2026-02-09) - Dictionaries

- NOWE: `Domain\Dictionaries\DictionariesRepository` (listForAdmin, find, save, delete, allUnits)
- NOWE: `admin\Controllers\DictionariesController` (lista + formularz na nowych komponentach)
- UPDATE: migracja słowników na `components/table-list` i `components/form-edit`
- FIX: obsługa `lang_id` jako string (`pl`, `en`) w zapisie tłumaczeń
- CLEANUP: usunięto legacy klasy Dictionaries (`admin\controls`, `admin\factory`, `front\factory`)
- Testy: **OK (82 tests, 181 assertions)**

---

## ver. 0.250 (2026-02-09) - Settings (refaktoryzacja)

- UPDATE: `Domain\Settings\SettingsRepository` ma bezpośredni dostęp do DB (bez delegacji do `admin\factory\Settings`)
- UPDATE: przepięto użycia `admin\factory\Settings` na `Domain\Settings\SettingsRepository`
- CLEANUP: usunięto legacy klasy Settings (`factory`, `controls`, `view`)
- Testy: **OK (82 tests, 181 assertions)**

---

## ver. 0.246 (2026-02-07) - Articles legacy cleanup

- CLEANUP: usunięto `autoload/admin/controls/class.Articles.php`
- UPDATE: `admin\Controllers\ArticlesController::galleryOrderSave()` uzywa `ArticleRepository::saveGalleryOrder()`
- FIX: sortowanie list admin po reloadzie - `RewriteRule` dla `/admin/...` ma `QSA`
- FIX: generator `\S::htacces()` komentuje dyrektywy `AddHandler|SetHandler|ForceType`
- Testy: **OK (65 tests, 131 assertions)**

---

## ver. 0.245 (2026-02-06) - Articles::archive

- UPDATE: `Domain\Article\ArticleRepository` - dodano `archive()` (status = -1)
- UPDATE: `admin\Controllers\ArticlesController` - nowa akcja `delete()` z DI
- UPDATE: `admin\factory\Articles::articles_set_archive()` deleguje do repozytorium
- Testy: **OK (59 tests, 123 assertions)**

---

## ver. 0.244 (2026-02-06) - Articles::save

- UPDATE: `Domain\Article\ArticleRepository` - dodano `save()` z prywatnych helperow
- UPDATE: `admin\Controllers\ArticlesController` - nowa akcja `save()` z DI
- UPDATE: `tests/bootstrap.php` - dodano stub `S::seo()`
- Testy: **OK (57 tests, 119 assertions)**

---

## ver. 0.243 (2026-02-06) - Articles cleanup

- UPDATE: `Domain\Article\ArticleRepository` - dodano `deleteNonassignedImages()` i `deleteNonassignedFiles()`
- UPDATE: `admin\Controllers\ArticlesController::edit()` uses repository cleanup methods
- Testy: **OK (50 tests, 95 assertions)**

---

## ver. 0.242 (2026-02-06) - Articles::edit

- NOWE: `Domain\Article\ArticleRepository` (find: artykuł + relacje)
- UPDATE: `admin\Controllers\ArticlesController` - konstruktor DI + `edit()` używa repozytorium
- UPDATE: `admin\factory\Articles::article_details()` deleguje do repozytorium
- Testy: **OK (48 tests, 91 assertions)**

---

## ver. 0.241 (2026-02-06) - ProductArchive

- NOWE: `admin\Controllers\ProductArchiveController` (DI)
- NOWE: `ProductRepository::archive()`, `unarchive()`
- RENAME: `admin/templates/archive/` → `admin/templates/product_archive/`
- FIX: SQL w `ajax_products_list_archive()` (puste wyszukiwanie + brak `archive = 1`)
- Testy: **OK (50 tests, 95 assertions)**

---

## ver. 0.240 (2026-02-05) - Settings + Cache

- NOWE: `Domain\Settings\SettingsRepository` (fasada → factory)
- NOWE: `Domain\Cache\CacheRepository` (dirs + Redis)
- NOWE: `admin\Controllers\SettingsController` (DI: clearCache, save, view)
- FIX: Brakujący `id="content"` w main-layout.php
- FIX: `persist_edit = true` w settings.php
- Testy: **OK (29 tests, 60 assertions)**

---

## ver. 0.239 (2026-02-05) - Banner + Product

- NOWE: `Domain\Banner\BannerRepository` (find, delete, save)
- NOWE: `admin\Controllers\BannerController` - pierwszy kontroler z DI
- NOWE: Router z mapą `$newControllers` + fallback na stare kontrolery
- NOWE: Autoloader PSR-4 fallback w 9 entry pointach
- Zmigrowano: `get_product_price()` → `ProductRepository::getPrice()`
- Zmigrowano: `get_product_name()` → `ProductRepository::getName()`
- Testy: **OK (15 tests, 31 assertions)**

---

## ver. 0.238 (2025-02-05) - Product Repository

- NOWE: `Domain\Product\ProductRepository` - pierwsza klasa w nowej architekturze
- NOWE: Dependency Injection zamiast `global $mdb`
- NOWE: Testy jednostkowe (5 testów, 100% pokrycie)
- Zmigrowano: `get_product_quantity()` → `ProductRepository::getQuantity()`
- Kompatybilność: Stara klasa `shop\Product` działa jako fasada

---

## ver. 0.237 (2025-02-05) - System cache produktów

- Automatyczne czyszczenie cache produktu po aktualizacji przez CRON
- AJAX dla przycisku "Wyczyść cache" w panelu admin
- Metody `delete()` i `deletePattern()` w CacheHandler
- Metoda `clear_product_cache()` w klasie S

---
*Dokument aktualizowany: 2026-02-17 (ver. 0.293)*
