diff --git a/.vscode/ftp-kr.json b/.vscode/ftp-kr.json index 85be91f..192f806 100644 --- a/.vscode/ftp-kr.json +++ b/.vscode/ftp-kr.json @@ -12,6 +12,10 @@ "ignoreRemoteModification": true, "ignore": [ ".git", - "/.vscode" + "/.vscode", + "/.serena", + "/.claude", + "CLAUDE.md", + "AGENTS.md" ] } \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..262f599 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,46 @@ +# Repository Guidelines + +## Struktura projektu i organizacja modułów +To repozytorium zawiera aplikację PHP w lekkiej architekturze MVC do zarządzania reklamami. + +- Punkty wejścia: `index.php`, `ajax.php`, `api.php`, `cron.php`, `install.php` +- Kontrolery: `autoload/controls/class.*.php` (`\controls`) +- Fabryki (dostęp do danych): `autoload/factory/class.*.php` (`\factory`) +- Warstwa widoku: `autoload/view/class.*.php` (`\view`) +- Integracje zewnętrzne (Google Ads, OpenAI, Claude, Meta): `autoload/services/` +- Szablony: `templates//` +- Style: `layout/style.scss` -> `layout/style.css` +- Zmiany schematu bazy: `migrations/*.sql` (numerowane, przyrostowe) +- Dokumentacja techniczna i notatki: `docs/` + +## Komendy build/test/development +- `php -S localhost:8000` - uruchamia lokalny serwer PHP z katalogu repozytorium. +- `php install.php` - wykonuje oczekujące migracje bazy danych. +- `php install.php --with_demo` - wykonuje migracje i ładuje dane demonstracyjne. +- `php install.php --force` - wymusza ponowne uruchomienie wszystkich migracji (ostrożnie). +- `php -l ścieżka\do\pliku.php` - sprawdza składnię pliku PHP. + +Projekt nie wymaga standardowo pipeline `Node`/`Composer` do uruchomienia. SCSS kompiluje się zwykle przez VS Code Live Sass Compiler podczas edycji `layout/style.scss`. + +## Styl kodu i konwencje nazewnictwa +- Zachowuj obecny wzorzec nazw plików/klas: `class.Moduł.php`, namespace małymi literami (np. `\controls`). +- Nazwy klas: `PascalCase`; metody, zmienne i kolumny DB: `snake_case`. +- Utrzymuj styl formatowania zgodny z edytowanym plikiem (historyczny styl nawiasów i wcięć). +- Preferuj małe, statyczne metody w kontrolerach/fabrykach oraz jawne tablice danych do szablonów/JSON. + +## Wytyczne testowania +W repozytorium nie ma obecnie skonfigurowanego automatycznego zestawu testów (`phpunit` nie jest skonfigurowany). + +- Wykonuj ręczne testy smoke dla zmienionych tras, np. `/campaigns/main_view`, `/users/settings`. +- Dla zmian w API/AJAX sprawdzaj odpowiedzi JSON zarówno dla sukcesu, jak i błędów. +- Przed PR uruchamiaj `php -l` dla każdego modyfikowanego pliku PHP. + +## Zasady commitów i pull requestów +- Stosuj krótkie, rzeczowe komunikaty commitów. Historia preferuje prefiksy Conventional Commits, szczególnie `feat:` (oraz `fix:`, `refactor:`, `chore:`). +- Jeden commit powinien obejmować jeden spójny zakres zmian (schema, backend, UI). +- PR powinien zawierać: cel zmian, listę zmienionych modułów/ścieżek, wpływ na migracje, kroki testowe i zrzuty ekranu dla zmian UI. +- Dodawaj powiązane ID zadania/issue, jeśli istnieją. + +## Bezpieczeństwo i konfiguracja +- Traktuj `config.php` i klucze API jako dane wrażliwe; nie commituj prawdziwych sekretów. +- Tymczasowe pliki debugowe z `tmp/` nie powinny trafiać do commitów produkcyjnych, chyba że jest to celowe. diff --git a/autoload/controls/class.Cron.php b/autoload/controls/class.Cron.php index f193c67..b955084 100644 --- a/autoload/controls/class.Cron.php +++ b/autoload/controls/class.Cron.php @@ -2201,6 +2201,16 @@ class Cron $campaigns_all_time = []; } + // Brak danych kampanii dla dnia: nie zapisujemy zerowego snapshotu historii. + if ( empty( $campaigns_30 ) ) + { + return [ + 'processed_records' => 0, + 'ad_groups_synced' => 0, + 'errors' => [] + ]; + } + $all_time_map = []; $all_time_totals = [ 'cost' => 0.0, 'conversion_value' => 0.0 ]; foreach ( $campaigns_all_time as $cat ) diff --git a/autoload/services/class.GoogleAdsApi.php b/autoload/services/class.GoogleAdsApi.php index a5d5564..3aa7478 100644 --- a/autoload/services/class.GoogleAdsApi.php +++ b/autoload/services/class.GoogleAdsApi.php @@ -2552,55 +2552,6 @@ class GoogleAdsApi unset( $c['cost_total'] ); } - // Fallback: gdy raport metryk zwraca pusty wynik dla danego dnia/okna, - // pobieramy aktywne kampanie, aby zachowac budzet/strategie zamiast pustych rekordow. - if ( empty( $campaigns ) ) - { - $meta_gaql = "SELECT " - . "campaign.id, " - . "campaign.name, " - . "campaign.advertising_channel_type, " - . "campaign.bidding_strategy_type, " - . "campaign.target_roas.target_roas, " - . "campaign_budget.amount_micros " - . "FROM campaign " - . "WHERE campaign.status = 'ENABLED'"; - - $meta_rows = $this -> search_stream( $customer_id, $meta_gaql ); - if ( is_array( $meta_rows ) ) - { - foreach ( $meta_rows as $row ) - { - $cid = $row['campaign']['id'] ?? null; - if ( !$cid ) - { - continue; - } - - if ( isset( $campaigns[ $cid ] ) ) - { - continue; - } - - $campaigns[ $cid ] = [ - 'campaign_id' => $cid, - 'campaign_name' => $row['campaign']['name'] ?? '', - 'advertising_channel_type' => (string) ( $row['campaign']['advertisingChannelType'] ?? '' ), - 'bidding_strategy' => $row['campaign']['biddingStrategyType'] ?? 'UNKNOWN', - 'target_roas' => isset( $row['campaign']['targetRoas']['targetRoas'] ) - ? (float) $row['campaign']['targetRoas']['targetRoas'] - : 0, - 'budget' => isset( $row['campaignBudget']['amountMicros'] ) - ? (float) $row['campaignBudget']['amountMicros'] / 1000000 - : 0, - 'money_spent' => 0, - 'conversion_value' => 0, - 'roas_30_days' => 0, - ]; - } - } - } - return array_values( $campaigns ); }