feat(127): polkurier integration foundation
Single-instance globalna konfiguracja polkurier.pl jako alternatywa dla Apaczki: szyfrowany login + Token API, karta w hubie integracji i realny test polaczenia przez apimetod=test_auth_api zweryfikowany na zywym koncie operatora (Autoryzacja: 1). ShipmentProviderRegistry netkniety - PolkurierShipmentService/ TrackingService w kolejnych fazach. Kluczowe ustalenia kontraktu API (z SDK polkurier-sdk): - POST https://api.polkurier.pl/ (jeden endpoint) - JSON body: {authorization:{login,token}, apimetod, data} - Sukces: top-level status === 'success' (nie 'ok') - Blad: tresc w polu 'response' envelope'a - Content-Type: application/json (strict, bez charset suffix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
---
|
||||
phase: 127-polkurier-integration-foundation
|
||||
plan: 01
|
||||
subsystem: integrations
|
||||
tags: [polkurier, courier, shipment-broker, settings, integration-hub, php]
|
||||
|
||||
requires:
|
||||
- phase: 116-hostedsms-integration-settings
|
||||
provides: single-instance integration repository pattern (IntegrationsRepository::ensureIntegration + updateTestResult + IntegrationSecretCipher)
|
||||
- phase: 120-alert-component-unification
|
||||
provides: resources/views/components/alert.php contract for all settings views
|
||||
provides:
|
||||
- polkurier_integration_settings DB table (single-instance, fixed id=1)
|
||||
- PolkurierIntegrationRepository (login + Token API, AES-encrypted)
|
||||
- PolkurierApiClient with verified live test connection against apimetod=test_auth_api
|
||||
- /settings/integrations/polkurier UI (form + Testuj polaczenie) + hub row
|
||||
- Foundation for future PolkurierShipmentService / PolkurierTrackingService
|
||||
affects:
|
||||
- future polkurier-shipment-service phase (uses getCredentials + verified API client contract)
|
||||
- future polkurier-tracking-service phase (delivery_status_mappings provider='polkurier')
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- single-instance integration ctor (PDO $pdo, string $secret) mirror HostedSMS/SMSPLANET
|
||||
- polkurier API contract: POST https://api.polkurier.pl/, JSON body {authorization:{login,token}, apimetod, data:{platform, platform_version}}, success when top-level status='success'
|
||||
- error path: payload from "response" field of envelope (string or struct) — mirror SDK ErrorException($response->get('response'))
|
||||
- strict Content-Type: application/json (no charset suffix — polkurier rejects)
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- database/migrations/20260514_000114_create_polkurier_integration_settings.sql
|
||||
- src/Modules/Settings/PolkurierIntegrationRepository.php
|
||||
- src/Modules/Settings/PolkurierApiClient.php
|
||||
- src/Modules/Settings/PolkurierIntegrationController.php
|
||||
- resources/views/settings/polkurier.php
|
||||
modified:
|
||||
- routes/web.php
|
||||
- src/Modules/Settings/IntegrationsHubController.php
|
||||
- resources/lang/pl.php
|
||||
- .paul/codebase/db_schema.md
|
||||
- .paul/codebase/architecture.md
|
||||
- .paul/codebase/tech_changelog.md
|
||||
|
||||
key-decisions:
|
||||
- "polkurier startuje jako single-instance globalna konfiguracja (mirror Apaczka/HostedSMS/SMSPLANET) — operator ma jedno konto polkurier"
|
||||
- "polkurier dziala obok Apaczki — ShipmentProviderRegistry netkniety; oba dostawcy zyja niezaleznie"
|
||||
- "API polkuriera wymaga login + token w body authorization (zweryfikowane w SDK polkurier-sdk); kolumna login dodana mimo ze PLAN AC-1 jej nie wymagal"
|
||||
- "Brak kolumny environment ENUM — polkurier ma jeden produkcyjny endpoint, sandbox nie istnieje"
|
||||
- "Test polaczenia uzywa apimetod=test_auth_api (nie tworzy przesylki, nie kosztuje); sukces gdy top-level status='success'"
|
||||
- "Content-Type MUSI byc dokladnie 'application/json' — polkurier odrzuca '; charset=UTF-8' suffix"
|
||||
|
||||
patterns-established:
|
||||
- "polkurier API client: jeden POST endpoint, ResponseStatus::SUCCESS='success', tresc bledu w polu 'response' envelope'a — wzorzec dla wszystkich przyszlych metod (createShipment, getLabel, getStatus, cancelOrder, AvailableCarriers, etc.)"
|
||||
- "Strict Content-Type bez charset suffix — pattern do reuse w innych integracjach jezeli odrzucaja parametry"
|
||||
|
||||
duration: ~45min
|
||||
started: 2026-05-14T19:00:00Z
|
||||
completed: 2026-05-14T19:45:00Z
|
||||
---
|
||||
|
||||
# Phase 127 Plan 01: polkurier Integration Foundation — Summary
|
||||
|
||||
**polkurier.pl broker kurierski dostepny jako alternatywa dla Apaczki: pojedyncza globalna konfiguracja w `/settings/integrations/polkurier` z zaszyfrowanym Token API + loginem, realny test polaczenia przez `apimetod=test_auth_api` zweryfikowany na produkcyjnym koncie operatora (`Autoryzacja: 1`).**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~45min (incl. live API debugging) |
|
||||
| Started | 2026-05-14T19:00:00Z |
|
||||
| Completed | 2026-05-14T19:45:00Z |
|
||||
| Tasks | 3 of 3 completed |
|
||||
| Files created | 5 |
|
||||
| Files modified | 6 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Migracja tworzy single-instance tabele konfiguracji | Pass (modified) | DDL idempotentny. **Modyfikacja:** kolumna `environment ENUM` pominieta (polkurier nie ma sandbox); dodana kolumna `login VARCHAR(190)` (polkurier wymaga login+token, nie samego tokena). |
|
||||
| AC-2: Repozytorium szyfruje Token API i zarzadza pojedynczym rekordem integrations | Pass | `getSettings()` zwraca `has_api_token: bool`, `saveSettings()` szyfruje przez `IntegrationSecretCipher`, `getCredentials()` gates na `is_active=1`. |
|
||||
| AC-3: Endpoint testowy realnie wywoluje API polkuriera i zapisuje wynik | Pass (live verified) | Operator potwierdzil: `Polaczenie z polkurier dziala. Autoryzacja: 1` (response z `apimetod=test_auth_api`). `IntegrationsRepository::updateTestResult()` zapisuje wynik. |
|
||||
| AC-4: Karta polkurier w hubie integracji | Pass | `buildPolkurierRow()` w `IntegrationsHubController` wstawia wiersz po Apaczce (semantycznie sasiednie). |
|
||||
| AC-5: Apaczka i istniejace ShipmentProviderRegistry netkniete | Pass | Zerowe modyfikacje w `src/Modules/Shipments/*` i `Apaczka*`. Grep `polkurier` w `ShipmentProviderRegistry.php` -> 0 trafien. |
|
||||
| AC-6: Dokumentacja zaktualizowana | Pass | `db_schema.md` +1 tabela (62 total), `architecture.md` +sekcja Phase 127, `tech_changelog.md` +wpis z deviation. |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- polkurier.pl wpiety jako drugi broker kurierski (obok Apaczki) — fundament gotowy i zweryfikowany na zywym API operatora.
|
||||
- Kontrakt API polkuriera zweryfikowany i udokumentowany w `architecture.md`: POST `https://api.polkurier.pl/`, JSON `{authorization:{login,token}, apimetod, data:{platform, platform_version}}`, sukces gdy `status='success'`, tresc bledu w polu `response` envelope'a.
|
||||
- 4 buggi z pierwszego draftu naprawione live (3 podczas testow operatora) — finalna implementacja sprawdzona na realnym Token API.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Commits jeszcze nie utworzone (czekaja na transition step). Calosc fazy 127 zostanie zacommitowana jako jeden `feat(127):` commit.
|
||||
|
||||
| Task | Commit | Type | Description |
|
||||
|------|--------|------|-------------|
|
||||
| Task 1: Migracja + Repository | (pending) | feat | DDL + PolkurierIntegrationRepository |
|
||||
| Task 2: ApiClient + Controller + widok + routy | (pending) | feat | PolkurierApiClient + Controller + view + i18n + DI |
|
||||
| Task 3: Hub + dokumentacja codebase | (pending) | feat | IntegrationsHubController buildPolkurierRow + db_schema/architecture/tech_changelog |
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `database/migrations/20260514_000114_create_polkurier_integration_settings.sql` | Created | DDL tabeli + seed `integrations.type='polkurier'` (idempotentny) |
|
||||
| `src/Modules/Settings/PolkurierIntegrationRepository.php` | Created | Single-instance repo, szyfrowanie tokena, getCredentials z gating na is_active |
|
||||
| `src/Modules/Settings/PolkurierApiClient.php` | Created | POST do api.polkurier.pl, testConnection z apimetod=test_auth_api, stuby createShipment/getLabel/getStatus/cancelOrder |
|
||||
| `src/Modules/Settings/PolkurierIntegrationController.php` | Created | GET/save/test endpointy z CSRF, flash, RedirectPathResolver |
|
||||
| `resources/views/settings/polkurier.php` | Created | Formularz konfiguracji + Test polaczenia, alerty przez komponent alert.php |
|
||||
| `routes/web.php` | Modified | DI wiring (Repo+Controller) + 3 routy + ctor IntegrationsHubController |
|
||||
| `src/Modules/Settings/IntegrationsHubController.php` | Modified | +param polkurier + buildPolkurierRow() + wstawienie wiersza po Apaczce |
|
||||
| `resources/lang/pl.php` | Modified | settings.polkurier.* + providers.polkurier |
|
||||
| `.paul/codebase/db_schema.md` | Modified | +tabela polkurier_integration_settings, 61->62 |
|
||||
| `.paul/codebase/architecture.md` | Modified | +sekcja Phase 127 |
|
||||
| `.paul/codebase/tech_changelog.md` | Modified | +wpis 2026-05-14 z deviation |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Kolumna `login VARCHAR(190)` w tabeli zamiast samego `api_token` | API polkuriera (zweryfikowane w SDK Auth.php/Request.php) wymaga login+token w body authorization, nie samego tokena | Wszystkie przyszle wywolania API musza miec login z `getCredentials()['login']` |
|
||||
| Pominieta kolumna `environment ENUM('production','sandbox')` z PLAN AC-1 | polkurier nie ma osobnego srodowiska sandbox (jeden URL: https://api.polkurier.pl/) | YAGNI; jezeli polkurier doda sandbox, dolozymy migracja `ALTER TABLE ... ADD COLUMN` |
|
||||
| Wykonanie planu inline zamiast delegated:auto z planu | Swiezy kontekst API research (Config/Auth/Methods z polkurier-sdk) — agent musialby ten research powtorzyc | Brak; boundaries i AC niezmienione, deviation udokumentowana |
|
||||
| `Content-Type: application/json` (bez `; charset=UTF-8` suffix) | polkurier API zwraca `Content type must be: application/json` gdy header ma charset suffix | Pattern do reuse jezeli inne integracje sa rownie strict |
|
||||
| `ResponseStatus::SUCCESS = 'success'` (nie `'ok'`) | Zweryfikowane w `src/Type/ResponseStatus.php` SDK polkuriera | Wszystkie przyszle metody API musza sprawdzac `status === 'success'` |
|
||||
| Tresc bledu z pola `response` envelope'a (nie `error_message`) | SDK polkuriera rzuca `ErrorException($response->get('response'))` gdy status != success | Wzorzec parser bledu dla wszystkich przyszlych metod API |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 3 | Krytyczne — bez tych poprawek test polaczenia nie zwracalby `success` |
|
||||
| Scope additions | 1 | Kolumna `login` w schemacie (poza zakresem AC-1 — wymagana przez kontrakt API) |
|
||||
| Scope removals | 1 | Kolumna `environment` z AC-1 pominieta (YAGNI) |
|
||||
| Execution mode | 1 | Plan: `delegation:auto`. Faktycznie: inline. Boundaries i AC niezmienione. |
|
||||
| Deferred | 0 | Brak |
|
||||
|
||||
**Total impact:** Wszystkie deviacje wymuszone realnym kontraktem API polkuriera. Plan z chwili pisania bazowal na publicznym opisie API; szczegoly (login, status='success', strict Content-Type) wyplynely dopiero przy weryfikacji SDK i testach na zywym koncie operatora.
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [API contract] `status === 'ok'` -> `status === 'success'`**
|
||||
- **Found during:** Live test po Task 2 (operator zglosil `Status: error`)
|
||||
- **Issue:** Kod sprawdzal `$status === 'ok'`, ale `ResponseStatus::SUCCESS` w SDK polkuriera = `'success'`
|
||||
- **Fix:** Zmiana porownania na `$status === 'success'`; parser bledu zaktualizowany do pobierania tresci z pola `response` envelope'a (mirror SDK ErrorException)
|
||||
- **Files:** `src/Modules/Settings/PolkurierApiClient.php`
|
||||
- **Verification:** Drugi test operatora — komunikat `Content type must be: application/json` (faktyczna tresc z polkuriera, nie generyczne `Status: error`)
|
||||
- **Commit:** TBD (przy transition)
|
||||
|
||||
**2. [HTTP headers] Content-Type strict**
|
||||
- **Found during:** Live test po fix #1 (operator zglosil `Content type must be: application/json`)
|
||||
- **Issue:** Header `Content-Type: application/json; charset=UTF-8` — polkurier robi strict equality check i odrzuca suffix `; charset=UTF-8`
|
||||
- **Fix:** Zmiana na `Content-Type: application/json` (sam mime, bez parametrow)
|
||||
- **Files:** `src/Modules/Settings/PolkurierApiClient.php`
|
||||
- **Verification:** Trzeci test operatora — `Polaczenie z polkurier dziala. Autoryzacja: 1` (sukces)
|
||||
- **Commit:** TBD (przy transition)
|
||||
|
||||
**3. [Error reporting] Brak tresci bledu w komunikacie UI**
|
||||
- **Found during:** Live test po Task 2 (`Status: error` bez detali)
|
||||
- **Issue:** Komunikat fallback `'Status: ' . $status` byl nieczytelny; tresc bledu z polkuriera siedzi w polu `response` envelope'a, nie `error_message` top-level
|
||||
- **Fix:** Parser bledu czyta `response` field (string albo zagniezdzona struktura `error_message/errorMessage/message/error`), z fallbackiem na top-level `error_message/message/error` i finalnie `Status: X (HTTP Y)`
|
||||
- **Files:** `src/Modules/Settings/PolkurierApiClient.php`
|
||||
- **Verification:** Fix #2 mozliwy tylko dzieki temu (operator zobaczyl `Content type must be: application/json` zamiast `Status: error`)
|
||||
- **Commit:** TBD (przy transition)
|
||||
|
||||
### Deferred Items
|
||||
|
||||
Brak — kontrakt API operatora zweryfikowany, fundament zamkniety. Kolejne fazy (PolkurierShipmentService, PolkurierTrackingService) sa zaplanowane jako oddzielne, swiadomie poza zakresem 127 (PLAN boundaries `SCOPE LIMITS`).
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| Operator: `Status: error` po pierwszym smoke | Fix #1 (status='success') + #3 (parser bledu) — operator widzi teraz realny komunikat polkuriera |
|
||||
| Operator: `Content type must be: application/json` po fix #1 | Fix #2 (strict Content-Type bez charset suffix) |
|
||||
| API research nieobecny przed planem | Pre-APPLY fetche SDK polkurier-sdk (Auth/Request/Methods/Config/ResponseStatus) — kontrakt zrekonstruowany przed implementacja |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- `PolkurierIntegrationRepository::getCredentials()` zwraca odszyfrowany `login + api_token + default_label_format` — gotowe do uzycia w `PolkurierShipmentService`.
|
||||
- `PolkurierApiClient` ma zweryfikowany kontrakt POST (single endpoint, JSON body, status='success', error w `response`) + stuby `createShipment/getLabel/getStatus/cancelOrder` z `RuntimeException("Not implemented in Phase 127")` jako placeholder dla nastepnej fazy.
|
||||
- 36 metod SDK polkuriera zidentyfikowanych: `AvailableCarriers`, `OrderValuationV2`, `CreateOrder`, `GetLabel`, `GetStatus`, `CancelOrder`, `InpostParcelMachines`, `PocztexPostOffices`, `Kurier48PostOffices`, `GetCourierPoint`, `Heartbeat`, etc. — gotowe do mapowania w kolejnych planach.
|
||||
- Hub integracji pokazuje stan polkuriera obok Apaczki — operator widzi obie integracje rownolegle.
|
||||
|
||||
**Concerns:**
|
||||
- Brak `PolkurierShipmentService` — operator nie moze jeszcze nadawac przesylek przez polkuriera. Zgodne z PLAN scope (`SCOPE LIMITS`).
|
||||
- Brak mapowan metod dostawy `order_delivery_method -> polkurier service` — wymaga analizy listy uslug z `AvailableCarriers` API.
|
||||
- Brak `delivery_status_mappings` dla `provider='polkurier'` — tracking polling rowniez deferred.
|
||||
|
||||
**Blockers:**
|
||||
- Operator musi uruchomic `php bin/migrate.php` na zywej bazie (XAMPP) zeby zalozyc tabele i seed rekord `integrations.type='polkurier'`. AKTUALNIE migracja juz uruchomiona (test polaczenia dzialal, wiec rekord `integrations` istnieje).
|
||||
|
||||
---
|
||||
*Phase: 127-polkurier-integration-foundation, Plan: 01*
|
||||
*Completed: 2026-05-14*
|
||||
Reference in New Issue
Block a user