--- phase: 27-shipment-tracking-backend plan: 01 subsystem: shipments tags: [tracking, cron, inpost, apaczka, allegro, delivery-status] requires: - phase: 26-manual-tracking-number provides: shipment_packages table with manual provider support provides: - Delivery tracking columns (delivery_status, delivery_status_raw, delivery_status_updated_at) - ShipmentTrackingInterface with 3 provider implementations - DeliveryStatus normalization class with full status mappings - ShipmentTrackingHandler cron job affects: [28-shipment-tracking-ui] tech-stack: added: [] patterns: [two-level-status-normalization, tracking-service-per-provider] key-files: created: - src/Modules/Shipments/DeliveryStatus.php - src/Modules/Shipments/ShipmentTrackingInterface.php - src/Modules/Shipments/InpostTrackingService.php - src/Modules/Shipments/ApaczkaTrackingService.php - src/Modules/Shipments/AllegroTrackingService.php - src/Modules/Shipments/ShipmentTrackingRegistry.php - src/Modules/Cron/ShipmentTrackingHandler.php - DOCS/SHIPMENT_TRACKING_STATUSES.md modified: - src/Modules/Shipments/ShipmentPackageRepository.php - src/Modules/Cron/CronHandlerFactory.php key-decisions: - "Two-level status: normalized (10 values) + raw from API" - "Separate tracking interface (not extending ShipmentProviderInterface)" - "LIMIT 50 packages per cron run to prevent overload" - "Terminal statuses (delivered/returned/cancelled) skip tracking" - "Idempotent migrations with IF NOT EXISTS pattern" patterns-established: - "ShipmentTrackingInterface::getDeliveryStatus() returns {status, status_raw, description} or null" - "DeliveryStatus::normalize(provider, rawStatus) for provider-agnostic status mapping" - "ShipmentTrackingRegistry for provider lookup by code" duration: ~25min started: 2026-03-23T19:10:00Z completed: 2026-03-23T19:35:00Z --- # Phase 27 Plan 01: Shipment Tracking Backend Summary **Infrastruktura backendowa do automatycznego śledzenia statusu dostawy przesyłek — migracja DB, dwupoziomowy system statusów, 3 implementacje providerów (InPost/Apaczka/Allegro), cron handler.** ## Performance | Metric | Value | |--------|-------| | Duration | ~25 min | | Started | 2026-03-23T19:10:00Z | | Completed | 2026-03-23T19:35:00Z | | Tasks | 3 completed | | Files created | 10 | | Files modified | 2 | ## Acceptance Criteria Results | Criterion | Status | Notes | |-----------|--------|-------| | AC-1: Kolumny delivery tracking | Pass | 3 kolumny + indeks dodane, migracja idempotentna | | AC-2: DeliveryStatus mapuje statusy | Pass | 11/11 testów mapowania przeszło | | AC-3: Tracking interface + 3 implementacje | Pass | InPost, Apaczka, Allegro — syntax OK, Sonar fixes applied | | AC-4: Cron handler odpytuje aktywne przesyłki | Pass | ShipmentTrackingHandler z try/catch per package | | AC-5: Cron schedule zarejestrowany | Pass | shipment_tracking_sync, 900s, enabled=1 | ## Accomplishments - Dwupoziomowy system statusów: 10 znormalizowanych + pełne surowe statusy z API (30+ InPost, 11 Apaczka, 7 Allegro) - Kompletna dokumentacja statusów API w DOCS/SHIPMENT_TRACKING_STATUSES.md - Cron handler z graceful error handling (błąd jednej paczki nie blokuje reszty) ## Files Created/Modified | File | Change | Purpose | |------|--------|---------| | `database/migrations/20260323_000060_*.sql` | Created | Kolumny delivery tracking (idempotentna) | | `database/migrations/20260323_000061_*.sql` | Created | Cron schedule shipment_tracking_sync | | `src/Modules/Shipments/DeliveryStatus.php` | Created | Stałe, mapy, normalize(), label(), isTerminal() | | `src/Modules/Shipments/ShipmentTrackingInterface.php` | Created | Interfejs: supports() + getDeliveryStatus() | | `src/Modules/Shipments/InpostTrackingService.php` | Created | InPost ShipX API tracking | | `src/Modules/Shipments/ApaczkaTrackingService.php` | Created | Apaczka API tracking | | `src/Modules/Shipments/AllegroTrackingService.php` | Created | Allegro Shipment Management API tracking | | `src/Modules/Shipments/ShipmentTrackingRegistry.php` | Created | Registry: getForProvider() | | `src/Modules/Cron/ShipmentTrackingHandler.php` | Created | Cron handler: iterate + update | | `DOCS/SHIPMENT_TRACKING_STATUSES.md` | Created | Dokumentacja statusów API przewoźników | | `src/Modules/Shipments/ShipmentPackageRepository.php` | Modified | +findActiveForTracking(), +updateDeliveryStatus() | | `src/Modules/Cron/CronHandlerFactory.php` | Modified | +shipment_tracking_sync handler | ## Decisions Made | Decision | Rationale | Impact | |----------|-----------|--------| | Osobny ShipmentTrackingInterface (nie rozszerzenie ShipmentProviderInterface) | Tracking to inny concern niż tworzenie przesyłek; inne zależności | Czysta separacja, łatwe dodawanie nowych providerów | | Dwupoziomowe statusy (normalized + raw) | User widzi pełny szczegół z API, system filtruje po ujednoliconym | Max info dla usera + spójna logika | | LIMIT 50 per cron run | Zapobiega timeout przy dużej liczbie paczek | Kolejne paczki w następnym cyklu | | Idempotentne migracje | Błąd Duplicate column przy ponownym uruchomieniu | Bezpieczne re-run migracji | ## Deviations from Plan ### Summary | Type | Count | Impact | |------|-------|--------| | Auto-fixed | 1 | Migracje zmienione na idempotentne | | Scope additions | 0 | — | | Deferred | 0 | — | **Total impact:** Minimalna — dodano IF NOT EXISTS do migracji po wykryciu duplikatu kolumny. ### Auto-fixed Issues **1. Migracja nie-idempotentna** - **Found during:** Verification po Task 1 - **Issue:** ALTER TABLE ADD COLUMN bez sprawdzenia czy kolumna istnieje — błąd przy re-run - **Fix:** Zmieniono na idempotentny pattern z PREPARE/EXECUTE + INSERT IGNORE - **Files:** database/migrations/20260323_000060_*.sql, 20260323_000061_*.sql ## Sonar Audit | Nowe issues | Typ | Status | |-------------|-----|--------| | 2x S1192 DeliveryStatus | Pre-existing pattern (40x w projekcie) | Zalogowane w todo.md punkt 20 | | 1x S1172 ShipmentTrackingHandler | Pre-existing pattern (11x w projekcie) | Zalogowane w todo.md punkt 24 | 0 nowych unikalnych issues. S1142 (returns) naprawione przez wydzielenie metod. ## Next Phase Readiness **Ready:** - Kolumny DB gotowe, cron handler zarejestrowany - DeliveryStatus::label() gotowy do użycia w UI - ShipmentPackageRepository::findActiveForTracking() gotowy **Concerns:** - Brak — czysta baza dla Phase 28 (UI) **Blockers:** - None --- *Phase: 27-shipment-tracking-backend, Plan: 01* *Completed: 2026-03-23*