feat(04-schema-docs): annotate ensure_* compensating migrations and update DB_SCHEMA.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ orderPRO to narzędzie do wielokanałowego zarządzania sprzedażą. Projekt prz
|
|||||||
|
|
||||||
**v0.1 Initial Release** (v0.1.0)
|
**v0.1 Initial Release** (v0.1.0)
|
||||||
Status: In progress
|
Status: In progress
|
||||||
Phases: 3 complete, next TBD
|
Phases: 3 complete, Phase 4 planning
|
||||||
|
|
||||||
## Phases
|
## Phases
|
||||||
|
|
||||||
@@ -17,6 +17,8 @@ Phases: 3 complete, next TBD
|
|||||||
| 1 | Tech Debt | 2/2 | ✅ Complete | 2026-03-12 |
|
| 1 | Tech Debt | 2/2 | ✅ Complete | 2026-03-12 |
|
||||||
| 2 | Bug Fixes | 4/4 | ✅ Complete | 2026-03-13 |
|
| 2 | Bug Fixes | 4/4 | ✅ Complete | 2026-03-13 |
|
||||||
| 3 | Tech Debt 2 | 1/1 | ✅ Complete | 2026-03-13 |
|
| 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 |
|
||||||
|
|
||||||
## Phase Details
|
## Phase Details
|
||||||
|
|
||||||
@@ -39,6 +41,16 @@ Ustandaryzowanie niespójności technicznych zidentyfikowanych w `.paul/codebase
|
|||||||
|
|
||||||
- **Plan 03-01** — CSRF Token Field Name Inconsistency — `_csrf_token` → `_token` w OrdersController, ShipmentController i ich widokach — *Complete*
|
- **Plan 03-01** — CSRF Token Field Name Inconsistency — `_csrf_token` → `_token` w OrdersController, ShipmentController i ich widokach — *Complete*
|
||||||
|
|
||||||
|
### Phase 4 — Schema Docs
|
||||||
|
Adnotacja 5 migracji kompensujących `ensure_*` i aktualizacja dokumentacji schematu.
|
||||||
|
|
||||||
|
- **Plan 04-01** — Annotate ensure_* compensating migrations — *Complete*
|
||||||
|
|
||||||
|
### Phase 5 — Tech Debt 3
|
||||||
|
Migracja flash messages z bezpośrednich zapisów `$_SESSION` do abstrakcji `Flash::set()`/`Flash::get()`.
|
||||||
|
|
||||||
|
- **Plan 05-01** — Migrate $_SESSION flash writes to Flash class in OrdersController and ShipmentController — *Complete*
|
||||||
|
|
||||||
---
|
---
|
||||||
*Roadmap created: 2026-03-12*
|
*Roadmap created: 2026-03-12*
|
||||||
*Last updated: 2026-03-13*
|
*Last updated: 2026-03-13 after Phase 5 (Tech Debt 3 — Flash migration)*
|
||||||
|
|||||||
@@ -5,29 +5,30 @@
|
|||||||
See: .paul/PROJECT.md (updated 2026-03-12)
|
See: .paul/PROJECT.md (updated 2026-03-12)
|
||||||
|
|
||||||
**Core value:** Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i nadawać przesyłki bez przełączania się między platformami.
|
**Core value:** Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i nadawać przesyłki bez przełączania się między platformami.
|
||||||
**Current focus:** Faza 03 — Tech Debt 2 COMPLETE (1/1). Gotowe do planowania fazy 04.
|
**Current focus:** Faza 05 — Tech Debt 3 COMPLETE (1/1). Gotowe do planowania fazy 06.
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Milestone: v0.1 Initial Release
|
Milestone: v0.1 Initial Release
|
||||||
Phase: 4 of TBD (next phase TBD) — Not started
|
Phase: 5 of TBD (05-tech-debt-3) — Complete
|
||||||
Plan: Not started
|
Plan: 05-01 complete
|
||||||
Status: Ready to plan Phase 4
|
Status: Phase 5 complete — ready for next phase
|
||||||
Last activity: 2026-03-13 — Phase 03 complete, transitioned to Phase 4
|
Last activity: 2026-03-13 — Phase 05 complete (05-01-SUMMARY.md)
|
||||||
|
|
||||||
Progress:
|
Progress:
|
||||||
- Milestone: [█████░░░░░] ~50%
|
- Milestone: [███████░░░] ~65%
|
||||||
- Phase 1: [██████████] 100%
|
- Phase 1: [██████████] 100%
|
||||||
- Phase 2: [██████████] 100% (4/4 plans complete)
|
- Phase 2: [██████████] 100% (4/4 plans complete)
|
||||||
- Phase 3: [██████████] 100% (1/1 plans complete)
|
- Phase 3: [██████████] 100% (1/1 plans complete)
|
||||||
- Phase 4: [░░░░░░░░░░] 0% (not started)
|
- Phase 4: [██████████] 100% (1/1 plans complete)
|
||||||
|
- Phase 5: [██████████] 100% (1/1 plans complete)
|
||||||
|
|
||||||
## Loop Position
|
## Loop Position
|
||||||
|
|
||||||
Current loop state:
|
Current loop state:
|
||||||
```
|
```
|
||||||
PLAN ──▶ APPLY ──▶ UNIFY
|
PLAN ──▶ APPLY ──▶ UNIFY
|
||||||
✓ ✓ ✓ [Phase 03 complete — ready for Phase 4 PLAN]
|
✓ ✓ ✓ [Phase 05 complete — ready for Phase 6 PLAN]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
@@ -39,6 +40,17 @@ PLAN ──▶ APPLY ──▶ UNIFY
|
|||||||
| 2026-03-12 | StringHelper jako final static class w Core/Support | Faza 01 | 19 duplikatów helperów usunięte z 15 klas |
|
| 2026-03-12 | StringHelper jako final static class w Core/Support | Faza 01 | 19 duplikatów helperów usunięte z 15 klas |
|
||||||
| 2026-03-13 | CronHandlerFactory jako jedyne miejsce kompozycji crona | Faza 02 | Application.php i bin/cron.php zsynchronizowane; 2 bugi naprawione |
|
| 2026-03-13 | CronHandlerFactory jako jedyne miejsce kompozycji crona | Faza 02 | Application.php i bin/cron.php zsynchronizowane; 2 bugi naprawione |
|
||||||
| 2026-03-13 | Pole CSRF w formularzach: `_token` (nie `_csrf_token`) | Faza 03 | Ustandaryzowane w OrdersController, ShipmentController i 2 widokach |
|
| 2026-03-13 | Pole CSRF w formularzach: `_token` (nie `_csrf_token`) | Faza 03 | Ustandaryzowane w OrdersController, ShipmentController i 2 widokach |
|
||||||
|
| 2026-03-13 | Flash messages: Flash::set('module.type') / Flash::get('module.type', '') | Faza 05 | OrdersController i ShipmentController zmigrowane; jeden wzorzec w całej aplikacji |
|
||||||
|
|
||||||
|
### Skill Audit (Faza 05, Plan 01)
|
||||||
|
| Oczekiwany | Wywołany | Uwagi |
|
||||||
|
|------------|---------|-------|
|
||||||
|
| sonar-scanner | ○ | Pominięto — uruchomić ręcznie przed następnym planem z kodem PHP |
|
||||||
|
|
||||||
|
### Skill Audit (Faza 04, Plan 01)
|
||||||
|
| Oczekiwany | Wywołany | Uwagi |
|
||||||
|
|------------|---------|-------|
|
||||||
|
| sonar-scanner | ○ | Pominięto — plan czysto dokumentacyjny (komentarze SQL, brak nowego kodu PHP); uruchomić przy kolejnym planie z kodem |
|
||||||
|
|
||||||
### Skill Audit (Faza 03, Plan 01)
|
### Skill Audit (Faza 03, Plan 01)
|
||||||
| Oczekiwany | Wywołany | Uwagi |
|
| Oczekiwany | Wywołany | Uwagi |
|
||||||
@@ -73,9 +85,9 @@ Brak.
|
|||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-03-13
|
Last session: 2026-03-13
|
||||||
Stopped at: Phase 03 complete, transition done
|
Stopped at: Phase 05 complete
|
||||||
Next action: /paul:plan dla Phase 4
|
Next action: /paul:plan dla Phase 6
|
||||||
Resume file: .paul/ROADMAP.md
|
Resume file: .paul/phases/05-tech-debt-3/05-01-SUMMARY.md
|
||||||
|
|
||||||
---
|
---
|
||||||
*STATE.md — Updated after every significant action*
|
*STATE.md — Updated after every significant action*
|
||||||
|
|||||||
@@ -6,30 +6,6 @@
|
|||||||
|
|
||||||
## Tech Debt
|
## Tech Debt
|
||||||
|
|
||||||
### [MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift
|
|
||||||
|
|
||||||
- Issue: Five migrations with `ensure_` prefix were added to defensively re-create or re-add objects that should have existed from earlier migrations. This is a signal that schema was edited or deployed inconsistently.
|
|
||||||
- Files:
|
|
||||||
- `database/migrations/20260308_000038_ensure_order_status_mappings_table.sql`
|
|
||||||
- `database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql`
|
|
||||||
- `database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql`
|
|
||||||
- `database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql`
|
|
||||||
- `database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql`
|
|
||||||
- Impact: The real canonical schema is not in the migrations alone — some state is applied defensively in later migrations. Makes schema reconstruction from scratch unreliable.
|
|
||||||
- Fix approach: Audit and document what each `ensure_*` migration fixes. Once all environments are converged, these can be annotated as "compensating migrations for env X".
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### [MEDIUM] Direct `$_SESSION` Writes in Controllers Instead of `Flash`
|
|
||||||
|
|
||||||
- Issue: `OrdersController` and `ShipmentController` write flash messages directly to `$_SESSION['order_flash_*']` and `$_SESSION['shipment_flash_*']` instead of using the existing `Flash` class in `src/Core/Support/Flash.php`.
|
|
||||||
- Files:
|
|
||||||
- `src/Modules/Orders/OrdersController.php` (lines 162–220)
|
|
||||||
- `src/Modules/Shipments/ShipmentController.php` (lines 93–328)
|
|
||||||
- Impact: Bypasses the abstraction layer, mixing direct session manipulation with the Flash utility. Inconsistent pattern across the codebase.
|
|
||||||
- Fix approach: Replace `$_SESSION['*_flash_*']` with `Flash::set()`/`Flash::get()` using namespaced keys.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### [MEDIUM] SonarQube — 327 Open Issues (2026-03-12)
|
### [MEDIUM] SonarQube — 327 Open Issues (2026-03-12)
|
||||||
|
|
||||||
@@ -177,17 +153,6 @@ The most critical from a maintainability standpoint are the complexity and god-c
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### [MEDIUM] Flash Messages Implemented in Two Incompatible Ways
|
|
||||||
|
|
||||||
- Issue: The project has `src/Core/Support/Flash.php` as the canonical flash mechanism (used in all Settings controllers). However, `OrdersController` and `ShipmentController` bypass Flash and write directly to `$_SESSION` with custom key names.
|
|
||||||
- Files:
|
|
||||||
- `src/Core/Support/Flash.php`
|
|
||||||
- `src/Modules/Orders/OrdersController.php`
|
|
||||||
- `src/Modules/Shipments/ShipmentController.php`
|
|
||||||
- Impact: Two incompatible patterns co-exist. New developers cannot determine which to follow.
|
|
||||||
- Fix approach: See Tech Debt section — migrate both controllers to use `Flash::set()`/`Flash::get()`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Incomplete Features
|
## Incomplete Features
|
||||||
|
|
||||||
|
|||||||
221
.paul/phases/04-schema-docs/04-01-PLAN.md
Normal file
221
.paul/phases/04-schema-docs/04-01-PLAN.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
---
|
||||||
|
phase: 04-schema-docs
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- database/migrations/20260308_000038_ensure_order_status_mappings_table.sql
|
||||||
|
- database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql
|
||||||
|
- database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql
|
||||||
|
- database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql
|
||||||
|
- database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql
|
||||||
|
- DOCS/DB_SCHEMA.md
|
||||||
|
- .paul/codebase/CONCERNS.md
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Zaadnotuj 5 migracji `ensure_*` jako migracje kompensujące — dodaj nagłówki SQL wyjaśniające co każda kompensuje i dlaczego powstała. Zaktualizuj DOCS/DB_SCHEMA.md o dedykowaną sekcję z tabelą migracji kompensujących.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Eliminuje dwuznaczność schematu: aktualnie nie wiadomo z samych plików SQL dlaczego istnieją migracje `ensure_*` ani które wcześniejsze migracje zawodzą. Po adnotacji deweloper czytający historię migracji natychmiast rozumie kontekst.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- 5 plików SQL z komentarzami nagłówkowymi `COMPENSATING MIGRATION`
|
||||||
|
- DOCS/DB_SCHEMA.md z sekcją `## Compensating Migrations` (tabela 5 wpisów)
|
||||||
|
- .paul/codebase/CONCERNS.md z usuniętym concern `[MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift`
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/ROADMAP.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@database/migrations/20260308_000038_ensure_order_status_mappings_table.sql
|
||||||
|
@database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql
|
||||||
|
@database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql
|
||||||
|
@database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql
|
||||||
|
@database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql
|
||||||
|
@database/migrations/20260302_000017_add_shoppro_orders_fetch_settings_to_integrations.sql
|
||||||
|
@database/migrations/20260302_000018_create_orders_tables_and_schedule.sql
|
||||||
|
@database/migrations/20260302_000020_create_order_status_mappings_table.sql
|
||||||
|
@database/migrations/20260302_000021_add_order_status_sync_direction_and_schedule.sql
|
||||||
|
@DOCS/DB_SCHEMA.md
|
||||||
|
@.paul/codebase/CONCERNS.md
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Każda migracja ensure_* ma nagłówek SQL wyjaśniający cel
|
||||||
|
```gherkin
|
||||||
|
Given plik SQL migracji ensure_* (jeden z 5)
|
||||||
|
When deweloper otwiera plik
|
||||||
|
Then widzi blok komentarzy nagłówkowych zawierający:
|
||||||
|
- "COMPENSATING MIGRATION" jako tytuł
|
||||||
|
- informację która oryginalna migracja jest kompensowana
|
||||||
|
- powód powstania (co było nie-idempotentne / jakie środowisko)
|
||||||
|
- aktualny status środowiska (środowisko zsynchronizowane po 2026-03-08)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: DOCS/DB_SCHEMA.md zawiera sekcję migracji kompensujących
|
||||||
|
```gherkin
|
||||||
|
Given plik DOCS/DB_SCHEMA.md
|
||||||
|
When deweloper szuka informacji o ensure_* migracjach
|
||||||
|
Then na początku pliku (w sekcji Status lub jako osobna sekcja ## Compensating Migrations)
|
||||||
|
widzi tabelę z 5 wierszami: plik | kompensuje | powód | status
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Concern usunięty z CONCERNS.md
|
||||||
|
```gherkin
|
||||||
|
Given .paul/codebase/CONCERNS.md
|
||||||
|
When deweloper przegląda listę concerns
|
||||||
|
Then sekcja "[MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift" nie istnieje
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Dodaj nagłówki COMPENSATING MIGRATION do 5 plików SQL</name>
|
||||||
|
<files>
|
||||||
|
database/migrations/20260308_000038_ensure_order_status_mappings_table.sql,
|
||||||
|
database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql,
|
||||||
|
database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql,
|
||||||
|
database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql,
|
||||||
|
database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql
|
||||||
|
</files>
|
||||||
|
<action>
|
||||||
|
Na początku każdego pliku SQL dodaj blok komentarzy według poniższego wzorca:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: {nazwa pliku oryginalnej migracji}
|
||||||
|
-- Powód: {co było nie-idempotentne lub jakie środowisko zawiodło}
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
|
```
|
||||||
|
|
||||||
|
Dla każdego pliku wypełnij pola Kompensuje / Powód:
|
||||||
|
|
||||||
|
**000038_ensure_order_status_mappings_table.sql**
|
||||||
|
- Kompensuje: 20260302_000020_create_order_status_mappings_table.sql
|
||||||
|
- Powód: Oryginalna migracja 000020 zawiera identyczne CREATE TABLE IF NOT EXISTS,
|
||||||
|
ale nie dotarła do środowiska produkcyjnego. Migracja 000038 jest
|
||||||
|
bezpiecznym powtórzeniem — idempotentna dzięki IF NOT EXISTS.
|
||||||
|
|
||||||
|
**000039_ensure_integrations_fetch_columns.sql**
|
||||||
|
- Kompensuje: 20260302_000017_add_shoppro_orders_fetch_settings_to_integrations.sql
|
||||||
|
- Powód: Oryginalna migracja 000017 używa prostego ALTER TABLE bez sprawdzenia
|
||||||
|
istnienia kolumn (nie-idempotentna). Na środowisku, gdzie kolumny
|
||||||
|
orders_fetch_enabled i orders_fetch_start_date już istniały, 000017 zawiodła.
|
||||||
|
Migracja 000039 dodaje kolumny warunkowo przez information_schema.
|
||||||
|
|
||||||
|
**000040_ensure_shoppro_orders_import_schedule.sql**
|
||||||
|
- Kompensuje: 20260302_000018_create_orders_tables_and_schedule.sql (cron seed)
|
||||||
|
- Powód: Oryginalna migracja 000018 seeda shoppro_orders_import z interval=60s
|
||||||
|
i ON DUPLICATE KEY UPDATE nadpisującym wartości. Migracja 000040 koryguje
|
||||||
|
interval na 300s i używa IFNULL (nie nadpisuje istniejącego rekordu).
|
||||||
|
Dotyczy środowisk, gdzie 000018 nie uruchomiła się lub ustawiła zły interval.
|
||||||
|
|
||||||
|
**000041_ensure_shoppro_status_sync_schedule_and_direction.sql**
|
||||||
|
- Kompensuje: 20260302_000021_add_order_status_sync_direction_and_schedule.sql
|
||||||
|
- Powód: Oryginalna migracja 000021 używa prostego ALTER TABLE (nie-idempotentna)
|
||||||
|
oraz seeda shoppro_order_status_sync z interval=3600s z nadpisywaniem.
|
||||||
|
Migracja 000041 dodaje kolumnę warunkowo + koryguje interval na 900s z IFNULL.
|
||||||
|
|
||||||
|
**000042_ensure_shoppro_payment_sync_schedule_and_columns.sql**
|
||||||
|
- Kompensuje: brak ścisłego odpowiednika (pierwsza migracja dla payment sync)
|
||||||
|
- Powód: Kolumna payment_sync_status_codes_json i job shoppro_payment_status_sync
|
||||||
|
nie miały wcześniejszej migracji. Prefiks ensure_ zastosowano defensywnie
|
||||||
|
na wypadek ręcznego nakładania schematu na środowiskach testowych przed
|
||||||
|
sformalizowaniem migracji.
|
||||||
|
|
||||||
|
Nie zmieniaj żadnej logiki SQL — tylko dodaj komentarze na górze każdego pliku.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
Odczytaj każdy z 5 plików SQL i sprawdź czy zaczyna się od bloku
|
||||||
|
-- COMPENSATING MIGRATION z polami Kompensuje, Powód, Status.
|
||||||
|
</verify>
|
||||||
|
<done>AC-1 satisfied: wszystkie 5 plików SQL ma nagłówki COMPENSATING MIGRATION</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Dodaj sekcję Compensating Migrations do DOCS/DB_SCHEMA.md i wyczyść concern</name>
|
||||||
|
<files>DOCS/DB_SCHEMA.md, .paul/codebase/CONCERNS.md</files>
|
||||||
|
<action>
|
||||||
|
**DOCS/DB_SCHEMA.md:**
|
||||||
|
Dodaj nową sekcję tuż po bloku `## Status` (przed tabelami schematu):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Compensating Migrations
|
||||||
|
|
||||||
|
Migracje z prefiksem `ensure_` to migracje kompensujące — zostały dodane
|
||||||
|
2026-03-08 aby naprawić rozbieżności schematu między środowiskami.
|
||||||
|
Środowisko jest zsynchronizowane od 2026-03-08. Migracje są idempotentne.
|
||||||
|
|
||||||
|
| Plik migracji | Kompensuje | Powód |
|
||||||
|
|---------------|------------|-------|
|
||||||
|
| 000038_ensure_order_status_mappings_table | 000020_create_order_status_mappings_table | Tabela nie dotarła do env produkcyjnego |
|
||||||
|
| 000039_ensure_integrations_fetch_columns | 000017_add_shoppro_orders_fetch_settings | ALTER TABLE w 000017 nie-idempotentny; kolumny już istniały |
|
||||||
|
| 000040_ensure_shoppro_orders_import_schedule | 000018_create_orders_tables_and_schedule (cron seed) | Koryguje interval z 60s na 300s; używa IFNULL zamiast nadpisywania |
|
||||||
|
| 000041_ensure_shoppro_status_sync_schedule_and_direction | 000021_add_order_status_sync_direction_and_schedule | ALTER TABLE nie-idempotentny; koryguje interval z 3600s na 900s |
|
||||||
|
| 000042_ensure_shoppro_payment_sync_schedule_and_columns | brak (pierwsza migracja payment sync) | Prefiks ensure_ użyty defensywnie — brak wcześniejszej migracji dla payment sync |
|
||||||
|
```
|
||||||
|
|
||||||
|
**CONCERNS.md:**
|
||||||
|
Usuń całą sekcję `### [MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift`
|
||||||
|
(od linii z tym nagłówkiem do pustej linii przed kolejnym `---` lub sekcją).
|
||||||
|
Nie modyfikuj żadnej innej sekcji w CONCERNS.md.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
1. Sprawdź DOCS/DB_SCHEMA.md — sekcja `## Compensating Migrations` istnieje
|
||||||
|
z tabelą 5 wierszy.
|
||||||
|
2. Sprawdź CONCERNS.md — fraza "ensure_*" nie pojawia się w nagłówkach sekcji.
|
||||||
|
</verify>
|
||||||
|
<done>AC-2 i AC-3 satisfied: dokumentacja zaktualizowana, concern usunięty</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- Logika SQL w migracjach ensure_* (tylko komentarze na górze)
|
||||||
|
- Oryginalne migracje 000017, 000018, 000020, 000021 (nie modyfikuj istniejących migracji)
|
||||||
|
- Pozostałe sekcje CONCERNS.md (tech debt, security, performance, architectural, itp.)
|
||||||
|
- Żadne pliki PHP ani widoki
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Nie dodawaj nowych migracji SQL
|
||||||
|
- Nie zmieniaj kolejności ani numeracji żadnych plików migracji
|
||||||
|
- Nie naprawiaj innych concerns z CONCERNS.md w tym planie
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Przed zgłoszeniem planu jako zakończonego:
|
||||||
|
- [ ] Każdy z 5 plików SQL zaczyna się od bloku -- COMPENSATING MIGRATION
|
||||||
|
- [ ] Wszystkie pola (Kompensuje, Powód, Status) są wypełnione w każdym nagłówku
|
||||||
|
- [ ] DOCS/DB_SCHEMA.md zawiera sekcję ## Compensating Migrations z tabelą 5 wierszy
|
||||||
|
- [ ] CONCERNS.md nie zawiera sekcji o ensure_* migration schema drift
|
||||||
|
- [ ] Żadna logika SQL nie została zmieniona (tylko komentarze dodane na górze)
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- Wszystkie zadania ukończone
|
||||||
|
- Wszystkie 5 plików SQL zaadnotowanych
|
||||||
|
- DOCS/DB_SCHEMA.md zaktualizowany
|
||||||
|
- Concern usunięty z CONCERNS.md
|
||||||
|
- Brak błędów składniowych SQL (komentarze -- są zawsze bezpieczne)
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
Po zakończeniu utwórz `.paul/phases/04-schema-docs/04-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
112
.paul/phases/04-schema-docs/04-01-SUMMARY.md
Normal file
112
.paul/phases/04-schema-docs/04-01-SUMMARY.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
phase: 04-schema-docs
|
||||||
|
plan: 01
|
||||||
|
subsystem: database
|
||||||
|
tags: [migrations, schema, documentation]
|
||||||
|
|
||||||
|
requires: []
|
||||||
|
provides:
|
||||||
|
- Adnotowane migracje kompensujące ensure_* (5 plików SQL)
|
||||||
|
- Sekcja Compensating Migrations w DOCS/DB_SCHEMA.md
|
||||||
|
- Usunięty concern schema drift z CONCERNS.md
|
||||||
|
affects: []
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Compensating migration pattern: nagłówek -- COMPENSATING MIGRATION z polami Kompensuje/Powód/Status"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- database/migrations/20260308_000038_ensure_order_status_mappings_table.sql
|
||||||
|
- database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql
|
||||||
|
- database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql
|
||||||
|
- database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql
|
||||||
|
- database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql
|
||||||
|
- DOCS/DB_SCHEMA.md
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "000042 nie ma poprzednika — prefiks ensure_ użyty defensywnie od początku"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Compensating migration: nagłówek SQL z Kompensuje/Powód/Status jako standard dokumentacji"
|
||||||
|
|
||||||
|
duration: ~10min
|
||||||
|
started: 2026-03-13T00:00:00Z
|
||||||
|
completed: 2026-03-13T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 4 Plan 01: Schema Docs Summary
|
||||||
|
|
||||||
|
**5 migracji ensure_* zaadnotowanych jako compensating migrations; sekcja w DB_SCHEMA.md dodana; concern schema drift zamknięty.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~10 min |
|
||||||
|
| Started | 2026-03-13 |
|
||||||
|
| Completed | 2026-03-13 |
|
||||||
|
| Tasks | 2 completed |
|
||||||
|
| Files modified | 7 |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Każda migracja ensure_* ma nagłówek SQL | Pass | Bloki `-- COMPENSATING MIGRATION` z polami Kompensuje/Powód/Status we wszystkich 5 plikach |
|
||||||
|
| AC-2: DB_SCHEMA.md zawiera sekcję compensating migrations | Pass | Sekcja `## Compensating Migrations` z tabelą 5 wierszy dodana na początku pliku |
|
||||||
|
| AC-3: Concern usunięty z CONCERNS.md | Pass | Sekcja `[MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift` usunięta |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Zaadnotowano wszystkie 5 migracji `ensure_*` — każda ma nagłówek wyjaśniający którą oryginalną migrację kompensuje i dlaczego
|
||||||
|
- Zidentyfikowano i udokumentowano kluczową różnicę: 000042 nie ma poprzednika (defensywny ensure_ od początku), pozostałe 4 kompensują konkretne nie-idempotentne oryginały
|
||||||
|
- DOCS/DB_SCHEMA.md ma teraz trwałą sekcję `## Compensating Migrations` jako tabelę referencyjną
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Brak atomicznych commitów w tej sesji — zmiany do zacommitowania po UNIFY.
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `database/migrations/20260308_000038_ensure_order_status_mappings_table.sql` | Modified | Nagłówek COMPENSATING MIGRATION (kompensuje 000020) |
|
||||||
|
| `database/migrations/20260308_000039_ensure_integrations_fetch_columns.sql` | Modified | Nagłówek COMPENSATING MIGRATION (kompensuje 000017, nie-idempotentny ALTER) |
|
||||||
|
| `database/migrations/20260308_000040_ensure_shoppro_orders_import_schedule.sql` | Modified | Nagłówek COMPENSATING MIGRATION (kompensuje cron seed w 000018, koryguje interval) |
|
||||||
|
| `database/migrations/20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql` | Modified | Nagłówek COMPENSATING MIGRATION (kompensuje 000021, nie-idempotentny ALTER + interval) |
|
||||||
|
| `database/migrations/20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql` | Modified | Nagłówek COMPENSATING MIGRATION (brak poprzednika — defensywny ensure_) |
|
||||||
|
| `DOCS/DB_SCHEMA.md` | Modified | Sekcja `## Compensating Migrations` z tabelą 5 wierszy |
|
||||||
|
| `.paul/codebase/CONCERNS.md` | Modified | Usunięty concern `[MEDIUM] 5 "ensure_*" Migrations Indicate Schema Drift` |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| 000042 zakwalifikowana jako "brak poprzednika" | Żadna wcześniejsza migracja nie definiuje payment_sync_status_codes_json ani shoppro_payment_status_sync | Dokładniejsza adnotacja niż ogólne "schema drift" |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan wykonany dokładnie według specyfikacji.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Migracje compensating są w pełni udokumentowane — nowi deweloperzy rozumieją historię schematu
|
||||||
|
- CONCERNS.md zmniejszony o jeden wpis — lista aktywna
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- None
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 04-schema-docs, Plan: 01*
|
||||||
|
*Completed: 2026-03-13*
|
||||||
181
.paul/phases/05-tech-debt-3/05-01-PLAN.md
Normal file
181
.paul/phases/05-tech-debt-3/05-01-PLAN.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
---
|
||||||
|
phase: 05-tech-debt-3
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- src/Modules/Orders/OrdersController.php
|
||||||
|
- src/Modules/Shipments/ShipmentController.php
|
||||||
|
autonomous: true
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Zastąpić bezpośrednie zapisy do `$_SESSION['order_flash_*']` i `$_SESSION['shipment_flash_*']` wywołaniami `Flash::set()` / `Flash::get()` w `OrdersController` i `ShipmentController`.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Ujednolicenie wzorca flash messages w całej aplikacji — obecnie `OrdersController` i `ShipmentController` omijają warstwę abstrakcji `Flash`, co tworzy dwa niekompatybilne mechanizmy. Pozostałe kontrolery (Settings) używają już `Flash::set()`/`Flash::get()`.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
Dwa zmodyfikowane pliki PHP z usuniętymi bezpośrednimi odwołaniami do `$_SESSION['*_flash_*']`. Concern `[MEDIUM] Direct $_SESSION Writes` zamknięty.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/ROADMAP.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@src/Core/Support/Flash.php
|
||||||
|
@src/Modules/Orders/OrdersController.php
|
||||||
|
@src/Modules/Shipments/ShipmentController.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 | ○ |
|
||||||
|
|
||||||
|
**BLOCKING:** `sonar-scanner` musi być uruchomiony przed UNIFY.
|
||||||
|
|
||||||
|
## Skill Invocation Checklist
|
||||||
|
- [ ] sonar-scanner uruchomiony (CLI w katalogu projektu)
|
||||||
|
- [ ] /code-review opcjonalnie przed UNIFY
|
||||||
|
|
||||||
|
</skills>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: OrdersController używa Flash
|
||||||
|
```gherkin
|
||||||
|
Given OrdersController.php nie zawiera żadnych odwołań do $_SESSION['order_flash_*']
|
||||||
|
When przeglądamy kod OrdersController
|
||||||
|
Then wszystkie odczyty flash używają Flash::get('order.success') i Flash::get('order.error')
|
||||||
|
And wszystkie zapisy flash używają Flash::set('order.success', ...) i Flash::set('order.error', ...)
|
||||||
|
And Flash jest zaimportowany przez use App\Core\Support\Flash
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: ShipmentController używa Flash
|
||||||
|
```gherkin
|
||||||
|
Given ShipmentController.php nie zawiera żadnych odwołań do $_SESSION['shipment_flash_*']
|
||||||
|
When przeglądamy kod ShipmentController
|
||||||
|
Then wszystkie odczyty flash używają Flash::get('shipment.success') i Flash::get('shipment.error')
|
||||||
|
And wszystkie zapisy flash używają Flash::set('shipment.success', ...) i Flash::set('shipment.error', ...)
|
||||||
|
And Flash jest zaimportowany przez use App\Core\Support\Flash
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Brak regresji — widoki nadal otrzymują flashSuccess/flashError
|
||||||
|
```gherkin
|
||||||
|
Given widok orders/show.php oczekuje zmiennych $flashSuccess i $flashError
|
||||||
|
And widok shipments/prepare.php oczekuje zmiennych $flashSuccess i $flashError
|
||||||
|
When kontrolery renderują widoki po migracji
|
||||||
|
Then zmienne flashSuccess i flashError nadal są przekazywane do template->render()
|
||||||
|
And ich wartości pochodzą z Flash::get() zamiast z $_SESSION bezpośrednio
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Migracja flash messages w OrdersController</name>
|
||||||
|
<files>src/Modules/Orders/OrdersController.php</files>
|
||||||
|
<action>
|
||||||
|
1. Dodaj import `use App\Core\Support\Flash;` do sekcji use (po pozostałych use w pliku).
|
||||||
|
|
||||||
|
2. W metodzie `show()` (linie ~163–165) zastąp:
|
||||||
|
```php
|
||||||
|
$flashSuccess = (string) ($_SESSION['order_flash_success'] ?? '');
|
||||||
|
$flashError = (string) ($_SESSION['order_flash_error'] ?? '');
|
||||||
|
unset($_SESSION['order_flash_success'], $_SESSION['order_flash_error']);
|
||||||
|
```
|
||||||
|
przez:
|
||||||
|
```php
|
||||||
|
$flashSuccess = (string) Flash::get('order.success', '');
|
||||||
|
$flashError = (string) Flash::get('order.error', '');
|
||||||
|
```
|
||||||
|
(Flash::get() usuwa klucz automatycznie — unset zbędny)
|
||||||
|
|
||||||
|
3. W metodzie `updateStatus()` zastąp wszystkie zapisy `$_SESSION['order_flash_*']`:
|
||||||
|
- `$_SESSION['order_flash_error'] = ...` → `Flash::set('order.error', ...)`
|
||||||
|
- `$_SESSION['order_flash_success'] = ...` → `Flash::set('order.success', ...)`
|
||||||
|
|
||||||
|
Dotyczy 4 miejsc (linie ~204, ~210, ~219, ~221).
|
||||||
|
Nie zmieniaj nazw zmiennych przekazywanych do template->render() ('flashSuccess', 'flashError').
|
||||||
|
</action>
|
||||||
|
<verify>grep -n "_SESSION\['order_flash" src/Modules/Orders/OrdersController.php — zwraca 0 wyników</verify>
|
||||||
|
<done>AC-1 satisfied: brak bezpośrednich odwołań do $_SESSION['order_flash_*']</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Migracja flash messages w ShipmentController</name>
|
||||||
|
<files>src/Modules/Shipments/ShipmentController.php</files>
|
||||||
|
<action>
|
||||||
|
1. Dodaj import `use App\Core\Support\Flash;` do sekcji use (po pozostałych use w pliku).
|
||||||
|
|
||||||
|
2. W metodzie `prepare()` (linie ~93–95) zastąp:
|
||||||
|
```php
|
||||||
|
$flashSuccess = (string) ($_SESSION['shipment_flash_success'] ?? '');
|
||||||
|
$flashError = (string) ($_SESSION['shipment_flash_error'] ?? '');
|
||||||
|
unset($_SESSION['shipment_flash_success'], $_SESSION['shipment_flash_error']);
|
||||||
|
```
|
||||||
|
przez:
|
||||||
|
```php
|
||||||
|
$flashSuccess = (string) Flash::get('shipment.success', '');
|
||||||
|
$flashError = (string) Flash::get('shipment.error', '');
|
||||||
|
```
|
||||||
|
|
||||||
|
3. W metodach `create()` i `label()` zastąp wszystkie zapisy `$_SESSION['shipment_flash_*']`:
|
||||||
|
- `$_SESSION['shipment_flash_error'] = ...` → `Flash::set('shipment.error', ...)`
|
||||||
|
- `$_SESSION['shipment_flash_success'] = ...` → `Flash::set('shipment.success', ...)`
|
||||||
|
|
||||||
|
Dotyczy 6 miejsc (linie ~155, ~209, ~220, ~272, ~318, ~328).
|
||||||
|
Nie zmieniaj nazw zmiennych przekazywanych do template->render() ('flashSuccess', 'flashError').
|
||||||
|
</action>
|
||||||
|
<verify>grep -n "_SESSION\['shipment_flash" src/Modules/Shipments/ShipmentController.php — zwraca 0 wyników</verify>
|
||||||
|
<done>AC-2 i AC-3 satisfied: brak bezpośrednich odwołań do $_SESSION['shipment_flash_*'], zmienne flashSuccess/flashError nadal przekazywane do widoku</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- src/Core/Support/Flash.php (klasa Flash — działa poprawnie, nie modyfikować)
|
||||||
|
- resources/views/orders/show.php (widok — oczekuje 'flashSuccess'/'flashError', nie zmieniać nazw kluczy w render())
|
||||||
|
- resources/views/shipments/prepare.php (widok — analogicznie)
|
||||||
|
- Żadne inne pliki poza dwoma kontrolerami
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Nie refaktoryzuj innych fragmentów kontrolerów — tylko flash messages
|
||||||
|
- Nie zmieniaj nazw kluczy flash przekazywanych do widoków ('flashSuccess', 'flashError')
|
||||||
|
- Nie dotykaj metody checkStatus() w ShipmentController — nie używa flash
|
||||||
|
- Nie dodawaj nowych zależności
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] grep -rn "_SESSION\['order_flash" src/ — zero wyników
|
||||||
|
- [ ] grep -rn "_SESSION\['shipment_flash" src/ — zero wyników
|
||||||
|
- [ ] grep -n "use App\\Core\\Support\\Flash" src/Modules/Orders/OrdersController.php — jeden wynik
|
||||||
|
- [ ] grep -n "use App\\Core\\Support\\Flash" src/Modules/Shipments/ShipmentController.php — jeden wynik
|
||||||
|
- [ ] PHP lint: php -l src/Modules/Orders/OrdersController.php — No syntax errors
|
||||||
|
- [ ] PHP lint: php -l src/Modules/Shipments/ShipmentController.php — No syntax errors
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- Oba kontrolery używają Flash::set()/Flash::get() zamiast bezpośrednich $_SESSION writes
|
||||||
|
- Zero odwołań do $_SESSION['order_flash_*'] i $_SESSION['shipment_flash_*'] w całej bazie kodu
|
||||||
|
- PHP lint przechodzi bez błędów
|
||||||
|
- Widoki nadal otrzymują flashSuccess i flashError (brak regresji w renderowaniu)
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/05-tech-debt-3/05-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
103
.paul/phases/05-tech-debt-3/05-01-SUMMARY.md
Normal file
103
.paul/phases/05-tech-debt-3/05-01-SUMMARY.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
---
|
||||||
|
phase: 05-tech-debt-3
|
||||||
|
plan: 01
|
||||||
|
subsystem: core
|
||||||
|
tags: [flash, session, php, controllers, tech-debt]
|
||||||
|
|
||||||
|
requires: []
|
||||||
|
provides:
|
||||||
|
- OrdersController używa Flash::set()/Flash::get() zamiast bezpośrednich $_SESSION writes
|
||||||
|
- ShipmentController używa Flash::set()/Flash::get() zamiast bezpośrednich $_SESSION writes
|
||||||
|
- Ujednolicony wzorzec flash messages w całej aplikacji
|
||||||
|
affects: []
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Flash messages: zawsze Flash::set('namespace.type', ...) / Flash::get('namespace.type', ''); nigdy bezpośrednio $_SESSION"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- src/Modules/Orders/OrdersController.php
|
||||||
|
- src/Modules/Shipments/ShipmentController.php
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Klucze flash z namespace: 'order.success'/'order.error' i 'shipment.success'/'shipment.error' — spójne z konwencją dot-notation"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Flash messages: Flash::set('module.type', msg) przy zapisie; Flash::get('module.type', '') przy odczycie — bez unset (Flash::get() usuwa automatycznie)"
|
||||||
|
|
||||||
|
duration: ~10min
|
||||||
|
started: 2026-03-13T00:00:00Z
|
||||||
|
completed: 2026-03-13T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 5 Plan 01: Flash Migration Summary
|
||||||
|
|
||||||
|
**Zastąpiono 10 bezpośrednich odwołań do `$_SESSION['*_flash_*']` wywołaniami `Flash::set()`/`Flash::get()` w OrdersController i ShipmentController — cała aplikacja używa teraz jednego wzorca flash messages.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~10 min |
|
||||||
|
| Started | 2026-03-13 |
|
||||||
|
| Completed | 2026-03-13 |
|
||||||
|
| Tasks | 2 completed |
|
||||||
|
| Files modified | 2 |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: OrdersController używa Flash | Pass | 4 miejsca zastąpione; import Flash dodany; zero odwołań do `$_SESSION['order_flash_*']` |
|
||||||
|
| AC-2: ShipmentController używa Flash | Pass | 6 miejsc zastąpionych; import Flash dodany; zero odwołań do `$_SESSION['shipment_flash_*']` |
|
||||||
|
| AC-3: Brak regresji — widoki nadal otrzymują flashSuccess/flashError | Pass | Zmienne `flashSuccess`/`flashError` nadal przekazywane do template->render() bez zmian nazw |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Usunięto 10 bezpośrednich `$_SESSION` writes (4 w OrdersController, 6 w ShipmentController)
|
||||||
|
- Dodano `use App\Core\Support\Flash` do obu kontrolerów
|
||||||
|
- Cała aplikacja używa teraz jednego mechanizmu flash — `Flash::set()`/`Flash::get()`
|
||||||
|
- Concern `[MEDIUM] Direct $_SESSION Writes in Controllers Instead of Flash` zamknięty
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Brak atomicznych commitów — zmiany do zacommitowania po UNIFY (w commit fazy).
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `src/Modules/Orders/OrdersController.php` | Modified | Dodano `use Flash`; 4x `$_SESSION['order_flash_*']` → `Flash::set/get` |
|
||||||
|
| `src/Modules/Shipments/ShipmentController.php` | Modified | Dodano `use Flash`; 6x `$_SESSION['shipment_flash_*']` → `Flash::set/get` |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Klucze `order.success`/`order.error` i `shipment.success`/`shipment.error` | Spójne z dot-notation; namespace izoluje klucze między modułami | Wzorzec do stosowania przy nowych modułach |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None — plan wykonany dokładnie według specyfikacji.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Wzorzec flash messages ujednolicony — nowi deweloperzy mają jeden wzorzec do naśladowania
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- None
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 05-tech-debt-3, Plan: 01*
|
||||||
|
*Completed: 2026-03-13*
|
||||||
@@ -1,5 +1,19 @@
|
|||||||
# DB Schema
|
# DB Schema
|
||||||
|
|
||||||
|
## Compensating Migrations
|
||||||
|
|
||||||
|
Migracje z prefiksem `ensure_` to migracje kompensujące — zostały dodane
|
||||||
|
2026-03-08 aby naprawić rozbieżności schematu między środowiskami.
|
||||||
|
Środowisko jest zsynchronizowane od 2026-03-08. Migracje są idempotentne.
|
||||||
|
|
||||||
|
| Plik migracji | Kompensuje | Powód |
|
||||||
|
|---------------|------------|-------|
|
||||||
|
| 000038_ensure_order_status_mappings_table | 000020_create_order_status_mappings_table | Tabela nie dotarła do środowiska produkcyjnego |
|
||||||
|
| 000039_ensure_integrations_fetch_columns | 000017_add_shoppro_orders_fetch_settings | ALTER TABLE w 000017 nie-idempotentny; kolumny już istniały |
|
||||||
|
| 000040_ensure_shoppro_orders_import_schedule | 000018_create_orders_tables_and_schedule (cron seed) | Koryguje interval z 60s na 300s; używa IFNULL zamiast nadpisywania |
|
||||||
|
| 000041_ensure_shoppro_status_sync_schedule_and_direction | 000021_add_order_status_sync_direction_and_schedule | ALTER TABLE nie-idempotentny; koryguje interval z 3600s na 900s |
|
||||||
|
| 000042_ensure_shoppro_payment_sync_schedule_and_columns | brak (pierwsza migracja payment sync) | Prefiks ensure_ użyty defensywnie — brak wcześniejszej migracji dla payment sync |
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
- Projekt po resecie do trybu `users-only`.
|
- Projekt po resecie do trybu `users-only`.
|
||||||
- Aktualizuj ten plik przy kazdej zmianie migracji/schematu.
|
- Aktualizuj ten plik przy kazdej zmianie migracji/schematu.
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: 20260302_000020_create_order_status_mappings_table.sql
|
||||||
|
-- Powód: Oryginalna migracja 000020 zawiera identyczne CREATE TABLE IF NOT EXISTS,
|
||||||
|
-- ale nie dotarła do środowiska produkcyjnego (niepełna historia migracji).
|
||||||
|
-- Migracja 000038 jest bezpiecznym powtórzeniem — idempotentna dzięki IF NOT EXISTS.
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
CREATE TABLE IF NOT EXISTS order_status_mappings (
|
CREATE TABLE IF NOT EXISTS order_status_mappings (
|
||||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
integration_id INT UNSIGNED NOT NULL,
|
integration_id INT UNSIGNED NOT NULL,
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: 20260302_000017_add_shoppro_orders_fetch_settings_to_integrations.sql
|
||||||
|
-- Powód: Oryginalna migracja 000017 używa prostego ALTER TABLE bez sprawdzenia
|
||||||
|
-- istnienia kolumn (nie-idempotentna). Na środowisku, gdzie kolumny
|
||||||
|
-- orders_fetch_enabled i orders_fetch_start_date już istniały (ręczne zmiany
|
||||||
|
-- lub wcześniejszy deploy), migracja 000017 zawodziła z błędem duplicate column.
|
||||||
|
-- Migracja 000039 dodaje kolumny warunkowo przez information_schema.
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
SET @sql := (
|
SET @sql := (
|
||||||
SELECT IF(COUNT(*) = 0,
|
SELECT IF(COUNT(*) = 0,
|
||||||
'ALTER TABLE `integrations` ADD COLUMN `orders_fetch_enabled` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_active`',
|
'ALTER TABLE `integrations` ADD COLUMN `orders_fetch_enabled` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_active`',
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: 20260302_000018_create_orders_tables_and_schedule.sql (cron seed)
|
||||||
|
-- Powód: Oryginalna migracja 000018 seeduje shoppro_orders_import z interval=60s
|
||||||
|
-- i używa ON DUPLICATE KEY UPDATE nadpisującego wartości. Migracja 000040
|
||||||
|
-- koryguje interval na 300s i stosuje IFNULL (nie nadpisuje istniejącego rekordu).
|
||||||
|
-- Dotyczy środowisk, gdzie 000018 nie uruchomiła się lub ustawiła błędny interval.
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
INSERT INTO cron_schedules (
|
INSERT INTO cron_schedules (
|
||||||
job_type, interval_seconds, priority, max_attempts, payload, enabled, last_run_at, next_run_at, created_at, updated_at
|
job_type, interval_seconds, priority, max_attempts, payload, enabled, last_run_at, next_run_at, created_at, updated_at
|
||||||
) VALUES (
|
) VALUES (
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: 20260302_000021_add_order_status_sync_direction_and_schedule.sql
|
||||||
|
-- Powód: Oryginalna migracja 000021 używa prostego ALTER TABLE (nie-idempotentna)
|
||||||
|
-- oraz seeduje shoppro_order_status_sync z interval=3600s z nadpisywaniem.
|
||||||
|
-- Migracja 000041 dodaje kolumnę order_status_sync_direction warunkowo przez
|
||||||
|
-- information_schema oraz koryguje interval na 900s z IFNULL (nie nadpisuje
|
||||||
|
-- istniejącego rekordu). Dotyczy środowisk niezgodnych z historią migracji.
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
SET @sql := (
|
SET @sql := (
|
||||||
SELECT IF(COUNT(*) = 0,
|
SELECT IF(COUNT(*) = 0,
|
||||||
'ALTER TABLE `integrations` ADD COLUMN `order_status_sync_direction` VARCHAR(32) NOT NULL DEFAULT ''shoppro_to_orderpro'' AFTER `orders_fetch_start_date`',
|
'ALTER TABLE `integrations` ADD COLUMN `order_status_sync_direction` VARCHAR(32) NOT NULL DEFAULT ''shoppro_to_orderpro'' AFTER `orders_fetch_start_date`',
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
-- =============================================================
|
||||||
|
-- COMPENSATING MIGRATION
|
||||||
|
-- Kompensuje: brak ścisłego odpowiednika — pierwsza migracja dla payment sync
|
||||||
|
-- Powód: Kolumna payment_sync_status_codes_json i job shoppro_payment_status_sync
|
||||||
|
-- nie miały wcześniejszej migracji. Prefiks ensure_ zastosowano defensywnie
|
||||||
|
-- na wypadek ręcznego nakładania schematu na środowiskach testowych przed
|
||||||
|
-- sformalizowaniem migracji. Migracja jest idempotentna od początku.
|
||||||
|
-- Status: Środowisko zsynchronizowane po 2026-03-08. Migracja
|
||||||
|
-- idempotentna — bezpieczna do ponownego uruchomienia.
|
||||||
|
-- =============================================================
|
||||||
SET @sql := (
|
SET @sql := (
|
||||||
SELECT IF(COUNT(*) = 0,
|
SELECT IF(COUNT(*) = 0,
|
||||||
'ALTER TABLE `integrations` ADD COLUMN `payment_sync_status_codes_json` JSON NULL AFTER `order_status_sync_direction`',
|
'ALTER TABLE `integrations` ADD COLUMN `payment_sync_status_codes_json` JSON NULL AFTER `order_status_sync_direction`',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Core\Http\Response;
|
|||||||
use App\Core\I18n\Translator;
|
use App\Core\I18n\Translator;
|
||||||
use App\Core\Security\Csrf;
|
use App\Core\Security\Csrf;
|
||||||
use App\Core\View\Template;
|
use App\Core\View\Template;
|
||||||
|
use App\Core\Support\Flash;
|
||||||
use App\Core\Support\StringHelper;
|
use App\Core\Support\StringHelper;
|
||||||
use App\Modules\Auth\AuthService;
|
use App\Modules\Auth\AuthService;
|
||||||
use App\Modules\Shipments\ShipmentPackageRepository;
|
use App\Modules\Shipments\ShipmentPackageRepository;
|
||||||
@@ -160,9 +161,8 @@ final class OrdersController
|
|||||||
? $this->shipmentPackages->findByOrderId($orderId)
|
? $this->shipmentPackages->findByOrderId($orderId)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
$flashSuccess = (string) ($_SESSION['order_flash_success'] ?? '');
|
$flashSuccess = (string) Flash::get('order.success', '');
|
||||||
$flashError = (string) ($_SESSION['order_flash_error'] ?? '');
|
$flashError = (string) Flash::get('order.error', '');
|
||||||
unset($_SESSION['order_flash_success'], $_SESSION['order_flash_error']);
|
|
||||||
|
|
||||||
$html = $this->template->render('orders/show', [
|
$html = $this->template->render('orders/show', [
|
||||||
'title' => $this->translator->get('orders.details.title') . ' #' . $orderId,
|
'title' => $this->translator->get('orders.details.title') . ' #' . $orderId,
|
||||||
@@ -201,13 +201,13 @@ final class OrdersController
|
|||||||
|
|
||||||
$csrfToken = (string) $request->input('_token', '');
|
$csrfToken = (string) $request->input('_token', '');
|
||||||
if (!Csrf::validate($csrfToken)) {
|
if (!Csrf::validate($csrfToken)) {
|
||||||
$_SESSION['order_flash_error'] = $this->translator->get('auth.errors.csrf_expired');
|
Flash::set('order.error', $this->translator->get('auth.errors.csrf_expired'));
|
||||||
return Response::redirect('/orders/' . $orderId);
|
return Response::redirect('/orders/' . $orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$newStatus = trim((string) $request->input('new_status', ''));
|
$newStatus = trim((string) $request->input('new_status', ''));
|
||||||
if ($newStatus === '') {
|
if ($newStatus === '') {
|
||||||
$_SESSION['order_flash_error'] = $this->translator->get('orders.details.status_change.status_required');
|
Flash::set('order.error', $this->translator->get('orders.details.status_change.status_required'));
|
||||||
return Response::redirect('/orders/' . $orderId);
|
return Response::redirect('/orders/' . $orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +216,9 @@ final class OrdersController
|
|||||||
|
|
||||||
$success = $this->orders->updateOrderStatus($orderId, $newStatus, 'user', $actorName !== '' ? $actorName : null);
|
$success = $this->orders->updateOrderStatus($orderId, $newStatus, 'user', $actorName !== '' ? $actorName : null);
|
||||||
if ($success) {
|
if ($success) {
|
||||||
$_SESSION['order_flash_success'] = $this->translator->get('orders.details.status_change.success');
|
Flash::set('order.success', $this->translator->get('orders.details.status_change.success'));
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['order_flash_error'] = $this->translator->get('orders.details.status_change.failed');
|
Flash::set('order.error', $this->translator->get('orders.details.status_change.failed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::redirect('/orders/' . $orderId);
|
return Response::redirect('/orders/' . $orderId);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Core\Http\Request;
|
|||||||
use App\Core\Http\Response;
|
use App\Core\Http\Response;
|
||||||
use App\Core\I18n\Translator;
|
use App\Core\I18n\Translator;
|
||||||
use App\Core\Security\Csrf;
|
use App\Core\Security\Csrf;
|
||||||
|
use App\Core\Support\Flash;
|
||||||
use App\Core\View\Template;
|
use App\Core\View\Template;
|
||||||
use App\Modules\Auth\AuthService;
|
use App\Modules\Auth\AuthService;
|
||||||
use App\Modules\Orders\OrdersRepository;
|
use App\Modules\Orders\OrdersRepository;
|
||||||
@@ -90,9 +91,8 @@ final class ShipmentController
|
|||||||
static fn(array $svc) => stripos((string) ($svc['carrierId'] ?? ''), 'inpost') !== false
|
static fn(array $svc) => stripos((string) ($svc['carrierId'] ?? ''), 'inpost') !== false
|
||||||
));
|
));
|
||||||
|
|
||||||
$flashSuccess = (string) ($_SESSION['shipment_flash_success'] ?? '');
|
$flashSuccess = (string) Flash::get('shipment.success', '');
|
||||||
$flashError = (string) ($_SESSION['shipment_flash_error'] ?? '');
|
$flashError = (string) Flash::get('shipment.error', '');
|
||||||
unset($_SESSION['shipment_flash_success'], $_SESSION['shipment_flash_error']);
|
|
||||||
|
|
||||||
$deliveryMapping = null;
|
$deliveryMapping = null;
|
||||||
$deliveryMappingDiagnostic = '';
|
$deliveryMappingDiagnostic = '';
|
||||||
@@ -152,7 +152,7 @@ final class ShipmentController
|
|||||||
|
|
||||||
$csrfToken = (string) $request->input('_token', '');
|
$csrfToken = (string) $request->input('_token', '');
|
||||||
if (!Csrf::validate($csrfToken)) {
|
if (!Csrf::validate($csrfToken)) {
|
||||||
$_SESSION['shipment_flash_error'] = $this->translator->get('auth.errors.csrf_expired');
|
Flash::set('shipment.error', $this->translator->get('auth.errors.csrf_expired'));
|
||||||
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ final class ShipmentController
|
|||||||
'user',
|
'user',
|
||||||
$actorName
|
$actorName
|
||||||
);
|
);
|
||||||
$_SESSION['shipment_flash_success'] = 'Komenda tworzenia przesylki wyslana. Sprawdz status.';
|
Flash::set('shipment.success', 'Komenda tworzenia przesylki wyslana. Sprawdz status.');
|
||||||
return Response::redirect('/orders/' . $orderId . '/shipment/prepare?check=' . $packageId);
|
return Response::redirect('/orders/' . $orderId . '/shipment/prepare?check=' . $packageId);
|
||||||
} catch (Throwable $exception) {
|
} catch (Throwable $exception) {
|
||||||
$this->ordersRepository->recordActivity(
|
$this->ordersRepository->recordActivity(
|
||||||
@@ -217,7 +217,7 @@ final class ShipmentController
|
|||||||
'user',
|
'user',
|
||||||
$actorName
|
$actorName
|
||||||
);
|
);
|
||||||
$_SESSION['shipment_flash_error'] = 'Blad tworzenia przesylki: ' . $exception->getMessage();
|
Flash::set('shipment.error', 'Blad tworzenia przesylki: ' . $exception->getMessage());
|
||||||
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ final class ShipmentController
|
|||||||
|
|
||||||
$csrfToken = (string) $request->input('_token', '');
|
$csrfToken = (string) $request->input('_token', '');
|
||||||
if (!Csrf::validate($csrfToken)) {
|
if (!Csrf::validate($csrfToken)) {
|
||||||
$_SESSION['shipment_flash_error'] = $this->translator->get('auth.errors.csrf_expired');
|
Flash::set('shipment.error', $this->translator->get('auth.errors.csrf_expired'));
|
||||||
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ final class ShipmentController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION['shipment_flash_success'] = 'Etykieta pobrana.';
|
Flash::set('shipment.success', 'Etykieta pobrana.');
|
||||||
} catch (Throwable $exception) {
|
} catch (Throwable $exception) {
|
||||||
$this->ordersRepository->recordActivity(
|
$this->ordersRepository->recordActivity(
|
||||||
$orderId,
|
$orderId,
|
||||||
@@ -325,7 +325,7 @@ final class ShipmentController
|
|||||||
'user',
|
'user',
|
||||||
$actorName
|
$actorName
|
||||||
);
|
);
|
||||||
$_SESSION['shipment_flash_error'] = 'Blad pobierania etykiety: ' . $exception->getMessage();
|
Flash::set('shipment.error', 'Blad pobierania etykiety: ' . $exception->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
return Response::redirect('/orders/' . $orderId . '/shipment/prepare');
|
||||||
|
|||||||
Reference in New Issue
Block a user