2.`SELECT * FROM cron_schedules WHERE job_type='storage_cleanup';` — potwierdzic wpis enabled=1.
3. Wymusic `UPDATE cron_schedules SET next_run_at=NOW() WHERE job_type='storage_cleanup'` + `php bin/cron.php` (1 cykl) — potwierdzic ze handler dziala przez scheduler.
## Poprzednia praca
UNIFY zakonczony dla `.paul/plans/20260520-1102-fix-allegro-delivery-mapping-save/`. Petla zamknieta. Root-cause: render dwoch widokow (`resources/views/settings/allegro.php` i `resources/views/shipments/prepare.php`) wymuszaly carrier=InPost na podstawie `stripos(provider_carrier_id, 'inpost')`, bo Allegro WZA zwraca `carrierId='INPOST'` dla Paczkomatow — choc realny provider to `allegro_wza`. Zapis DB dzialal poprawnie. Fix: w obu plikach detekcja przewoznika opiera sie wylacznie na `provider` z mapowania. Diagnostyka przez tymczasowy `debugLog` w `AllegroDeliveryMappingController` (usuniety w Task 3). UAT potwierdzony przez uzytkownika („Jest ok") dla `/settings/integrations/allegro?tab=delivery` i `/orders/1189/shipment/prepare`. SUMMARY: `.paul/plans/20260520-1102-fix-allegro-delivery-mapping-save/SUMMARY.md`.
**Zrodlo prawdy:**`database/migrations/` (104 SQL: od `20260221_000001_create_users_table.sql` do `20260517_000118_add_invoice_external_idempotency_state.sql`).
**Zrodlo prawdy:**`database/migrations/` (105 SQL: od `20260221_000001_create_users_table.sql` do `20260520_000119_seed_storage_cleanup_cron.sql`).
-`.env.example` + `CLAUDE.md`: nowy klucz `STORAGE_CLEANUP_DAYS=30` (fallback gdy payload pusty).
- Wpis logu w `storage/logs/app.log` po kazdym uruchomieniu (`[ISO] storage_cleanup: days=N, total_deleted=M, freed_bytes=K, per_dir={...}`).
### Dlaczego
- Brak jakiegokolwiek mechanizmu purge powodowal niekontrolowany wzrost `storage/`: tysiace etykiet PDF w `storage/labels/`, setki plikow sesji PHP w `storage/sessions/`. Operacje na katalogu (backup, kopia, listing) staly sie bardzo wolne.
### Zabezpieczenia
-`storage/data/` (m.in. `users.json`) POZA zakresem skanowania (nie ma na liscie `TARGET_DIRECTORIES`).
-`storage/logs/app.log` na liscie `PROTECTED_RELATIVE` — nigdy nie usuwany niezaleznie od mtime.
-`max(1, days)` przez `resolveDays()` — odporne na payload `{"days":0}`.
- Idempotentne (`ON DUPLICATE KEY UPDATE` w migracji; `@unlink()` bez bledow gdy plik znika rownolegle).
{"ts":"2026-05-19T07:10:01Z","tool":"Bash","cmd":"mkdir -p .paul/plans .paul/codebase/radar .paul/rules/ast-grep .paul/rules/jscpd .paul/changelog .paul/handoffs && ls .paul/\",\"description\":\"Create PAUL directory structure\"},\"tool_response\":{\","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:10:22Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:10:33Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:10:40Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\config.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:10:47Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\radar\\\\impact_map.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:10:55Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\radar\\\\quality_risks.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:11:03Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\radar\\\\tooling_status.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:21:57Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find . -maxdepth 3 -type d | head -100\",\"description\":\"List directory structure\"},\"tool_response\":{\"stdout\":\".\\n./.claude\\n./.claude/comma","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:05Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find . -not -path \"./.git/*\" -type f -name \"*.php\" -o -name \"*.md\" | grep -E \"(config|routes|bootstrap|migration|database)\" | head -50\",\"des","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:10Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find . -not -path \"./.git/*\" -type d | grep -v \"\\\\.git\\\\|node_modules\" | sort\",\"description\":\"List all project directories excluding git\"","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:12Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && pwd && ls -la | head -20\"},\"tool_response\":{\"stdout\":\"/c/visual studio code/projekty/orderPRO\\ntotal 98\\ndrwxr-xr-x 1 jacek 197121 0 M","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:20Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find ./src/Core -type f -name \"*.php\" | head -30\",\"description\":\"List PHP files in src/Core\"},\"tool_response\":{\"stdout\":\"./src/Core/Applic","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:20Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find ./database/migrations -type f -name \"*.php\" | sort\",\"description\":\"List all migration files in order\"},\"tool_response\":{\"stdout\":\"\",","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:21Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && ls -la ./bin/ 2>/dev/null | head -20\",\"description\":\"List files in bin directory\"},\"tool_response\":{\"stdout\":\"total 104\\ndrwxr-xr-x 1 jacek","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:22Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find . -path ./vendor -prune -o -type f -name \"*.php\" | grep -E \"(Controller|Model|Service)\" | head -15\"},\"tool_response\":{\"stdout\":\"./.","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:27Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && ls -la ./database/migrations/\",\"description\":\"List migration files\"},\"tool_response\":{\"stdout\":\"total 398\\ndrwxr-xr-x 1 jacek 197121 0 M","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:28Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && ls -la src/Core/\"},\"tool_response\":{\"stdout\":\"total 28\\ndrwxr-xr-x 1 jacek 197121 0 May 4 10:18 .\\ndrwxr-xr-x 1 jacek 197121 0 May ","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:32Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && ls -la src/Modules/ | head -20\"},\"tool_response\":{\"stdout\":\"total 88\\ndrwxr-xr-x 1 jacek 197121 0 May 12 19:30 .\\ndrwxr-xr-x 1 jacek 19712","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:35Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && ls -la src/Modules/Auth/\"},\"tool_response\":{\"stdout\":\"total 20\\ndrwxr-xr-x 1 jacek 197121 0 May 18 09:30 .\\ndrwxr-xr-x 1 jacek 197121 ","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:39Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find resources -type f | head -20\"},\"tool_response\":{\"stdout\":\"resources/lang/pl.php\\nresources/modules/jquery-alerts/jquery-alerts.css\\nr","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:46Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find resources/views -type f -name \"*.php\" | head -10\"},\"tool_response\":{\"stdout\":\"resources/views/accounting/index.php\\nresources/views/","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:50Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find ./src/Modules -maxdepth 2 -type f -name \"*.php\" | grep -E \"(Controller|Repository|Service)\" | sort\",\"description\":\"Find key classes in Mo","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:54Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find tests -type f -name \"*.php\" | head -15\"},\"tool_response\":{\"stdout\":\"tests/bootstrap.php\\ntests/Unit/AllegroOrderImportServiceTest.ph","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:55Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find ./resources/views -maxdepth 1 -type d | sort\",\"description\":\"List view directories\"},\"tool_response\":{\"stdout\":\"./resources/views\\n./r","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:22:56Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && ls -la ./resources/views/layouts/\",\"description\":\"List layout files\"},\"tool_response\":{\"stdout\":\"total 32\\ndrwxr-xr-x 1 jacek 197121 0 ","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:01Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && ls -la log.md 2>/dev/null | head -5 || echo \"log.md nie znaleziony\"\"},\"tool_response\":{\"stdout\":\"-rw-r--r-- 1 jacek 197121 4574 May 4 10:","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:05Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && head -80 CLAUDE.md\"},\"tool_response\":{\"stdout\":\"# Projektowe zasady dla Codex\\r\\n\\r\\n## Baza danych i migracje\\r\\n- `DB_HOST_REMOTE` j","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:07Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -50 ./database/migrations/20260305_000032_create_company_settings_table.sql\",\"description\":\"Read company settings migration\"},\"tool_respons","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:07Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -80 ./database/migrations/20260330_000073_create_order_payments_table.sql\",\"description\":\"Read order payments migration\"},\"tool_response\":","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:08Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -60 ./database/migrations/20260224_000011_create_cron_and_product_link_alerts_tables.sql\",\"description\":\"Read cron table migration\"},\"tool_","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:08Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && head -100 AGENTS.md\"},\"tool_response\":{\"stdout\":\"# Projektowe zasady dla Codex\\r\\n\\r\\n## Baza danych i migracje\\r\\n- `DB_HOST_REMOTE` ","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:15Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && find ./src/Modules -maxdepth 1 -type d | sort\",\"description\":\"List all modules\"},\"tool_response\":{\"stdout\":\"./src/Modules\\n./src/Modules/Ac","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:18Z","tool":"Bash","cmd":"wc -l \"C:/visual studio code/projekty/orderPRO/src/Modules/Orders/OrdersController.php\"\"},\"tool_response\":{\"stdout\":\"1490 C:/visual studio code/projekty/orderPRO/src/Modules/Orders/OrdersContr","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:21Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -60 ./database/migrations/20260315_000055_create_email_templates_table.sql\"},\"tool_response\":{\"stdout\":\"CREATE TABLE IF NOT EXISTS `email_t","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:21Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -60 ./database/migrations/20260512_000112_create_sms_templates.sql\"},\"tool_response\":{\"stdout\":\"CREATE TABLE IF NOT EXISTS sms_templates (\","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:22Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -60 ./database/migrations/20260412_000097_add_project_generation.sql\"},\"tool_response\":{\"stdout\":\"-- Phase 97: Project Generation\\r\\n-- T","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:27Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && ls -la ./bin/\",\"description\":\"List bin files\"},\"tool_response\":{\"stdout\":\"total 104\\ndrwxr-xr-x 1 jacek 197121 0 May 6 09:59 .\\ndrwxr","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:28Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -40 ./bin/migrate.php\",\"description\":\"Read migrate bin file\"},\"tool_response\":{\"stdout\":\"<?php\\r\\ndeclare(strict_types=1);\\r\\n\\r\\","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:28Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && head -40 ./bin/cron.php\",\"description\":\"Read cron bin file\"},\"tool_response\":{\"stdout\":\"<?php\\r\\ndeclare(strict_types=1);\\r\\n\\r\\nuse A","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:29Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find src/Core -type f -name \"*.php\" | head -20\"},\"tool_response\":{\"stdout\":\"src/Core/Application.php\\nsrc/Core/Constants/IntegrationSourc","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:34Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/orderPRO\" && wc -l database/migrations/*.sql | tail -1\",\"description\":\"Count total lines in migrations\"},\"tool_response\":{\"stdout\":\" 2880 total\",\"stde","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:39Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && ls -la resources/lang/\"},\"tool_response\":{\"stdout\":\"total 84\\ndrwxr-xr-x 1 jacek 197121 0 May 19 09:07 .\\ndrwxr-xr-x 1 jacek 197121 ","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:45Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && head -50 src/Modules/Auth/AuthService.php\"},\"tool_response\":{\"stdout\":\"<?php\\r\\ndeclare(strict_types=1);\\r\\n\\r\\nnamespace App\\\\Modul","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:48Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find src/Modules -name \"*Repository.php\" -type f | head -5\"},\"tool_response\":{\"stdout\":\"src/Modules/Accounting/InvoiceRepository.php\\nsrc","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:23:57Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && grep -r \"function e(\" src/ --include=\"*.php\" | head -5\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\"","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:02Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && grep -r \"e\\\\(\" resources/views/ --include=\"*.php\" | head -3\"},\"tool_response\":{\"stdout\":\"grep: Unmatched ( or \\\\(\",\"stderr\":\"\",","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:07Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && grep -r '$e(' resources/views/ --include=\"*.php\" | head -3\"},\"tool_response\":{\"stdout\":\"resources/views/accounting/index.php: <h2 cla","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:13Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && find src/Core -name \"*.php\" | xargs grep -l \"function.*escape\\\\|e(\" 2>/dev/null | head -5\"},\"tool_response\":{\"stdout\":\"src/Core/Applic","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:19Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && grep -A 5 \"function e\\\\|escape\\\\|\\\\$e =\" src/Core/View/*.php | head -30\"},\"tool_response\":{\"stdout\":\" $e = static fn (mixed $","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:24Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && head -40 resources/scss/app.scss\"},\"tool_response\":{\"stdout\":\"@use \"shared/ui-components\";\\r\\n@use \"modules/email-send\";\\r\\n@use \"m","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:29Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && head -60 resources/modules/jquery-alerts/jquery-alerts.js\"},\"tool_response\":{\"stdout\":\"\"use strict\";\\r\\n\\r\\n(function (factory) {\\r\\","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:24:34Z","tool":"Bash","cmd":"cd /c/visual\\\\ studio\\\\ code/projekty/orderPRO && tail -50 resources/modules/jquery-alerts/jquery-alerts.js | head -40\"},\"tool_response\":{\"stdout\":\" }\\r\\n };\\r\\n var cle","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:25:00Z","tool":"Bash","cmd":"for dir in \"C:/visual studio code/projekty/orderPRO/src/Modules\"/*; do echo \"=== $(basename \"$dir\") ===\"; ls -1 \"$dir\" | head -10; done\"},\"tool_response\":{\"stdout\":\"=== Accounting ===\\n","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:27:18Z","tool":"Bash","cmd":"for file in \"C:/visual studio code/projekty/orderPRO/src/Modules/Orders/OrdersController.php\" \"C:/visual studio code/projekty/orderPRO/src/Modules/Orders/OrdersRepository.php\" \"C:/visual studio c","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:29:00Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\stack.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:29:31Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\integrations.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:30:16Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\architecture.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:31:51Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\db_schema.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:32:34Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\conventions.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:32:57Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\testing.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:33:51Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\impact_map.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:34:50Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\quality_risks.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:35:11Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\tooling_status.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:35:27Z","tool":"Bash","cmd":"rm .paul/codebase/radar/impact_map.md .paul/codebase/radar/quality_risks.md .paul/codebase/radar/tooling_status.md && ls .paul/codebase/ && echo \"--- radar:\" && ls .paul/codebase/radar/\",\"descript","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:35:38Z","tool":"Edit","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:45:08Z","tool":"Write","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\radar\\\\codebase-memory-full.txt","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T07:45:15Z","tool":"Edit","file":"c:\\\\visual studio code\\\\projekty\\\\orderPRO\\\\.paul\\\\codebase\\\\tooling_status.md","cwd":"/c/visual studio code/projekty/orderPRO"}
{"ts":"2026-05-19T10:33:16Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Auto/pudełka na chrzest - mak","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:35:51Z","tool":"Bash","cmd":"python tools/generowanie/_rename_layers.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Auto/pudełka na chrzest - m","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:38:26Z","tool":"Bash","cmd":"rm tools/generowanie/_explore_psd.py tools/generowanie/_rename_layers.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV ","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:52:45Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:53:17Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:57:36Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:58:02Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/Pudełko na pieniądze z","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T10:59:13Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:00:23Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:01:05Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:01:44Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:02:26Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:03:17Z","tool":"Bash","cmd":"python tools/generowanie/_explore_psd.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ma","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:03:54Z","tool":"Bash","cmd":"python tools/generowanie/_check_layers.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - m","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T11:04:30Z","tool":"Bash","cmd":"python tools/generowanie/_rename_layers.py \"d:/pomysloweprezenty.pl/projekty/ślub - pudełka na pieniądze/Pudełko na pieniądze z życzeniami na Ślub z nadrukiem UV - Serce/pudełka na chrzest - ","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:02:44Z","tool":"Bash","cmd":"vendor/bin/phpunit tests/Unit/Core/Routing/ 2>&1 | tail -20\",\"description\":\"Run new ServiceRegistry tests\"},\"tool_response\":{\"stdout\":\"/usr/bin/bash: line 1: vendor/bin/phpunit: No such file","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:03:05Z","tool":"Bash","cmd":"composer install --no-interaction 2>&1 | tail -20\",\"timeout\":180000,\"description\":\"Install composer dependencies\"},\"tool_response\":{\"stdout\":\"/usr/bin/bash: line 1: composer: command not f","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:03:54Z","tool":"Bash","cmd":"php -r \"require 'src/Core/Routing/ServiceRegistry.php'; \\\\$r = new App\\\\Core\\\\Routing\\\\ServiceRegistry(); \\\\$calls = 0; \\\\$r->set('foo', function() use (&\\\\$calls) { \\\\$calls++; retur","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:16:33Z","tool":"Bash","cmd":"php -l routes/web.php && wc -l routes/web.php\",\"description\":\"Lint new routes/web.php\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in routes/web.php\\n78 routes/web.php\",\"stderr\","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:17:06Z","tool":"Bash","cmd":"vendor/bin/phpunit 2>&1 | tail -25\",\"timeout\":120000,\"description\":\"Run full test suite\"},\"tool_response\":{\"stdout\":\"C:\\\\visual-studio-code\\\\projekty\\\\orderPRO\\\\src\\\\Modules\\\\S","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:17:20Z","tool":"Bash","cmd":"vendor/bin/phpunit 2>&1 | grep -E \"^[0-9]+\\\\)|FAILED|OK|Tests:|^There were\" | head -30\",\"description\":\"Summary of test results\"},\"tool_response\":{\"stdout\":\"There were 3 errors:\\n1) Test","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:17:34Z","tool":"Bash","cmd":"git stash -u 2>&1 | tail -3; vendor/bin/phpunit 2>&1 | tail -3; git stash pop 2>&1 | tail -3\",\"timeout\":180000,\"description\":\"Compare test results with pre-refactor baseline\"},\"tool_response\"","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:19:36Z","tool":"Bash","cmd":"php tests/route_smoke.php 2>&1 | head -10\",\"description\":\"Run register() smoke test\"},\"tool_response\":{\"stdout\":\"WARN: Application could not boot (DB unavailable). Smoke test limited to regi","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T19:22:19Z","tool":"Bash","cmd":"git status --short 2>&1 | head -40\",\"description\":\"Show changed files\"},\"tool_response\":{\"stdout\":\" M .paul/STATE.md\\n M .paul/codebase/architecture.md\\n M .paul/governance/governance_2026","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-19T20:59:10Z","tool":"Bash","cmd":"git diff --name-only HEAD; echo ---; git status -s\",\"description\":\"Lista zmienionych plików\"},\"tool_response\":{\"stdout\":\"warning: in the working copy of '.paul/codebase/tech_changelog.md', ","cwd":"/c/visual-studio-code/projekty/orderPRO"}
{"ts":"2026-05-20T06:23:51Z","tool":"Bash","cmd":"mkdir -p .paul/plans/20260520-1200-fix-login-page-and-remember-me\",\"description\":\"Create plan directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":fals","cwd":"/c/visual-studio-code/projekty/orderPRO"}
Dodać cyklicznie uruchamiany handler crona, który usuwa pliki starsze niż 30 dni z katalogów `storage/labels/`, `storage/sessions/`, `storage/tmp/`, `storage/logs/` oraz `storage/cache/`.
## Powod
`storage/` rośnie w nieskończoność — w `storage/labels/` są już tysiące PDFów etykiet kurierskich, w `storage/sessions/` setki plików sesji. Brak jakiegokolwiek mechanizmu purge powoduje stały przyrost zajmowanego miejsca na dysku i znacznie wydłuża operacje na katalogu (kopia, backup, listing). Konwencja w projekcie istnieje już dla `automation_execution_logs` (`AutomationHistoryCleanupHandler`) — replikujemy ten wzorzec dla plików.
## Wynik
- Nowa klasa `App\Modules\Cron\StorageCleanupHandler` (handler crona, < 100 lin., jedna odpowiedzialność).
- Wpis w `CronHandlerFactory::handlers()` z kluczem `storage_cleanup`.
- Migracja seedująca wpis `cron_schedules` (interwał 86400 s = doba, payload `{"days":30}`).
- Konfiguracja przez `STORAGE_CLEANUP_DAYS` w `.env.example` (override payloadu domyślnie 30).
- Log wykonania w `storage/logs/app.log` (sumarycznie per katalog: ile plików usunięto, ile bajtów odzyskano).
-`storage/data/` jest WYŁĄCZONE z czyszczenia (runtime data, m.in. `users.json`).
- Aktywny plik `storage/logs/app.log` jest pomijany (nigdy nie usuwamy, niezależnie od `mtime`) — gdyby był starszy niż 30 dni, jego rotacja może być zrobiona w osobnym planie.
- Aktywne pliki sesji (z `mtime` w okresie żywotności PHP session) i tak zostaną usunięte tylko jeśli > 30 dni — w praktyce sesje wygasają wcześniej, więc bezpiecznie.
</clarifications>
<impact_scan>
## Quality Radar
**Status:** ok
**Tools:** codebase-memory-mcp (jscpd/ast-grep disabled by policy — bez zmian)
## Affected Areas
-`src/Modules/Cron/` — nowy handler (klucz `storage_cleanup`) + rejestracja w `CronHandlerFactory::handlers()`.
-`database/migrations/` — nowa migracja seed `cron_schedules` (numer 000119, kolizji z istniejącymi numerami brak — ostatnia migracja `20260517_000118_*`).
-`config/app.php` / `.env.example` — opcjonalny klucz `STORAGE_CLEANUP_DAYS` (czytany w handlerze z `$payload['days']`, fallback do env, fallback do 30).
- Powtarzający się szablon "cron handler + seed migration" (`AutomationHistoryCleanupHandler`, `OrderStatusAgedHandler`, `ShipmentTrackingHandler` itp.) — świadomie akceptujemy ten sam wzorzec, jest stabilny. Nie wprowadzamy bazowej klasy w tym planie (out of scope).
- Hardcoded lista katalogów do czyszczenia — trzymana jako stała `private const TARGET_DIRECTORIES` wewnątrz handlera (jasna source-of-truth w jednym miejscu).
## Explicit Deferrals
- Rotacja `storage/logs/app.log` (rolling log file, np. dzienny) — odrębne wymaganie, nie w zakresie tego planu.
- Czyszczenie `storage/data/` — celowo poza zakresem (runtime persistence).
- Bazowy `AbstractCronHandler` redukujący boilerplate — patrz `quality_risks.md` ("Cron handlery `*OrdersImportHandler` ... szablon ten sam") — out of scope.
</impact_scan>
<skills>
Brak `.paul/SPECIAL-FLOWS.md` w projekcie — sekcja pomijana.
</skills>
<acceptance_criteria>
## AC-1: Handler usuwa pliki starsze niż 30 dni z wskazanych katalogów
```gherkin
Given katalogistorage/labels,storage/sessions,storage/tmp,storage/logs,storage/cachezawierająpliki
- rozwiń pełną ścieżkę przez `$this->basePath . '/' . $dir`,
- jeśli katalog nie istnieje — pomiń (zapisz `deleted=0, freed_bytes=0`),
- skanuj rekurencyjnie przez `RecursiveIteratorIterator(RecursiveDirectoryIterator(..., SKIP_DOTS))`,
- dla każdego pliku (NIE katalogu): sprawdź czy nie jest w `PROTECTED_FILES` (porównuj po znormalizowanej ścieżce względem `$basePath`), jeśli `filemtime() < $threshold` — `@unlink()` i agreguj `deleted++, freed_bytes += filesize()` (rozmiar pobierz przed unlink).
4. Zapisz do `app.log` przez `error_log("[storage_cleanup] days=$days, total_deleted=$total, freed_bytes=$bytes, per_dir=" . json_encode($perDir), 3, $this->logPath)`.
1. W `CronHandlerFactory.php` w metodzie `handlers()` po wpisie `'automation_history_cleanup' => ...` dodaj:
```php
'storage_cleanup' => new StorageCleanupHandler(
$this->basePath,
$this->basePath . '/storage/logs/app.log'
),
```
2. Dodaj `use App\Modules\Cron\StorageCleanupHandler;` jeśli wymagane (sprawdź czy klasy w tym samym namespace nie wymagają use — w tym pliku nie wymagają, bo to ten sam namespace).
3. Jeśli `$this->basePath` nie istnieje jako property w `CronHandlerFactory` — sprawdź konstruktor (`__construct(... $basePath ...)`). Jeśli brakuje — dopisz `private readonly string $basePath` do propertis i parametru konstruktora; w `CronModule.php` przekaż `$app->basePath()` do `CronHandlerFactory::__construct`.
Interwał 86400 s = raz dziennie. Priority 80 (po `automation_history_cleanup=70`, niżej niż importy ~10).
</action>
<verify>Uruchom `composer migrate` (lub `php bin/migrate.php`) na środowisku lokalnym i potwierdź wpis: `SELECT job_type, enabled, payload FROM cron_schedules WHERE job_type='storage_cleanup';`</verify>
<done>AC-3</done>
</task>
<task type="auto">
<name>Task 4: Konfiguracja .env.example i CLAUDE.md</name>
<files>.env.example, CLAUDE.md</files>
<action>
1. W `.env.example` w sekcji crona (po `CRON_PUBLIC_TOKEN=`) dopisz:
2. W `CLAUDE.md` (root) dodaj sekcję (po istniejących regułach):
```
## Storage retention
- Pliki w `storage/labels/`, `storage/sessions/`, `storage/tmp/`, `storage/logs/`, `storage/cache/` starsze niż `STORAGE_CLEANUP_DAYS` (default 30) są usuwane przez cron handler `storage_cleanup`.
- `storage/data/` jest WYŁĄCZONE z czyszczenia (runtime data jak users.json).
- `storage/logs/app.log` jest chroniony przed usunięciem niezależnie od mtime.
1. `architecture.md` — w tabeli "Moduly domenowe" w wierszu Cron dopisz handler `storage_cleanup` (lista handlerów). W sekcji "Konwencje katalogow" przy `storage/` dopisz "z auto-czyszczeniem >30 dni (cron `storage_cleanup`, wyjątek `storage/data/`, `storage/logs/app.log`)".
2. `db_schema.md` — w sekcji "Cron i app settings" dopisz wpis o migracji `000119` (seed `storage_cleanup` w `cron_schedules`). W sekcji "Uwaga: kolizje numerow migracji" zaktualizuj zakres `do 000119`.
- `storage/data/` — runtime data (users.json, etc.). Nigdy nie skanować ani usuwać.
- `storage/logs/app.log` — aktywny plik logu, na liście `PROTECTED_FILES`.
- Istniejące handlery crona (`AutomationHistoryCleanupHandler`, `OrderStatusAgedHandler`, itp.) — bez zmian.
- Kontrakt `CronRunner` / `CronRepository` — bez zmian, korzystamy z istniejącego mechanizmu rejestracji handlerów.
- Numeracja istniejących migracji — używamy nowego numeru 000119.
## Scope Limits
- Nie wprowadzamy bazowego `AbstractCronHandler` (boilerplate akceptowalny).
- Nie wprowadzamy rotacji `app.log` (osobne wymaganie).
- Nie dodajemy UI do zarządzania zadaniem (cron już ma własne tabele i istniejące widoki w `/settings/cron`).
- Nie dodajemy testów PHPUnit (zgodnie z lukami testowymi w `quality_risks.md` — Cron handlery nie mają pokrycia; nie wprowadzamy precedensu w tym planie).
- Nie zmieniamy `php.ini` ustawień session GC.
</boundaries>
<verification>
- [ ] `php -l` czysty dla wszystkich zmienionych/nowych plików PHP.
- [ ] `php bin/migrate.php` wykonuje migrację 000119 bez błędu.
- [ ] `SELECT * FROM cron_schedules WHERE job_type='storage_cleanup'` zwraca wpis enabled=1, payload `{"days":30}`.
- [ ] Smoke test (Task 6) potwierdza: stary plik (mtime -40d) usunięty, świeży plik (mtime dziś) zachowany, log zapisany.
- [ ] `storage/data/` po smoke teście niezmieniony (`ls storage/data/` przed i po identyczne).
- [ ] `storage/logs/app.log` istnieje po smoke teście (nawet jeśli stary).
Dodanie cyklicznego mechanizmu purgu plikow >30 dni w `storage/{labels,sessions,tmp,logs,cache}`. Przed tym planem `storage/` rosl w nieskonczonosc (tysiace etykiet PDF, setki plikow sesji) — brak jakiegokolwiek auto-cleanup.
| AC-3 | Rejestracja w CronHandlerFactory + migracja seed | **PASS (kod)** / **PARTIAL (runtime)** | `grep` potwierdza wpis `storage_cleanup` w `CronHandlerFactory.php`; migracja `000119` utworzona, ALE NIE zaaplikowana w DB (DB niedostepna w sesji APPLY). Pelne potwierdzenie wymaga `php bin/migrate.php` + `SELECT FROM cron_schedules`. |
| AC-4 | Konfiguracja przez env, payload ma priorytet, `max(1, days)` | **PASS** | `resolveDays()`: payload>0 wygrywa, inaczej `getenv('STORAGE_CLEANUP_DAYS')`, inaczej fallback 30; smoke test z `{days:30}` zwrocil `days=30` |
| Offline smoke test (`storage/tmp/storage_cleanup_smoke.php`) | **PASS** (7/7) | Stary plik usuniety, swiezy zachowany, `app.log` chroniony, `storage/data/` nietkniete, result OK, `days=30`, `deleted_count>=1` |
| Log do `storage/logs/app.log` | **PASS** | 2 wpisy `storage_cleanup: ...` w formacie ISO 8601 |
| `php bin/migrate.php` (migracja 000119 w DB) | **SKIPPED** | DB niedostepna w sesji (`mysql:host=localhost` connection refused). Do recznego UAT. |
| `php bin/cron.php` (uruchomienie przez scheduler) | **SKIPPED** | Wymaga DB. Do recznego UAT. |
## Quality Radar Results
**Status:** skipped (post-apply scan pominiety — pojedynczy nowy plik handlera w ramach istniejacego wzorca `Cron/*Handler.php`; brak nowych typow ryzyka)
- Nowe ryzyka: brak. Wzorzec "cron handler" juz znany (`AutomationHistoryCleanupHandler`, `OrderStatusAgedHandler`).
- Rozwiazane ryzyka: brak konkretnego wpisu w `quality_risks.md` byl zglaszany jako "brak czyszczenia storage/" — nie istnial formalnie w radarze, byl zglaszony przez uzytkownika ad-hoc.
- Odroczone ryzyka: rotacja `storage/logs/app.log` (osobne wymaganie), bazowy `AbstractCronHandler` (refaktor boilerplate "Cron handlery `*OrdersImportHandler` ... szablon ten sam" z `quality_risks.md`).
- Raw outputs: brak nowych w `.paul/codebase/radar/`.
## Deviations
- **Task 6 (smoke test pelny) — SKIPPED**: DB niedostepna w sesji (`mysql:host=localhost` aktywnie odmawia polaczenia). Zamiast tego wykonano **offline smoke test** (`storage/tmp/storage_cleanup_smoke.php`, usuniety po wykonaniu) — 7/7 OK, walidujacy logike handlera w izolacji od crona. Migracja `000119` i uruchomienie przez `CronRunner` wymagaja recznego UAT po stronie uzytkownika (kroki opisane w STATE.md "Do weryfikacji recznej").
- **Task 2 — `CronModule` NIE byl modyfikowany**: w planie sugerowano, ze moze byc konieczne dopisanie `basePath` do konstruktora `CronHandlerFactory`. W praktyce property `private readonly string $basePath` juz istniala (`CronHandlerFactory.php:75`) — wystarczyl jeden wpis w `handlers()`. Mniej zmian niz w planie.
## Key Decisions / Patterns
- **`PROTECTED_RELATIVE` jako lista whitelistowa** zamiast specjalnej logiki per katalog: handler zna jedna stala z relatywnymi sciezkami plikow nigdy-nie-usuwalnych. Pozwala latwo dolozyc kolejne (np. `storage/data/users.json` gdyby kiedys zostal wciagniety do skanowania).
- **`resolveDays()` priorytetuje payload nad env** — pozwala adminowi nadpisac retencje per-srodowisko (env) ale zachowac kontrole na poziomie wpisu DB (payload), zgodnie z konwencja istniejacych handlerow.
- **Wpis logu jako pojedyncza linia z `json_encode(per_dir)`** — czytelne dla `tail -f` i parsowalne maszynowo, zgodne z innymi wpisami w `app.log`.
- **Priority 80** w `cron_schedules` (po `automation_history_cleanup=70`, znacznie nizej niz importy ~10) — czyszczenie to "housekeeping", nie blokuje importow.
## Follow-up
1.**Reczny UAT (DB-side)** — kolejnosc krokow w STATE.md:
-`php bin/migrate.php` (zaaplikowac 000119),
-`SELECT * FROM cron_schedules WHERE job_type='storage_cleanup'` (potwierdzic enabled=1),
-`UPDATE cron_schedules SET next_run_at=NOW() WHERE job_type='storage_cleanup'` + `php bin/cron.php` (jeden cykl),
- Bazowy `AbstractCronHandler` redukujacy boilerplate w handlerach (`quality_risks.md`).
3.**Commit:** plan gotowy do skomitowania razem z zaleglymi pracami (refaktory Statistics + Allegro + DeliveryStatus + obecny cron). Sugestia: osobny commit `feat(cron): storage_cleanup handler with 30-day retention`.
- Komenda `php` jest dostepna z instalacji XAMPP (`C:\xampp\php\php.exe`).
- Jezeli `php` nie jest widoczne w terminalu, dodaj `C:\xampp\php` do zmiennej `PATH` (User).
## Storage retention
- Pliki w `storage/labels/`, `storage/sessions/`, `storage/tmp/`, `storage/logs/`, `storage/cache/` starsze niz `STORAGE_CLEANUP_DAYS` (default 30) sa usuwane przez cron handler `storage_cleanup` (`src/Modules/Cron/StorageCleanupHandler.php`), interwal 24h.
-`storage/data/` jest WYLACZONE z czyszczenia (runtime data jak `users.json`).
-`storage/logs/app.log` jest chroniony przed usunieciem niezaleznie od mtime.
- Override liczby dni: payload `{"days":N}` w `cron_schedules` dla wpisu `storage_cleanup` (priorytetowo) lub `STORAGE_CLEANUP_DAYS` w `.env` (fallback).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.