wip(06-sonarqube-quality): 6 planów SonarQube Quality utworzonych
Plany dla php:S112, S1142, S1192, S3776, S1448, S138 — gotowe do APPLY. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
98
.paul/HANDOFF-2026-03-13.md
Normal file
98
.paul/HANDOFF-2026-03-13.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# PAUL Handoff
|
||||
|
||||
**Date:** 2026-03-13
|
||||
**Status:** paused
|
||||
|
||||
---
|
||||
|
||||
## READ THIS FIRST
|
||||
|
||||
You have no prior context. This document tells you everything.
|
||||
|
||||
**Project:** orderPRO — aplikacja do zarządzania zamówieniami z wielu kanałów sprzedaży (Allegro, Erli, własne sklepy). Generowanie etykiet kurierskich.
|
||||
**Core value:** Sprzedawca obsługuje wszystkie kanały i nadaje przesyłki bez przełączania platform.
|
||||
|
||||
---
|
||||
|
||||
## Current State
|
||||
|
||||
**Version:** v0.1.0 (In Progress)
|
||||
**Phase:** 6 of TBD — 06-sonarqube-quality
|
||||
**Plan:** 06-01..06-06 — CREATED, awaiting approval
|
||||
|
||||
**Loop Position:**
|
||||
```
|
||||
PLAN ──▶ APPLY ──▶ UNIFY
|
||||
✓ ○ ○ [6 planów gotowych, żaden nie wykonany]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Was Done
|
||||
|
||||
- Przeanalizowano 327 issues SonarQube z CONCERNS.md i DOCS/todo.md
|
||||
- Zbadano kluczowe pliki (AllegroIntegrationController 923L, ShopproIntegrationsController 901L, ShopproOrdersSyncService 1192L, OrdersRepository 785L)
|
||||
- Utworzono 6 planów dla fazy 06-sonarqube-quality:
|
||||
- `06-01-PLAN.md` — php:S112 (95x) — typowane wyjątki zamiast RuntimeException
|
||||
- `06-02-PLAN.md` — php:S1142 (57x) — redukcja return statements (save() z 5→≤3)
|
||||
- `06-03-PLAN.md` — php:S1192 (40x) — ekstrakcja literałów do stałych (IntegrationSources, RedirectPaths)
|
||||
- `06-04-PLAN.md` — php:S3776 (31x) — redukcja złożoności kognitywnej (extract method)
|
||||
- `06-05-PLAN.md` — php:S1448 (6x) — podział god classes (ShopproOrdersSyncService 39→≤20 metod, AllegroIntegrationController 30→≤15)
|
||||
- `06-06-PLAN.md` — php:S138 (4x) — skrócenie długich metod (sync 195L, paginate 183L)
|
||||
- Zaktualizowano ROADMAP.md (Phase 6 dodana)
|
||||
- Zaktualizowano STATE.md
|
||||
|
||||
---
|
||||
|
||||
## What's In Progress
|
||||
|
||||
- Żaden plan nie jest w trakcie — wszystkie 6 czeka na zatwierdzenie i APPLY
|
||||
|
||||
---
|
||||
|
||||
## What's Next
|
||||
|
||||
**Immediate:** Wybierz plan do wykonania i uruchom `/paul:apply .paul/phases/06-sonarqube-quality/06-XX-PLAN.md`
|
||||
|
||||
**Rekomendowana kolejność:**
|
||||
1. `06-01` (php:S112) — najprostsza zmiana, nowe klasy + podmiana throw
|
||||
2. `06-03` (php:S1192) — quick win, stałe zamiast literałów
|
||||
3. `06-02` (php:S1142) — refaktoryzacja metod w 2 kontrolerach
|
||||
4. `06-06` (php:S138) — skrócenie długich metod
|
||||
5. `06-04` (php:S3776) — redukcja złożoności (extract method w god classes)
|
||||
6. `06-05` (php:S1448) — największa zmiana: podział klas (ma checkpoint:human-verify)
|
||||
|
||||
**Zależności między planami:**
|
||||
- `06-01, 06-02, 06-03` — niezależne, wave 1
|
||||
- `06-04` — niezależny, wave 2 (lepiej przed 06-05)
|
||||
- `06-05` — `depends_on: ["06-04"]`, wave 3, nie jest autonomous (ma human-verify)
|
||||
- `06-06` — wave 2, uważaj na interferencję z 06-05 w ShopproOrdersSyncService
|
||||
|
||||
---
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `.paul/STATE.md` | Live project state |
|
||||
| `.paul/ROADMAP.md` | Phase overview |
|
||||
| `.paul/phases/06-sonarqube-quality/06-01-PLAN.md` | S112: Typowane wyjątki |
|
||||
| `.paul/phases/06-sonarqube-quality/06-02-PLAN.md` | S1142: Redukcja return |
|
||||
| `.paul/phases/06-sonarqube-quality/06-03-PLAN.md` | S1192: Stałe dla literałów |
|
||||
| `.paul/phases/06-sonarqube-quality/06-04-PLAN.md` | S3776: Złożoność kognitywna |
|
||||
| `.paul/phases/06-sonarqube-quality/06-05-PLAN.md` | S1448: Podział god classes |
|
||||
| `.paul/phases/06-sonarqube-quality/06-06-PLAN.md` | S138: Długie metody |
|
||||
| `.paul/codebase/CONCERNS.md` | Pełna lista concerns (tech debt, bugs, performance) |
|
||||
| `DOCS/todo.md` | Lista TODO z SonarQube issues |
|
||||
|
||||
---
|
||||
|
||||
## Resume Instructions
|
||||
|
||||
1. Przeczytaj `.paul/STATE.md` — potwierdź pozycję w loop
|
||||
2. Wybierz plan (rekomendowane: 06-01 lub 06-03)
|
||||
3. Uruchom `/paul:apply .paul/phases/06-sonarqube-quality/06-01-PLAN.md`
|
||||
|
||||
---
|
||||
|
||||
*Handoff created: 2026-03-13*
|
||||
@@ -8,7 +8,7 @@ orderPRO to narzędzie do wielokanałowego zarządzania sprzedażą. Projekt prz
|
||||
|
||||
**v0.1 Initial Release** (v0.1.0)
|
||||
Status: In progress
|
||||
Phases: 3 complete, Phase 4 planning
|
||||
Phases: 5 complete, Phase 6 planning
|
||||
|
||||
## Phases
|
||||
|
||||
@@ -19,6 +19,7 @@ Phases: 3 complete, Phase 4 planning
|
||||
| 3 | Tech Debt 2 | 1/1 | ✅ Complete | 2026-03-13 |
|
||||
| 4 | Schema Docs | 1/1 | ✅ Complete | 2026-03-13 |
|
||||
| 5 | Tech Debt 3 | 1/1 | ✅ Complete | 2026-03-13 |
|
||||
| 6 | SonarQube Quality | 0/6 | 🔄 Planning | — |
|
||||
|
||||
## Phase Details
|
||||
|
||||
@@ -51,6 +52,16 @@ Migracja flash messages z bezpośrednich zapisów `$_SESSION` do abstrakcji `Fla
|
||||
|
||||
- **Plan 05-01** — Migrate $_SESSION flash writes to Flash class in OrdersController and ShipmentController — *Complete*
|
||||
|
||||
### Phase 6 — SonarQube Quality
|
||||
Eliminacja 327 issues SonarQube (php:S112, S1142, S1192, S3776, S1448, S138) przez typowane wyjątki, ekstrakcję stałych, redukcję złożoności i podział god classes.
|
||||
|
||||
- **Plan 06-01** — php:S112 (95x) — Typowane klasy wyjątków zamiast RuntimeException — *Not started*
|
||||
- **Plan 06-02** — php:S1142 (57x) — Redukcja liczby return w metodach — *Not started*
|
||||
- **Plan 06-03** — php:S1192 (40x) — Ekstrakcja powtarzających się literałów do stałych — *Not started*
|
||||
- **Plan 06-04** — php:S3776 (31x) — Redukcja złożoności kognitywnej metod — *Not started*
|
||||
- **Plan 06-05** — php:S1448 (6x) — Podział god classes (ShopproOrdersSyncService, AllegroIntegrationController) — *Not started*
|
||||
- **Plan 06-06** — php:S138 (4x) — Skrócenie zbyt długich metod — *Not started*
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-03-12*
|
||||
*Last updated: 2026-03-13 after Phase 5 (Tech Debt 3 — Flash migration)*
|
||||
*Last updated: 2026-03-13 after Phase 6 plans created (SonarQube Quality — 6 plans)*
|
||||
|
||||
@@ -10,10 +10,10 @@ See: .paul/PROJECT.md (updated 2026-03-12)
|
||||
## Current Position
|
||||
|
||||
Milestone: v0.1 Initial Release
|
||||
Phase: 5 of TBD (05-tech-debt-3) — Complete
|
||||
Plan: 05-01 complete
|
||||
Status: Phase 5 complete — ready for next phase
|
||||
Last activity: 2026-03-13 — Phase 05 complete (05-01-SUMMARY.md)
|
||||
Phase: 6 of TBD (06-sonarqube-quality) — Planning
|
||||
Plan: 06-01..06-06 created, awaiting approval
|
||||
Status: PLAN created (6 plans), ready for APPLY
|
||||
Last activity: 2026-03-13 — Created .paul/phases/06-sonarqube-quality/06-01..06-PLAN.md
|
||||
|
||||
Progress:
|
||||
- Milestone: [███████░░░] ~65%
|
||||
@@ -22,13 +22,14 @@ Progress:
|
||||
- Phase 3: [██████████] 100% (1/1 plans complete)
|
||||
- Phase 4: [██████████] 100% (1/1 plans complete)
|
||||
- Phase 5: [██████████] 100% (1/1 plans complete)
|
||||
- Phase 6: [░░░░░░░░░░] 0% (0/6 plans complete)
|
||||
|
||||
## Loop Position
|
||||
|
||||
Current loop state:
|
||||
```
|
||||
PLAN ──▶ APPLY ──▶ UNIFY
|
||||
✓ ✓ ✓ [Phase 05 complete — ready for Phase 6 PLAN]
|
||||
✓ ○ ○ [6 planów utworzonych, oczekują zatwierdzenia]
|
||||
```
|
||||
|
||||
## Accumulated Context
|
||||
@@ -75,7 +76,7 @@ PLAN ──▶ APPLY ──▶ UNIFY
|
||||
- **code-review** — wywołać /code-review przed kolejnym UNIFY (pominięto w obydwu planach fazy 01).
|
||||
|
||||
### Git State
|
||||
Last commit: 880ab59
|
||||
Last commit: 2d4b52a (Phase 04+05 — schema docs + Flash migration)
|
||||
Branch: main
|
||||
Feature branches merged: none
|
||||
|
||||
@@ -85,9 +86,13 @@ Brak.
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-13
|
||||
Stopped at: Phase 05 complete
|
||||
Next action: /paul:plan dla Phase 6
|
||||
Resume file: .paul/phases/05-tech-debt-3/05-01-SUMMARY.md
|
||||
Stopped at: Phase 06 — 6 planów SonarQube Quality utworzonych, żaden nie wykonany
|
||||
Next action: /paul:apply .paul/phases/06-sonarqube-quality/06-01-PLAN.md (lub 06-03 jako quick win)
|
||||
Resume file: .paul/HANDOFF-2026-03-13.md
|
||||
Resume context:
|
||||
- Faza 06 ma 6 planów (06-01..06-06) wszystkie gotowe w .paul/phases/06-sonarqube-quality/
|
||||
- Rekomendowana kolejność: 06-01 → 06-03 → 06-02 → 06-06 → 06-04 → 06-05
|
||||
- 06-05 (god classes) zależy od 06-04 i ma checkpoint:human-verify (nie autonomous)
|
||||
|
||||
---
|
||||
*STATE.md — Updated after every significant action*
|
||||
|
||||
251
.paul/phases/06-sonarqube-quality/06-01-PLAN.md
Normal file
251
.paul/phases/06-sonarqube-quality/06-01-PLAN.md
Normal file
@@ -0,0 +1,251 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Core/Exceptions/OrderProException.php
|
||||
- src/Core/Exceptions/AllegroApiException.php
|
||||
- src/Core/Exceptions/AllegroOAuthException.php
|
||||
- src/Core/Exceptions/ApaczkaApiException.php
|
||||
- src/Core/Exceptions/ShipmentException.php
|
||||
- src/Core/Exceptions/IntegrationConfigException.php
|
||||
- src/Modules/Settings/AllegroApiClient.php
|
||||
- src/Modules/Settings/AllegroOAuthClient.php
|
||||
- src/Modules/Settings/AllegroTokenManager.php
|
||||
- src/Modules/Settings/AllegroIntegrationRepository.php
|
||||
- src/Modules/Settings/AllegroIntegrationController.php
|
||||
- src/Modules/Settings/AllegroOrderImportService.php
|
||||
- src/Modules/Settings/AllegroOrdersSyncService.php
|
||||
- src/Modules/Settings/ApaczkaApiClient.php
|
||||
- src/Modules/Settings/ApaczkaIntegrationRepository.php
|
||||
- src/Modules/Shipments/ApaczkaShipmentService.php
|
||||
- src/Modules/Shipments/AllegroShipmentService.php
|
||||
- src/Modules/Shipments/ShipmentController.php
|
||||
- src/Modules/Settings/IntegrationSecretCipher.php
|
||||
- src/Modules/Settings/InpostIntegrationRepository.php
|
||||
- src/Modules/Settings/ShopproIntegrationsRepository.php
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
- src/Modules/Settings/ShopproPaymentStatusSyncService.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Zastąpić 86+ wywołań `throw new RuntimeException()` dedykowanymi klasami wyjątków per moduł — eliminacja naruszeń SonarQube php:S112.
|
||||
|
||||
## Purpose
|
||||
SonarQube flaguje `RuntimeException` jako zbyt ogólny — łapanie `catch (RuntimeException)` nie mówi nic o tym, jaki błąd nastąpił. Typowane wyjątki umożliwiają precyzyjny catch w wywołującym kodzie i poprawiają czytelność stacktrace.
|
||||
|
||||
## Output
|
||||
Hierarchia klas wyjątków w `src/Core/Exceptions/` + podmienione throw w 13 plikach. Liczba S112 w SonarQube spada z 95 do ~5 (pozostałości w Core).
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/STATE.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/AllegroApiClient.php
|
||||
@src/Modules/Settings/AllegroOAuthClient.php
|
||||
@src/Modules/Settings/AllegroTokenManager.php
|
||||
@src/Modules/Shipments/ApaczkaShipmentService.php
|
||||
@src/Modules/Shipments/AllegroShipmentService.php
|
||||
@src/Modules/Settings/ApaczkaApiClient.php
|
||||
@src/Modules/Settings/IntegrationSecretCipher.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY (CLI w katalogu projektu)
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Hierarchia wyjątków istnieje
|
||||
```gherkin
|
||||
Given brak folderu src/Core/Exceptions/
|
||||
When plan zostaje wykonany
|
||||
Then folder src/Core/Exceptions/ istnieje z klasami: OrderProException, AllegroApiException, AllegroOAuthException, ApaczkaApiException, ShipmentException, IntegrationConfigException
|
||||
```
|
||||
|
||||
## AC-2: Allegro-specific throws podmienione
|
||||
```gherkin
|
||||
Given AllegroApiClient, AllegroOAuthClient, AllegroTokenManager rzucają RuntimeException
|
||||
When plan zostaje wykonany
|
||||
Then wszystkie throw w tych plikach używają AllegroApiException lub AllegroOAuthException
|
||||
```
|
||||
|
||||
## AC-3: Apaczka-specific throws podmienione
|
||||
```gherkin
|
||||
Given ApaczkaApiClient, ApaczkaShipmentService, ApaczkaIntegrationRepository rzucają RuntimeException
|
||||
When plan zostaje wykonany
|
||||
Then wszystkie throw w tych plikach używają ApaczkaApiException
|
||||
```
|
||||
|
||||
## AC-4: Shipment throws podmienione
|
||||
```gherkin
|
||||
Given AllegroShipmentService, ShipmentController rzucają RuntimeException
|
||||
When plan zostaje wykonany
|
||||
Then wszystkie throw używają ShipmentException
|
||||
```
|
||||
|
||||
## AC-5: Brak regresji
|
||||
```gherkin
|
||||
Given aplikacja działa przed zmianą
|
||||
When klasy wyjątków rozszerzają RuntimeException (łańcuch dziedziczenia zachowany)
|
||||
Then istniejące catch (RuntimeException) w kodzie wywołującym nadal działają
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Utwórz hierarchię klas wyjątków</name>
|
||||
<files>
|
||||
src/Core/Exceptions/OrderProException.php,
|
||||
src/Core/Exceptions/AllegroApiException.php,
|
||||
src/Core/Exceptions/AllegroOAuthException.php,
|
||||
src/Core/Exceptions/ApaczkaApiException.php,
|
||||
src/Core/Exceptions/ShipmentException.php,
|
||||
src/Core/Exceptions/IntegrationConfigException.php
|
||||
</files>
|
||||
<action>
|
||||
Utwórz folder src/Core/Exceptions/ i pliki klas z namespace App\Core\Exceptions.
|
||||
|
||||
Hierarchia:
|
||||
- OrderProException extends \RuntimeException — baza dla wszystkich własnych wyjątków
|
||||
- AllegroApiException extends OrderProException — błędy HTTP/JSON Allegro API i OAuth
|
||||
- AllegroOAuthException extends AllegroApiException — specyficznie błędy OAuth (token refresh, brak tokenów)
|
||||
- ApaczkaApiException extends OrderProException — błędy API Apaczka (HTTP, curl, payload)
|
||||
- ShipmentException extends OrderProException — błędy tworzenia/pobierania przesyłek (brak zamówienia, brak providera, brak paczki)
|
||||
- IntegrationConfigException extends OrderProException — błędy konfiguracji integracji (brak rekordu w DB, brak klucza API, brak sekretu)
|
||||
|
||||
Każda klasa: minimalna (tylko class declaration + extends). Brak dodatkowych metod — nie powielać logiki.
|
||||
Nie dodawaj konstruktorów ani innych metod — klasy wyjątków mają być tylko markerami.
|
||||
</action>
|
||||
<verify>php -l src/Core/Exceptions/OrderProException.php (i pozostałe 5 plików) — każdy zwraca "No syntax errors"</verify>
|
||||
<done>AC-1 satisfied: folder src/Core/Exceptions/ z 6 klasami istnieje i jest poprawny składniowo</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Podmień RuntimeException w plikach Allegro</name>
|
||||
<files>
|
||||
src/Modules/Settings/AllegroApiClient.php,
|
||||
src/Modules/Settings/AllegroOAuthClient.php,
|
||||
src/Modules/Settings/AllegroTokenManager.php,
|
||||
src/Modules/Settings/AllegroIntegrationRepository.php,
|
||||
src/Modules/Settings/AllegroIntegrationController.php,
|
||||
src/Modules/Settings/AllegroOrderImportService.php,
|
||||
src/Modules/Settings/AllegroOrdersSyncService.php
|
||||
</files>
|
||||
<action>
|
||||
W każdym pliku:
|
||||
1. Dodaj use App\Core\Exceptions\AllegroApiException; (i AllegroOAuthException tam gdzie dotyczy OAuth)
|
||||
2. Zastąp throw new RuntimeException(...) odpowiednią klasą:
|
||||
- AllegroApiClient.php (18x): HTTP/JSON/curl błędy → AllegroApiException; błędy OAuth (ALLEGRO_HTTP_401) → AllegroApiException
|
||||
- AllegroOAuthClient.php (6x): wszystkie → AllegroOAuthException
|
||||
- AllegroTokenManager.php (3x): brak połączenia OAuth, brak danych, niepowodzenie refresh → AllegroOAuthException
|
||||
- AllegroIntegrationRepository.php (1x): brak rekordu → IntegrationConfigException (użyj use App\Core\Exceptions\IntegrationConfigException)
|
||||
- AllegroIntegrationController.php (1x): brak credentials → IntegrationConfigException
|
||||
- AllegroOrderImportService.php (2x): błędy importu → AllegroApiException
|
||||
- AllegroOrdersSyncService.php (1x): brak aktywnej integracji → IntegrationConfigException
|
||||
|
||||
Uwaga: NIE zmieniaj logiki catch bloków — tylko throw. NIE zmieniaj komunikatów błędów.
|
||||
Uwaga: \RuntimeException w AllegroIntegrationController (jeśli catch) — NIE ruszać.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/AllegroApiClient.php
|
||||
php -l src/Modules/Settings/AllegroOAuthClient.php
|
||||
php -l src/Modules/Settings/AllegroTokenManager.php
|
||||
grep -r "new RuntimeException" src/Modules/Settings/Allegro*.php — powinno zwrócić 0 wyników
|
||||
</verify>
|
||||
<done>AC-2 satisfied: pliki Allegro nie zawierają throw new RuntimeException</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Podmień RuntimeException w plikach Apaczka, Shipment i pozostałych</name>
|
||||
<files>
|
||||
src/Modules/Settings/ApaczkaApiClient.php,
|
||||
src/Modules/Settings/ApaczkaIntegrationRepository.php,
|
||||
src/Modules/Shipments/ApaczkaShipmentService.php,
|
||||
src/Modules/Shipments/AllegroShipmentService.php,
|
||||
src/Modules/Shipments/ShipmentController.php,
|
||||
src/Modules/Settings/IntegrationSecretCipher.php,
|
||||
src/Modules/Settings/InpostIntegrationRepository.php,
|
||||
src/Modules/Settings/ShopproIntegrationsRepository.php,
|
||||
src/Modules/Settings/ShopproOrdersSyncService.php,
|
||||
src/Modules/Settings/ShopproPaymentStatusSyncService.php
|
||||
</files>
|
||||
<action>
|
||||
Podmień RuntimeException:
|
||||
- ApaczkaApiClient.php (9x): curl/HTTP/JSON błędy → ApaczkaApiException
|
||||
- ApaczkaIntegrationRepository.php (4x): brak rekordu/klucza → IntegrationConfigException
|
||||
- ApaczkaShipmentService.php (15x): brak zamówienia/paczki/etykiety → ShipmentException; brak konfiguracji (brak app_id) → IntegrationConfigException; brak danych nadawcy → IntegrationConfigException
|
||||
- AllegroShipmentService.php (8x): brak zamówienia/paczki/przesyłki → ShipmentException; brak danych nadawcy → IntegrationConfigException
|
||||
- ShipmentController.php (3x): nieznany provider, brak paczki, brak providera → ShipmentException
|
||||
- IntegrationSecretCipher.php (3x): brak sekretu, błąd szyfrowania → IntegrationConfigException
|
||||
- InpostIntegrationRepository.php (1x): brak rekordu → IntegrationConfigException
|
||||
- ShopproIntegrationsRepository.php (1x): INTEGRATION_NOT_FOUND → IntegrationConfigException
|
||||
- ShopproOrdersSyncService.php (2x): brak danych API, błąd pobierania zamówień → \RuntimeException (zostawić — są wewnątrz try-catch i message pochodzi z zewnętrznego API)
|
||||
- ShopproPaymentStatusSyncService.php (1x): zostawić jako \RuntimeException (message z zewnętrznego API)
|
||||
|
||||
W każdym pliku dodaj odpowiednie use statements na górze.
|
||||
NIE zmieniaj logiki catch — tylko throw.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Shipments/ApaczkaShipmentService.php
|
||||
php -l src/Modules/Shipments/AllegroShipmentService.php
|
||||
php -l src/Modules/Settings/ApaczkaApiClient.php
|
||||
grep -rn "new RuntimeException" src/ — powinno zwrócić maks. 5 wyników (ShopproOrdersSyncService, ShopproPaymentStatusSyncService, CronRunner, AllegroTokenRefreshHandler — intentional pozostałości)
|
||||
</verify>
|
||||
<done>AC-3, AC-4, AC-5 satisfied: Apaczka i Shipment pliki używają typowanych wyjątków; łańcuch dziedziczenia od RuntimeException zachowany</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Bloki catch (RuntimeException) w controllers/handlers — łańcuch dziedziczenia zachowuje kompatybilność, ale NIE ruszaj istniejących catch
|
||||
- Komunikaty błędów w throw — tylko typ wyjątku się zmienia
|
||||
- src/Core/Exceptions/ — nie tworzyć tu nic poza 6 klasami z tego planu
|
||||
- routes/web.php
|
||||
- Pliki widoków (resources/views/)
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Nie refaktoryzuj logiki poza podmianą throw
|
||||
- Nie dodawaj konstruktorów ani metod do klas wyjątków
|
||||
- Nie zmieniaj sposobu obsługi błędów w UI (flash messages, HTTP redirecty)
|
||||
- Core wyjątki (Router.php, Template.php, Translator.php, ConnectionFactory.php, Migrator.php) — zostawić jako RuntimeException (mają sens jako generyczne)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l na wszystkich zmodyfikowanych plikach PHP — zero błędów składniowych
|
||||
- [ ] grep -rn "new RuntimeException" src/ — max 5 wyników (tylko Core + 2 Shoppro intentional)
|
||||
- [ ] ls src/Core/Exceptions/ — 6 plików: OrderProException, AllegroApiException, AllegroOAuthException, ApaczkaApiException, ShipmentException, IntegrationConfigException
|
||||
- [ ] Aplikacja startuje bez błędów (wejście na stronę główną, brak PHP fatal errors w logach)
|
||||
- [ ] sonar-scanner uruchomiony — sprawdź czy S112 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Wszystkie 3 taski ukończone
|
||||
- Zero błędów składniowych PHP
|
||||
- grep "new RuntimeException" src/ zwraca ≤5 wyników
|
||||
- SonarQube S112 spada z 95 do ≤10
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-01-SUMMARY.md`
|
||||
</output>
|
||||
190
.paul/phases/06-sonarqube-quality/06-02-PLAN.md
Normal file
190
.paul/phases/06-sonarqube-quality/06-02-PLAN.md
Normal file
@@ -0,0 +1,190 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Modules/Settings/AllegroIntegrationController.php
|
||||
- src/Modules/Settings/ShopproIntegrationsController.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Zredukować liczbę `return` w metodach do maksymalnie 3 — eliminacja naruszeń SonarQube php:S1142 (57 wystąpień).
|
||||
|
||||
## Purpose
|
||||
Metody z 4+ returnami (np. `save()` z 5 returnami) są trudne do śledzenia — nie wiadomo jaką ścieżką wróciła wartość. Wydzielenie walidacji do osobnych metod upraszcza główną ścieżkę logiki.
|
||||
|
||||
## Output
|
||||
`AllegroIntegrationController` i `ShopproIntegrationsController` z metodami o max 3 return statements. SonarQube S1142 spada o ~15-20 violations.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/AllegroIntegrationController.php
|
||||
@src/Modules/Settings/ShopproIntegrationsController.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: AllegroIntegrationController::save() — max 3 return
|
||||
```gherkin
|
||||
Given save() ma 5 return statements (walidacja CSRF, URL, credentials, dates, etc.)
|
||||
When refaktoryzujesz przez wydzielenie walidacji do private validateSaveInput(): ?string
|
||||
Then save() ma ≤3 return statements; zachowanie identyczne
|
||||
```
|
||||
|
||||
## AC-2: AllegroIntegrationController::saveImportSettings() — max 3 return
|
||||
```gherkin
|
||||
Given saveImportSettings() ma 4 return statements
|
||||
When wydzielasz walidację do private validateImportSettingsInput(): ?string
|
||||
Then saveImportSettings() ma ≤3 return statements
|
||||
```
|
||||
|
||||
## AC-3: AllegroIntegrationController::oauthCallback() — max 3 return
|
||||
```gherkin
|
||||
Given oauthCallback() ma 4 return statements (walidacja state, code, brak credentials, etc.)
|
||||
When wydzielasz walidację parametrów do private validateOAuthCallbackParams(): ?string
|
||||
Then oauthCallback() ma ≤3 return statements
|
||||
```
|
||||
|
||||
## AC-4: ShopproIntegrationsController::save() — max 3 return
|
||||
```gherkin
|
||||
Given save() ma 5 return statements
|
||||
When wydzielasz walidację do private validateSaveInput(): ?string
|
||||
Then save() ma ≤3 return statements
|
||||
```
|
||||
|
||||
## AC-5: Brak regresji funkcjonalnej
|
||||
```gherkin
|
||||
Given formularze integracji Allegro i Shoppro działają przed zmianą
|
||||
When refaktoryzacja jest czysto strukturalna (ta sama logika, inne rozłożenie)
|
||||
Then wszystkie walidacje nadal działają, komunikaty błędów identyczne
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Refaktoryzacja AllegroIntegrationController — redukcja return w save(), saveImportSettings(), oauthCallback()</name>
|
||||
<files>src/Modules/Settings/AllegroIntegrationController.php</files>
|
||||
<action>
|
||||
Przeczytaj dokładnie trzy metody: save(), saveImportSettings(), oauthCallback().
|
||||
|
||||
**Wzorzec refaktoryzacji (stosuj w każdej metodzie):**
|
||||
- Wydziel bloki walidacji (if + return z błędem) do private helper: validateXxxInput(array $input): ?string
|
||||
- Helper zwraca komunikat błędu lub null (gdy wszystko OK)
|
||||
- W głównej metodzie: $error = $this->validateXxxInput($data); if ($error !== null) { [flash + redirect z $error]; return; }
|
||||
- Dzięki temu główna metoda ma: 1 return po walidacji + 1 return po logice = 2 return zamiast 5
|
||||
|
||||
**save() (linia ~115):**
|
||||
- Wydziel do private validateSaveInput(array $data): ?string
|
||||
- Walidacje do wydzielenia: CSRF check, URL validation, credentials check, date validations
|
||||
- Zwraca pierwszy napotkany błąd jako string, lub null
|
||||
|
||||
**saveImportSettings() (linia ~169):**
|
||||
- Wydziel do private validateImportSettingsInput(array $data): ?string
|
||||
- Walidacje: CSRF, date range checks, inne
|
||||
|
||||
**oauthCallback() (linia ~403):**
|
||||
- Wydziel do private validateOAuthCallbackParams(array $params): ?string
|
||||
- Walidacje: state parameter, code parameter, CSRF state match
|
||||
|
||||
Zasady:
|
||||
- NIE zmieniaj logiki biznesowej — tylko strukturę
|
||||
- NIE zmieniaj komunikatów błędów ani flash keys
|
||||
- NIE zmieniaj redirect paths
|
||||
- Nowe private metody dodaj na końcu klasy, przed ostatnim }
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/AllegroIntegrationController.php
|
||||
grep -c "return" w obrębie save(), saveImportSettings(), oauthCallback() — każda ≤3
|
||||
</verify>
|
||||
<done>AC-1, AC-2, AC-3 satisfied: trzy metody mają ≤3 return statements; składnia poprawna</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Refaktoryzacja ShopproIntegrationsController — redukcja return w save() i innych metodach</name>
|
||||
<files>src/Modules/Settings/ShopproIntegrationsController.php</files>
|
||||
<action>
|
||||
Przeczytaj dokładnie: save(), test(), saveStatusMappings(), syncStatuses().
|
||||
|
||||
**save() (linia ~112):**
|
||||
- Wydziel do private validateSaveInput(array $data): ?string
|
||||
- Walidacje: CSRF, URL, credentials, data range checks
|
||||
- Docelowo: ≤3 return w save()
|
||||
|
||||
**test() (linia ~202):**
|
||||
- 3 return — sprawdź czy można zredukować do 2 przez wydzielenie warunków wejściowych
|
||||
- Jeśli nie da się bez utraty czytelności, zostaw (SonarQube limit to 3 — akceptowalne)
|
||||
|
||||
**saveStatusMappings() (linia ~238):**
|
||||
- Jeśli ma 4+ return: wydziel wstępną walidację
|
||||
|
||||
**syncStatuses() (linia ~301):**
|
||||
- Jeśli ma 4+ return: wydziel walidację
|
||||
|
||||
Stosuj ten sam wzorzec co Task 1: private validateXxxInput(): ?string.
|
||||
Nowe private metody dodaj na końcu klasy.
|
||||
NIE zmieniaj logiki, komunikatów, redirect paths.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproIntegrationsController.php
|
||||
Ręczne przeliczenie: save(), saveStatusMappings(), syncStatuses() — każda ≤3 return
|
||||
</verify>
|
||||
<done>AC-4 satisfied: ShopproIntegrationsController::save() i inne metody mają ≤3 return statements</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Logika biznesowa (warunki, komunikaty błędów, redirect paths, flash keys)
|
||||
- Inne metody poza wymienionymi — nie ruszaj
|
||||
- Pliki widoków, routes/web.php, inne kontrolery
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Refaktoryzacja strukturalna tylko w 2 plikach
|
||||
- Nowe private helper methods — tylko walidacja (nie wydzielaj logiki zapisu do bazy)
|
||||
- Nie wydzielaj metod do osobnych klas (to jest zakres planu 06-05)
|
||||
- Nie zmieniaj visibility metod (public/private)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l src/Modules/Settings/AllegroIntegrationController.php — brak błędów
|
||||
- [ ] php -l src/Modules/Settings/ShopproIntegrationsController.php — brak błędów
|
||||
- [ ] Ręczne sprawdzenie: save() i oauthCallback() w AllegroIntegrationController — ≤3 return każda
|
||||
- [ ] Ręczne sprawdzenie: save() w ShopproIntegrationsController — ≤3 return
|
||||
- [ ] sonar-scanner uruchomiony — S1142 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Oba pliki bez błędów składniowych
|
||||
- save(), saveImportSettings(), oauthCallback() (Allegro) — ≤3 return każda
|
||||
- save() (Shoppro) — ≤3 return
|
||||
- SonarQube S1142 spada o min. 10 violations
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-02-SUMMARY.md`
|
||||
</output>
|
||||
231
.paul/phases/06-sonarqube-quality/06-03-PLAN.md
Normal file
231
.paul/phases/06-sonarqube-quality/06-03-PLAN.md
Normal file
@@ -0,0 +1,231 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Core/Constants/IntegrationSources.php
|
||||
- src/Core/Constants/RedirectPaths.php
|
||||
- src/Modules/Settings/AllegroIntegrationController.php
|
||||
- src/Modules/Settings/ShopproIntegrationsController.php
|
||||
- src/Modules/Orders/OrdersRepository.php
|
||||
- src/Modules/Settings/AllegroOrdersSyncService.php
|
||||
- src/Modules/Settings/AllegroStatusSyncService.php
|
||||
- src/Modules/Settings/AllegroOrderImportService.php
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
- src/Modules/Settings/ShopproStatusSyncService.php
|
||||
- src/Modules/Settings/ShopproPaymentStatusSyncService.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Wyciągnąć 40+ powtarzających się literałów string do stałych — eliminacja naruszeń SonarQube php:S1192.
|
||||
|
||||
## Purpose
|
||||
Ciągi jak `'allegro'` (23x), `'shoppro'` (15x), redirect paths (5-6x) i identyfikatory statusów rozsiane po całym kodzie to pułapki na literówki i utrudnienie przy refaktoryzacji. Stałe zapewniają jedno miejsce zmiany i wykrycie błędu przez IDE.
|
||||
|
||||
## Output
|
||||
Dwie klasy stałych w `src/Core/Constants/`, wszystkie powtórzenia zastąpione — S1192 spada z 40 do ~5.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Orders/OrdersRepository.php
|
||||
@src/Modules/Settings/AllegroIntegrationController.php
|
||||
@src/Modules/Settings/ShopproIntegrationsController.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Klasy stałych istnieją
|
||||
```gherkin
|
||||
Given brak src/Core/Constants/
|
||||
When plan zostaje wykonany
|
||||
Then src/Core/Constants/IntegrationSources.php zawiera ALLEGRO, SHOPPRO, APACZKA, INPOST
|
||||
src/Core/Constants/RedirectPaths.php zawiera stałe dla ścieżek integracji
|
||||
```
|
||||
|
||||
## AC-2: Identyfikatory źródeł podmienione
|
||||
```gherkin
|
||||
Given 'allegro' (23x), 'shoppro' (15x), 'apaczka' (10x), 'inpost' (7x) rozsiane w src/
|
||||
When plan zostaje wykonany
|
||||
Then wszystkie wystąpienia w plikach PHP (poza SQL query strings) używają IntegrationSources::ALLEGRO etc.
|
||||
```
|
||||
|
||||
## AC-3: Redirect paths podmienione w kontrolerach
|
||||
```gherkin
|
||||
Given '/settings/integrations/allegro' (5x), '/settings/integrations/shoppro' (6x) w kontrolerach
|
||||
When plan zostaje wykonany
|
||||
Then AllegroIntegrationController i ShopproIntegrationsController używają RedirectPaths::*
|
||||
```
|
||||
|
||||
## AC-4: Brak regresji
|
||||
```gherkin
|
||||
Given aplikacja działa z twardymi stringami
|
||||
When stałe mają identyczne wartości co podmienianie literały
|
||||
Then zachowanie aplikacji identyczne — routing, source matching, redirect paths
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Utwórz klasy stałych IntegrationSources i RedirectPaths</name>
|
||||
<files>
|
||||
src/Core/Constants/IntegrationSources.php,
|
||||
src/Core/Constants/RedirectPaths.php
|
||||
</files>
|
||||
<action>
|
||||
Utwórz folder src/Core/Constants/ i dwa pliki:
|
||||
|
||||
**IntegrationSources.php** (namespace App\Core\Constants):
|
||||
```php
|
||||
final class IntegrationSources {
|
||||
public const ALLEGRO = 'allegro';
|
||||
public const SHOPPRO = 'shoppro';
|
||||
public const APACZKA = 'apaczka';
|
||||
public const INPOST = 'inpost';
|
||||
}
|
||||
```
|
||||
|
||||
**RedirectPaths.php** (namespace App\Core\Constants):
|
||||
Przejrzyj AllegroIntegrationController i ShopproIntegrationsController i wypisz wszystkie unikalne redirect paths (np. '/settings/integrations/allegro', '/settings/integrations/allegro?tab=settings', '/settings/integrations/shoppro', etc.).
|
||||
Utwórz stałe dla każdego unikalnego path:
|
||||
```php
|
||||
final class RedirectPaths {
|
||||
public const ALLEGRO_INTEGRATION = '/settings/integrations/allegro';
|
||||
public const ALLEGRO_SETTINGS_TAB = '/settings/integrations/allegro?tab=settings';
|
||||
public const ALLEGRO_STATUS_MAPPING_TAB = '/settings/integrations/allegro?tab=status-mapping';
|
||||
public const ALLEGRO_DELIVERY_TAB = '/settings/integrations/allegro?tab=delivery-mapping';
|
||||
public const SHOPPRO_INTEGRATION = '/settings/integrations/shoppro';
|
||||
public const SHOPPRO_SETTINGS_TAB = '/settings/integrations/shoppro?tab=settings';
|
||||
// ... dodaj wszystkie które znajdziesz w plikach kontrolerów
|
||||
}
|
||||
```
|
||||
|
||||
Klasy final, bez konstruktora, bez metod — tylko stałe.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Core/Constants/IntegrationSources.php
|
||||
php -l src/Core/Constants/RedirectPaths.php
|
||||
</verify>
|
||||
<done>AC-1 satisfied: oba pliki istnieją, poprawna składnia PHP</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Podmień identyfikatory źródeł w Services i Repositories</name>
|
||||
<files>
|
||||
src/Modules/Settings/AllegroOrdersSyncService.php,
|
||||
src/Modules/Settings/AllegroStatusSyncService.php,
|
||||
src/Modules/Settings/AllegroOrderImportService.php,
|
||||
src/Modules/Settings/ShopproOrdersSyncService.php,
|
||||
src/Modules/Settings/ShopproStatusSyncService.php,
|
||||
src/Modules/Settings/ShopproPaymentStatusSyncService.php,
|
||||
src/Modules/Orders/OrdersRepository.php
|
||||
</files>
|
||||
<action>
|
||||
W każdym pliku:
|
||||
1. Dodaj use App\Core\Constants\IntegrationSources; na górze
|
||||
2. Podmień literały:
|
||||
- 'allegro' (gdy to identyfikator źródła/integracji, NIE gdy nazwa tabeli SQL) → IntegrationSources::ALLEGRO
|
||||
- 'shoppro' → IntegrationSources::SHOPPRO
|
||||
- 'apaczka' → IntegrationSources::APACZKA
|
||||
- 'inpost' → IntegrationSources::INPOST
|
||||
|
||||
WAŻNE — co NIE podmieniać:
|
||||
- String w zapytaniach SQL (np. WHERE source = 'allegro' w OrdersRepository) — zostaw literal (SonarQube wyjątek dla SQL)
|
||||
- Nazwy tabel, kolumn — zostaw
|
||||
- Klucze tłumaczeń (np. 'settings.allegro.*') — zostaw
|
||||
- Redirect URL paths — podmieniane w Task 3
|
||||
|
||||
Sprawdź kontekst każdego wystąpienia przed podmianą.
|
||||
</action>
|
||||
<verify>
|
||||
php -l na każdym zmodyfikowanym pliku
|
||||
grep -n "'allegro'" src/Modules/Settings/AllegroOrdersSyncService.php — 0 wyników (lub tylko w SQL/komentarzach)
|
||||
grep -n "'shoppro'" src/Modules/Settings/ShopproOrdersSyncService.php — 0 wyników (lub tylko w SQL/komentarzach)
|
||||
</verify>
|
||||
<done>AC-2 satisfied: identyfikatory źródeł w services/repositories używają IntegrationSources::*</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Podmień redirect paths i source literals w kontrolerach</name>
|
||||
<files>
|
||||
src/Modules/Settings/AllegroIntegrationController.php,
|
||||
src/Modules/Settings/ShopproIntegrationsController.php
|
||||
</files>
|
||||
<action>
|
||||
W obu plikach:
|
||||
1. Dodaj use App\Core\Constants\IntegrationSources;
|
||||
2. Dodaj use App\Core\Constants\RedirectPaths;
|
||||
3. Podmień redirect path strings → odpowiednie RedirectPaths::*
|
||||
4. Podmień identyfikatory źródeł 'allegro', 'shoppro' → IntegrationSources::*
|
||||
|
||||
Szczególna uwaga:
|
||||
- Header redirect strings (np. header('Location: /settings/integrations/allegro')) → RedirectPaths::ALLEGRO_INTEGRATION
|
||||
- URL z tabami → odpowiednie stałe z RedirectPaths
|
||||
- Nie podmieniaj kluczy tłumaczeń (settings.allegro.*)
|
||||
- Nie podmieniaj niczego w widokach (resources/views/)
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/AllegroIntegrationController.php
|
||||
php -l src/Modules/Settings/ShopproIntegrationsController.php
|
||||
grep -c "'/settings/integrations/allegro'" src/Modules/Settings/AllegroIntegrationController.php — 0
|
||||
grep -c "'/settings/integrations/shoppro'" src/Modules/Settings/ShopproIntegrationsController.php — 0
|
||||
</verify>
|
||||
<done>AC-3, AC-4 satisfied: redirect paths podmienione; aplikacja zachowuje identyczne zachowanie</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Zapytania SQL z literałami (np. 'allegro' w WHERE clauses) — SonarQube nie flaguje string w SQL
|
||||
- Klucze tłumaczeń (settings.allegro.*, settings.integrations.*)
|
||||
- Pliki widoków (resources/views/)
|
||||
- routes/web.php
|
||||
- Nazwy tabel i kolumn w SQL
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko pliki wymienione w files_modified
|
||||
- Nie tworzyć stałych dla string które pojawiają się tylko 1-2 razy (SonarQube S1192 flaguje 3+ powtórzenia)
|
||||
- Nie przenosić stałych do modułów — zostają w Core/Constants (globalne identyfikatory)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l na wszystkich zmodyfikowanych plikach — zero błędów
|
||||
- [ ] ls src/Core/Constants/ — IntegrationSources.php, RedirectPaths.php
|
||||
- [ ] grep -rn "'allegro'" src/ (bez SQL context) — drastycznie zredukowane
|
||||
- [ ] grep -rn "'shoppro'" src/ (bez SQL context) — drastycznie zredukowane
|
||||
- [ ] sonar-scanner — S1192 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Oba pliki Constants istnieją i są poprawne składniowo
|
||||
- Wszystkie zmodyfikowane pliki bez błędów PHP
|
||||
- SonarQube S1192 spada z 40 do ≤10
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-03-SUMMARY.md`
|
||||
</output>
|
||||
246
.paul/phases/06-sonarqube-quality/06-04-PLAN.md
Normal file
246
.paul/phases/06-sonarqube-quality/06-04-PLAN.md
Normal file
@@ -0,0 +1,246 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Modules/Settings/AllegroIntegrationController.php
|
||||
- src/Modules/Settings/ShopproIntegrationsController.php
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Obniżyć złożoność kognitywną (cognitive complexity) w 5 najbardziej skomplikowanych metodach — eliminacja naruszeń SonarQube php:S3776 (31 wystąpień).
|
||||
|
||||
## Purpose
|
||||
Metody z zagnieżdżonymi if/foreach/switch na 4+ poziomach są trudne do testowania i modyfikacji. Wydzielenie fragmentów do private helper methods upraszcza główny przepływ i obniża wynik SonarQube poniżej progu 15.
|
||||
|
||||
## Output
|
||||
Zmniejszona złożoność w 5 kluczowych metodach w 3 plikach. SonarQube S3776 spada z 31 do ~15.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/AllegroIntegrationController.php
|
||||
@src/Modules/Settings/ShopproIntegrationsController.php
|
||||
@src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: AllegroIntegrationController::oauthCallback() uproszczone
|
||||
```gherkin
|
||||
Given oauthCallback() ma 6 zagnieżdżonych if (validation chain)
|
||||
When wydzielasz każdy blok walidacji do osobnej private metody
|
||||
Then oauthCallback() ma max 2 poziomy zagnieżdżenia
|
||||
```
|
||||
|
||||
## AC-2: AllegroIntegrationController::loadDeliveryServices() uproszczone
|
||||
```gherkin
|
||||
Given loadDeliveryServices() ma try-catch z 4 poziomami zagnieżdżenia
|
||||
When wydzielasz ładowanie Allegro services i Apaczka services do osobnych private metod
|
||||
Then loadDeliveryServices() ma max 2 poziomy zagnieżdżenia
|
||||
```
|
||||
|
||||
## AC-3: ShopproIntegrationsController::saveStatusMappings() uproszczone
|
||||
```gherkin
|
||||
Given saveStatusMappings() ma 3 zagnieżdżone pętle (foreach w foreach z if)
|
||||
When wydzielasz przetwarzanie pojedynczego mappingu do private metody
|
||||
Then saveStatusMappings() ma max 2 poziomy zagnieżdżenia
|
||||
```
|
||||
|
||||
## AC-4: ShopproOrdersSyncService::sync() uproszczone
|
||||
```gherkin
|
||||
Given sync() (195 linii) ma triple nested loop (for pages > foreach candidates > try-catch > if)
|
||||
When wydzielasz przetwarzanie pojedynczej strony do private processPage() i pojedynczego zamówienia do processCandidate()
|
||||
Then sync() ma max 3 poziomy zagnieżdżenia; główna pętla jest czytelna
|
||||
```
|
||||
|
||||
## AC-5: Brak regresji
|
||||
```gherkin
|
||||
Given funkcjonalność działa przed refaktoryzacją
|
||||
When zmiany są czysto strukturalne (extract method, nie zmiana logiki)
|
||||
Then zachowanie identyczne — OAuth flow, status mappings, sync działają
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Uproszczenie AllegroIntegrationController — oauthCallback() i loadDeliveryServices()</name>
|
||||
<files>src/Modules/Settings/AllegroIntegrationController.php</files>
|
||||
<action>
|
||||
Przeczytaj oauthCallback() i loadDeliveryServices() dokładnie.
|
||||
|
||||
**oauthCallback() — wzorzec uproszczenia:**
|
||||
Każdy blok `if (warunek) { flash error; return; }` to kandydat do wydzielenia.
|
||||
Stwórz private validateOAuthState(array $params): bool — sprawdza state parameter
|
||||
Stwórz private validateOAuthCode(array $params): bool — sprawdza code parameter
|
||||
Główna metoda: series of guard checks bez zagnieżdżenia.
|
||||
Docelowy kształt:
|
||||
```php
|
||||
public function oauthCallback(): void {
|
||||
if (!$this->validateOAuthState($params)) { [flash + redirect]; return; }
|
||||
if (!$this->validateOAuthCode($params)) { [flash + redirect]; return; }
|
||||
// logika bez zagnieżdżenia
|
||||
}
|
||||
```
|
||||
|
||||
**loadDeliveryServices() — wzorzec uproszczenia:**
|
||||
Wydziel ładowanie Allegro delivery services do private loadAllegroDeliveryServices(): array
|
||||
Wydziel ładowanie Apaczka services do private loadApaczkaServices(): array
|
||||
Główna metoda wywołuje oba i buduje odpowiedź — bez zagnieżdżonych try-catch.
|
||||
Każda z wydzielonych metod ma swój własny try-catch wewnętrznie.
|
||||
|
||||
Zasady:
|
||||
- NIE zmieniaj logiki — tylko gdzie jest kod
|
||||
- NIE zmieniaj komunikatów, flash keys, redirect paths
|
||||
- Nowe private metody na końcu klasy
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/AllegroIntegrationController.php
|
||||
Ręczne sprawdzenie oauthCallback(): max 2 poziomy zagnieżdżenia w ciele metody
|
||||
Ręczne sprawdzenie loadDeliveryServices(): max 2 poziomy zagnieżdżenia
|
||||
</verify>
|
||||
<done>AC-1, AC-2 satisfied: obie metody uproszczone, składnia poprawna</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Uproszczenie ShopproIntegrationsController — saveStatusMappings()</name>
|
||||
<files>src/Modules/Settings/ShopproIntegrationsController.php</files>
|
||||
<action>
|
||||
Przeczytaj saveStatusMappings() i loadDeliveryServices().
|
||||
|
||||
**saveStatusMappings() — wzorzec uproszczenia:**
|
||||
Jeśli metoda zawiera zagnieżdżone foreach z logiką wewnątrz:
|
||||
```php
|
||||
foreach ($mappings as $mapping) {
|
||||
foreach ($mapping['items'] as $item) {
|
||||
if (...) {
|
||||
// logika
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Wydziel wewnętrzny foreach+if do private processMappingItem(array $item, ...): void
|
||||
lub private processSingleStatusMapping(array $mapping): void
|
||||
|
||||
**loadDeliveryServices() (jeśli jest w Shoppro):**
|
||||
Ten sam wzorzec co Allegro — wydziel ładowanie per-provider.
|
||||
|
||||
Główna zasada: metoda po refaktoryzacji powinna być "czytalna jak lista kroków" — bez zagłębiania się w szczegóły.
|
||||
|
||||
NIE zmieniaj logiki biznesowej.
|
||||
Nowe private metody na końcu klasy.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproIntegrationsController.php
|
||||
Ręczne sprawdzenie saveStatusMappings(): max 2 poziomy zagnieżdżenia
|
||||
</verify>
|
||||
<done>AC-3 satisfied: saveStatusMappings() uproszczone</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Uproszczenie ShopproOrdersSyncService::sync()</name>
|
||||
<files>src/Modules/Settings/ShopproOrdersSyncService.php</files>
|
||||
<action>
|
||||
Przeczytaj metodę sync() (ok. 195 linii).
|
||||
|
||||
**sync() — wzorzec uproszczenia:**
|
||||
Obecna struktura (schemat):
|
||||
```
|
||||
foreach ($integrations) {
|
||||
for ($page = 1; ...) {
|
||||
foreach ($candidates) {
|
||||
try {
|
||||
if (...) {
|
||||
// przetwarzanie zamówienia
|
||||
}
|
||||
} catch (...) { ... }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Wydziel:
|
||||
1. private processOrderCandidate(array $candidate, array $integration, array $statusMap, ...): void
|
||||
- zawiera: try-catch + logikę przetwarzania jednego zamówienia
|
||||
2. private processPageCandidates(array $candidates, array $integration, array $statusMap, array &$results): void
|
||||
- zawiera: foreach ($candidates) + wywołanie processOrderCandidate()
|
||||
|
||||
Po wydzieleniu sync() powinna wyglądać jak:
|
||||
```
|
||||
foreach ($integrations) {
|
||||
for ($page = 1; ...) {
|
||||
$candidates = $this->buildCandidates($orders);
|
||||
$this->processPageCandidates($candidates, $integration, $statusMap, $results);
|
||||
if (brak kolejnej strony) break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Zachowaj wszystkie parametry które są potrzebne (przekaż przez argumenty lub &$results).
|
||||
NIE zmieniaj logiki przetwarzania — tylko gdzie jest kod.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
Ręczne sprawdzenie sync(): max 3 poziomy zagnieżdżenia (foreach integrations > for pages > processPageCandidates)
|
||||
</verify>
|
||||
<done>AC-4, AC-5 satisfied: sync() uproszczone, ShopproOrdersSyncService poprawna składniowo</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Logika biznesowa — warunkowa, obliczeniowa, API calls
|
||||
- Komunikaty błędów, flash keys, redirect paths
|
||||
- Publiczne sygnatury metod (public function names + parameters)
|
||||
- Inne metody poza wymienionymi w AC
|
||||
- Pliki poza files_modified
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Wydzielanie metod tylko wewnątrz istniejącej klasy (nie tworzyć nowych klas — to zakres 06-05)
|
||||
- Nowe metody: private, na końcu klasy, jasna nazwa opisująca co robią
|
||||
- Nie optymalizuj algorytmicznie — tylko strukturalnie
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l na wszystkich 3 plikach — zero błędów
|
||||
- [ ] oauthCallback() — max 2 poziomy zagnieżdżenia (ręczne sprawdzenie)
|
||||
- [ ] loadDeliveryServices() (Allegro) — max 2 poziomy zagnieżdżenia
|
||||
- [ ] saveStatusMappings() (Shoppro) — max 2 poziomy zagnieżdżenia
|
||||
- [ ] sync() (ShopproOrdersSyncService) — max 3 poziomy zagnieżdżenia
|
||||
- [ ] sonar-scanner — S3776 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Wszystkie 3 pliki bez błędów składniowych
|
||||
- 5 wskazanych metod z zredukowanym zagnieżdżeniem
|
||||
- SonarQube S3776 spada z 31 do ≤18
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-04-SUMMARY.md`
|
||||
</output>
|
||||
298
.paul/phases/06-sonarqube-quality/06-05-PLAN.md
Normal file
298
.paul/phases/06-sonarqube-quality/06-05-PLAN.md
Normal file
@@ -0,0 +1,298 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 05
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: ["06-04"]
|
||||
files_modified:
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
- src/Modules/Settings/ShopproOrderMapper.php
|
||||
- src/Modules/Settings/ShopproProductImageResolver.php
|
||||
- src/Modules/Settings/AllegroIntegrationController.php
|
||||
- src/Modules/Settings/AllegroStatusMappingController.php
|
||||
- src/Modules/Settings/AllegroDeliveryMappingController.php
|
||||
autonomous: false
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Rozdzielić 2 z 3 god classes przekraczające 20 metod — eliminacja naruszeń SonarQube php:S1448.
|
||||
- `ShopproOrdersSyncService` (39 metod) → 3 klasy
|
||||
- `AllegroIntegrationController` (30 metod) → 3 kontrolery
|
||||
|
||||
## Purpose
|
||||
God classes naruszają SRP i S1448. `ShopproOrdersSyncService` z 39 metodami i 1192 liniami jest najtrudniejszą do testowania klasą w projekcie. Podział ułatwia izolowane modyfikacje integracji Shoppro bez ryzyka regresi w całym module.
|
||||
|
||||
## Output
|
||||
5 nowych klas/kontrolerów, `ShopproOrdersSyncService` spada do ~15 metod, `AllegroIntegrationController` do ~12. S1448 spada z 6x do 1x (ShopproIntegrationsController pozostaje na następny plan).
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
@src/Modules/Settings/AllegroIntegrationController.php
|
||||
@routes/web.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
| /code-review | optional | Po implementacji, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
||||
- [ ] /code-review rozważyć (duże zmiany strukturalne)
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: ShopproOrderMapper wydzielony
|
||||
```gherkin
|
||||
Given ShopproOrdersSyncService zawiera 15+ metod mapujących (mapOrderAggregate, mapAddresses, mapItems, etc.)
|
||||
When wydzielasz je do src/Modules/Settings/ShopproOrderMapper.php
|
||||
Then ShopproOrderMapper zawiera wszystkie metody mapowania; ShopproOrdersSyncService wstrzykuje go przez konstruktor
|
||||
```
|
||||
|
||||
## AC-2: ShopproProductImageResolver wydzielony
|
||||
```gherkin
|
||||
Given ShopproOrdersSyncService zawiera resolveProductImagesForOrder() i fetchPrimaryProductImageUrl()
|
||||
When wydzielasz je do src/Modules/Settings/ShopproProductImageResolver.php
|
||||
Then ShopproProductImageResolver obsługuje image fetching; ShopproOrdersSyncService używa go przez konstruktor
|
||||
```
|
||||
|
||||
## AC-3: ShopproOrdersSyncService ma ≤20 metod
|
||||
```gherkin
|
||||
Given ShopproOrdersSyncService ma 39 metod
|
||||
When wydzielono ShopproOrderMapper i ShopproProductImageResolver
|
||||
Then ShopproOrdersSyncService ma ≤20 metod (sync + orchestration + state management)
|
||||
```
|
||||
|
||||
## AC-4: AllegroIntegrationController podzielony
|
||||
```gherkin
|
||||
Given AllegroIntegrationController ma 30 metod (status mapping, delivery mapping, main settings)
|
||||
When wydzielasz AllegroStatusMappingController i AllegroDeliveryMappingController
|
||||
Then każdy kontroler ma ≤15 metod; routes/web.php zaktualizowane
|
||||
```
|
||||
|
||||
## AC-5: Brak regresji
|
||||
```gherkin
|
||||
Given Shoppro sync i Allegro integration działają przed podziałem
|
||||
When podział jest czysto strukturalny (move method, nie zmiana logiki)
|
||||
Then sync Shoppro importuje zamówienia; mapowania Allegro zapisują się; OAuth działa
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Wydziel ShopproOrderMapper z ShopproOrdersSyncService</name>
|
||||
<files>
|
||||
src/Modules/Settings/ShopproOrderMapper.php,
|
||||
src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
</files>
|
||||
<action>
|
||||
Przeczytaj ShopproOrdersSyncService dokładnie. Zidentyfikuj metody mapujące dane zamówień.
|
||||
|
||||
**Metody do przeniesienia do ShopproOrderMapper:**
|
||||
Przenieś wszystkie private metody których jedynym zadaniem jest konwersja danych API → struktury wewnętrzne:
|
||||
- mapOrderAggregate() — główna metoda mapowania
|
||||
- mapAddresses() — mapowanie adresów
|
||||
- mapItems() — mapowanie pozycji
|
||||
- mapPayments() — mapowanie płatności
|
||||
- mapShipments() — mapowanie wysyłek
|
||||
- mapNotes() — mapowanie notatek
|
||||
- buildInvoiceAddress() — budowanie adresu faktury
|
||||
- normalizeOrderId(), normalizePaidFlag(), mapPaymentStatus(), sanitizePlainText()
|
||||
- buildDeliveryMethodLabel(), formatMoneyCompact(), normalizeMediaUrl()
|
||||
- toFloatOrNull(), toFloatOrDefault(), readPath(), readSinglePath(), composeName()
|
||||
- hasAddressData(), resolveInvoiceRequested(), parsePickupPoint()
|
||||
|
||||
**ShopproOrderMapper (nowy plik):**
|
||||
- namespace App\Modules\Settings
|
||||
- class ShopproOrderMapper
|
||||
- Konstruktor przyjmuje zależności potrzebne metodom (np. ShopproOrderSyncStateRepository jeśli potrzebne)
|
||||
- Przenieś metody bez zmiany logiki (tylko zmień z private na public te, które sync() wywołuje bezpośrednio)
|
||||
|
||||
**ShopproOrdersSyncService (aktualizacja):**
|
||||
- Dodaj private ShopproOrderMapper $mapper; w konstruktorze
|
||||
- CronHandlerFactory tworzy ShopproOrdersSyncService — sprawdź src/Modules/Cron/CronHandlerFactory.php i zaktualizuj kompozycję
|
||||
- Zastąp wywołania $this->mapOrderAggregate() → $this->mapper->mapOrderAggregate()
|
||||
- Usuń przeniesione metody z ShopproOrdersSyncService
|
||||
|
||||
UWAGA: Sprawdź CronHandlerFactory.php — musi przekazać nowy ShopproOrderMapper do konstruktora.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproOrderMapper.php
|
||||
php -l src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
php -l src/Modules/Cron/CronHandlerFactory.php
|
||||
grep -c "function " src/Modules/Settings/ShopproOrdersSyncService.php — powinno być ≤25 (po Task 1, przed Task 2)
|
||||
</verify>
|
||||
<done>AC-1 satisfied: ShopproOrderMapper istnieje z metodami mapowania; ShopproOrdersSyncService go używa</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Wydziel ShopproProductImageResolver i finalizuj ShopproOrdersSyncService</name>
|
||||
<files>
|
||||
src/Modules/Settings/ShopproProductImageResolver.php,
|
||||
src/Modules/Settings/ShopproOrdersSyncService.php,
|
||||
src/Modules/Cron/CronHandlerFactory.php
|
||||
</files>
|
||||
<action>
|
||||
**ShopproProductImageResolver (nowy plik):**
|
||||
- Przenieś z ShopproOrdersSyncService:
|
||||
- resolveProductImagesForOrder()
|
||||
- fetchPrimaryProductImageUrl()
|
||||
- Konstruktor przyjmuje ShopproApiClient (potrzebny do fetch)
|
||||
- namespace App\Modules\Settings
|
||||
|
||||
**ShopproOrdersSyncService (finalizacja):**
|
||||
- Dodaj private ShopproProductImageResolver $imageResolver;
|
||||
- Zastąp $this->resolveProductImagesForOrder() → $this->imageResolver->resolveProductImagesForOrder()
|
||||
- Po Task 1 + Task 2 ShopproOrdersSyncService powinien mieć ≤20 metod
|
||||
|
||||
**CronHandlerFactory.php (aktualizacja):**
|
||||
- Sprawdź gdzie tworzona jest instancja ShopproOrdersSyncService
|
||||
- Dodaj nowe zależności: new ShopproOrderMapper(...), new ShopproProductImageResolver($shopproApiClient)
|
||||
- Przekaż do konstruktora ShopproOrdersSyncService
|
||||
|
||||
Sprawdź czy ShopproOrderMapper też potrzebuje ShopproApiClient lub innych zależności — jeśli tak, przekaż z CronHandlerFactory.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproProductImageResolver.php
|
||||
php -l src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
php -l src/Modules/Cron/CronHandlerFactory.php
|
||||
grep -c "function " src/Modules/Settings/ShopproOrdersSyncService.php — ≤20
|
||||
</verify>
|
||||
<done>AC-2, AC-3 satisfied: ShopproProductImageResolver wydzielony; ShopproOrdersSyncService ≤20 metod</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<what-built>
|
||||
ShopproOrdersSyncService podzielony na 3 klasy:
|
||||
- ShopproOrderMapper (metody mapowania danych)
|
||||
- ShopproProductImageResolver (pobieranie zdjęć produktów)
|
||||
- ShopproOrdersSyncService (orchestrator, ≤20 metod)
|
||||
CronHandlerFactory zaktualizowany z nowymi zależnościami.
|
||||
</what-built>
|
||||
<how-to-verify>
|
||||
1. Uruchom aplikację (XAMPP)
|
||||
2. Przejdź do Ustawień → Integracje → ShopPRO
|
||||
3. Uruchom ręczny import zamówień (jeśli dostępny) lub uruchom cron
|
||||
4. Sprawdź logi crona: importy Shoppro działają bez błędów
|
||||
5. Sprawdź że zamówienia pojawiają się / nie ma regresji
|
||||
</how-to-verify>
|
||||
<resume-signal>Wpisz "approved" aby kontynuować do podziału AllegroIntegrationController, lub opisz błędy</resume-signal>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Podziel AllegroIntegrationController na 3 kontrolery</name>
|
||||
<files>
|
||||
src/Modules/Settings/AllegroIntegrationController.php,
|
||||
src/Modules/Settings/AllegroStatusMappingController.php,
|
||||
src/Modules/Settings/AllegroDeliveryMappingController.php,
|
||||
routes/web.php
|
||||
</files>
|
||||
<action>
|
||||
Przeczytaj AllegroIntegrationController i routes/web.php dokładnie.
|
||||
|
||||
**Podział metod:**
|
||||
|
||||
AllegroStatusMappingController (nowy):
|
||||
- saveStatusMapping()
|
||||
- saveStatusMappingsBulk()
|
||||
- deleteStatusMapping()
|
||||
- syncStatusesFromAllegro()
|
||||
- buildImportImageWarningMessage() (private helper)
|
||||
- reasonLabel() (private helper)
|
||||
|
||||
AllegroDeliveryMappingController (nowy):
|
||||
- saveDeliveryMappings()
|
||||
- loadDeliveryServices()
|
||||
- (prywatne helpery potrzebne tym metodom)
|
||||
|
||||
AllegroIntegrationController (zostaje z):
|
||||
- index()
|
||||
- save()
|
||||
- saveImportSettings()
|
||||
- startOAuth()
|
||||
- oauthCallback()
|
||||
- refreshOAuthToken()
|
||||
- importSingleOrder()
|
||||
- (prywatne walidatory i helpery potrzebne tym metodom)
|
||||
|
||||
**Nowe pliki kontrolerów:**
|
||||
- Skopiuj konstruktor i zależności z AllegroIntegrationController
|
||||
- namespace App\Modules\Settings
|
||||
- Przenieś metody bez zmiany logiki
|
||||
|
||||
**routes/web.php:**
|
||||
- Utwórz instancje nowych kontrolerów (ten sam wzorzec co istniejące)
|
||||
- Przepnij route definicje dla:
|
||||
- status mapping routes → AllegroStatusMappingController
|
||||
- delivery mapping routes → AllegroDeliveryMappingController
|
||||
- AllegroIntegrationController obsługuje resztę
|
||||
|
||||
Sprawdź które zależności ($this->repository, $this->translator etc.) są potrzebne każdemu kontrolerowi.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/AllegroIntegrationController.php
|
||||
php -l src/Modules/Settings/AllegroStatusMappingController.php
|
||||
php -l src/Modules/Settings/AllegroDeliveryMappingController.php
|
||||
php -l routes/web.php
|
||||
grep -c "function " src/Modules/Settings/AllegroIntegrationController.php — ≤15
|
||||
</verify>
|
||||
<done>AC-4, AC-5 satisfied: AllegroIntegrationController ≤15 metod; nowe kontrolery poprawne; routes zaktualizowane</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Logika biznesowa w żadnej z przenoszonych metod
|
||||
- Publiczne sygnatury metod (nazwy, parametry)
|
||||
- Pliki widoków i SCSS
|
||||
- ShopproIntegrationsController — zakres następnego planu (06-06 jeśli powstanie)
|
||||
- Inne moduły (Orders, Shipments, Auth, etc.)
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Podział 2 klas (ShopproOrdersSyncService + AllegroIntegrationController)
|
||||
- ShopproIntegrationsController pomijamy w tym planie (30 metod — podobny refactoring)
|
||||
- Nie zmieniaj publicznych URL routes — tylko który controller je obsługuje
|
||||
- CronHandlerFactory — tylko minimalne zmiany potrzebne dla nowych dependencies
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l na wszystkich nowych i zmodyfikowanych plikach
|
||||
- [ ] ShopproOrdersSyncService: grep -c "function " ≤20
|
||||
- [ ] AllegroIntegrationController: grep -c "function " ≤15
|
||||
- [ ] ShopproOrderMapper.php istnieje z metodami mapowania
|
||||
- [ ] ShopproProductImageResolver.php istnieje
|
||||
- [ ] AllegroStatusMappingController.php i AllegroDeliveryMappingController.php istnieją
|
||||
- [ ] routes/web.php poprawny składniowo
|
||||
- [ ] Checkpoint human-verify zaliczony (Shoppro sync działa)
|
||||
- [ ] sonar-scanner — S1448 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 4 nowe pliki PHP
|
||||
- ShopproOrdersSyncService ≤20 metod
|
||||
- AllegroIntegrationController ≤15 metod
|
||||
- Zero błędów składniowych
|
||||
- Shoppro import działa (human-verify passed)
|
||||
- SonarQube S1448 spada z 6 do ≤2
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-05-SUMMARY.md`
|
||||
</output>
|
||||
204
.paul/phases/06-sonarqube-quality/06-06-PLAN.md
Normal file
204
.paul/phases/06-sonarqube-quality/06-06-PLAN.md
Normal file
@@ -0,0 +1,204 @@
|
||||
---
|
||||
phase: 06-sonarqube-quality
|
||||
plan: 06
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
- src/Modules/Orders/OrdersRepository.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Skrócić 4 metody przekraczające limit linii — eliminacja naruszeń SonarQube php:S138. Dodatkowo: `OrdersRepository::paginate()` (183 linie) i `findDetails()` (101 linii) jako najdłuższe metody w module Orders.
|
||||
|
||||
## Purpose
|
||||
Metody o 87-195 liniach są niereviewowalne w MR i trudne do lokalnego rozumowania. Wydzielenie sub-metod ogranicza zakres zmian przy przyszłych modyfikacjach — edytujesz 30-liniową metodę, nie 200-liniowy monolit.
|
||||
|
||||
## Output
|
||||
6 metod skróconych do ≤50 linii każda przez ekstrakcję sub-metod. SonarQube S138 spada z 4 do 0.
|
||||
|
||||
**Uwaga na kolejność z planem 06-05:**
|
||||
Ten plan (06-06) modyfikuje ShopproOrdersSyncService. Plan 06-05 podnosi zależność `depends_on: ["06-04"]`. Jeśli 06-05 jest w trakcie, odłóż zmiany w ShopproOrdersSyncService do po zakończeniu 06-05.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
@src/Modules/Orders/OrdersRepository.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
## Skill Invocation Checklist
|
||||
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: ShopproOrdersSyncService — sync() skrócone
|
||||
```gherkin
|
||||
Given sync() ma 195 linii
|
||||
When wydzielasz procesPage() i processOrderCandidate() (jeśli nie zrobione w 06-04)
|
||||
Then sync() ma ≤60 linii; wydzielone metody mają ≤50 linii każda
|
||||
```
|
||||
|
||||
## AC-2: ShopproOrdersSyncService — mapAddresses() skrócone
|
||||
```gherkin
|
||||
Given mapAddresses() ma 166 linii (budowanie customer + delivery address)
|
||||
When wydzielasz buildCustomerAddress(): array i buildDeliveryAddress(): array
|
||||
Then mapAddresses() ma ≤50 linii; każda sub-metoda ≤60 linii
|
||||
```
|
||||
|
||||
## AC-3: OrdersRepository::paginate() skrócone
|
||||
```gherkin
|
||||
Given paginate() ma 183 linie (dynamic SQL building + data transformation)
|
||||
When wydzielasz buildFilters(): array i transformRow(array $row): array
|
||||
Then paginate() ma ≤80 linii; sub-metody mają ≤50 linii każda
|
||||
```
|
||||
|
||||
## AC-4: OrdersRepository::findDetails() skrócone
|
||||
```gherkin
|
||||
Given findDetails() ma 101 linii (8 kolejnych zapytań DB)
|
||||
When wydzielasz osobne private metody per query group (loadOrderItems, loadOrderShipments, etc.)
|
||||
Then findDetails() ma ≤50 linii; każdy loader ≤30 linii
|
||||
```
|
||||
|
||||
## AC-5: Brak regresji
|
||||
```gherkin
|
||||
Given lista zamówień i szczegóły zamówienia działają przed zmianą
|
||||
When zmiany są czysto strukturalne (extract method)
|
||||
Then paginate() i findDetails() zwracają identyczne dane
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Skróć ShopproOrdersSyncService — sync() i mapAddresses()</name>
|
||||
<files>src/Modules/Settings/ShopproOrdersSyncService.php</files>
|
||||
<action>
|
||||
Przeczytaj ShopproOrdersSyncService dokładnie.
|
||||
|
||||
**Sprawdź najpierw:** czy 06-04 już wydzielił processPageCandidates() z sync(). Jeśli tak, sprawdź czy sync() jest już ≤60 linii. Jeśli nie — wydziel.
|
||||
|
||||
**sync() (195 linii) — jeśli jeszcze nie zrobione w 06-04:**
|
||||
Wydziel:
|
||||
- private processPageCandidates(array $candidates, array $integration, array $statusMap, array &$results): void
|
||||
→ zawiera foreach ($candidates) + try-catch + logikę przetwarzania 1 zamówienia
|
||||
- private fetchOrdersPage(array $integration, int $page, string $startDate): array
|
||||
→ zawiera wywołanie API + obsługę błędów odpowiedzi
|
||||
|
||||
**mapAddresses() (166 linii):**
|
||||
Wydziel:
|
||||
- private buildCustomerAddress(array $payload): array
|
||||
→ adres klienta (billing address)
|
||||
- private buildDeliveryAddress(array $payload): array
|
||||
→ adres dostawy (shipping address)
|
||||
- private buildPickupPointData(array $payload): array (jeśli dotyczy)
|
||||
|
||||
mapAddresses() staje się kompozytorem: wywołuje buildCustomerAddress() i buildDeliveryAddress().
|
||||
|
||||
NIE zmieniaj logiki — tylko gdzie jest kod.
|
||||
Nowe private metody na końcu klasy (ale przed zamknięciem `}`).
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
Ręcznie: sync() ≤60 linii, mapAddresses() ≤50 linii
|
||||
</verify>
|
||||
<done>AC-1, AC-2 satisfied: sync() i mapAddresses() skrócone</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Skróć OrdersRepository — paginate() i findDetails()</name>
|
||||
<files>src/Modules/Orders/OrdersRepository.php</files>
|
||||
<action>
|
||||
Przeczytaj OrdersRepository dokładnie — paginate() i findDetails().
|
||||
|
||||
**paginate() (183 linie):**
|
||||
Ma dwie odrębne odpowiedzialności: budowanie SQL z filtrami + transformacja wierszy.
|
||||
|
||||
Wydziel:
|
||||
- private buildPaginateFilters(array $filters): array
|
||||
→ zwraca ['conditions' => [], 'bindings' => []]
|
||||
→ zawiera bloki if ($filter['source']), if ($filter['status']), if ($filter['date_from']), etc.
|
||||
|
||||
- private transformOrderRow(array $row): array
|
||||
→ transformuje jeden wiersz z DB → format gotowy dla widoku
|
||||
→ jeśli nie ma transformacji per-row, wydziel transformOrderRows(array $rows): array
|
||||
|
||||
paginate() staje się: build SQL structure → execute → transform → return.
|
||||
|
||||
WAŻNE: Medoo query syntax — zachowaj dokładnie ten sam format przekazywania warunków do Medoo. NIE zmieniaj sposobu budowania prepared statements.
|
||||
|
||||
**findDetails() (101 linii):**
|
||||
Metoda wykonuje 8 kolejnych zapytań DB. Wydziel każde lub grupuj logicznie:
|
||||
- private loadOrderAddresses(int $orderId): array
|
||||
- private loadOrderItems(int $orderId): array
|
||||
- private loadOrderShipments(int $orderId): array
|
||||
- private loadOrderHistory(int $orderId): array
|
||||
- (i inne grupy które znajdziesz w metodzie)
|
||||
|
||||
findDetails() staje się: załaduj dane orderu + złóż w całość + return.
|
||||
|
||||
NIE zmieniaj logiki SQL, kolumn, tabel, sposobu bindingu.
|
||||
NIE zmieniaj zwracanej struktury danych.
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Orders/OrdersRepository.php
|
||||
Ręcznie: paginate() ≤80 linii, findDetails() ≤50 linii
|
||||
</verify>
|
||||
<done>AC-3, AC-4, AC-5 satisfied: paginate() i findDetails() skrócone; brak zmiany logiki SQL</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Logika SQL w OrdersRepository — prepared statements, WHERE conditions, column names
|
||||
- Zwracana struktura danych z paginate() i findDetails() — widoki zależą od tych kluczy
|
||||
- Publiczne sygnatury metod
|
||||
- Inne pliki poza ShopproOrdersSyncService.php i OrdersRepository.php
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko extract method refactoring — nie zmieniaj algorytmów
|
||||
- Nie przenoś metod do innych klas (to zakres 06-05)
|
||||
- Nie zmieniaj logiki filtrowania w paginate() — tylko gdzie jest kod
|
||||
- ShopproOrdersSyncService: uważaj na interferencję z 06-05 (jeśli 06-05 już zmienił tę klasę — dostosuj)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Przed zamknięciem planu:
|
||||
- [ ] php -l src/Modules/Settings/ShopproOrdersSyncService.php — brak błędów
|
||||
- [ ] php -l src/Modules/Orders/OrdersRepository.php — brak błędów
|
||||
- [ ] sync() w ShopproOrdersSyncService: ≤60 linii (ręczne sprawdzenie)
|
||||
- [ ] mapAddresses(): ≤50 linii
|
||||
- [ ] paginate(): ≤80 linii
|
||||
- [ ] findDetails(): ≤50 linii
|
||||
- [ ] Lista zamówień ładuje się (brak PHP fatal errors)
|
||||
- [ ] sonar-scanner — S138 violations zmalały
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Oba pliki bez błędów składniowych
|
||||
- 4 metody skrócone poniżej limitu SonarQube
|
||||
- Nowe private helper metody ≤50 linii każda
|
||||
- SonarQube S138 spada z 4 do 0
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Po zakończeniu utwórz `.paul/phases/06-sonarqube-quality/06-06-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user