Phase 2 complete (4/4 plans): - Plan 02-01: Fix dead ZPL page size condition in AllegroShipmentService - Plan 02-02: Add time-based cursor to AllegroStatusSyncService - Plan 02-03: Fix ShopproOrdersSyncService using wrong state repository - Plan 02-04: Extract CronHandlerFactory as single cron composition point Plan 02-04 specifics: - New CronHandlerFactory builds complete cron object graph - Application::maybeRunCronOnWeb() reduced from 80+ to ~20 lines - bin/cron.php reduced from 123 to 26 lines - Fixed 2 bugs: AllegroOAuthClient→AllegroTokenManager, AllegroOrderSyncStateRepository→ShopproOrderSyncStateRepository Co-Authored-By: Claude <noreply@anthropic.com>
242 lines
11 KiB
Markdown
242 lines
11 KiB
Markdown
---
|
||
phase: 02-bug-fixes
|
||
plan: 04
|
||
type: execute
|
||
wave: 1
|
||
depends_on: []
|
||
files_modified:
|
||
- src/Modules/Cron/CronHandlerFactory.php
|
||
- src/Core/Application.php
|
||
- bin/cron.php
|
||
autonomous: true
|
||
---
|
||
|
||
<objective>
|
||
## Cel
|
||
Wydzielić `CronHandlerFactory` — jedyne miejsce, które buduje graf obiektów dla crona. Zastąpić nią ręczną konstrukcję w `Application::maybeRunCronOnWeb()` oraz `bin/cron.php`.
|
||
|
||
## Powód
|
||
`Application.php` (linie 274–353) zawiera 80+ linii ręcznego `new X($this->db)` powielających okablowanie z `bin/cron.php`. Oba miejsca mogą się rozjechać — już teraz `bin/cron.php` przekazuje `AllegroOAuthClient` tam, gdzie powinien być `AllegroTokenManager`, oraz używa `AllegroOrderSyncStateRepository` zamiast `ShopproOrderSyncStateRepository` dla shopPRO.
|
||
|
||
## Output
|
||
- Nowy plik `src/Modules/Cron/CronHandlerFactory.php`
|
||
- `Application.php::maybeRunCronOnWeb()` skrócona do ~10 linii
|
||
- `bin/cron.php` skrócone do ~15 linii
|
||
- Oba błędy w `bin/cron.php` naprawione przy okazji
|
||
</objective>
|
||
|
||
<context>
|
||
## Kontekst projektu
|
||
@.paul/PROJECT.md
|
||
@.paul/ROADMAP.md
|
||
@.paul/STATE.md
|
||
|
||
## Pliki źródłowe
|
||
@src/Core/Application.php
|
||
@bin/cron.php
|
||
@routes/web.php
|
||
</context>
|
||
|
||
<skills>
|
||
## Required Skills (from SPECIAL-FLOWS.md)
|
||
|
||
| Skill | Priority | When to Invoke | Loaded? |
|
||
|-------|----------|----------------|---------|
|
||
| /code-review | required | Po implementacji, przed UNIFY | ○ |
|
||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||
|
||
**BLOCKING:** Required skills MUST be loaded before APPLY proceeds.
|
||
|
||
## Skill Invocation Checklist
|
||
- [ ] /code-review loaded
|
||
- [ ] sonar-scanner run po zakończeniu implementacji
|
||
</skills>
|
||
|
||
<acceptance_criteria>
|
||
|
||
## AC-1: Jeden punkt definicji handlerow crona
|
||
```gherkin
|
||
Given codebase z trzema miejscami budującymi graf obiektów crona
|
||
When plik CronHandlerFactory.php istnieje
|
||
Then Application.php i bin/cron.php nie zawierają już new AllegroIntegrationRepository / new ShopproIntegrationsRepository / new AllegroOrderImportService w kontekście crona — wszystkie obiekty buduje fabryka
|
||
```
|
||
|
||
## AC-2: Web cron działa identycznie jak przed zmianą
|
||
```gherkin
|
||
Given ustawienie cron_run_on_web = true w bazie
|
||
When użytkownik odwiedza dowolną stronę aplikacji
|
||
Then maybeRunCronOnWeb() uruchamia CronRunner z tymi samymi handlerami co wcześniej — brak regresji funkcjonalnej
|
||
```
|
||
|
||
## AC-3: bin/cron.php używa poprawnych zależności
|
||
```gherkin
|
||
Given bin/cron.php przed zmianą używał AllegroOAuthClient zamiast AllegroTokenManager (arg #2 AllegroOrderImportService i AllegroOrdersSyncService) oraz AllegroOrderSyncStateRepository zamiast ShopproOrderSyncStateRepository dla ShopproOrdersSyncService
|
||
When bin/cron.php zostanie zaktualizowany do użycia CronHandlerFactory
|
||
Then oba błędy są naprawione — fabryka przekazuje AllegroTokenManager i ShopproOrderSyncStateRepository
|
||
```
|
||
|
||
</acceptance_criteria>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto">
|
||
<name>Task 1: Utwórz CronHandlerFactory</name>
|
||
<files>src/Modules/Cron/CronHandlerFactory.php</files>
|
||
<action>
|
||
Utwórz klasę `App\Modules\Cron\CronHandlerFactory` w nowym pliku.
|
||
|
||
Konstruktor: `__construct(private readonly \PDO $db, private readonly string $integrationSecret)`.
|
||
|
||
Metoda publiczna: `build(CronRepository $cronRepository, \App\Core\Support\Logger $logger): CronRunner`.
|
||
|
||
Wewnątrz `build()` skonstruuj dokładnie te same obiekty co w `Application::maybeRunCronOnWeb()` (stan po naprawie z planu 02-03, czyli wersja z `Application.php` — NIE z `bin/cron.php`):
|
||
|
||
```
|
||
$integrationRepository = new AllegroIntegrationRepository($this->db, $this->integrationSecret)
|
||
$oauthClient = new AllegroOAuthClient()
|
||
$tokenManager = new AllegroTokenManager($integrationRepository, $oauthClient)
|
||
$apiClient = new AllegroApiClient()
|
||
$statusMappingRepository = new AllegroStatusMappingRepository($this->db)
|
||
$orderImportService = new AllegroOrderImportService(
|
||
$integrationRepository, $tokenManager, $apiClient,
|
||
new OrderImportRepository($this->db), $statusMappingRepository, new OrdersRepository($this->db)
|
||
)
|
||
$ordersSyncService = new AllegroOrdersSyncService(
|
||
$integrationRepository, new AllegroOrderSyncStateRepository($this->db),
|
||
$tokenManager, $apiClient, $orderImportService
|
||
)
|
||
$shopproIntegrationsRepo = new ShopproIntegrationsRepository($this->db, $this->integrationSecret)
|
||
$shopproSyncService = new ShopproOrdersSyncService(
|
||
$shopproIntegrationsRepo, new ShopproOrderSyncStateRepository($this->db),
|
||
new ShopproApiClient(), new OrderImportRepository($this->db),
|
||
new ShopproStatusMappingRepository($this->db), new OrdersRepository($this->db)
|
||
)
|
||
$shopproStatusSyncService = new ShopproStatusSyncService($shopproIntegrationsRepo, $shopproSyncService)
|
||
$shopproPaymentSyncService = new ShopproPaymentStatusSyncService(
|
||
$shopproIntegrationsRepo, new ShopproApiClient(), new OrdersRepository($this->db), $this->db
|
||
)
|
||
```
|
||
|
||
Zwróć `new CronRunner($cronRepository, $logger, [ handlers array ])` — lista handlerów identyczna jak w `Application.php` (allegro_token_refresh, allegro_orders_import, allegro_status_sync, shoppro_orders_import, shoppro_order_status_sync, shoppro_payment_status_sync).
|
||
|
||
Dodaj wszystkie potrzebne `use` na górze pliku. Klasa powinna być `final`.
|
||
|
||
UNIKAJ: przyjmowania całego `Application` lub tablicy konfiguracji jako parametru — tylko `$db` i `$integrationSecret` są potrzebne.
|
||
</action>
|
||
<verify>
|
||
Plik istnieje: `src/Modules/Cron/CronHandlerFactory.php`.
|
||
Składnia PHP poprawna: `php -l src/Modules/Cron/CronHandlerFactory.php` zwraca "No syntax errors detected".
|
||
</verify>
|
||
<done>AC-1 częściowo — fabryka istnieje i buduje kompletny graf obiektów</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 2: Uproszczenie Application::maybeRunCronOnWeb()</name>
|
||
<files>src/Core/Application.php</files>
|
||
<action>
|
||
W metodzie `maybeRunCronOnWeb()` zastąp blok `try { ... $runner = new CronRunner(...) ... }` wywołaniem fabryki:
|
||
|
||
```php
|
||
$factory = new CronHandlerFactory(
|
||
$this->db,
|
||
(string) $this->config('app.integrations.secret', '')
|
||
);
|
||
$runner = $factory->build($repository, $this->logger);
|
||
$runner->run($webLimit);
|
||
```
|
||
|
||
Zachowaj blok `finally { $this->releaseWebCronLock(); }`.
|
||
|
||
Dodaj `use App\Modules\Cron\CronHandlerFactory;` do importów na górze pliku.
|
||
|
||
Usuń z `Application.php` wszystkie `use` instrukcje które były potrzebne wyłącznie dla ręcznej konstrukcji grafu crona (AllegroIntegrationRepository, AllegroOAuthClient, AllegroTokenManager, AllegroApiClient, AllegroStatusMappingRepository, AllegroOrderImportService, AllegroOrdersSyncService, AllegroOrderSyncStateRepository, AllegroStatusSyncService, ShopproApiClient, ShopproIntegrationsRepository, ShopproOrdersSyncService, ShopproOrderSyncStateRepository, ShopproPaymentStatusSyncService, ShopproStatusSyncService, ShopproStatusMappingRepository, OrderImportRepository, OrdersRepository) — TYLKO jeśli nie są używane nigdzie indziej w Application.php.
|
||
|
||
UNIKAJ usuwania `use` dla CronRunner, CronRepository, AllegroOrdersImportHandler i innych klas Cron, bo mogą być używane.
|
||
SPRAWDŹ przed usunięciem każdego `use` czy nie pojawia się w innych metodach lub właściwościach klasy.
|
||
</action>
|
||
<verify>
|
||
`php -l src/Core/Application.php` — brak błędów składni.
|
||
Metoda `maybeRunCronOnWeb()` liczy ≤25 linii (było 80+).
|
||
Grep na "new AllegroIntegrationRepository" w Application.php — brak wystąpień w metodzie maybeRunCronOnWeb.
|
||
</verify>
|
||
<done>AC-1 spełnione — Application.php nie buduje już własnego grafu crona; AC-2 spełnione — ta sama fabryka, te same handlery</done>
|
||
</task>
|
||
|
||
<task type="auto">
|
||
<name>Task 3: Uproszczenie bin/cron.php z naprawą błędów</name>
|
||
<files>bin/cron.php</files>
|
||
<action>
|
||
Zastąp całą sekcję od `$cronRepository = new CronRepository(...)` do `$runner = new CronRunner(...)` wywołaniem fabryki:
|
||
|
||
```php
|
||
$cronRepository = new CronRepository($app->db());
|
||
$factory = new CronHandlerFactory(
|
||
$app->db(),
|
||
(string) $app->config('app.integrations.secret', '')
|
||
);
|
||
$runner = $factory->build($cronRepository, $app->logger());
|
||
```
|
||
|
||
Zachowaj blok `$result = $runner->run($limit)` i `fwrite(...)`.
|
||
|
||
Zachowaj blok parsowania `--limit` z `$argv`.
|
||
|
||
Usuń wszystkie `use` instrukcje które nie są już potrzebne — zastąp je jednym `use App\Modules\Cron\CronHandlerFactory;` (obok `use App\Core\Application;` i `use App\Modules\Cron\CronRepository;`).
|
||
|
||
To NAPRAWIA dwa istniejące błędy w bin/cron.php:
|
||
- AllegroOAuthClient zamiast AllegroTokenManager w AllegroOrderImportService i AllegroOrdersSyncService
|
||
- AllegroOrderSyncStateRepository zamiast ShopproOrderSyncStateRepository dla ShopproOrdersSyncService
|
||
</action>
|
||
<verify>
|
||
`php -l bin/cron.php` — brak błędów składni.
|
||
bin/cron.php liczy ≤25 linii łącznie (było 123).
|
||
Grep "AllegroOAuthClient" w bin/cron.php — brak (usunięto nieprawidłowe użycie).
|
||
Grep "AllegroOrderSyncStateRepository" w bin/cron.php — brak (usunięto nieprawidłowe użycie).
|
||
</verify>
|
||
<done>AC-3 spełnione — bin/cron.php używa poprawnych zależności przez fabrykę</done>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<boundaries>
|
||
|
||
## DO NOT CHANGE
|
||
- Logika wewnątrz handlerów (AllegroOrdersImportHandler, AllegroStatusSyncHandler, itp.)
|
||
- Klasa CronRunner — interfejs publiczny pozostaje niezmieniony
|
||
- Metody Application poza maybeRunCronOnWeb() i blokiem use
|
||
- routes/web.php — nie dotykamy, nie buduje handlerow crona
|
||
- Migracje i schemat bazy danych
|
||
|
||
## SCOPE LIMITS
|
||
- Nie wprowadzamy DI container — to osobny temat (CONCERNS.md [MEDIUM] No DI Container)
|
||
- Nie naprawiamy innych bugów z CONCERNS.md w tym planie
|
||
- Nie przenosimy crona do routes/web.php — fabryka jest prostszym i bardziej przenośnym rozwiązaniem
|
||
- Nie zmieniamy publicznego API CronHandlerFactory po jego stworzeniu bez potrzeby
|
||
|
||
</boundaries>
|
||
|
||
<verification>
|
||
Przed deklaracją planu jako zakończonego:
|
||
- [ ] `php -l src/Modules/Cron/CronHandlerFactory.php` — No syntax errors
|
||
- [ ] `php -l src/Core/Application.php` — No syntax errors
|
||
- [ ] `php -l bin/cron.php` — No syntax errors
|
||
- [ ] Grep "new AllegroIntegrationRepository" w Application.php — 0 wyników w maybeRunCronOnWeb
|
||
- [ ] Grep "new ShopproIntegrationsRepository" w Application.php — 0 wyników w maybeRunCronOnWeb
|
||
- [ ] Grep "AllegroOrderSyncStateRepository" w bin/cron.php — 0 wyników
|
||
- [ ] Grep "AllegroOAuthClient" w bin/cron.php — 0 wyników
|
||
- [ ] Wszystkie kryteria akceptacji AC-1, AC-2, AC-3 spełnione
|
||
</verification>
|
||
|
||
<success_criteria>
|
||
- CronHandlerFactory istnieje i buduje kompletny, poprawny graf obiektów crona
|
||
- Application::maybeRunCronOnWeb() liczy ≤25 linii (skrócone z 80+)
|
||
- bin/cron.php liczy ≤25 linii (skrócone ze 123)
|
||
- Dwa błędy w bin/cron.php naprawione (AllegroOAuthClient → AllegroTokenManager, AllegroOrderSyncStateRepository → ShopproOrderSyncStateRepository)
|
||
- Brak błędów składni PHP we wszystkich zmienionych plikach
|
||
- Brak duplikacji okablowania crona między Application.php a bin/cron.php
|
||
</success_criteria>
|
||
|
||
<output>
|
||
Po zakończeniu utwórz `.paul/phases/02-bug-fixes/02-04-SUMMARY.md`
|
||
</output>
|