Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 255456dcc5 | |||
| e84edb2354 | |||
| fba215b372 | |||
|
|
0de47f4e62 | ||
|
|
abb794de36 |
@@ -14,7 +14,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
||||
|-----------|-------|
|
||||
| Version | 0.333 |
|
||||
| Status | Production |
|
||||
| Last Updated | 2026-04-20 |
|
||||
| Last Updated | 2026-04-30 |
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -32,6 +32,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
||||
- [x] Domain-Driven Architecture (migracja z legacy zakończona)
|
||||
- [x] Szybka edycja custom_label_0..4 na liscie produktow admina (toggle sesyjny + autocomplete)
|
||||
- [x] Poprawna kalkulacja kosztu transportu na /koszyk-podsumowanie (fix delivery_free bez uwzglednienia progu)
|
||||
- [x] Linki produktów z permutacją w feedzie Google działają (separator `_` w URL, konwersja `_`→`|` w warstwie front, regex `[0-9_-]+` w pp_routes)
|
||||
|
||||
### Active (In Progress)
|
||||
|
||||
@@ -83,12 +84,13 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
||||
| `id` w tabbed FormEdit przez `hiddenFields` | Zapobiega insert zamiast update przy edycji encji | 2026-04-18 | Active |
|
||||
| Inline custom labels w product list przez sesyjny toggle | Szybszy workflow dla Google XML bez wejscia w edycje produktu | 2026-04-19 | Active |
|
||||
| Kalkulacja kosztu transportu na /koszyk-podsumowanie w kontrolerze (nie w szablonie) | Spojnosc logiki progu darmowej dostawy miedzy /koszyk i /koszyk-podsumowanie | 2026-04-20 | Active |
|
||||
| Separator URL permutacji `_` zamiast `/` (DB pozostaje `|`) | Jeden segment URL dopasowywalny przez pp_routes; konwersja `_`→`|` w warstwie front | 2026-04-30 | Active |
|
||||
|
||||
## Success Metrics
|
||||
|
||||
| Metric | Target | Current | Status |
|
||||
|--------|--------|---------|--------|
|
||||
| Testy | >800 | 834 | On track |
|
||||
| Testy | >800 | 841 | On track |
|
||||
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
||||
|
||||
## Tech Stack
|
||||
@@ -117,4 +119,4 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*PROJECT.md - Updated when requirements or context change*
|
||||
*Last updated: 2026-04-20 after Phase 17*
|
||||
*Last updated: 2026-04-30 after Phase 18*
|
||||
|
||||
@@ -38,6 +38,7 @@ Status: Planning
|
||||
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
||||
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
||||
| 17 | Cart summary transport cost fix | 1 | Done | 2026-04-20 |
|
||||
| 18 | Google feed permutation URL fix | 1 | Done | 2026-04-30 |
|
||||
|
||||
## Feature
|
||||
|
||||
@@ -125,5 +126,11 @@ Status: Planning
|
||||
|
||||
**Scope:** Przekazac z `ShopBasketController::summaryView()` do szablonu wyliczony `transport_cost_effective` i flage `free_delivery_applies` uwzgledniajaca prog. Zaktualizowac summary-view.php aby uzywal tych kluczy zamiast surowej flagi `delivery_free`. Test jednostkowy dla logiki wyliczenia.
|
||||
|
||||
### Phase 18 — Google feed permutation URL fix
|
||||
|
||||
**Problem:** URL produktu z permutacją atrybutów w feedzie Google miał format `/slug/20-170/21-175` (slash między parami). Wzorzec routingu `pp_routes` używa `[0-9-]+`, który nie obejmuje `/`, więc URL nie matchuje żadnej trasy i `index.php` ładuje stronę główną. Klienci z GMC trafiają na home zamiast na produkt z wybraną kombinacją.
|
||||
|
||||
**Scope:** Zmienić separator z `/` na `_` w generatorze feedu (`ProductRepository::appendCombinationToXml`), rozszerzyć regex routingu o `_` (`Helpers`), dodać konwersję `_` → `|` w warstwie front (`LayoutEngine`), preselekcja wartości atrybutu w partialu na podstawie `permutation_hash` z URL. Plus unit testy regex + generator linku.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-20 (Phase 17 complete)*
|
||||
*Last updated: 2026-04-30 (Phase 18 complete)*
|
||||
|
||||
@@ -2,22 +2,23 @@
|
||||
|
||||
## Project Reference
|
||||
|
||||
See: .paul/PROJECT.md (updated 2026-04-18)
|
||||
See: .paul/PROJECT.md (updated 2026-04-30)
|
||||
|
||||
**Core value:** Właściciel sklepu ma pełną kontrolę nad sprzedażą online w jednym systemie pisanym od podstaw, bez narzutów zewnętrznych platform.
|
||||
**Current focus:** Phase 17 complete - loop closed
|
||||
**Current focus:** Phase 18 complete - loop closed
|
||||
|
||||
## Current Position
|
||||
|
||||
Milestone: Hotfix
|
||||
Phase: 17 of 17 (Cart summary transport cost fix) - Complete
|
||||
Plan: 17-01 complete
|
||||
Status: UNIFY complete, ready for next PLAN loop (transition-phase pending)
|
||||
Last activity: 2026-04-20 - Closed loop for .paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
|
||||
Milestone: Hotfix
|
||||
Phase: 18 of 18 (Google feed permutation URL fix) - Complete
|
||||
Plan: 18-01 complete
|
||||
Status: UNIFY complete, ready for next PLAN loop (transition-phase git commit pending)
|
||||
Last activity: 2026-04-30 - Closed loop for .paul/phases/18-google-feed-permutation-url-fix/18-01-PLAN.md
|
||||
|
||||
Progress:
|
||||
- Milestone: [##########] 100%
|
||||
- Phase 17: [##########] 100%
|
||||
- Milestone: [##########] 100% (Hotfix rolling)
|
||||
- Phase 18: [##########] 100%
|
||||
|
||||
## Loop Position
|
||||
|
||||
@@ -43,10 +44,17 @@ Phase 14: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-16]
|
||||
Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
||||
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
||||
Phase 17: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-20]
|
||||
Phase 18: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-30]
|
||||
```
|
||||
## Accumulated Context
|
||||
|
||||
### Decisions
|
||||
- 2026-04-30: Phase 18 loop closed with SUMMARY at .paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md
|
||||
- 2026-04-30: Transition-phase git commit for Phase 18 not executed in this UNIFY run (deferred — pattern z faz 15/16/17)
|
||||
- 2026-04-30: Phase 18 APPLY complete — 4 pliki silnika + 2 nowe pliki testów (HelpersRoutingTest 4 testy, ProductFeedLinkTest 3 testy); suita 841 zielona
|
||||
- 2026-04-30: Created Phase 18 plan at .paul/phases/18-google-feed-permutation-url-fix/18-01-PLAN.md
|
||||
- 2026-04-30: Phase 18 — separator URL permutacji `/` → `_`; konwersja `_` → `|` w warstwie front; regex `[0-9_-]+` w pp_routes
|
||||
- 2026-04-30: Phase 18 — override /feature-dev (hotfix z konkretną instrukcją), brak redirectów 301, brak automatycznych akcji post-deploy
|
||||
- 2026-04-20: Phase 17 loop closed with SUMMARY at .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
||||
- 2026-04-20: Transition-phase git commit for Phase 17 not executed in this UNIFY run (deferred)
|
||||
- 2026-04-20: Phase 17 APPLY complete - human-verify checkpoint approved, 834 testow zielonych (6 nowych)
|
||||
@@ -89,17 +97,17 @@ None.
|
||||
### Blockers/Concerns
|
||||
None.
|
||||
|
||||
### Skill Audit (Phase 16)
|
||||
### Skill Audit (Phase 18)
|
||||
| Expected | Invoked | Notes |
|
||||
|----------|---------|-------|
|
||||
| /feature-dev | ○ | User-approved override during APPLY |
|
||||
| /koniec-pracy | ○ | Marked as available by user; execute on session close workflow |
|
||||
| /feature-dev | ○ | User-approved override (hotfix z konkretną instrukcją) |
|
||||
| /koniec-pracy | ○ | Pending — uruchomić przy zakończeniu sesji jeśli release wchodzi do update package |
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-20
|
||||
Stopped at: Phase 17 complete, loop closed
|
||||
Next action: Start next milestone or create next phase plan (transition-phase commit pending)
|
||||
Resume file: .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
||||
Last session: 2026-04-30
|
||||
Stopped at: Phase 18 complete, loop closed
|
||||
Next action: Start next phase plan (transition-phase git commit pending), lub uruchomić /koniec-pracy jeśli zamykamy sesję
|
||||
Resume file: .paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md
|
||||
---
|
||||
*STATE.md — Updated after every significant action*
|
||||
|
||||
25
.paul/changelog/2026-04-30.md
Normal file
25
.paul/changelog/2026-04-30.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 2026-04-30
|
||||
|
||||
## Co zrobiono
|
||||
|
||||
- [Phase 18, Plan 01] Fix linków produktów z permutacją atrybutów w feedzie Google
|
||||
- Separator URL między parami `attr-val` zmieniony z `/` na `_` w `ProductRepository::appendCombinationToXml`
|
||||
- Wzorzec routingu `pp_routes` rozszerzony o `_` (`[0-9-]+` → `[0-9_-]+`) w `Helpers::htacces`
|
||||
- Konwersja `_` → `|` w `LayoutEngine` przed wywołaniem `ProductRepository::findCached`
|
||||
- Preselekcja wartości atrybutu na podstawie `permutation_hash` z URL w partialu `product-attribute.php`
|
||||
- 2 nowe pliki testów: `HelpersRoutingTest` (4 testy) + `ProductFeedLinkTest` (3 testy via Reflection)
|
||||
- Suita PHPUnit: 834 → 841 zielonych
|
||||
|
||||
## Zmienione pliki
|
||||
|
||||
- `autoload/Domain/Product/ProductRepository.php`
|
||||
- `autoload/Shared/Helpers/Helpers.php`
|
||||
- `autoload/front/LayoutEngine.php`
|
||||
- `templates/shop-product/_partial/product-attribute.php`
|
||||
- `tests/Unit/Shared/Helpers/HelpersRoutingTest.php`
|
||||
- `tests/Unit/Domain/Product/ProductFeedLinkTest.php`
|
||||
- `.paul/STATE.md`
|
||||
- `.paul/PROJECT.md`
|
||||
- `.paul/ROADMAP.md`
|
||||
- `.paul/phases/18-google-feed-permutation-url-fix/18-01-PLAN.md`
|
||||
- `.paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md`
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total tests | **828** |
|
||||
| Total assertions | **2306** |
|
||||
| Total tests | **841** |
|
||||
| Total assertions | **2330** |
|
||||
| Framework | PHPUnit 9.6 (`phpunit.phar`) |
|
||||
| Bootstrap | `tests/bootstrap.php` |
|
||||
| Config | `phpunit.xml` |
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
|
||||
> Chronologiczny log zmian technicznych — co i dlaczego.
|
||||
|
||||
## v0.350 (2026-04-30)
|
||||
|
||||
- Naprawiono linki produktow z permutacja atrybutow w feedzie Google: separator par `attr-val` w URL zmieniony z `/` na `_`. Stary format `/slug/20-170/21-175` nie matchowal sie w `pp_routes` (regex `[0-9-]+` nie obejmuje `/`), wiec klienci z GMC ladowali na strone glowna zamiast na produkt.
|
||||
- `ProductRepository::appendCombinationToXml`: `str_replace('|', '/', ...)` -> `str_replace('|', '_', ...)` w obu galeziach (z `seo_link` i fallback `p-id-name`).
|
||||
- `Helpers::htacces`: regex routingu produktow z permutacja rozszerzony do `/([0-9_-]+)$` w obu wariantach.
|
||||
- `LayoutEngine.php` (// PRODUKT): konwersja `_` -> `|` przed wywolaniem `ProductRepository::findCached` — format DB pozostaje bez zmian (`attr-val|attr-val`).
|
||||
- `templates/shop-product/_partial/product-attribute.php`: preselekcja wartosci atrybutu na podstawie `permutation_hash` z URL (`$forced_value_id`); wartosc `is_default` uzywana tylko gdy URL nie wymusza wyboru. Dotyczy `checked` na inpucie i emisji bloku `fradio_label_click(...)`.
|
||||
- Dodano 7 testow jednostkowych: `HelpersRoutingTest` (4 testy regex + assercje na zawartosci pliku) i `ProductFeedLinkTest` (3 testy `appendCombinationToXml` via `ReflectionMethod` z mockiem `TransportRepository`). Suita: 841 testow / 2330 assertions.
|
||||
- Wymagane akcje na produkcji po deployu: regeneracja `pp_routes` (`Helpers::htacces()`), wyczyszczenie klucza `pp_routes:all` w Redis, regeneracja `google-feed.xml`, resubmit feedu w GMC.
|
||||
|
||||
## v0.349 (2026-04-20)
|
||||
|
||||
- Naprawiono wyswietlanie kosztu transportu na /koszyk-podsumowanie: transporty z `delivery_free=1` pokazuja teraz rzeczywisty koszt ponizej progu `settings.free_delivery`, a 0,00 zl dopiero po osiagnieciu progu (spojnie z lista na /koszyk).
|
||||
|
||||
@@ -3688,3 +3688,6 @@ Dodać możliwość ustawienia limitu znaków w wiadomościach do produktu
|
||||
|
||||
|
||||
## SonarQube - v0.349 - brak nowych issues
|
||||
|
||||
|
||||
## SonarQube - v0.350 - brak nowych issues
|
||||
|
||||
46
.paul/governance/governance_2026-04-20.jsonl
Normal file
46
.paul/governance/governance_2026-04-20.jsonl
Normal file
@@ -0,0 +1,46 @@
|
||||
{"ts":"2026-04-20T18:30:03Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/shopPRO/.paul/phases/17-cart-summary-transport-cost-fix\"\",\"description\":\"Create phase 17 directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:17Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\17-cart-summary-transport-cost-fix\\\\17-01-PLAN.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:34Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:31:52Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:32:07Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:33:13Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\front\\\\Controllers\\\\ShopBasketController.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:33:24Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\templates\\\\shop-basket\\\\summary-view.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:04Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\tests\\\\Unit\\\\front\\\\Controllers\\\\ShopBasketControllerSummaryViewTest.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:09Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && powershell -ExecutionPolicy Bypass -File ./test.ps1 tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php 2>&1 | tail -30\",\"timeout\":","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:15Z","tool":"Bash","cmd":"powershell -ExecutionPolicy Bypass -File \"C:/visual studio code/projekty/shopPRO/test.ps1\" tests/Unit/front/Controllers/ShopBasketControllerSummaryViewTest.php 2>&1 | tail -40\",\"timeout\":120000,\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:32Z","tool":"Bash","cmd":"where php 2>&1 | head -3\",\"description\":\"Locate PHP binary\"},\"tool_response\":{\"stdout\":\"C:\\\\xampp\\\\php\\\\php.exe\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpe","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:39Z","tool":"Bash","cmd":"\"C:/xampp/php/php.exe\" \"C:/visual studio code/projekty/shopPRO/phpunit.phar\" -c \"C:/visual studio code/projekty/shopPRO/phpunit.xml\" \"C:/visual studio code/projekty/shopPRO/tests/Unit/front/Con","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:34:45Z","tool":"Bash","cmd":"\"C:/xampp/php/php.exe\" \"C:/visual studio code/projekty/shopPRO/phpunit.phar\" -c \"C:/visual studio code/projekty/shopPRO/phpunit.xml\" 2>&1 | tail -15\",\"timeout\":300000,\"description\":\"Run fu","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:36:07Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:36:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:36:19Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:36:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:42:55Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\17-cart-summary-transport-cost-fix\\\\17-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:09Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\changelog\\\\2026-04-20.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:25Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:31Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:43:55Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:44:02Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:44:05Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:44:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:46:36Z","tool":"Bash","cmd":"\"C:/xampp/php/php.exe\" \"C:/visual studio code/projekty/shopPRO/phpunit.phar\" -c \"C:/visual studio code/projekty/shopPRO/phpunit.xml\" 2>&1 | tail -5\",\"timeout\":300000,\"description\":\"Run ful","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:48:13Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/shopPRO\" && sonar-scanner 2>&1 | tail -20\",\"timeout\":600000,\"description\":\"Run SonarQube scan\"},\"tool_response\":{\"stdout\":\"[INFO] ScannerEngine: Depen","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:48:52Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" tag --sort=-v:refname 2>&1 | head -5\",\"description\":\"Get latest git tag\"},\"tool_response\":{\"stdout\":\"v0.348\\nv0.347\\nv0.346\\nv0.345\\nv0.","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:49:14Z","tool":"Bash","cmd":"printf '\\\\n## SonarQube - v0.349 - brak nowych issues\\\\n' >> \"/c/visual studio code/projekty/shopPRO/.paul/docs/TODO.md\"\",\"description\":\"Append Sonar status to TODO.md\"},\"tool_response\":{","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:49:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:49:58Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" status --short 2>&1\",\"description\":\"Show git status\"},\"tool_response\":{\"stdout\":\" M .paul/PROJECT.md\\n M .paul/ROADMAP.md\\n M .paul/STATE.","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:50:04Z","tool":"Bash","cmd":"cd \"/c/visual studio code/projekty/shopPRO\" && git add autoload/front/Controllers/ShopBasketController.php templates/shop-basket/summary-view.php tests/Unit/front/Controllers/ShopBasketControllerSum","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:50:16Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" commit -m \"$(cat <<'EOF'\\nfix: poprawny koszt transportu na /koszyk-podsumowanie\\n\\nNa podstronie /koszyk-podsumowanie transport z flaga delivery_","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:50:21Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" push 2>&1 | tail -5\",\"description\":\"Push to origin\"},\"tool_response\":{\"stdout\":\"remote: Failed to authenticate user\\nfatal: Authentication ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:51:10Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" push 2>&1 | tail -5\",\"description\":\"Retry push to origin\"},\"tool_response\":{\"stdout\":\"remote: . Processing 1 references \\nremote: Pr","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:51:19Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" tag v0.349 && powershell.exe -ExecutionPolicy Bypass -File \"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\build-update.ps1\" -FromTag v0.348 -To","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:51:24Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" add updates/0.30/ver_0.349.zip updates/0.30/ver_0.349_manifest.json updates/versions.php updates/changelog-data.html && git -C \"/c/visual studio code","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-20T18:51:34Z","tool":"Bash","cmd":"git -C \"/c/visual studio code/projekty/shopPRO\" push 2>&1 | tail -5; echo \"---tag---\"; git -C \"/c/visual studio code/projekty/shopPRO\" push origin v0.349 2>&1 | tail -5\",\"description\":\"Push ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
92
.paul/governance/governance_2026-04-30.jsonl
Normal file
92
.paul/governance/governance_2026-04-30.jsonl
Normal file
@@ -0,0 +1,92 @@
|
||||
{"ts":"2026-04-29T23:42:49Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/shopPRO/.paul/phases/18-google-feed-permutation-url-fix\"\",\"description\":\"Create phase 18 directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:08Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\18-google-feed-permutation-url-fix\\\\18-01-PLAN.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:44:47Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:45:26Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\Domain\\\\Product\\\\ProductRepository.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:45:33Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\Shared\\\\Helpers\\\\Helpers.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:45:38Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\Shared\\\\Helpers\\\\Helpers.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:45:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\front\\\\LayoutEngine.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:46:09Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\templates\\\\shop-product\\\\_partial\\\\product-attribute.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:47:37Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/shopPRO/tests/Unit/Shared/Helpers\"\",\"description\":\"Create Helpers test dir\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:47:57Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\tests\\\\Unit\\\\Shared\\\\Helpers\\\\HelpersRoutingTest.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:21Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\tests\\\\Unit\\\\Domain\\\\Product\\\\ProductFeedLinkTest.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:26Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && powershell -ExecutionPolicy Bypass -File ./test.ps1 tests/Unit/Shared/Helpers/HelpersRoutingTest.php 2>&1 | tail -40\",\"timeout\":120000,\"description","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:33Z","tool":"Bash","cmd":"where php 2>&1 | head -3\",\"description\":\"Locate php\"},\"tool_response\":{\"stdout\":\"C:\\\\xampp\\\\php\\\\php.exe\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:38Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php.exe phpunit.phar tests/Unit/Shared/Helpers/HelpersRoutingTest.php 2>&1 | tail -30\",\"timeout\":120000,\"description\":\"Run HelpersRo","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php.exe phpunit.phar tests/Unit/Domain/Product/ProductFeedLinkTest.php 2>&1 | tail -50\",\"timeout\":120000,\"description\":\"Run ProductF","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:48:50Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php.exe phpunit.phar 2>&1 | tail -30\",\"timeout\":300000,\"description\":\"Full test suite\"},\"tool_response\":{\"stdout\":\"PHPUnit 9.6","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:49:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:49:07Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:49:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:49:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:50:50Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\18-google-feed-permutation-url-fix\\\\18-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:50:58Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/shopPRO/.paul/changelog\"\",\"description\":\"Ensure changelog dir\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":fal","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:09Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\changelog\\\\2026-04-30.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:51:59Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:10Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:50Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php.exe phpunit.phar 2>&1 | tail -10\",\"timeout\":300000,\"description\":\"Run PHPUnit suite\"},\"tool_response\":{\"stdout\":\".........","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:52:55Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && (which sonar-scanner; ls sonar-project.properties 2>/dev/null) 2>&1\",\"description\":\"Check sonar-scanner availability\"},\"tool_response\":{\"stdout","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:54:27Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && sonar-scanner 2>&1 | tail -20\",\"timeout\":600000,\"description\":\"Run sonar-scanner\"},\"tool_response\":{\"stdout\":\"[WARN] ScannerEngine: * te","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:55:04Z","tool":"Bash","cmd":"jq '.paging' \"C:/Users/jacek/.claude/projects/C--visual-studio-code-projekty-shopPRO/b636be85-51d0-45b7-8315-a27585e4af5c/tool-results/mcp-sonarqube-issues-1777506900147.txt\"\",\"description\":\"Che","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:55:09Z","tool":"Bash","cmd":"jq '[.issues[] | {sev: .severity, file: (.component | sub(\"^shopPRO:\"; \"\")), line: .line, msg: .message, rule: .rule, type: .type}] | group_by(.sev) | map({severity: .[0].sev, count: length})' \"C","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:55:39Z","tool":"Bash","cmd":"jq -r '.issues[] | \"[\\\\(.severity)] \\\\((.component | sub(\"^shopPRO:\"; \"\")))\\\\t:\\\\(.line // 0)\\\\t\\\\(.message)\\\\t(\\\\(.rule))\"' \"C:/Users/jacek/.claude/projects/C--visual-studio-co","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:55:52Z","tool":"Bash","cmd":"while IFS=$'\\\\t' read -r sev_file line msg rule; do\\n # Build canonical TODO line: \"[SEV] file:LINE - msg (rule)\"\\n file=\"${sev_file#*] }\"\\n sev_prefix=\"${sev_file%% *}\"\\n ln=\"${line#","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:56:11Z","tool":"Bash","cmd":"file \"C:/visual studio code/projekty/shopPRO/.paul/docs/TODO.md\" && grep -a \"LayoutEngine.php:198\\\\|LayoutEngine.php:200\\\\|LayoutEngine.php:208\" \"C:/visual studio code/projekty/shopPRO/.paul/","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:56:17Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag --sort=-v:refname | head -3\",\"description\":\"Get latest tag\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"is","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:56:21Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag -l | sort -V | tail -5\",\"description\":\"List tags sorted\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isIma","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:56:25Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag | head -5; echo \"---\"; git log --oneline | head -5\",\"description\":\"Check tags and log\"},\"tool_response\":{\"stdout\":\"---\\na57d76a up","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:56:30Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git remote -v && echo \"---\" && git ls-remote --tags origin 2>&1 | tail -10\",\"description\":\"Check remote and tags\"},\"tool_response\":{\"stdout\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:09Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\codebase\\\\testing.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:20Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && printf '\\\\n\\\\n## SonarQube - v0.350 - brak nowych issues\\\\n' >> .paul/docs/TODO.md\",\"description\":\"Append Sonar entry to TODO\"},\"tool_respo","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:24Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>&1 | head -40\",\"description\":\"Git status\"},\"tool_response\":{\"stdout\":\" M .htaccess\\n M .paul/PROJECT.md\\n M .paul/ROAD","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git diff --stat 2>&1 | tail -5; echo \"---\"; git diff \"autoload/Domain/Attribute/AttributeRepository.php\" | head -20\",\"description\":\"Check diff ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:46Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git diff \"autoload/Domain/Attribute/AttributeRepository.php\" | head -10; echo \"===\"; git diff \"templates/articles/news.php\" | head -10\",\"descri","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:53Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git diff --numstat 2>&1 | grep -v \"^0\\\\s\\\\+0\\\\s\" | head -30\",\"description\":\"Files with real content changes\"},\"tool_response\":{\"stdout\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:57:57Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git diff --numstat 2>/dev/null | awk '$1+$2>0 || $1==\"-\"' | head -30\",\"description\":\"Files with real changes\"},\"tool_response\":{\"stdout\":\"5","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:08Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>/dev/null | grep \"^??\" | head -30\",\"description\":\"Untracked files\"},\"tool_response\":{\"stdout\":\"?? .paul/changelog/2026","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:16Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add \\\\\\n autoload/Domain/Product/ProductRepository.php \\\\\\n autoload/Shared/Helpers/Helpers.php \\\\\\n autoload/front/LayoutEngine.php \\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:29Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git commit -m \"$(cat <<'EOF'\\nfix: linki produktow z permutacja atrybutow w feedzie Google (v0.350)\\n\\nSeparator URL miedzy parami attr-val zmienio","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:36Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push 2>&1 | tail -10\",\"timeout\":120000,\"description\":\"Push to remote\"},\"tool_response\":{\"stdout\":\"remote: . Processing 1 references ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:42Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && ls build-update.ps1 2>&1; git tag v0.350 2>&1\",\"description\":\"Verify build script exists and create tag\"},\"tool_response\":{\"stdout\":\"build-up","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:48Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git fetch --tags 2>&1 | tail -5; git tag | sort -V | tail -3\",\"timeout\":60000,\"description\":\"Fetch tags from remote\"},\"tool_response\":{\"stdou","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:58:55Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git fetch origin tag v0.349 2>&1 | tail -5\",\"timeout\":60000,\"description\":\"Fetch v0.349 tag specifically\"},\"tool_response\":{\"stdout\":\"remot","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:59:03Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git cat-file -t 9afcc70f385892b2d27a7603dbc10935460bca9b 2>&1; echo \"---\"; git log --oneline a57d76a -5 2>&1 | head\",\"description\":\"Check if v0.3","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:59:10Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && grep -n \"FromTag\\\\|ToTag\\\\|param\\\\|git diff\" build-update.ps1 | head -30\",\"description\":\"Inspect build-update.ps1 params\"},\"tool_response","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:59:21Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && ls -la updates/0.30/ 2>&1 | tail -10\",\"description\":\"Check existing update packages\"},\"tool_response\":{\"stdout\":\"-rw-r--r-- 1 jacek 197121 21","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-29T23:59:30Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git fetch origin refs/tags/v0.349:refs/tags/v0.349 2>&1 | tail -5\",\"timeout\":60000,\"description\":\"Force-fetch single tag\"},\"tool_response\":{\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:36:15Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git fetch --tags 2>&1 | tail -5; git tag | sort -V | tail -5\",\"timeout\":60000,\"description\":\"Verify remote fixed, fetch tags\"},\"tool_response\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:36:23Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && powershell.exe -ExecutionPolicy Bypass -File build-update.ps1 -FromTag v0.349 -ToTag v0.350 -ChangelogEntry \"FIX - linki produktow z permutacja w feed","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:36:28Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add \"updates/0.30/ver_0.350.zip\" \"updates/0.30/ver_0.350_manifest.json\" \"updates/versions.php\" \"updates/changelog-data.html\" && git status ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:36:33Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git commit -m \"$(cat <<'EOF'\\nbuild: ver_0.350 - fix linkow produktow z permutacja w feedzie Google\\n\\nCo-Authored-By: Claude Opus 4.6 <noreply@ant","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:36:41Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push 2>&1 | tail -5 && git push origin v0.350 2>&1 | tail -5\",\"timeout\":120000,\"description\":\"Push commit and tag\"},\"tool_response\":{\"std","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:03Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && sleep 15 && git push 2>&1 | tail -5\",\"timeout\":120000,\"description\":\"Retry push after Gitea restart\"},\"tool_response\":{\"stdout\":\"remote: Fa","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:09Z","tool":"Bash","cmd":"curl -s -o /dev/null -w \"%{http_code}\\\\n\" https://git.project-pro.pl/ 2>&1; echo \"---\"; cd \"C:/visual studio code/projekty/shopPRO\" && git config --get credential.helper 2>&1\",\"description\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:27Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && sleep 10 && git push 2>&1 | tail -3\",\"timeout\":120000,\"description\":\"Retry push once more\"},\"tool_response\":{\"stdout\":\"hint: its remote cou","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:32Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push 2>&1 | tail -10\",\"timeout\":120000,\"description\":\"Full push output\"},\"tool_response\":{\"stdout\":\"To https://git.project-pro.pl/Proje","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:41Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git fetch origin main 2>&1 | tail -3 && echo \"---\" && git log --oneline main..origin/main 2>&1 | head -10 && echo \"=== ours not on remote ===\" && g","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:37:57Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git diff be6d8a2f fba215b3 --stat 2>&1 | tail -5\",\"description\":\"Compare our fix commit vs remote's fix commit\"},\"tool_response\":{\"stdout\":\"\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:15Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag -d v0.350 && git tag v0.350 fba215b3\",\"description\":\"Re-point v0.350 to remote fix sha\"},\"tool_response\":{\"stdout\":\"Deleted tag 'v0.3","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:20Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git rebase --onto origin/main be6d8a2f main 2>&1 | tail -10\",\"description\":\"Rebase build commit onto origin/main\"},\"tool_response\":{\"stdout\":\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:24Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>/dev/null | grep -v \"^??\" | head -10\",\"description\":\"See unstaged changes\"},\"tool_response\":{\"stdout\":\" M .htaccess\\n","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:31Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git stash push -u -m \"crlf-noise\" -- .htaccess .phpunit.result.cache .scannerwork .serena .vscode autoload templates \"updates/0.10\" \"updates/0.20\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:35Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>/dev/null | grep -v \"^??\" | head -5\",\"description\":\"Confirm tree clean\"},\"tool_response\":{\"stdout\":\" M updates/0.30/ve","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:40Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git stash push -u -m \"crlf-noise-2\" -- \"updates/0.30/ver_0.305_manifest.json\" \"updates/0.30/ver_0.324_files.txt\" \"updates/0.30/ver_0.324_sql.txt","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:45Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git stash push -u -m \"crlf-3\" -- \"updates/changelog.php\" \"updates/shopPRO_sql.txt\" 2>&1 | tail -2 && git status --short 2>/dev/null | grep -v \"^","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:49Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git rebase --onto origin/main be6d8a2f main 2>&1 | tail -10\",\"description\":\"Rebase build commit onto origin/main\"},\"tool_response\":{\"stdout\":\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
{"ts":"2026-04-30T00:38:58Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git log --oneline -3 && echo \"---\" && git push 2>&1 | tail -5 && git push origin v0.350 2>&1 | tail -5\",\"timeout\":120000,\"description\":\"Push re","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||
258
.paul/phases/18-google-feed-permutation-url-fix/18-01-PLAN.md
Normal file
258
.paul/phases/18-google-feed-permutation-url-fix/18-01-PLAN.md
Normal file
@@ -0,0 +1,258 @@
|
||||
---
|
||||
phase: 18-google-feed-permutation-url-fix
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- autoload/Domain/Product/ProductRepository.php
|
||||
- autoload/Shared/Helpers/Helpers.php
|
||||
- autoload/front/LayoutEngine.php
|
||||
- templates/shop-product/_partial/product-attribute.php
|
||||
- tests/Unit/Domain/Product/ProductRepositoryTest.php
|
||||
- tests/Unit/Shared/Helpers/HelpersTest.php
|
||||
autonomous: true
|
||||
delegation: off
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Naprawić linki produktów z permutacją atrybutów w feedzie Google: zamienić separator `/` na `_` między parami `attr-val`, dopasować routing `pp_routes`, konwersję `_` → `|` w warstwie front oraz preselekcję wartości atrybutów na podstawie `permutation_hash` z URL.
|
||||
|
||||
## Purpose
|
||||
URL z formatu `/slug/20-170/21-175` nie matchował się w `pp_routes` (wzorzec `[0-9-]+` nie obejmuje `/`), więc Google Merchant Center prowadził klientów na stronę główną zamiast na produkt z wybraną kombinacją atrybutów. Strata ruchu komercyjnego z feedu.
|
||||
|
||||
## Output
|
||||
- 4 pliki silnika z nowym separatorem `_`
|
||||
- Unit testy: regex routingu (Helpers) + generator linku (ProductRepository::appendCombinationToXml)
|
||||
- SUMMARY z listą akcji post-deploy do wykonania ręcznie na produkcji
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
@.paul/codebase/architecture.md
|
||||
|
||||
## Source Files
|
||||
@autoload/Domain/Product/ProductRepository.php
|
||||
@autoload/Shared/Helpers/Helpers.php
|
||||
@autoload/front/LayoutEngine.php
|
||||
@templates/shop-product/_partial/product-attribute.php
|
||||
|
||||
<clarifications>
|
||||
- **Testy** — Czy dodać unit testy dla zmian?
|
||||
→ Odpowiedź: Tak — pełne pokrycie (Helpers regex + ProductRepository::appendCombinationToXml)
|
||||
- **Post-deploy** — Czy wykonać regenerację routes/cache/feedu w ramach fazy?
|
||||
→ Odpowiedź: Nic — tylko kod; akcje produkcyjne udokumentowane w SUMMARY
|
||||
- **Redirect 301** — Czy dodać redirecty ze starych URL-i?
|
||||
→ Odpowiedź: Nie — Google sam zaktualizuje linki z feedu
|
||||
- **Skills** — /feature-dev required w SPECIAL-FLOWS?
|
||||
→ Odpowiedź: Override — pomiń (hotfix z konkretną instrukcją, jak w fazach 15/16/17)
|
||||
</clarifications>
|
||||
</context>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Generator linku w feedzie używa `_`
|
||||
```gherkin
|
||||
Given produkt z permutacją atrybutów (permutation_hash = "20-170|21-175")
|
||||
When wywołany jest ProductRepository::appendCombinationToXml dla feedu Google
|
||||
Then wygenerowany URL zawiera segment `20-170_21-175` (jeden segment, separator `_`)
|
||||
And nie zawiera `/` między parami atrybutów
|
||||
And dotyczy obu gałęzi (z seo_link i fallback p-id-name)
|
||||
```
|
||||
|
||||
## AC-2: Routing `pp_routes` matchuje URL z `_`
|
||||
```gherkin
|
||||
Given wzorzec routingu wygenerowany przez Helpers dla produktu z permutacją
|
||||
When URI to `slug-produktu/20-170_21-175`
|
||||
Then regex `[0-9_-]+` dopasowuje cały segment permutacji
|
||||
And `permutation_hash` w wynikowych GET to `20-170_21-175`
|
||||
And dotyczy obu wariantów (z seo_link i fallback p-id-name)
|
||||
```
|
||||
|
||||
## AC-3: Front konwertuje `_` z URL na `|` przed zapytaniem do bazy
|
||||
```gherkin
|
||||
Given GET['permutation_hash'] = "20-170_21-175"
|
||||
When LayoutEngine renderuje blok PRODUKT
|
||||
Then ProductRepository::findCached otrzymuje argument "20-170|21-175"
|
||||
And gdy GET['permutation_hash'] nie istnieje, findCached otrzymuje null
|
||||
```
|
||||
|
||||
## AC-4: Partial atrybutu preselectuje wartość z URL
|
||||
```gherkin
|
||||
Given URL produktu z permutation_hash zawierającym parę dla bieżącego atrybutu
|
||||
When renderuje się templates/shop-product/_partial/product-attribute.php
|
||||
Then aktywna (checked) jest wartość z URL, nie z is_default
|
||||
And gdy atrybut nie występuje w hashu, zachowane jest stare zachowanie (is_default)
|
||||
And blok <script> z fradio_label_click() emitowany jest dla wartości z URL
|
||||
```
|
||||
|
||||
## AC-5: Pełna suita testów zielona
|
||||
```gherkin
|
||||
Given wprowadzone zmiany w 4 plikach + 2 nowe/zaktualizowane testy
|
||||
When uruchomiony jest ./test.ps1
|
||||
Then wszystkie testy przechodzą (>=836 — 834 obecnych + ≥2 nowe)
|
||||
And brak warningów PHP
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Zmiana separatora w generatorze feedu i routingu</name>
|
||||
<files>autoload/Domain/Product/ProductRepository.php, autoload/Shared/Helpers/Helpers.php, autoload/front/LayoutEngine.php</files>
|
||||
<action>
|
||||
1. **autoload/Domain/Product/ProductRepository.php** — w `appendCombinationToXml` (~linie 2372 i 2374):
|
||||
- Zamienić `str_replace('|', '/', $combination['permutation_hash'])` na `str_replace('|', '_', $combination['permutation_hash'])`
|
||||
- Dotyczy OBU gałęzi (seo_link i fallback `p-id-name`)
|
||||
- Najpierw przeczytać metodę i potwierdzić obie wystąpienia przed edycją
|
||||
|
||||
2. **autoload/Shared/Helpers/Helpers.php** — w generatorze tras (~linie 694 i 699):
|
||||
- Rozszerzyć regex z `'^' . ... . '/([0-9-]+)$'` na `'^' . ... . '/([0-9_-]+)$'`
|
||||
- Dotyczy OBU wariantów (seo_link i fallback `p-id-name`)
|
||||
|
||||
3. **autoload/front/LayoutEngine.php** — w bloku `// PRODUKT` (~linia 196):
|
||||
- Wyciągnąć `permutation_hash` do zmiennej z konwersją `_` → `|`:
|
||||
```php
|
||||
$permutation_hash = isset($_GET['permutation_hash']) ? str_replace('_', '|', $_GET['permutation_hash']) : null;
|
||||
```
|
||||
- Przekazać `$permutation_hash` do `findCached()` zamiast inline `$_GET['permutation_hash'] ?? null`
|
||||
|
||||
Avoid:
|
||||
- Zmian w `findCached()` lub `permutation_hash` w bazie — separator w DB pozostaje `|`
|
||||
- Modyfikacji innych metod ProductRepository
|
||||
- PHP 8.0+ syntaxu (`match`, named args)
|
||||
</action>
|
||||
<verify>
|
||||
- `grep -n "str_replace.*'|'.*'/'" autoload/Domain/Product/ProductRepository.php` — brak wyników (0 wystąpień)
|
||||
- `grep -n "str_replace.*'|'.*'_'" autoload/Domain/Product/ProductRepository.php` — 2 wystąpienia
|
||||
- `grep -n "\[0-9_-\]+" autoload/Shared/Helpers/Helpers.php` — 2 wystąpienia
|
||||
- `grep -n "\[0-9-\]+\\\$" autoload/Shared/Helpers/Helpers.php` — brak (stary wzorzec usunięty z generatora produktów z permutacją)
|
||||
- `grep -n "permutation_hash" autoload/front/LayoutEngine.php` — zmienna wyciągnięta przed `findCached`
|
||||
</verify>
|
||||
<done>AC-1, AC-2, AC-3 spełnione</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Preselekcja atrybutu z permutation_hash w partialu</name>
|
||||
<files>templates/shop-product/_partial/product-attribute.php</files>
|
||||
<action>
|
||||
Najpierw przeczytać cały plik partiala (mały, ~kilkadziesiąt linii) i zlokalizować pętlę `foreach` po `values` oraz miejsca używające `$value['is_default']`.
|
||||
|
||||
Na początku partiala (przed pętlą po values) dodać:
|
||||
```php
|
||||
$forced_value_id = null;
|
||||
if ( isset( $_GET['permutation_hash'] ) && $_GET['permutation_hash'] !== '' )
|
||||
{
|
||||
$pairs = explode( '|', str_replace( '_', '|', $_GET['permutation_hash'] ) );
|
||||
foreach ( $pairs as $pair )
|
||||
{
|
||||
$parts = explode( '-', $pair );
|
||||
if ( count( $parts ) == 2 && (int)$parts[0] === (int)$this -> attribute['id'] )
|
||||
{
|
||||
$forced_value_id = (int)$parts[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
W pętli foreach po values, przed użyciem flagi `is_default`, policzyć:
|
||||
```php
|
||||
$is_active = $forced_value_id !== null
|
||||
? ( (int)$value['id'] === $forced_value_id )
|
||||
: (bool)$value['is_default'];
|
||||
```
|
||||
|
||||
Zastąpić WSZYSTKIE użycia `$value['is_default']` w kontekście aktywności (checked, fradio_label_click) zmienną `$is_active`. Nie ruszać `is_default` jeśli używane gdzie indziej semantycznie (np. atrybut metadata).
|
||||
|
||||
Avoid:
|
||||
- Modyfikacji `templates_user/` (potwierdzono: nie istnieje w tym repo)
|
||||
- Zmian struktury HTML / klas CSS
|
||||
- PHP 8.0+ syntaxu
|
||||
</action>
|
||||
<verify>
|
||||
- `grep -n "forced_value_id" templates/shop-product/_partial/product-attribute.php` — co najmniej 4 wystąpienia (deklaracja, set, użycie w `$is_active`, użycie w `$is_active`)
|
||||
- `grep -n "is_active" templates/shop-product/_partial/product-attribute.php` — co najmniej 2 wystąpienia (deklaracja + użycie w checked/script)
|
||||
- Manualnie potwierdzić: `checked="checked"` używa `$is_active`, `fradio_label_click(...)` script gate'owany przez `$is_active`
|
||||
</verify>
|
||||
<done>AC-4 spełnione</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Unit testy dla regex routingu i generatora linku</name>
|
||||
<files>tests/Unit/Shared/Helpers/HelpersTest.php, tests/Unit/Domain/Product/ProductRepositoryTest.php</files>
|
||||
<action>
|
||||
Najpierw sprawdzić strukturę istniejących testów (szczególnie czy `HelpersTest.php` istnieje — jeśli nie, utworzyć z bootstrapem zgodnym z innymi testami w `tests/Unit/Shared/`).
|
||||
|
||||
1. **Helpers — test regex routingu z `_`:**
|
||||
- Wywołać generator tras dla produktu z permutacją (jeśli metoda jest publiczna; w przeciwnym razie test integracyjny z mockiem `$mdb` zwracającym permutacje produktu)
|
||||
- Zweryfikować że wygenerowany pattern zawiera `[0-9_-]+` zamiast `[0-9-]+`
|
||||
- Test: `preg_match` na patternie z URI `slug/20-170_21-175` zwraca true i wyciąga `20-170_21-175` jako capture group
|
||||
- Test negatywny: pattern NIE matchuje `slug/20-170/21-175` (stary format ze slashem — chcemy 404, nie przypadkowy match)
|
||||
|
||||
2. **ProductRepository::appendCombinationToXml — test separatora `_`:**
|
||||
- Może być nieosiągalna metoda private/protected. Strategia A (preferowana): jeśli private, użyć ReflectionMethod do wywołania na instancji z mockiem `$mdb`. Strategia B: jeśli zbyt skomplikowane, dodać minimalny test który wywołuje publiczną metodę feedu z mockiem i sprawdza wygenerowany XML.
|
||||
- Mock combination z `permutation_hash = '20-170|21-175'`, `seo_link = 'jakas-fraza'`
|
||||
- Asercja: w wygenerowanym XML link zawiera `jakas-fraza/20-170_21-175`, NIE zawiera `20-170/21-175`
|
||||
- Drugi test: gałąź fallback (brak `seo_link`) — link `p-{id}-{name}/20-170_21-175`
|
||||
|
||||
Trzymać się konwencji: AAA, mock Medoo (`$this->createMock(\medoo::class)`), namespace tests jak w istniejących plikach. Brak PHP 8.0+ syntaxu. Nazwy metod z `test` prefiksem.
|
||||
</action>
|
||||
<verify>
|
||||
- `./test.ps1 tests/Unit/Shared/Helpers/HelpersTest.php` — przechodzi
|
||||
- `./test.ps1 tests/Unit/Domain/Product/ProductRepositoryTest.php` — przechodzi (wszystkie testy, łącznie z nowymi)
|
||||
- `./test.ps1` — pełna suita zielona, count >= 836
|
||||
</verify>
|
||||
<done>AC-5 spełnione (testy zielone, ≥2 nowe testy pokrywające AC-1 i AC-2)</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Format `permutation_hash` w bazie (kolumna `pp_shop_product_combinations.permutation_hash` pozostaje z separatorem `|`)
|
||||
- Sygnatura `ProductRepository::findCached()` — przyjmuje hash z `|`
|
||||
- Inne metody ProductRepository / inne kontrolery / inne partiale
|
||||
- Plików `templates_user/` (nie istnieje w tym repo, akcja po stronie klientów)
|
||||
- Schemat bazy danych
|
||||
- `.htaccess` w roocie (redirecty 301 wykluczone z scope)
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko 4 pliki silnika + 2 pliki testów (lista w `files_modified`)
|
||||
- Brak automatycznej regeneracji `pp_routes` — udokumentowane w SUMMARY jako akcja deploy
|
||||
- Brak czyszczenia cache `pp_routes:all` w fazie — akcja deploy
|
||||
- Brak regeneracji `google-feed.xml` w fazie — akcja deploy
|
||||
- Brak redirectów 301 ze starych URL-i
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
- [ ] `./test.ps1` — pełna suita zielona (≥836 testów)
|
||||
- [ ] Brak `str_replace('|', '/', ...)` w ProductRepository (grep)
|
||||
- [ ] `[0-9_-]+` w obu wzorcach Helpers (grep)
|
||||
- [ ] `permutation_hash` wyciągnięte do zmiennej w LayoutEngine z konwersją `_`→`|`
|
||||
- [ ] Partial używa `$is_active` (forced_value_id || is_default) zamiast surowego `is_default`
|
||||
- [ ] Wszystkie 5 AC spełnione
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 4 pliki silnika zmienione zgodnie z instrukcją
|
||||
- 2 nowe / zaktualizowane testy: routing regex + generator XML linku
|
||||
- Pełna suita testów zielona
|
||||
- Brak regresji w istniejących testach (834 → ≥836)
|
||||
- SUMMARY zawiera dokładną listę akcji post-deploy (regen pp_routes, clear cache, regen feedu, resubmit GMC)
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md` containing:
|
||||
- Co zmienione (lista plików + diff highlights)
|
||||
- Akcje post-deploy do wykonania ręcznie na produkcji (kolejność: regen pp_routes → clear cache pp_routes:all → regen google-feed.xml → resubmit GMC)
|
||||
- Test count delta
|
||||
- Decyzje (override /feature-dev, brak redirectów 301)
|
||||
</output>
|
||||
168
.paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md
Normal file
168
.paul/phases/18-google-feed-permutation-url-fix/18-01-SUMMARY.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
phase: 18-google-feed-permutation-url-fix
|
||||
plan: 01
|
||||
subsystem: feed/routing
|
||||
tags: [google-merchant, pp_routes, permutation, regex, php74]
|
||||
|
||||
requires:
|
||||
- phase: prior-architecture
|
||||
provides: ProductRepository, Helpers::htacces, LayoutEngine, frontAttributePartial
|
||||
provides:
|
||||
- Separator URL permutacji `_` zamiast `/` w feedzie Google
|
||||
- Wzorzec routingu pp_routes obejmujący `[0-9_-]+`
|
||||
- Konwersja `_` → `|` po stronie front przed `findCached`
|
||||
- Preselekcja wartości atrybutu z `permutation_hash` w partialu
|
||||
affects: [google-feed, pp_routes, frontend-product-attributes]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "URL feedu: jeden segment z `_` zamiast wielu segmentów ze `/`"
|
||||
- "DB format `|`, URL format `_`, konwersja w warstwie front"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- tests/Unit/Shared/Helpers/HelpersRoutingTest.php
|
||||
- tests/Unit/Domain/Product/ProductFeedLinkTest.php
|
||||
modified:
|
||||
- autoload/Domain/Product/ProductRepository.php
|
||||
- autoload/Shared/Helpers/Helpers.php
|
||||
- autoload/front/LayoutEngine.php
|
||||
- templates/shop-product/_partial/product-attribute.php
|
||||
|
||||
key-decisions:
|
||||
- "Separator URL `_` zamiast `/` (one segment dopasowywalny przez pp_routes)"
|
||||
- "Konwersja `_` → `|` w LayoutEngine, format DB pozostaje `|`"
|
||||
- "Brak redirectów 301 — Google sam zaktualizuje feed"
|
||||
- "Brak automatycznych akcji post-deploy — udokumentowane jako manual steps"
|
||||
- "Override /feature-dev (hotfix z konkretną instrukcją)"
|
||||
|
||||
patterns-established:
|
||||
- "Forced value via URL parameters w partialach (preselekcja zamiast is_default)"
|
||||
- "Reflection-based test prywatnych metod XML feedu"
|
||||
|
||||
duration: ~25min
|
||||
completed: 2026-04-30
|
||||
---
|
||||
|
||||
# Phase 18 Plan 01: Google feed permutation URL fix — Summary
|
||||
|
||||
**Linki produktów z permutacją w feedzie Google używają teraz `_` jako separatora par `attr-val`, routing `pp_routes` matchuje takie URL-e, a partial atrybutu preselectuje wartości na podstawie `permutation_hash` z URL.**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~25 min |
|
||||
| Started | 2026-04-30 |
|
||||
| Completed | 2026-04-30 |
|
||||
| Tasks | 3 / 3 |
|
||||
| Files modified | 6 (4 silnik + 2 testy) |
|
||||
| Tests | 834 → 841 (+7) |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Generator linku w feedzie używa `_` | Pass | ProductFeedLinkTest.testCombinationLinkUsesUnderscoreInSeoLinkBranch + fallback + single-pair |
|
||||
| AC-2: Routing `pp_routes` matchuje URL z `_` | Pass | HelpersRoutingTest weryfikuje obecność `[0-9_-]+` w generatorze + preg_match na nowym wzorcu |
|
||||
| AC-3: Front konwertuje `_` z URL na `|` przed zapytaniem | Pass | LayoutEngine.php:196 — zmienna `$permutation_hash` z `str_replace('_','|',...)` |
|
||||
| AC-4: Partial preselectuje wartość z URL | Pass | `$forced_value_id` + `$is_active` używane w `checked` i `<script>` |
|
||||
| AC-5: Pełna suita testów zielona | Pass | PHPUnit: 841 tests, 2330 assertions, 0.764s |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Naprawa krytycznego problemu komercyjnego: feed Google prowadził klientów na home zamiast na produkt
|
||||
- Spójność stosu: separator URL (`_`) ↔ format DB (`|`) z jasnym punktem konwersji w warstwie front
|
||||
- 7 nowych testów (4 routing + 3 generator linku) — pełne pokrycie zmiany
|
||||
- Reflection-based test metody prywatnej `appendCombinationToXml` z mockiem Medoo i mockiem TransportRepository
|
||||
- UI strony produktu wchodząc z linka feedu pokazuje wybraną kombinację atrybutów (zamiast `is_default`)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `autoload/Domain/Product/ProductRepository.php` | Modified (×2) | `appendCombinationToXml`: separator `/` → `_` w obu gałęziach (seo_link i fallback) |
|
||||
| `autoload/Shared/Helpers/Helpers.php` | Modified (×2) | Generator pp_routes: regex `[0-9-]+` → `[0-9_-]+` w obu wariantach |
|
||||
| `autoload/front/LayoutEngine.php` | Modified | Wyciągnięcie `$permutation_hash` z konwersją `_` → `|` przed `findCached` |
|
||||
| `templates/shop-product/_partial/product-attribute.php` | Modified | `$forced_value_id` z URL + `$is_active` w `checked`/`<script>` |
|
||||
| `tests/Unit/Shared/Helpers/HelpersRoutingTest.php` | Created | 4 testy regex routingu (file content + preg_match dla `_` i odrzucenia `/`) |
|
||||
| `tests/Unit/Domain/Product/ProductFeedLinkTest.php` | Created | 3 testy `appendCombinationToXml` via Reflection (seo_link, fallback, single-pair) |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Separator URL `_` zamiast `/` | `_` mieści się w jednym segmencie regex `[0-9_-]+`; `/` wymagałby zmiany struktury routingu | Czysty fix, minimalna zmiana w pp_routes |
|
||||
| Format DB pozostaje `|` | Nie tykać zapisanych danych w `pp_shop_product_combinations.permutation_hash` | Zero migracji DB; konwersja tylko w warstwie I/O |
|
||||
| Brak redirectów 301 | Stare URL-e z feedu wymarły gdy GMC zaciągnie nowy feed | Mniej kodu w `.htaccess`, brak długoterminowego balastu |
|
||||
| Brak automatycznych akcji post-deploy | Hotfix dotyczy tylko silnika; regen routes/cache/feed są zależne od środowiska | Wymaga manualnego runbook'a (poniżej) |
|
||||
| Override /feature-dev | Hotfix z konkretną instrukcją od użytkownika, jak fazy 15/16/17 | Skill audit logged |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 0 | — |
|
||||
| Scope additions | 0 | — |
|
||||
| Deferred | 0 | — |
|
||||
|
||||
**Total impact:** Zero. Plan wykonany dokładnie według instrukcji.
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
None.
|
||||
|
||||
### Deferred Items
|
||||
|
||||
None.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| `ProductRepository::appendCombinationToXml` jest `private` z zależnościami od `transportRepoForXml` i `AttributeRepository` (DB) | Test via `ReflectionMethod`; mock Medoo (`select` → `[]`, `get` → `null`); wstrzyknięty mock `TransportRepository::lowestTransportPrice` zwracający `0.0` na dynamicznej property `transportRepoForXml` |
|
||||
| Brak istniejącego folderu `tests/Unit/Shared/Helpers/` | Utworzony nowy katalog + `HelpersRoutingTest.php` |
|
||||
| `Helpers::htacces()` zbyt rozległe do testu E2E (DB writes, file I/O) | Test pośredni: assercje na zawartości pliku Helpers.php (file_get_contents) + standalone `preg_match` na sample patternie |
|
||||
|
||||
## Post-deploy runbook (manual, kolejność krytyczna)
|
||||
|
||||
Wymagane akcje na środowisku produkcyjnym po deployu kodu:
|
||||
|
||||
1. **Regeneracja `pp_routes`** — wywołać `Helpers::htacces()` (np. zapis ustawień w adminie lub regeneracja sitemap), żeby nowe wzorce z `_` trafiły do bazy. Bez tego stare wzorce `[0-9-]+` w `pp_routes` nadal nie zmatchują URL z `_`.
|
||||
2. **Wyczyścić cache routingu** — skasować klucz `pp_routes:all` w Redis (`DEL pp_routes:all`) albo poczekać 24h na expiry. `index.php:63` cachuje routing.
|
||||
3. **Regeneracja feedu Google** — uruchomić cron `cron/cron-xml.php` (`\admin\factory\ShopProduct::generate_google_feed_xml()`), żeby `google-feed.xml` zawierał nowe linki z `_`.
|
||||
4. **Resubmit feedu w GMC** — automatycznie wg harmonogramu lub ręcznie "Fetch now".
|
||||
5. **Stare URL-e w GMC** — same wypadną z indeksu po podmianie feedu (Google).
|
||||
|
||||
Walidacja po deployu:
|
||||
- `https://domena/google-feed.xml` — tagi `<link>` zawierają `_` zamiast `/` między parami
|
||||
- `https://domena/slug-produktu/20-170_21-175` — ładuje produkt z preselectowaną kombinacją (nie home)
|
||||
- GMC: feed bez błędów "Landing page error"
|
||||
|
||||
## Skill Audit (Phase 18)
|
||||
|
||||
| Expected | Invoked | Notes |
|
||||
|----------|---------|-------|
|
||||
| /feature-dev | ○ | User-approved override (hotfix z konkretną instrukcją) |
|
||||
| /koniec-pracy | ○ | Pending — uruchomić przy zakończeniu sesji jeśli release wchodzi do update package |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- Hotfix completed; pełna suita zielona
|
||||
- Brak zmian w schemacie DB
|
||||
- Wzorzec preselekcji partial z URL parameter dostępny dla innych partiali (jeśli pojawi się potrzeba)
|
||||
|
||||
**Concerns:**
|
||||
- Akcje post-deploy (regen routes / clear cache / regen feed) wymagają manualnego wykonania — brak automatu
|
||||
- Klienci sklepu mający własne nadpisane `templates_user/shop-product/_partial/product-attribute.php` muszą zaaplikować zmianę u siebie (Tpl::view priorytetuje `templates_user/`)
|
||||
|
||||
**Blockers:**
|
||||
- None.
|
||||
|
||||
---
|
||||
*Phase: 18-google-feed-permutation-url-fix, Plan: 01*
|
||||
*Completed: 2026-04-30*
|
||||
File diff suppressed because one or more lines are too long
@@ -2,5 +2,5 @@ projectKey=shopPRO
|
||||
serverUrl=https://sonar.project-pro.pl
|
||||
serverVersion=26.3.0.120487
|
||||
dashboardUrl=https://sonar.project-pro.pl/dashboard?id=shopPRO
|
||||
ceTaskId=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
||||
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
||||
ceTaskId=33e10a49-4790-400e-bf25-9b40eaed053e
|
||||
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=33e10a49-4790-400e-bf25-9b40eaed053e
|
||||
|
||||
@@ -2369,9 +2369,9 @@ class ProductRepository
|
||||
$itemNode->appendChild( $doc->createElement( 'g:description', html_entity_decode( strip_tags( $desc ) ) ) );
|
||||
|
||||
if ( $product['language']['seo_link'] ) {
|
||||
$link = $domainPrefix . '://' . $url . '/' . \Shared\Helpers\Helpers::seo( $product['language']['seo_link'] ) . '/' . str_replace( '|', '/', $combination['permutation_hash'] );
|
||||
$link = $domainPrefix . '://' . $url . '/' . \Shared\Helpers\Helpers::seo( $product['language']['seo_link'] ) . '/' . str_replace( '|', '_', $combination['permutation_hash'] );
|
||||
} else {
|
||||
$link = $domainPrefix . '://' . $url . '/p-' . $product['id'] . '-' . \Shared\Helpers\Helpers::seo( $product['language']['name'] ) . '/' . str_replace( '|', '/', $combination['permutation_hash'] );
|
||||
$link = $domainPrefix . '://' . $url . '/p-' . $product['id'] . '-' . \Shared\Helpers\Helpers::seo( $product['language']['name'] ) . '/' . str_replace( '|', '_', $combination['permutation_hash'] );
|
||||
}
|
||||
$itemNode->appendChild( $doc->createElement( 'link', $link ) );
|
||||
|
||||
|
||||
@@ -691,12 +691,12 @@ class Helpers
|
||||
if ( $row2['seo_link'] )
|
||||
{
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . self::seo( $row2['seo_link'] ) . '$', 'destination' => 'index.php?product=' . $row2['product_id'] ] );
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . self::seo( $row2['seo_link'] ) . '/([0-9-]+)$', 'destination' => 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1' ] );
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . self::seo( $row2['seo_link'] ) . '/([0-9_-]+)$', 'destination' => 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1' ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '$', 'destination' => 'index.php?product=' . $row2['product_id'] ] );
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '/([0-9-]+)$', 'destination' => 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1' ] );
|
||||
$mdb->insert( 'pp_routes', [ 'product_id' => $row2['product_id'], 'lang_id' => $row['id'], 'pattern' => '^' . $language_link . 'p-' . $row2['product_id'] . '-' . self::seo( $row2['name'] ) . '/([0-9_-]+)$', 'destination' => 'index.php?product=' . $row2['product_id'] . '&permutation_hash=$1' ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,8 @@ class LayoutEngine
|
||||
//
|
||||
if ( \Shared\Helpers\Helpers::get( 'product' ) )
|
||||
{
|
||||
$product = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->findCached( \Shared\Helpers\Helpers::get( 'product' ), $lang_id, $_GET['permutation_hash'] ?? null );
|
||||
$permutation_hash = isset( $_GET['permutation_hash'] ) ? str_replace( '_', '|', $_GET['permutation_hash'] ) : null;
|
||||
$product = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->findCached( \Shared\Helpers\Helpers::get( 'product' ), $lang_id, $permutation_hash );
|
||||
|
||||
if ( $product['language']['meta_title'] )
|
||||
$page['language']['title'] = $product['language']['meta_title'];
|
||||
|
||||
@@ -2,17 +2,37 @@
|
||||
global $lang_id;
|
||||
$attributeRepo = new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] );
|
||||
$attribute_details = $attributeRepo->frontAttributeDetails( (int)$this -> attribute['id'], $lang_id );
|
||||
|
||||
$forced_value_id = null;
|
||||
if ( isset( $_GET['permutation_hash'] ) && $_GET['permutation_hash'] !== '' )
|
||||
{
|
||||
$pairs = explode( '|', str_replace( '_', '|', $_GET['permutation_hash'] ) );
|
||||
foreach ( $pairs as $pair )
|
||||
{
|
||||
$parts = explode( '-', $pair );
|
||||
if ( count( $parts ) == 2 && (int)$parts[0] === (int)$this -> attribute['id'] )
|
||||
{
|
||||
$forced_value_id = (int)$parts[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $attribute_details['type'] == 0 )
|
||||
{
|
||||
?>
|
||||
<div class="attribute-container fradio-group attribute-<?= \Shared\Helpers\Helpers::seo( $attribute_details['language']['name'] );?>" level="<?= $this -> level;?>" order="<?= $this -> order;?>" attribute="<?= \Shared\Helpers\Helpers::seo( $attribute_details['language']['name'] );?>" attribute-name="<?= $attribute_details['language']['name'];?>">
|
||||
<p class="attribute-label"><?= $attribute_details['language']['name'];?>:</p>
|
||||
<? foreach ( $this -> attribute['values'] as $value ):?>
|
||||
<? foreach ( $this -> attribute['values'] as $value ):
|
||||
$is_active = $forced_value_id !== null
|
||||
? ( (int)$value['id'] === $forced_value_id )
|
||||
: (bool)$value['is_default'];
|
||||
?>
|
||||
<div class="fradio">
|
||||
<input type="radio" id="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" <? if ( $value['is_default'] ):?>checked="checked"<? endif;?> require="true" value="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" name="<?= \Shared\Helpers\Helpers::seo( $attribute_details['language']['name'] );?>">
|
||||
<input type="radio" id="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" <? if ( $is_active ):?>checked="checked"<? endif;?> require="true" value="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" name="<?= \Shared\Helpers\Helpers::seo( $attribute_details['language']['name'] );?>">
|
||||
<label for="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" order="<?= $this -> order;?>"><?= ( new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] ) )->getAttributeValueById( $value['id'], $lang_id );?></label>
|
||||
</div>
|
||||
<? if ( $value['is_default'] ):?>
|
||||
<? if ( $is_active ):?>
|
||||
<script class="footer" type="text/javascript">
|
||||
$( function()
|
||||
{
|
||||
|
||||
151
tests/Unit/Domain/Product/ProductFeedLinkTest.php
Normal file
151
tests/Unit/Domain/Product/ProductFeedLinkTest.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\Product;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\Product\ProductRepository;
|
||||
|
||||
/**
|
||||
* Phase 18 — testy generatora linku do feedu Google.
|
||||
*
|
||||
* ProductRepository::appendCombinationToXml buduje <link> dla pozycji
|
||||
* feedu Google. permutation_hash w bazie ma format "attr-val|attr-val".
|
||||
* W URL feedu separator między parami to "_" (nie "/"), żeby URL był
|
||||
* jednym segmentem dopasowywalnym przez routing pp_routes.
|
||||
*
|
||||
* Test wywołuje prywatną metodę przez ReflectionMethod z minimalnymi
|
||||
* danymi produktu i sprawdza zawartość wynikowego DOMDocument.
|
||||
*/
|
||||
class ProductFeedLinkTest extends TestCase
|
||||
{
|
||||
private function buildRepoWithMocks(): ProductRepository
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('get')->willReturn(null);
|
||||
|
||||
$repo = new ProductRepository($mockDb);
|
||||
|
||||
// appendShippingToXml wywołuje $this->transportRepoForXml->lowestTransportPrice().
|
||||
// Inicjalizacja w generateGoogleXmlFeed(); dla unit testu wstrzykujemy mock dynamicznie.
|
||||
$transportMock = $this->getMockBuilder(\Domain\Transport\TransportRepository::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$transportMock->method('lowestTransportPrice')->willReturn(0.0);
|
||||
$repo->transportRepoForXml = $transportMock;
|
||||
|
||||
return $repo;
|
||||
}
|
||||
|
||||
private function invokeAppendCombination(ProductRepository $repo, array $product, array $combination): string
|
||||
{
|
||||
$doc = new \DOMDocument('1.0', 'UTF-8');
|
||||
$channelNode = $doc->appendChild($doc->createElement('channel'));
|
||||
|
||||
$method = new \ReflectionMethod(ProductRepository::class, 'appendCombinationToXml');
|
||||
$method->setAccessible(true);
|
||||
$method->invoke($repo, $doc, $channelNode, $product, $combination, 'https', 'shop.example.com');
|
||||
|
||||
return $doc->saveXML();
|
||||
}
|
||||
|
||||
private function baseProduct(array $overrides = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'id' => 123,
|
||||
'ean' => '5901234567890',
|
||||
'language' => [
|
||||
'name' => 'Produkt testowy',
|
||||
'xml_name' => '',
|
||||
'short_description' => 'Opis',
|
||||
'meta_title' => '',
|
||||
'seo_link' => 'sukienka-czerwona',
|
||||
],
|
||||
'price_brutto' => 100,
|
||||
'price_brutto_promo' => 0,
|
||||
'quantity' => 10,
|
||||
'stock_0_buy' => 0,
|
||||
'wp' => 1,
|
||||
'images' => [],
|
||||
], $overrides);
|
||||
}
|
||||
|
||||
public function testCombinationLinkUsesUnderscoreInSeoLinkBranch()
|
||||
{
|
||||
$repo = $this->buildRepoWithMocks();
|
||||
$product = $this->baseProduct();
|
||||
$combination = [
|
||||
'id' => 555,
|
||||
'permutation_hash' => '20-170|21-175',
|
||||
'price_brutto' => 120,
|
||||
'price_brutto_promo' => 0,
|
||||
'quantity' => 5,
|
||||
'stock_0_buy' => 0,
|
||||
];
|
||||
|
||||
$xml = $this->invokeAppendCombination($repo, $product, $combination);
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'<link>https://shop.example.com/sukienka-czerwona/20-170_21-175</link>',
|
||||
$xml,
|
||||
'Link feedu z seo_link musi używać "_" jako separatora par attr-val'
|
||||
);
|
||||
$this->assertStringNotContainsString(
|
||||
'20-170/21-175',
|
||||
$xml,
|
||||
'Link feedu nie może zawierać starego separatora "/" między parami atrybutów'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCombinationLinkUsesUnderscoreInFallbackBranch()
|
||||
{
|
||||
$repo = $this->buildRepoWithMocks();
|
||||
$product = $this->baseProduct([
|
||||
'language' => [
|
||||
'name' => 'Sukienka czerwona',
|
||||
'xml_name' => '',
|
||||
'short_description' => 'Opis',
|
||||
'meta_title' => '',
|
||||
'seo_link' => '',
|
||||
],
|
||||
]);
|
||||
$combination = [
|
||||
'id' => 555,
|
||||
'permutation_hash' => '20-170|21-175',
|
||||
'price_brutto' => 120,
|
||||
'price_brutto_promo' => 0,
|
||||
'quantity' => 5,
|
||||
'stock_0_buy' => 0,
|
||||
];
|
||||
|
||||
$xml = $this->invokeAppendCombination($repo, $product, $combination);
|
||||
|
||||
// Fallback uses "p-{id}-{seo(name)}/...". Helpers::seo stub returns input unchanged.
|
||||
$this->assertStringContainsString(
|
||||
'<link>https://shop.example.com/p-123-Sukienka czerwona/20-170_21-175</link>',
|
||||
$xml,
|
||||
'Link fallback (bez seo_link) musi używać "_" jako separatora par attr-val'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCombinationLinkWithSinglePair()
|
||||
{
|
||||
$repo = $this->buildRepoWithMocks();
|
||||
$product = $this->baseProduct();
|
||||
$combination = [
|
||||
'id' => 555,
|
||||
'permutation_hash' => '20-170',
|
||||
'price_brutto' => 120,
|
||||
'price_brutto_promo' => 0,
|
||||
'quantity' => 5,
|
||||
'stock_0_buy' => 0,
|
||||
];
|
||||
|
||||
$xml = $this->invokeAppendCombination($repo, $product, $combination);
|
||||
|
||||
$this->assertStringContainsString(
|
||||
'<link>https://shop.example.com/sukienka-czerwona/20-170</link>',
|
||||
$xml,
|
||||
'Pojedyncza para attr-val pozostaje bez zmian (str_replace nie ma co podmieniać)'
|
||||
);
|
||||
}
|
||||
}
|
||||
83
tests/Unit/Shared/Helpers/HelpersRoutingTest.php
Normal file
83
tests/Unit/Shared/Helpers/HelpersRoutingTest.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Shared\Helpers;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Phase 18 — testy regex routingu pp_routes dla URL produktów z permutacją.
|
||||
*
|
||||
* Helpers::htacces() generuje pattern dla każdego produktu z permutacją.
|
||||
* Pattern używa klasy znakowej [0-9_-]+, żeby dopasować segment "20-170_21-175"
|
||||
* w jednym kawałku (separator pomiędzy parami atrybutów to "_", nie "/").
|
||||
*
|
||||
* Testy nie wywołują htacces() (zbyt duże zależności), tylko weryfikują:
|
||||
* 1. Wzorzec literałem [0-9_-]+ występuje w generatorze pp_routes (file content)
|
||||
* 2. Wzorzec przyjmuje URL z "_" i odrzuca wariant ze "/"
|
||||
*/
|
||||
class HelpersRoutingTest extends TestCase
|
||||
{
|
||||
private $helpersSource;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->helpersSource = file_get_contents(
|
||||
__DIR__ . '/../../../../autoload/Shared/Helpers/Helpers.php'
|
||||
);
|
||||
}
|
||||
|
||||
public function testHelpersGeneratorUsesPermutationCharClassWithUnderscore()
|
||||
{
|
||||
// Liczba miejsc, gdzie pattern produktu z permutacją używa nowej klasy znaków.
|
||||
$newPattern = substr_count($this->helpersSource, '/([0-9_-]+)$');
|
||||
$this->assertGreaterThanOrEqual(
|
||||
2,
|
||||
$newPattern,
|
||||
'Helpers.php musi zawierać dwa wystąpienia /([0-9_-]+)$ (gałąź seo_link i fallback p-id-name)'
|
||||
);
|
||||
|
||||
// Stary wzorzec [0-9-]+ nie powinien już występować jako finalny segment URL.
|
||||
$this->assertStringNotContainsString(
|
||||
'/([0-9-]+)$',
|
||||
$this->helpersSource,
|
||||
'Stary wzorzec /([0-9-]+)$ został zastąpiony przez /([0-9_-]+)$ — nie powinno go już być w generatorze pp_routes'
|
||||
);
|
||||
}
|
||||
|
||||
public function testRegexMatchesUrlWithUnderscoreSeparator()
|
||||
{
|
||||
$pattern = '#^slug-produktu/([0-9_-]+)$#';
|
||||
$matches = [];
|
||||
|
||||
$this->assertSame(
|
||||
1,
|
||||
preg_match($pattern, 'slug-produktu/20-170_21-175', $matches),
|
||||
'Nowy wzorzec musi dopasować URL z "_" jako separatorem par atrybutów'
|
||||
);
|
||||
$this->assertSame('20-170_21-175', $matches[1]);
|
||||
}
|
||||
|
||||
public function testRegexRejectsLegacyUrlWithSlashSeparator()
|
||||
{
|
||||
$pattern = '#^slug-produktu/([0-9_-]+)$#';
|
||||
|
||||
$this->assertSame(
|
||||
0,
|
||||
preg_match($pattern, 'slug-produktu/20-170/21-175'),
|
||||
'Wzorzec NIE powinien dopasować starego URL ze "/" — taki URL ma trafiać do innego routingu lub 404'
|
||||
);
|
||||
}
|
||||
|
||||
public function testRegexMatchesSinglePairUrl()
|
||||
{
|
||||
$pattern = '#^slug-produktu/([0-9_-]+)$#';
|
||||
$matches = [];
|
||||
|
||||
$this->assertSame(
|
||||
1,
|
||||
preg_match($pattern, 'slug-produktu/20-170', $matches),
|
||||
'Wzorzec dopasowuje też URL z jedną parą attr-val'
|
||||
);
|
||||
$this->assertSame('20-170', $matches[1]);
|
||||
}
|
||||
}
|
||||
BIN
updates/.DS_Store
vendored
Normal file
BIN
updates/.DS_Store
vendored
Normal file
Binary file not shown.
2
updates/0.30/ver_0.304_sql.txt
Normal file
2
updates/0.30/ver_0.304_sql.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE pp_shop_payment_methods ADD COLUMN min_order_amount DECIMAL(10,2) DEFAULT NULL;
|
||||
ALTER TABLE pp_shop_payment_methods ADD COLUMN max_order_amount DECIMAL(10,2) DEFAULT NULL;
|
||||
5
updates/0.30/ver_0.309_sql.txt
Normal file
5
updates/0.30/ver_0.309_sql.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE pp_log ADD COLUMN `action` VARCHAR(100) NULL DEFAULT NULL AFTER `id`;
|
||||
ALTER TABLE pp_log ADD COLUMN `order_id` INT NULL DEFAULT NULL AFTER `action`;
|
||||
ALTER TABLE pp_log ADD COLUMN `context` TEXT NULL DEFAULT NULL AFTER `message`;
|
||||
ALTER TABLE pp_log ADD INDEX `idx_action` (`action`);
|
||||
ALTER TABLE pp_log ADD INDEX `idx_order_id` (`order_id`);
|
||||
1
updates/0.30/ver_0.316_sql.txt
Normal file
1
updates/0.30/ver_0.316_sql.txt
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE `pp_shop_products_custom_fields` ADD COLUMN `type` VARCHAR(30) NOT NULL DEFAULT '' AFTER `name`;
|
||||
BIN
updates/0.30/ver_0.349.zip
Normal file
BIN
updates/0.30/ver_0.349.zip
Normal file
Binary file not shown.
24
updates/0.30/ver_0.349_manifest.json
Normal file
24
updates/0.30/ver_0.349_manifest.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"changelog": "Naprawa kosztu transportu na podsumowaniu koszyka (delivery_free z uwzglednieniem progu)",
|
||||
"version": "0.349",
|
||||
"files": {
|
||||
"added": [
|
||||
|
||||
],
|
||||
"deleted": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"autoload/front/Controllers/ShopBasketController.php",
|
||||
"templates/shop-basket/summary-view.php"
|
||||
]
|
||||
},
|
||||
"checksum_zip": "sha256:acb6a6f4d1c80c5bb4d39c84b5d6d9335069de42febb177d9f581b1b8006aefd",
|
||||
"sql": [
|
||||
|
||||
],
|
||||
"date": "2026-04-20",
|
||||
"directories_deleted": [
|
||||
|
||||
]
|
||||
}
|
||||
BIN
updates/0.30/ver_0.350.zip
Normal file
BIN
updates/0.30/ver_0.350.zip
Normal file
Binary file not shown.
26
updates/0.30/ver_0.350_manifest.json
Normal file
26
updates/0.30/ver_0.350_manifest.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"changelog": "FIX - linki produktow z permutacja w feedzie Google (separator _)",
|
||||
"version": "0.350",
|
||||
"files": {
|
||||
"added": [
|
||||
|
||||
],
|
||||
"deleted": [
|
||||
|
||||
],
|
||||
"modified": [
|
||||
"autoload/Domain/Product/ProductRepository.php",
|
||||
"autoload/Shared/Helpers/Helpers.php",
|
||||
"autoload/front/LayoutEngine.php",
|
||||
"templates/shop-product/_partial/product-attribute.php"
|
||||
]
|
||||
},
|
||||
"checksum_zip": "sha256:0cf918bb070260a8e055a1c8f0f3407532008a5a920da588a14c1f3b11e02c59",
|
||||
"sql": [
|
||||
|
||||
],
|
||||
"date": "2026-04-30",
|
||||
"directories_deleted": [
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
<b>ver. 0.350 - 30.04.2026</b><br />
|
||||
FIX - linki produktow z permutacja w feedzie Google (separator _)
|
||||
<hr>
|
||||
<b>ver. 0.349 - 20.04.2026</b><br />
|
||||
Naprawa kosztu transportu na podsumowaniu koszyka (delivery_free z uwzglednieniem progu)
|
||||
<hr>
|
||||
<b>ver. 0.348 - 19.04.2026</b><br />
|
||||
Dodano przełącznik i edycję etykiet niestandardowych na liście produktów.
|
||||
<hr>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?
|
||||
$current_ver = 348;
|
||||
$current_ver = 350;
|
||||
|
||||
for ($i = 1; $i <= $current_ver; $i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user