---
phase: 04-products-aggregate-breakdown
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- autoload/factory/class.Products.php
- autoload/controls/class.Products.php
- templates/products/main_view.php
autonomous: false
delegation: off
---
## Goal
Na stronie `/products` zmienic tryb listy tak, aby przy braku wybranej grupy reklam (`ad_group_id` puste/0) tabela pokazywala 1 wiersz glowny na produkt z metrykami zagregowanymi, oraz rozwijane podwiersze z pelnym rozbiciem na kampanie i grupy reklam.
## Purpose
Obecny widok miesza poziomy agregacji i utrudnia szybka analize produktu jako calosci. Wiersz glowny ma pokazywac wynik laczny produktu, a szczegoly (kampania/grupa) maja byc dostepne na zadanie przez rozwiniecie.
## Output
- Backend zwracajacy dane zagregowane per produkt oraz szczegoly per scope (kampania/grupa) dla aktualnej strony.
- Frontend DataTable z przyciskiem rozwin/zwin i podwierszem z pelnymi metrykami.
- Brak mozliwosci edycji w podwierszach (edycja tylko w wierszu glownym).
## Project Context
@.paul/STATE.md
@.paul/phases/03-products-all-campaigns-view/03-01-SUMMARY.md
## Source Files
@autoload/factory/class.Products.php
@autoload/controls/class.Products.php
@templates/products/main_view.php
## Constraints from user
- Podwiersze maja byc zwijane/rozwijane przyciskiem.
- Podwiersze maja pokazywac pelny zestaw metryk.
- Edycja (`min_roas`, `CL1`, `CL4`, akcje) tylko w wierszu glownym produktu.
## Notes
Repo dziala w trybie ad-hoc PAUL (bez ROADMAP.md / PROJECT.md). Plan tworzony jako kolejna faza ad-hoc.
## AC-1: Agregacja produktu przy braku wybranej grupy reklam
```gherkin
Given uzytkownik jest na `/products` i ma wybranego klienta
And filtr grupy reklam jest pusty (`#products_ad_group_id` = "")
When tabela laduje dane
Then kazdy produkt wystepuje tylko raz jako wiersz glowny
And metryki wiersza glownego (wyswietlenia, klikniecia, koszt, konwersje, wartosc konwersji, ROAS itd.) sa suma ze wszystkich pasujacych scope
```
## AC-2: Rozwijane podwiersze z pelnym rozbiciem
```gherkin
Given tabela produktow jest zaladowana w trybie z AC-1
When uzytkownik kliknie przycisk rozwin przy produkcie
Then pod wierszem glownym pojawia sie podwiersz(e) z rozbiciem per kampania+grupa reklam
And kazdy podwiersz pokazuje pelen zestaw kolumn metryk jak w widoku glownym (w formie tylko-do-odczytu)
And ponowne klikniecie przycisku zwija szczegoly
```
## AC-3: Edycja tylko w wierszu glownym
```gherkin
Given produkt ma rozwiniete podwiersze
When uzytkownik przeglada podwiersze
Then nie ma tam inputow ani przyciskow edycji/usuwania
And inputy `min_roas`, `custom_label_1`, `custom_label_4` oraz akcje pozostaja dostepne tylko w wierszu glownym produktu
```
## AC-4: Brak regresji dla filtrowania i wydajnosci listy
```gherkin
Given nowy tryb agregacji i podwierszy
When uzytkownik zmienia filtry (kampania, grupa, search, CL1, CL4), sortowanie i paginacje
Then tabela zachowuje poprawna liczbe rekordow i sortowanie
And przy wybranej konkretnej grupie reklam zachowanie pozostaje logicznie spojne (bez duplikacji i bez bledow JS/PHP)
And endpoint DataTables nie zwraca bledow SQL ani warningow
```
Task 1: Przebudowa warstwy danych na agregat produktu + szczegoly scope
autoload/factory/class.Products.php
Rozszerzyc factory tak, aby `get_products()` zwracalo dane glownych wierszy agregowane per `p.id` przy `ad_group_id <= 0`, oraz by mozna bylo pobrac szczegoly per kampania/grupa dla zestawu `product_id` z biezacej strony.
Zakres:
- Utrzymac medoo/prepared statements.
- Dostosowac `GROUP BY` i logike licznikow tak, aby `recordsTotal` liczyl produkty, a nie scope, gdy nie ma wybranej grupy.
- Dodac/metody pomocnicze do pobrania breakdownu dla listy produktow bez N+1 (jedno zapytanie z `IN (...)` + grupowanie po stronie PHP).
- Utrzymac zgodnosc sortowania kolumn DataTables dla wiersza glownego.
Unikac:
- SQL sklejanych stringiem bez parametrow.
- Dublowania tej samej logiki obliczen metryk w wielu metodach bez wspolnego helpera.
- `php -l autoload/factory/class.Products.php`
- Szybki test endpointu `/products/get_products/` dla: (a) ad_group_id="", (b) ad_group_id>0 i porownanie liczby rekordow.
- Brak warningow SQL / PHP w logu.
AC-1 i czesc AC-4 spelnione: poprawna agregacja i poprawne liczenie rekordow.
Task 2: Adaptacja kontrolera odpowiedzi DataTables pod dane glowne + breakdown
autoload/controls/class.Products.php
W `get_products()` przebudowac format odpowiedzi JSON tak, aby kazdy wiersz glowny produktu zawieral identyfikator i dane potrzebne do renderu rozwijanych podwierszy (np. `row_meta` / `breakdown_rows`).
Zakres:
- Zachowac obecne formatowanie komorek glownych (ROAS bar, warningi, linki, akcje).
- Dla podwierszy zwracac pelne metryki, ale bez kontrolnych elementow edycji.
- Zachowac kompatybilnosc z istniejacymi handlerami JS, ktore operuja na kolumnach glownych.
Unikac:
- Wykonywania dodatkowego zapytania DB na kazdy pojedynczy wiersz.
- Mieszania HTML edycyjnego do danych podwierszy.
- `php -l autoload/controls/class.Products.php`
- Odpowiedz endpointu zawiera dane breakdown tylko dla produktow z biezacej strony i nie psuje `recordsTotal`, `recordsFiltered`, `data`.
AC-2 i AC-3 backend-ready: API dostarcza dane do podwierszy i oddziela je od edycji.
Task 3: UI DataTable - przycisk rozwin i render podwierszy
templates/products/main_view.php
Dodac w tabeli produktow obsluge rozwijanych podwierszy:
- Przycisk w wierszu glownym (rozwin/zwin) widoczny tylko gdy sa szczegoly.
- Render child-row (DataTables child row) z pelnym zestawem metryk dla kampania+grupa.
- Podwiersze readonly: bez inputow i bez akcji edycyjnych/usuwania.
- Zachowac obecne akcje edycyjne tylko dla glownego wiersza.
Dodatkowo:
- Dodac czytelne style dla child-row (wizualnie odroznione od glownej tabeli).
- Nie przekraczac 3 poziomow zagniezdzenia - wydzielic helpery JS do budowy HTML podwierszy i toggla.
- `php -l templates/products/main_view.php`
- Manual: rozwin/zwin dziala, brak bledow w konsoli, sortowanie/paginacja dalej dziala.
AC-2, AC-3 i pozostala czesc AC-4 spelnione po stronie UI.
Nowy widok listy produktow: glowny agregat per produkt + rozwijane podwiersze kampania/grupa z pelnymi metrykami, bez edycji w podwierszach.
1. Otworz `/products`, wybierz klienta.
2. Ustaw kampanie dowolnie, ale pozostaw "Grupa reklam" na "- wszystkie grupy -".
3. Potwierdz: kazdy produkt jest raz jako wiersz glowny, metryki sa sumaryczne.
4. Kliknij przycisk rozwin przy kilku produktach.
5. Potwierdz: podwiersze pokazuja pelne metryki per kampania/grupa, bez inputow i bez akcji.
6. Zweryfikuj, ze edycja (`min_roas`, `CL1`, `CL4`) dziala tylko w wierszu glownym.
7. Sprawdz sortowanie, paginacje i filtry tekstowe.
8. Sprawdz konsolę przegladarki i logi PHP: brak nowych bledow.
Wpisz "approved" aby przejsc do UNIFY, albo opisz odchylenia do poprawy.
## DO NOT CHANGE
- Migracje bazy i schemat tabel.
- Logika niezalezna od /products (inne kontrolery/widoki).
- Mechanika CSRF/sesji i routing aplikacji.
## SCOPE LIMITS
- Tylko zakladka `/products`.
- Tylko zachowanie listy i sposob prezentacji danych.
- Bez nowych funkcji biznesowych poza agregacja + podwiersze.
Before declaring plan complete:
- [ ] `php -l autoload/factory/class.Products.php`
- [ ] `php -l autoload/controls/class.Products.php`
- [ ] `php -l templates/products/main_view.php`
- [ ] Manualna weryfikacja AC-1..AC-4
- [ ] Brak nowych bledow JS/PHP/SQL
- Widok przy pustym `ad_group_id` pokazuje agregat 1 produkt = 1 wiersz glowny.
- Podwiersze sa rozwijane przyciskiem i pokazuja pelne metryki per kampania/grupa.
- Edycja pozostaje tylko w wierszu glownym.
- Brak regresji filtrow, sortowania i paginacji.