Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fce4bdb1f1 | |||
| adfabaf3fa | |||
| 073069c303 | |||
| 8a89305f29 | |||
| d858f74de3 | |||
| 18bdf8384f | |||
| 6c924ae542 | |||
| 255456dcc5 | |||
| e84edb2354 | |||
| fba215b372 | |||
|
|
0de47f4e62 | ||
|
|
abb794de36 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
.vscode/ftp-kr.sync.cache.json
|
.vscode/ftp-kr.sync.cache.json
|
||||||
|
temp/
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Właściciel sklepu internetowego ma pełną kontrolę nad sprzedażą online -
|
|||||||
|-----------|-------|
|
|-----------|-------|
|
||||||
| Version | 0.333 |
|
| Version | 0.333 |
|
||||||
| Status | Production |
|
| Status | Production |
|
||||||
| Last Updated | 2026-04-20 |
|
| Last Updated | 2026-04-30 |
|
||||||
|
|
||||||
## Requirements
|
## 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] Domain-Driven Architecture (migracja z legacy zakończona)
|
||||||
- [x] Szybka edycja custom_label_0..4 na liscie produktow admina (toggle sesyjny + autocomplete)
|
- [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] 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)
|
### 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 |
|
| `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 |
|
| 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 |
|
| 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
|
## Success Metrics
|
||||||
|
|
||||||
| Metric | Target | Current | Status |
|
| Metric | Target | Current | Status |
|
||||||
|--------|--------|---------|--------|
|
|--------|--------|---------|--------|
|
||||||
| Testy | >800 | 834 | On track |
|
| Testy | >800 | 841 | On track |
|
||||||
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
| Pokrycie architektury DDD | 100% | 100% | Achieved |
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
@@ -117,4 +119,4 @@ Quick Reference:
|
|||||||
|
|
||||||
---
|
---
|
||||||
*PROJECT.md - Updated when requirements or context change*
|
*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,10 @@ Status: Planning
|
|||||||
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
| 9 | Apilo email notification + infinite retry | 1 | Done | 2026-03-19 |
|
||||||
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
| 15 | Scontainers edit saves as new record | 1 | Done | 2026-04-18 |
|
||||||
| 17 | Cart summary transport cost fix | 1 | Done | 2026-04-20 |
|
| 17 | Cart summary transport cost fix | 1 | Done | 2026-04-20 |
|
||||||
|
| 18 | Google feed permutation URL fix | 1 | Done | 2026-04-30 |
|
||||||
|
| 19 | Frontend meta tags fix (category + product) | 1 | Done | 2026-05-13 |
|
||||||
|
| 20 | Category edit mojibake fix (UI labels) | 1 | Done | 2026-05-13 |
|
||||||
|
| 21 | Admin update view JS fix (przyciski aktualizacji + cache) | 1 | Done | 2026-05-13 |
|
||||||
|
|
||||||
## Feature
|
## Feature
|
||||||
|
|
||||||
@@ -125,5 +129,34 @@ 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.
|
**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.
|
||||||
|
|
||||||
|
### Phase 19 — Frontend meta tags fix
|
||||||
|
|
||||||
|
**Problem:** Strony kategorii (np. `/sen-i-otulenie`) i strony produktów (np. `/kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja`) renderują `<title>` strony głównej oraz literalne wartości `content="keywords"`/`content="description"` zamiast właściwych metatagów SEO z bazy. Niepoprawne meta blokują indeksację Google i Merchant Center.
|
||||||
|
|
||||||
|
**Scope:** Diagnostyka (pp_routes + meta w DB + sesyjny $page), checkpoint:decision z 4 opcjami fixu (routes/engine/data/session), implementacja wybranej opcji w `LayoutEngine.php` lub `index.php`, test jednostkowy, human-verify na 3 URL-ach.
|
||||||
|
|
||||||
---
|
---
|
||||||
*Last updated: 2026-04-20 (Phase 17 complete)*
|
### Phase 20 — Category edit mojibake fix
|
||||||
|
|
||||||
|
**Problem:** Etykiety formularza edycji kategorii (`/admin/shop_category/category_edit/id=X`) pokazują double-encoded UTF-8 mojibake: `Treść` zamiast "Treść", `JÄ™zyk domyĹ›lny` zamiast "Język domyślny", `Sortowanie produktĂłw` zamiast "Sortowanie produktów" itp.
|
||||||
|
|
||||||
|
**Root cause:** Plik `admin/templates/shop-category/category-edit.php` został kiedyś zapisany z UTF-8 zinterpretowanym jako Windows-1252 i ponownie zakodowanym do UTF-8. 9 wystąpień. To JEDYNY taki plik w całym repo — grep `Ä[\x{84}-\x{99}]|Ĺ|Ăł` po całym `admin/templates/`, `templates/`, `autoload/` nie wskazuje innych dotknietych plików.
|
||||||
|
|
||||||
|
**Scope:** Podmienić 9 hardcoded labelek na poprawne polskie znaki (Treść, Język domyślny, Tytuł, rozwinięcie, Sortowanie produktów, Wyświetlić podkategorie, Blokuj indeksację). Brak zmian w logice/HTML structure, plik zostaje UTF-8 bez BOM. Human-verify w panelu admina.
|
||||||
|
|
||||||
|
### Phase 21 — Admin update view JS fix
|
||||||
|
|
||||||
|
**Problem:** Na `/admin/update/main_view/` nie działają przyciski "Aktualizuj do wyższej wersji", "Aktualizuj do najwyższej wersji" oraz globalny "Wyczyść cache" z headera admina. Klient nie może zaktualizować systemu. Brak błędu JS w konsoli — kliknięcie tylko dopisuje `#` do URL.
|
||||||
|
|
||||||
|
**Root cause:** `admin/templates/update/main-view.php` pobiera zdalny changelog przez `file_get_contents` z `shoppro.project-dc.pl/updates/changelog.php`. Odpowiedź zawiera niezbalansowany HTML (niezamknięty `<script>`, `<!--`, `<style>` lub `<textarea>`), który „połyka" pozostałą część dokumentu jako tekst — inline-script z handlerami i footer-script z `main-layout.php` nigdy się nie parsują.
|
||||||
|
|
||||||
|
**Scope:** (1) Przenieść blok `<script>` z handlerami przyciskami PRZED sekcję Changelog. (2) Sanityzować zdalny changelog: `preg_replace` usuwa komentarze HTML, `strip_tags` z białą listą tagów formatujących. Jeden plik: `admin/templates/update/main-view.php`. Human-verify w panelu admina.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Last updated: 2026-05-13 (Phase 21 complete)*
|
||||||
|
|||||||
@@ -2,22 +2,22 @@
|
|||||||
|
|
||||||
## Project Reference
|
## 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.
|
**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 21 complete — loop closed
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Milestone: Hotfix
|
Milestone: Hotfix
|
||||||
Phase: 17 of 17 (Cart summary transport cost fix) - Complete
|
Phase: 21 of 21 (Admin update view JS fix) — Complete
|
||||||
Plan: 17-01 complete
|
Plan: 21-01 complete
|
||||||
Status: UNIFY complete, ready for next PLAN loop (transition-phase pending)
|
Status: UNIFY complete, ready for next PLAN loop (transition-phase git commit pending)
|
||||||
Last activity: 2026-04-20 - Closed loop for .paul/phases/17-cart-summary-transport-cost-fix/17-01-PLAN.md
|
Last activity: 2026-05-13 — Closed loop for .paul/phases/21-admin-update-view-js-fix/21-01-PLAN.md
|
||||||
|
|
||||||
Progress:
|
Progress:
|
||||||
- Milestone: [##########] 100%
|
- Milestone: [##########] 100% (Hotfix rolling)
|
||||||
- Phase 17: [##########] 100%
|
- Phase 21: [##########] 100%
|
||||||
|
|
||||||
## Loop Position
|
## Loop Position
|
||||||
|
|
||||||
@@ -43,10 +43,34 @@ Phase 14: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-16]
|
|||||||
Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
Phase 15: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-18]
|
||||||
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
Phase 16: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-19]
|
||||||
Phase 17: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-20]
|
Phase 17: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-20]
|
||||||
|
Phase 18: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-04-30]
|
||||||
|
Phase 19: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-05-13]
|
||||||
|
Phase 20: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-05-13]
|
||||||
|
Phase 21: PLAN --> APPLY --> UNIFY ✓ ✓ ✓ [COMPLETE - 2026-05-13]
|
||||||
```
|
```
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
### Decisions
|
### Decisions
|
||||||
|
- 2026-05-13: Phase 21 loop closed with SUMMARY at .paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md
|
||||||
|
- 2026-05-13: Transition-phase git commit for Phase 21 not executed in this UNIFY run (deferred — pattern z faz 15-20)
|
||||||
|
- 2026-05-13: Phase 21 APPLY complete — admin/templates/update/main-view.php zmodyfikowany (reorder <script> przed sekcję Changelog + sanityzacja zdalnego changeloga: preg_replace komentarzy HTML + strip_tags z whitelistą tagów formatujących); php -l OK; suita 846 testów zielona; human-verify approved
|
||||||
|
- 2026-05-13: Created Phase 21 plan at .paul/phases/21-admin-update-view-js-fix/21-01-PLAN.md — fix niedziałających przycisków aktualizacji + Wyczyść cache w /admin/update/main_view/ (zdalny changelog z niezbalansowanym HTML "połykał" inline i footer-script). Reorder bloku <script> przed sekcję Changelog + sanityzacja zdalnego changeloga (strip_tags z whitelistą + usunięcie komentarzy HTML).
|
||||||
|
- 2026-05-13: Phase 20 loop closed with SUMMARY at .paul/phases/20-category-edit-mojibake-fix/20-01-SUMMARY.md
|
||||||
|
- 2026-05-13: Transition-phase git commit for Phase 20 not executed in this UNIFY run (deferred — pattern z faz 15-19)
|
||||||
|
- 2026-05-13: Phase 20 APPLY complete — 9 wystąpień mojibake w admin/templates/shop-category/category-edit.php naprawionych (Treść, Język domyślny x2, rozwinięcie, Sortowanie produktów, Wyświetlić podkategorie, Tytuł kategorii, Blokuj indeksację); suita 846 zielona; human-verify approved
|
||||||
|
- 2026-05-13: Created Phase 20 plan at .paul/phases/20-category-edit-mojibake-fix/20-01-PLAN.md — fix mojibake w labelkach formularza edycji kategorii (double-encoded UTF-8 w admin/templates/shop-category/category-edit.php, 9 wystąpień, jedyny dotknięty plik w repo)
|
||||||
|
- 2026-05-13: Phase 19 loop closed with SUMMARY at .paul/phases/19-frontend-meta-tags-fix/19-01-SUMMARY.md
|
||||||
|
- 2026-05-13: Transition-phase git commit for Phase 19 not executed in this UNIFY run (deferred — pattern z faz 15/16/17/18)
|
||||||
|
- 2026-05-13: Phase 19 APPLY complete — LayoutEngine.php zmodyfikowany (3 gałęzie + nowa metoda applyEntityMetaToPage), test LayoutEngineMetaTagsTest 5 testów/18 asercji, suita 846 zielona; weryfikacja na produkcji (curl) pokazuje poprawne tytuły dla /sen-i-otulenie, /kocyk-niemowlaka-... i /
|
||||||
|
- 2026-05-13: Phase 19 checkpoint:decision — wybrano `fix-engine-detection`. Root cause: LayoutEngine::show() w gałęziach category/article/product nadpisuje $page['language']['title'] ale NIE $page['language']['meta_title']. Wartość meta_title homepage ('Sklep z akcesoriami...') wycieka do linii 332. Dane DB klienta (literalne 'description'/'keywords' w kategorii) to oddzielny issue — admin uzupełnia.
|
||||||
|
- 2026-05-13: Created Phase 19 plan at .paul/phases/19-frontend-meta-tags-fix/19-01-PLAN.md — fix metatagów <title>/<meta description>/<meta keywords> dla kategorii i produktu (homepage tytuł wycieka na wszystkie podstrony)
|
||||||
|
- 2026-05-13: Phase 19 — najpierw diagnostyka (pp_routes + DB meta + session $page), checkpoint:decision, potem fix; ustalanie root cause przed implementacją (3 hipotezy: pp_routes destination bez category=/product=, sesyjny $page bleed, lub literalne zaślepki w DB)
|
||||||
|
- 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: 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: 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)
|
- 2026-04-20: Phase 17 APPLY complete - human-verify checkpoint approved, 834 testow zielonych (6 nowych)
|
||||||
@@ -89,17 +113,17 @@ None.
|
|||||||
### Blockers/Concerns
|
### Blockers/Concerns
|
||||||
None.
|
None.
|
||||||
|
|
||||||
### Skill Audit (Phase 16)
|
### Skill Audit (Phase 21)
|
||||||
| Expected | Invoked | Notes |
|
| Expected | Invoked | Notes |
|
||||||
|----------|---------|-------|
|
|----------|---------|-------|
|
||||||
| /feature-dev | ○ | User-approved override during APPLY |
|
| /feature-dev | ○ | Hotfix template-only z konkretną instrukcją w change.md — override per pattern poprzednich faz |
|
||||||
| /koniec-pracy | ○ | Marked as available by user; execute on session close workflow |
|
| /koniec-pracy | ○ | Pending — uruchomić przy release update package |
|
||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-20
|
Last session: 2026-05-13
|
||||||
Stopped at: Phase 17 complete, loop closed
|
Stopped at: Phase 21 complete, loop closed
|
||||||
Next action: Start next milestone or create next phase plan (transition-phase commit pending)
|
Next action: Start next phase plan (transition-phase git commit pending), lub uruchomić /koniec-pracy jeśli zamykamy sesję
|
||||||
Resume file: .paul/phases/17-cart-summary-transport-cost-fix/17-01-SUMMARY.md
|
Resume file: .paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md
|
||||||
---
|
---
|
||||||
*STATE.md — Updated after every significant action*
|
*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`
|
||||||
34
.paul/changelog/2026-05-13.md
Normal file
34
.paul/changelog/2026-05-13.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 2026-05-13
|
||||||
|
|
||||||
|
## Co zrobiono
|
||||||
|
|
||||||
|
- [Phase 19, Plan 01] Fix metatagów na stronach kategorii/artykułu/produktu — eliminacja wycieku meta_title homepage
|
||||||
|
- Task 1: Diagnostyka produkcyjnej DB (pp_routes + pp_shop_categories_langs + pp_shop_products_langs + pp_pages_langs) — wynik w DIAGNOSTICS.md
|
||||||
|
- Task 2 (checkpoint:decision): Wybrano fix-engine-detection (root cause w kodzie, nie w danych)
|
||||||
|
- Task 3: Wyodrębniono `\front\LayoutEngine::applyEntityMetaToPage()` jako pure-function; 3 gałęzie (category/article/product) wywołują helper; suita 846 testów zielona (5 nowych w LayoutEngineMetaTagsTest)
|
||||||
|
- Task 4 (human-verify): Weryfikacja curl na produkcji — 3 strony pokazują 3 różne `<title>`, homepage meta nie wycieka
|
||||||
|
- .gitignore — dodano `temp/` (skrypty diagnostyczne z DB credentials)
|
||||||
|
|
||||||
|
- [Phase 20, Plan 01] Fix mojibake (double-encoded UTF-8) w labelkach formularza edycji kategorii
|
||||||
|
- Task 1: Podmiana 9 wystąpień mojibake na poprawne polskie znaki (Treść, Język domyślny, Tytuł kategorii, Sortowanie produktów, Wyświetlić podkategorie, Blokuj indeksację, Opis kategorii rozwinięcie)
|
||||||
|
- Task 2: Weryfikacja braku regresji (grep w całym repo — 0 innych plików dotkniętych), suita 846 zielona
|
||||||
|
- Task 3 (human-verify): Weryfikacja w panelu admina shoppro.project-dc.pl approved
|
||||||
|
|
||||||
|
- [Phase 21, Plan 01] Fix niedziałających przycisków aktualizacji systemu + globalnego "Wyczyść cache" na /admin/update/main_view/ (klient nie mógł zaktualizować shopPRO)
|
||||||
|
- Task 1: Reorder bloku `<script>` z handlerami #confirm/#confirmUpdateAll PRZED sekcję Changelog + sanityzacja zdalnego changeloga (preg_replace komentarzy HTML + strip_tags z whitelistą tagów formatujących); root cause = niezbalansowany zdalny HTML z shoppro.project-dc.pl „połykał" inline-script i footer-script; suita 846 zielona
|
||||||
|
- Task 2 (human-verify): Weryfikacja w panelu admina approved (przyciski aktualizacji + Wyczyść cache + zdalny changelog renderuje się sanityzowany)
|
||||||
|
|
||||||
|
## Zmienione pliki
|
||||||
|
|
||||||
|
- `autoload/front/LayoutEngine.php`
|
||||||
|
- `admin/templates/shop-category/category-edit.php`
|
||||||
|
- `admin/templates/update/main-view.php`
|
||||||
|
- `tests/Unit/front/LayoutEngineMetaTagsTest.php` (nowy)
|
||||||
|
- `.paul/phases/19-frontend-meta-tags-fix/19-01-PLAN.md` (nowy)
|
||||||
|
- `.paul/phases/19-frontend-meta-tags-fix/19-01-SUMMARY.md` (nowy)
|
||||||
|
- `.paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md` (nowy)
|
||||||
|
- `.paul/phases/21-admin-update-view-js-fix/21-01-PLAN.md` (nowy)
|
||||||
|
- `.paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md` (nowy)
|
||||||
|
- `.paul/STATE.md`
|
||||||
|
- `.paul/ROADMAP.md`
|
||||||
|
- `.gitignore`
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
|--------|-------|
|
|--------|-------|
|
||||||
| Total tests | **828** |
|
| Total tests | **846** |
|
||||||
| Total assertions | **2306** |
|
| Total assertions | **2348** |
|
||||||
| Framework | PHPUnit 9.6 (`phpunit.phar`) |
|
| Framework | PHPUnit 9.6 (`phpunit.phar`) |
|
||||||
| Bootstrap | `tests/bootstrap.php` |
|
| Bootstrap | `tests/bootstrap.php` |
|
||||||
| Config | `phpunit.xml` |
|
| Config | `phpunit.xml` |
|
||||||
|
|||||||
@@ -2,6 +2,43 @@
|
|||||||
|
|
||||||
> Chronologiczny log zmian technicznych — co i dlaczego.
|
> Chronologiczny log zmian technicznych — co i dlaczego.
|
||||||
|
|
||||||
|
## v0.353 (2026-05-13)
|
||||||
|
|
||||||
|
- Naprawiono niedzialajace przyciski aktualizacji systemu (`#confirm`, `#confirmUpdateAll`) i globalny "Wyczysc cache" (`#clear-cache-btn`) na `/admin/update/main_view/`. Klienci nie mogli aktualizowac shopPRO na instancjach.
|
||||||
|
- Root cause: `admin/templates/update/main-view.php` pobieral zdalny changelog przez `file_get_contents` z `shoppro.project-dc.pl/updates/changelog.php`. Odpowiedz zawierala niezbalansowany HTML (niezamkniety `<script>`, `<!--`, `<style>` lub `<textarea>`), ktory "polykal" reszte dokumentu — inline-script z handlerami przyciskow i footer-script z `main-layout.php` (Wyczysc cache) nigdy sie nie parsowal jako JS. Brak bledu w konsoli — to nie byl blad JS, to byl HTML, ktory nigdy nie zostal wykonany jako skrypt.
|
||||||
|
- Fix 1: blok `<script>` z handlerami przeniesiony PRZED sekcje Changelog (wczesniej kolejnosc: wersje -> log -> changelog -> script; teraz: wersje -> log -> script -> changelog). Handlery podpinaja sie niezaleznie od tego, co zwroci zdalny serwer.
|
||||||
|
- Fix 2: sanityzacja zdalnego changeloga przed wyrenderowaniem: `preg_replace('/<!--.*?-->/s', '', $html)` + `strip_tags($html, '<p><br><b><strong><i><em><u><ul><ol><li><h1>-<h6><span><div><a><pre><code><hr>')`. Tagi strukturalne i "polykajace" (`<script>`, `<style>`, `<textarea>`, `<iframe>`, `<body>`, `</html>`) sa usuwane.
|
||||||
|
- Skutek uboczny: footer-script z `main-layout.php` (przycisk Wyczysc cache + globalne wyszukiwanie produktow/zamowien + sprawdzanie aktualizacji w menu) dziala teraz na podstronie update.
|
||||||
|
- Zysk bezpieczenstwa: zdalny serwis nie moze juz wstrzyknac JS w panel admina.
|
||||||
|
- Wymagane akcje na produkcji po wgraniu update package: hard-reload przegladarki (Ctrl+F5) + restart PHP-FPM / wyczyszczenie OPcache (inaczej stary skompilowany szablon dalej bedzie serwowany).
|
||||||
|
- Suita PHPUnit bez zmian: 846 testow / 2348 assertions.
|
||||||
|
|
||||||
|
## v0.352 (2026-05-13)
|
||||||
|
|
||||||
|
- Naprawiono mojibake w labelkach formularza edycji kategorii w panelu admina (`/admin/shop_category/category_edit/id=X`). Plik `admin/templates/shop-category/category-edit.php` byl kiedys zapisany z UTF-8 zinterpretowanym jako Windows-1252 i ponownie zakodowanym do UTF-8 (classic double-encoding). 9 wystapien naprawione: `Treść`→Treść, `JÄ™zyk domyĹ›lny`→Język domyślny (x2), `rozwiniÄ™cie`→rozwinięcie, `Sortowanie produktĂłw`→Sortowanie produktów, `WyĹ›wietlić podkategorie`→Wyświetlić podkategorie, `TytuĹ‚ kategorii (h1)`→Tytuł kategorii (h1), `Blokuj indeksacjÄ™`→Blokuj indeksację.
|
||||||
|
- Wykluczono regresje: grep `Ä[\\x{84}-\\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć|Ĺ„` w `admin/templates/`, `templates/`, `autoload/` zwraca 0 plikow — to byl jedyny przypadek mojibake w repo.
|
||||||
|
- Suita PHPUnit bez zmian: 846 testow / 2348 assertions.
|
||||||
|
|
||||||
|
## v0.351 (2026-05-13)
|
||||||
|
|
||||||
|
- Naprawiono wyciek metatagow ze strony glownej na podstrony kategorii/artykulu/produktu: `<title>` wszystkich podstron pokazywal tytul homepage ("Sklep z akcesoriami..."), bo `LayoutEngine::show()` nadpisywal w galezi kategorii/artykulu/produktu tylko `$page['language']['title']`, a `meta_title` z domyslnej strony zylo dalej i wygrywalo w linii substytucji `[TITLE]`.
|
||||||
|
- Wyodrebniono nowa metode publiczna `\front\LayoutEngine::applyEntityMetaToPage($page, $entityLanguage, $fallbackTitle)`: zawsze nadpisuje `meta_title`, `meta_keywords`, `meta_description` w `$page['language']` wartosciami encji (nawet pustym/null), eliminujac wyciek.
|
||||||
|
- `LayoutEngine.php`: 3 galezie (category, article, product) wywoluja helper zamiast inline'ow z nadpisywaniem czesci pol.
|
||||||
|
- Dodano 5 testow jednostkowych (`tests/Unit/front/LayoutEngineMetaTagsTest.php`) na pure-function helper: meta_title encji wygrywa, NULL czysci homepage, all-null product, null entity safe, empty page struct. Suita: 846 testow / 2348 assertions.
|
||||||
|
- Diagnostyka root cause na produkcyjnej DB: pp_routes mapuje poprawnie (`category=10`, `product=522`); literalne 'description'/'keywords' w `pp_shop_categories_langs.id=331` to dane klienta (admin uzupelnia w panelu), nie bug shopPRO.
|
||||||
|
- `.gitignore` rozszerzony o `temp/` (skrypty diagnostyczne z DB credentials).
|
||||||
|
- Wymagane akcje na produkcji po deployu: poczekac na TTL cache Redis (24h) lub wyczyscic klucze `pp_routes:all`, `front_category_details:*`, `shop\\product:*` — opcjonalne (fix jest w warstwie poza cache).
|
||||||
|
|
||||||
|
## 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)
|
## 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).
|
- 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.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"}
|
||||||
133
.paul/governance/governance_2026-05-13.jsonl
Normal file
133
.paul/governance/governance_2026-05-13.jsonl
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
{"ts":"2026-05-13T20:12:07Z","tool":"Bash","cmd":"curl -s -A \"Mozilla/5.0\" https://shoppro.project-dc.pl/sen-i-otulenie | grep -iE \"<title>|<meta\" | head -40\",\"description\":\"Fetch category page metatags\"},\"tool_response\":{\"stdout\":\" ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:12:11Z","tool":"Bash","cmd":"curl -s -A \"Mozilla/5.0\" https://shoppro.project-dc.pl/kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja | grep -iE \"<title>|<meta\" | head -40\",\"description\":\"Fetch product page metatags\"},\"too","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:19:03Z","tool":"Bash","cmd":"mkdir \"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\19-frontend-meta-tags-fix\"\",\"description\":\"Create phase 19 directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:21Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\19-frontend-meta-tags-fix\\\\19-01-PLAN.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:30Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:50Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:20:59Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:23:00Z","tool":"Bash","cmd":"mysql -h host117523.hostido.net.pl -u host117523_shoppro -p'mhA9WCEXEnRfTtbN33hL' host117523_shoppro -e \"SELECT pattern, destination FROM pp_routes WHERE 'sen-i-otulenie' REGEXP CONCAT('^', pattern) ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:24:13Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:24:36Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta2.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:24:46Z","tool":"Bash","cmd":"/c/xampp/php/php \"C:/visual studio code/projekty/shopPRO/temp/diag_meta2.php\" 2>&1\",\"description\":\"Run diagnostic 2\"},\"tool_response\":{\"stdout\":\"=== Tables related to categories, products,","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:25:01Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta3.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:25:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta3.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:25:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta3.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:26:15Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\diag_meta4.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:26:21Z","tool":"Bash","cmd":"/c/xampp/php/php \"C:/visual studio code/projekty/shopPRO/temp/diag_meta4.php\" 2>&1\",\"description\":\"Run diagnostic 4 — homepage meta\"},\"tool_response\":{\"stdout\":\"=== pp_pages_langs PL whe","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:26:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.gitignore","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:27:20Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\19-frontend-meta-tags-fix\\\\DIAGNOSTICS.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:28:47Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:29:05Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\front\\\\LayoutEngine.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:29:35Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\autoload\\\\front\\\\LayoutEngine.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:29:47Z","tool":"Bash","cmd":"/c/xampp/php/php -l \"C:/visual studio code/projekty/shopPRO/autoload/front/LayoutEngine.php\"\",\"description\":\"PHP syntax check\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in C:/v","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:30:26Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\tests\\\\Unit\\\\front\\\\LayoutEngineMetaTagsTest.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:30:34Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php phpunit.phar tests/Unit/front/LayoutEngineMetaTagsTest.php 2>&1 | tail -25\",\"description\":\"Run new test\"},\"tool_response\":{\"st","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:30:46Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php phpunit.phar 2>&1 | tail -15\",\"timeout\":300000,\"description\":\"Run full PHPUnit suite\"},\"tool_response\":{\"stdout\":\"........","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:30:58Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\temp\\\\clear_cache.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:18Z","tool":"Bash","cmd":"curl -s -A \"Mozilla/5.0\" https://shoppro.project-dc.pl/sen-i-otulenie | grep -iE \"<title>|<meta name=\\\\\"(description|keywords)\\\\\"\" | head -5\\necho \"---\"\\ncurl -s -A \"Mozilla/5.0\" https","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:32:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:34:11Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\19-frontend-meta-tags-fix\\\\19-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:34:39Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\changelog\\\\2026-05-13.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:34:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:34:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:35:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:35:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:35:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:35:28Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:35:56Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php phpunit.phar 2>&1 | tail -5\",\"timeout\":300000,\"description\":\"Run full test suite\"},\"tool_response\":{\"stdout\":\"............","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:36:08Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && sonar-scanner 2>&1 | tail -15\",\"timeout\":600000,\"description\":\"Run SonarQube scanner\"},\"tool_response\":{\"stdout\":\"/usr/bin/bash: line 1: so","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:36:48Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag --sort=-v:refname | head -3\",\"description\":\"Get latest tag\"},\"tool_response\":{\"stdout\":\"v0.350\\nv0.349\\nv0.348\",\"stderr\":\"\",\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:37:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:37:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\codebase\\\\testing.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:37:37Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>&1 | head -30\",\"description\":\"Git status\"},\"tool_response\":{\"stdout\":\" M .gitignore\\n M .paul/ROADMAP.md\\n M .paul/STA","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:37:44Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git log --oneline -5 2>&1\",\"description\":\"Recent commits style\"},\"tool_response\":{\"stdout\":\"255456d update\\ne84edb2 build: ver_0.350 - fix l","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:37:52Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add .gitignore .paul/ROADMAP.md .paul/STATE.md .paul/codebase/testing.md .paul/docs/TECH_CHANGELOG.md autoload/front/LayoutEngine.php .paul/changel","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:38:03Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git commit -m \"$(cat <<'EOF'\\nfix: wyciek meta_title homepage na podstrony kategorii/artykulu/produktu (v0.351)\\n\\nLayoutEngine::show() w 3 galezia","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:38:13Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push 2>&1 | tail -5\",\"description\":\"Git push\"},\"tool_response\":{\"stdout\":\"remote: . Processing 1 references \\nremote: Processed 1","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:38:21Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag v0.351 2>&1 && echo \"Tag created\"\",\"description\":\"Create tag\"},\"tool_response\":{\"stdout\":\"Tag created\",\"stderr\":\"\",\"interrupt","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:38:28Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && ls build-update.ps1 2>&1; head -50 build-update.ps1 2>&1\",\"description\":\"Check build script\"},\"tool_response\":{\"stdout\":\"build-update.ps1\\n<","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:38:50Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add updates/0.30/ver_0.351.zip updates/0.30/ver_0.351_manifest.json updates/versions.php updates/changelog-data.html && git commit -m \"build: ver_","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:39:03Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push && git push origin v0.351 2>&1 | tail -10\",\"description\":\"Push branch + tag\"},\"tool_response\":{\"stdout\":\"remote: . Processing 1 refe","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:41:36Z","tool":"Bash","cmd":"curl -s \"https://shoppro.project-dc.pl/admin/shop_category/category_edit/id=10\" 2>&1 | head -5; echo \"---needs auth---\"\",\"description\":\"Try fetching admin page (likely requires auth)\"},\"tool","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:43:08Z","tool":"Bash","cmd":"file \"C:/visual studio code/projekty/shopPRO/admin/templates/shop-category/\"*.php 2>&1 | head -10\",\"description\":\"Check encoding of category templates\"},\"tool_response\":{\"stdout\":\"C:/visua","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:44:04Z","tool":"Bash","cmd":"mkdir \"C:/visual studio code/projekty/shopPRO/.paul/phases/20-category-edit-mojibake-fix\"\",\"description\":\"Create phase 20 directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interr","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:04Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\20-category-edit-mojibake-fix\\\\20-01-PLAN.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:13Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:19Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:26Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:38Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:45:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:24Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:29Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:34Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:46:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\shop-category\\\\category-edit.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:47:02Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && grep -cP \"Ä[\\\\x{84}-\\\\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć|Ĺ„\" admin/templates/shop-category/category-edit.php\\necho \"---file encod","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:47:17Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && grep -rlP \"Ä[\\\\x{84}-\\\\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć\" admin/templates/ templates/ autoload/ 2>&1\\necho \"---no other files affec","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:47:28Z","tool":"Bash","cmd":"curl -s \"https://shoppro.project-dc.pl/admin/shop_category/category_edit/id=10\" 2>&1 | grep -P \"Treść|JÄ™zyk|Treść|Język\" | head -5\\necho \"---\"\\necho \"(strona admin wymaga auth ","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:50:54Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:51:00Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:51:06Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:51:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:15Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\20-category-edit-mojibake-fix\\\\20-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\changelog\\\\2026-05-13.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:52Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:52:58Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:53:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:54:47Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && /c/xampp/php/php phpunit.phar 2>&1 | tail -5\",\"timeout\":300000,\"description\":\"Run test suite\"},\"tool_response\":{\"stdout\":\".................","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:54:54Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag --sort=-v:refname | head -1\",\"description\":\"Latest tag\"},\"tool_response\":{\"stdout\":\"v0.351\",\"stderr\":\"\",\"interrupted\":false,\"","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:55:08Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:55:16Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git status --short 2>&1\",\"description\":\"Git status\"},\"tool_response\":{\"stdout\":\" M .paul/ROADMAP.md\\n M .paul/STATE.md\\n M .paul/changelog/","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:55:28Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add .paul/ROADMAP.md .paul/STATE.md .paul/changelog/2026-05-13.md .paul/docs/TECH_CHANGELOG.md admin/templates/shop-category/category-edit.php .pau","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:55:37Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git push 2>&1 | tail -3\",\"description\":\"Git push\"},\"tool_response\":{\"stdout\":\"remote: Processed 1 references in total \\nTo https://gi","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:55:45Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git tag v0.352\",\"description\":\"Create v0.352 tag\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"no","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:56:09Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && git add updates/0.30/ver_0.352.zip updates/0.30/ver_0.352_manifest.json updates/versions.php updates/changelog-data.html && git commit -m \"build: ver_","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T20:59:58Z","tool":"Bash","cmd":"mkdir -p \".paul/phases/21-admin-update-view-js-fix\"\",\"description\":\"Create phase directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutpu","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:00:44Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\21-admin-update-view-js-fix\\\\21-01-PLAN.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:00:55Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:01:03Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:01:10Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:01:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:01:25Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:03:04Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\admin\\\\templates\\\\update\\\\main-view.php","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:03:11Z","tool":"Bash","cmd":"php -l \"admin/templates/update/main-view.php\" 2>&1\",\"description\":\"PHP lint check\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in admin/templates/update/main-view.php\",\"stderr\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:04:15Z","tool":"Bash","cmd":"powershell -ExecutionPolicy Bypass -File ./test.ps1 2>&1 | tail -30\",\"timeout\":300000,\"description\":\"Run full PHPUnit suite\"},\"tool_response\":{\"stdout\":\"The argument './test.ps1' to the -F","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:04:22Z","tool":"Bash","cmd":"powershell -ExecutionPolicy Bypass -File \"test.ps1\" 2>&1 | tail -20\",\"timeout\":300000,\"description\":\"Run PHPUnit suite via test.ps1\"},\"tool_response\":{\"stdout\":\"The argument 'test.ps1' t","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:04:38Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && ls *.ps1 *.bat 2>&1 | head\",\"description\":\"List test runner scripts in project root\"},\"tool_response\":{\"stdout\":\"ls: cannot access '*.bat': N","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:04:53Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && ls phpunit* composer* 2>&1 | head\",\"description\":\"Check for phpunit and composer\"},\"tool_response\":{\"stdout\":\"composer.json\\ncomposer.lock\\","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:05:01Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && php phpunit.phar 2>&1 | tail -15\",\"timeout\":300000,\"description\":\"Run full PHPUnit suite\"},\"tool_response\":{\"stdout\":\".....................","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:05:11Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:05:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:05:26Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:05:33Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:06:40Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\phases\\\\21-admin-update-view-js-fix\\\\21-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:05Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\changelog\\\\2026-05-13.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:15Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:30Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:44Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:07:54Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:08:48Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/shopPRO\" && php phpunit.phar 2>&1 | tail -5\",\"timeout\":300000,\"description\":\"Run PHPUnit full suite\"},\"tool_response\":{\"stdout\":\"......................","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:08:55Z","tool":"Bash","cmd":"where sonar-scanner 2>&1 | head -3\",\"description\":\"Check sonar-scanner availability\"},\"tool_response\":{\"stdout\":\"INFO: Could not find files for the given pattern(s).\",\"stderr\":\"\",\"inte","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:09:03Z","tool":"Bash","cmd":"git tag --sort=-v:refname | head -3\",\"description\":\"Get latest tag\"},\"tool_response\":{\"stdout\":\"v0.352\\nv0.351\\nv0.350\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputE","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:09:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\shopPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:09:48Z","tool":"Bash","cmd":"git status --short\",\"description\":\"Git status\"},\"tool_response\":{\"stdout\":\" M .paul/ROADMAP.md\\n M .paul/STATE.md\\n M .paul/changelog/2026-05-13.md\\n M .paul/docs/TECH_CHANGELOG.md\\n M .","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:09:55Z","tool":"Bash","cmd":"git add admin/templates/update/main-view.php .paul/ROADMAP.md .paul/STATE.md .paul/changelog/2026-05-13.md .paul/docs/TECH_CHANGELOG.md .paul/phases/21-admin-update-view-js-fix/ change.md && git statu","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:10:09Z","tool":"Bash","cmd":"git commit -m \"$(cat <<'EOF'\\nfix: dziala aktualizacja systemu i Wyczysc cache na /admin/update/main_view/ (v0.353)\\n\\nZdalny changelog z shoppro.project-dc.pl/updates/changelog.php zwracal\\nniez","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:10:17Z","tool":"Bash","cmd":"git push 2>&1 | tail -10\",\"description\":\"Push to remote\"},\"tool_response\":{\"stdout\":\"remote: . Processing 1 references \\nremote: Processed 1 references in total \\nTo https://","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:10:31Z","tool":"Bash","cmd":"git tag v0.353 && powershell.exe -ExecutionPolicy Bypass -File build-update.ps1 -FromTag v0.352 -ToTag v0.353 -ChangelogEntry \"fix: dziala aktualizacja systemu i Wyczysc cache na /admin/update/main_v","cwd":"/c/visual studio code/projekty/shopPRO"}
|
||||||
|
{"ts":"2026-05-13T21:10:42Z","tool":"Bash","cmd":"git add updates/0.30/ver_0.353.zip updates/0.30/ver_0.353_manifest.json updates/versions.php updates/changelog-data.html && git commit -m \"build: ver_0.353 - fix aktualizacji systemu i Wyczysc cache ","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*
|
||||||
264
.paul/phases/19-frontend-meta-tags-fix/19-01-PLAN.md
Normal file
264
.paul/phases/19-frontend-meta-tags-fix/19-01-PLAN.md
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
---
|
||||||
|
phase: 19-frontend-meta-tags-fix
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- autoload/front/LayoutEngine.php
|
||||||
|
- tests/Unit/Front/LayoutEngineMetaTagsTest.php
|
||||||
|
autonomous: false
|
||||||
|
delegation: off
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Strona kategorii (np. `/sen-i-otulenie`) i strona produktu (np. `/kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja`) renderują poprawne `<title>`, `<meta name="description">` i `<meta name="keywords">` zgodne z danymi SEO kategorii/produktu z bazy. Obecnie wszystkie podstrony pokazują tytuł strony głównej (`"Sklep z akcesoriami dla dzieci i niemowląt... | shopPRO 1"`) oraz literalne wartości `keywords`/`description` z layoutu/danych homepage.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Niepoprawne metatagi blokują indeksację SEO i wyświetlanie w Google Merchant Center / wynikach wyszukiwania. Klient sklepu (właściciel) traci ruch organiczny — każda podstrona ma identyczny title i puste meta.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- Diagnostyka: ustalona root cause (pp_routes vs sesyjny `$page` vs dane w DB)
|
||||||
|
- Fix w `autoload/front/LayoutEngine.php` (lub w sąsiednim kodzie inicjującym `$page`)
|
||||||
|
- Test jednostkowy dla logiki podmiany metatagów
|
||||||
|
- Suita testów PHPUnit zielona
|
||||||
|
- Weryfikacja human-verify: 3 URL-e (homepage, kategoria, produkt) zwracają różne `<title>` / `<meta description>`
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/ROADMAP.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@autoload/front/LayoutEngine.php
|
||||||
|
@index.php
|
||||||
|
@autoload/Domain/Category/CategoryRepository.php
|
||||||
|
@autoload/Domain/Product/ProductRepository.php
|
||||||
|
@autoload/Domain/Pages/PagesRepository.php
|
||||||
|
|
||||||
|
## Clarifications
|
||||||
|
- **Root cause** — Hipoteza wymaga weryfikacji w bazie (pp_routes + pp_shop_categories_languages + pp_shop_products_languages). Brak dostępu do DB z lokalnego środowiska planowania.
|
||||||
|
→ Odpowiedź: Najpierw diagnostyka, potem fix — nie zakładamy bugu w kodzie ani w danych a priori.
|
||||||
|
- **pp_routes content** — Nie znamy treści destination dla URL-i kategorii/produktu w bazie produkcyjnej.
|
||||||
|
→ Odpowiedź: Sprawdź w bazie (Task 1).
|
||||||
|
- **DB meta values** — Nie wiemy czy meta_keywords/meta_description dla `sen-i-otulenie` w bazie są wypełnione poprawnie, czy zawierają literalne `"keywords"`/`"description"`.
|
||||||
|
→ Odpowiedź: Sprawdź w bazie (Task 1).
|
||||||
|
|
||||||
|
## Background — co już wiemy
|
||||||
|
- `LayoutEngine::show()` (linie 152, 174, 194) podmienia `$page['language']['title']`, `meta_keywords`, `meta_description` tylko jeżeli `$_GET['category']`, `$_GET['article']` lub `$_GET['product']` są ustawione (przez `Helpers::get(...)`).
|
||||||
|
- `$_GET` jest zasilane przez `pp_routes` — `index.php:76-94` matchuje regex, parsuje destination jako query string i merge'uje z `$_GET`.
|
||||||
|
- `$page` jest cache'owane w sesji (`index.php:147` — `Helpers::get_session('page')`) i fallbackuje do `frontPageDetails('')` (homepage) jeśli puste.
|
||||||
|
- Na produkcji: layout HTML zawiera `<title>[TITLE]</title>`, `<meta name="keywords" content="[META_KEYWORDS]">`, `<meta name="description" content="[META_DESCRIPTION]">` — placeholder mechanizm działa, ale podmieniane wartości są nieprawidłowe.
|
||||||
|
- og:title/og:description dla produktu działają poprawnie (są dorzucane bezpośrednio przez DOM w `index.php:242-292`).
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Diagnostyka — ustalona root cause
|
||||||
|
```gherkin
|
||||||
|
Given dostęp do bazy produkcyjnej shoppro.project-dc.pl (FTP/SSH/phpMyAdmin)
|
||||||
|
When wykonamy SQL diagnostyczne dla pp_routes + meta kategorii sen-i-otulenie + meta produktu 522
|
||||||
|
Then znamy konkretną przyczynę: czy pp_routes nie ustawia category=/product=, czy meta w DB są zaślepkami, czy bug jest w session caching $page
|
||||||
|
And wynik diagnostyki jest zapisany w plan-fix sekcji `<context>` przed Task 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Strona kategorii pokazuje własny `<title>` i `<meta description>`
|
||||||
|
```gherkin
|
||||||
|
Given kategoria w bazie ma wypełnione meta_title="Pościel dla dzieci" i meta_description="Kocyki, pościele..."
|
||||||
|
When klient otwiera /sen-i-otulenie
|
||||||
|
Then `<title>` zawiera meta_title kategorii (plus ' | ' + firm_name)
|
||||||
|
And `<meta name="description" content="...">` zawiera meta_description kategorii
|
||||||
|
And NIE pokazuje tytułu strony głównej
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Strona produktu pokazuje własny `<title>` i `<meta description>`
|
||||||
|
```gherkin
|
||||||
|
Given produkt w bazie ma wypełnione meta_title i meta_description
|
||||||
|
When klient otwiera /kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja
|
||||||
|
Then `<title>` zawiera meta_title produktu (plus ' | ' + firm_name)
|
||||||
|
And `<meta name="description" content="...">` zawiera meta_description produktu
|
||||||
|
And NIE pokazuje tytułu strony głównej
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-4: Fallback dla pustego meta_title/meta_description
|
||||||
|
```gherkin
|
||||||
|
Given kategoria/produkt ma puste meta_title w bazie
|
||||||
|
When klient otwiera tę stronę
|
||||||
|
Then `<title>` używa nazwy kategorii/produktu + ' | ' + firm_name
|
||||||
|
And `<meta description>` jest puste (zachowanie obecne — brak fallbacku do opisu, by nie zmieniać semantyki)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-5: Test jednostkowy + cała suita zielona
|
||||||
|
```gherkin
|
||||||
|
Given nowy test tests/Unit/Front/LayoutEngineMetaTagsTest.php
|
||||||
|
When ./test.ps1 zostanie uruchomione
|
||||||
|
Then test pokrywa scenariusz: poprawnie podmieniony [TITLE]/[META_KEYWORDS]/[META_DESCRIPTION] dla kategorii i produktu
|
||||||
|
And cała suita 841+N testów przechodzi na zielono
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Diagnostyka produkcji — pp_routes + meta w DB</name>
|
||||||
|
<files>(brak modyfikacji kodu — tylko zapytania SQL)</files>
|
||||||
|
<action>
|
||||||
|
Uruchom diagnostyczne SQL na bazie shoppro.project-dc.pl (przez FTP→phpMyAdmin lub SSH):
|
||||||
|
|
||||||
|
1. **pp_routes dla URL-i:**
|
||||||
|
```sql
|
||||||
|
SELECT pattern, destination FROM pp_routes
|
||||||
|
WHERE 'sen-i-otulenie' REGEXP CONCAT('^', pattern)
|
||||||
|
OR 'kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja' REGEXP CONCAT('^', pattern);
|
||||||
|
```
|
||||||
|
Sprawdź: czy destination zawiera `category=` / `product=` jako query param.
|
||||||
|
|
||||||
|
2. **Meta kategorii sen-i-otulenie:**
|
||||||
|
```sql
|
||||||
|
SELECT c.id, c.url, cl.title, cl.meta_title, cl.meta_keywords, cl.meta_description
|
||||||
|
FROM pp_shop_categories c
|
||||||
|
JOIN pp_shop_categories_languages cl ON cl.shop_category_id = c.id
|
||||||
|
WHERE c.url = 'sen-i-otulenie';
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Meta produktu kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja:**
|
||||||
|
```sql
|
||||||
|
SELECT p.id, p.url, pl.name, pl.meta_title, pl.meta_keywords, pl.meta_description
|
||||||
|
FROM pp_shop_products p
|
||||||
|
JOIN pp_shop_products_languages pl ON pl.shop_product_id = p.id
|
||||||
|
WHERE p.url = 'kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja';
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Default page meta (czy tytuł "Sklep z akcesoriami..." stamtąd pochodzi):**
|
||||||
|
```sql
|
||||||
|
SELECT pp.id, ppl.title, ppl.meta_title, ppl.meta_keywords, ppl.meta_description
|
||||||
|
FROM pp_pages pp
|
||||||
|
JOIN pp_pages_languages ppl ON ppl.shop_page_id = pp.id
|
||||||
|
WHERE ppl.title LIKE 'Sklep z akcesoriami%' OR ppl.meta_title LIKE 'Sklep z akcesoriami%';
|
||||||
|
```
|
||||||
|
|
||||||
|
Zapisz wyniki w pliku `.paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md` — surowe wyniki SQL + interpretacja (która z hipotez się potwierdza).
|
||||||
|
|
||||||
|
Unikaj: zakładania root cause bez danych. Nie modyfikuj kodu w tym tasku.
|
||||||
|
</action>
|
||||||
|
<verify>Plik .paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md istnieje, zawiera wyniki 4 zapytań SQL i konkluzję wskazującą jedną z hipotez (pp_routes / DB meta / session $page)</verify>
|
||||||
|
<done>AC-1 satisfied: root cause ustalona i udokumentowana</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="checkpoint:decision" gate="blocking">
|
||||||
|
<decision>Który fix wdrażamy w Task 3 na podstawie wyników diagnostyki?</decision>
|
||||||
|
<context>Zależnie od wyniku Task 1 — fix dotyka różnych miejsc kodu. Decyzja blokuje Task 3.</context>
|
||||||
|
<options>
|
||||||
|
<option id="fix-routes">
|
||||||
|
<name>Fix pp_routes (jeśli destination nie zawiera category=/product=)</name>
|
||||||
|
<pros>Naprawia źródło — wszystkie podstrony zaczynają działać; nie dotyka silnika</pros>
|
||||||
|
<cons>Wymaga update SQL w paczce instalacyjnej; ryzyko nadpisania custom routes klienta</cons>
|
||||||
|
</option>
|
||||||
|
<option id="fix-engine-detection">
|
||||||
|
<name>Fix LayoutEngine — niezależna detekcja kategorii/produktu (jeśli pp_routes OK, ale sesyjny $page wycieka)</name>
|
||||||
|
<pros>Defensywny — engine sam wykrywa kontekst i nadpisuje meta, niezależnie od $page session</pros>
|
||||||
|
<cons>Dodaje logikę; może zmienić zachowanie dla custom stron</cons>
|
||||||
|
</option>
|
||||||
|
<option id="fix-db-data">
|
||||||
|
<name>Fix danych w DB (jeśli meta_keywords/meta_description = literalne "keywords"/"description")</name>
|
||||||
|
<pros>Najprostsze — admin uzupełnia poprawne SEO przez panel</pros>
|
||||||
|
<cons>To nie jest bug w shopPRO tylko w danych klienta; nie wchodzi do update package</cons>
|
||||||
|
</option>
|
||||||
|
<option id="fix-session-bleed">
|
||||||
|
<name>Fix session $page bleed — index.php nie używa session $page gdy URL wskazuje na category/product/article</name>
|
||||||
|
<pros>Naprawia konkretną klasę bugów; zmiana ograniczona do index.php</pros>
|
||||||
|
<cons>Wymaga uważnej regresji — $page jest używane też do menu/breadcrumbs</cons>
|
||||||
|
</option>
|
||||||
|
</options>
|
||||||
|
<resume-signal>Wybierz: fix-routes | fix-engine-detection | fix-db-data | fix-session-bleed (lub kombinacja)</resume-signal>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Implementacja fixu + test jednostkowy</name>
|
||||||
|
<files>autoload/front/LayoutEngine.php (lub index.php), tests/Unit/Front/LayoutEngineMetaTagsTest.php</files>
|
||||||
|
<action>
|
||||||
|
Zaimplementuj fix wybrany w Task 2.
|
||||||
|
|
||||||
|
Kluczowe zasady (niezależnie od wybranej opcji):
|
||||||
|
- PHP < 8.0 — bez `match`, bez named args, bez union types, bez str_contains/str_starts_with
|
||||||
|
- Medoo `$db->get()` zwraca null gdy brak rekordu (NIE false)
|
||||||
|
- Cache Redis: po fixie wyczyść `pp_routes:all` i `shop\\product:*` jeśli dotykamy danych (Helpers::clear_product_cache lub CacheHandler::deletePattern)
|
||||||
|
- Nie dotykaj logiki og:title/og:description w index.php — to działa poprawnie
|
||||||
|
- Zachowaj zachowanie dla strony głównej i CMS pages (regresja!)
|
||||||
|
|
||||||
|
Test jednostkowy (`tests/Unit/Front/LayoutEngineMetaTagsTest.php`):
|
||||||
|
- Mock Medoo via createMock(\medoo::class)
|
||||||
|
- Scenariusze:
|
||||||
|
1. category=ID + meta_title wypełniony → `<title>` = meta_title + ' | ' + firm_name
|
||||||
|
2. category=ID + meta_title pusty → `<title>` = category.title + ' | ' + firm_name
|
||||||
|
3. product=ID + meta_description wypełniony → `<meta description>` zawiera tę wartość
|
||||||
|
4. brak category/product/article (homepage) → tytuł strony page'a (regresja)
|
||||||
|
|
||||||
|
Komentarze tylko gdzie wyjaśniają "dlaczego" (np. dlaczego ignorujemy sesyjny $page dla kategorii).
|
||||||
|
</action>
|
||||||
|
<verify>./test.ps1 tests/Unit/Front/LayoutEngineMetaTagsTest.php zwraca OK; ./test.ps1 (cała suita) — 841+N tests zielono</verify>
|
||||||
|
<done>AC-2, AC-3, AC-4, AC-5 satisfied</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="checkpoint:human-verify" gate="blocking">
|
||||||
|
<what-built>Fix metatagów dla kategorii i produktu na froncie</what-built>
|
||||||
|
<how-to-verify>
|
||||||
|
1. Wyczyść cache Redis (`pp_routes:all` + product cache) lub poczekaj na TTL
|
||||||
|
2. Otwórz w przeglądarce 3 URL-e:
|
||||||
|
- https://shoppro.project-dc.pl/ (homepage — baseline)
|
||||||
|
- https://shoppro.project-dc.pl/sen-i-otulenie (kategoria)
|
||||||
|
- https://shoppro.project-dc.pl/kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja (produkt)
|
||||||
|
3. View Source (Ctrl+U) na każdym z nich. Sprawdź:
|
||||||
|
- `<title>` jest RÓŻNY dla 3 stron
|
||||||
|
- `<meta name="description" content="...">` zawiera opis kategorii/produktu (nie "description")
|
||||||
|
- `<meta name="keywords" content="...">` zawiera słowa kluczowe z DB (lub puste, ale NIE "keywords")
|
||||||
|
4. Powtórz na innej kategorii i innym produkcie (regresja)
|
||||||
|
5. Potwierdź że strona główna nadal pokazuje swój oryginalny `<title>` (regresja)
|
||||||
|
</how-to-verify>
|
||||||
|
<resume-signal>Wpisz "approved" by kontynuować, lub opisz issues</resume-signal>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- `index.php:242-292` — logika og:title/og:description/og:image dla produktu (działa poprawnie, nie ruszać)
|
||||||
|
- `pp_routes` regex dla permutacji (`[0-9_-]+`) — Phase 18 fix, nie regresować
|
||||||
|
- `Helpers::clear_product_cache()` — sygnatura stała
|
||||||
|
- Mechanizm `[META_INDEX]` / `[CANONICAL]` / `[CSS]` / `[JAVA_SCRIPT]` — niezwiązane
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Plan dotyczy TYLKO `<title>`, `<meta description>`, `<meta keywords>` dla stron kategorii i produktu
|
||||||
|
- NIE dodajemy og:* dla kategorii (deferred — osobny plan jeśli wyjdzie potrzeba)
|
||||||
|
- NIE rozszerzamy fallbacku meta_description o auto-generowany opis (deferred)
|
||||||
|
- NIE dotykamy CMS pages, articles, producers — chyba że wynik diagnostyki pokaże wspólny mechanizm
|
||||||
|
- Bez build/update package — to robi się w `/koniec-pracy` po UNIFY
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Przed zamknięciem planu:
|
||||||
|
- [ ] DIAGNOSTICS.md istnieje i wskazuje konkretną przyczynę
|
||||||
|
- [ ] Fix zaimplementowany w wybranej lokalizacji (Task 2 decision)
|
||||||
|
- [ ] Nowy test jednostkowy przechodzi
|
||||||
|
- [ ] Cała suita PHPUnit zielona (841+ testów)
|
||||||
|
- [ ] Human-verify na 3 URL-ach z różnymi `<title>` zatwierdzony
|
||||||
|
- [ ] Brak regresji dla strony głównej i CMS pages
|
||||||
|
- [ ] Wszystkie acceptance criteria spełnione
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- Strona kategorii i strona produktu zwracają poprawne metatagi SEO
|
||||||
|
- Diagnostyka udokumentowana (DIAGNOSTICS.md) dla przyszłej referencji
|
||||||
|
- Test regresyjny pokrywa scenariusz
|
||||||
|
- Bez regresji w istniejących funkcjach (suita zielona)
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion: `.paul/phases/19-frontend-meta-tags-fix/19-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
147
.paul/phases/19-frontend-meta-tags-fix/19-01-SUMMARY.md
Normal file
147
.paul/phases/19-frontend-meta-tags-fix/19-01-SUMMARY.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
---
|
||||||
|
phase: 19-frontend-meta-tags-fix
|
||||||
|
plan: 01
|
||||||
|
subsystem: frontend
|
||||||
|
tags: [seo, metatags, layout-engine, frontend, cache]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: none
|
||||||
|
provides: n/a
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- poprawne <title>/<meta description>/<meta keywords> dla stron kategorii/artykułu/produktu
|
||||||
|
- applyEntityMetaToPage() — testowalna metoda helper w \front\LayoutEngine
|
||||||
|
- regression test suite dla bug "homepage meta_title leak"
|
||||||
|
|
||||||
|
affects: [future-seo-fixes, layout-engine-refactor, og-tags-for-category]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Helper static method pattern w LayoutEngine — wyodrębnianie pure-function logic dla testowalności"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- tests/Unit/front/LayoutEngineMetaTagsTest.php
|
||||||
|
- .paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md
|
||||||
|
modified:
|
||||||
|
- autoload/front/LayoutEngine.php
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Root cause to bug w kodzie (LayoutEngine), nie dane w DB ani pp_routes"
|
||||||
|
- "Fix przez wyodrębnienie applyEntityMetaToPage() — zawsze nadpisuje meta_title/keywords/description encji (nawet pustym/null), żeby homepage nie wyciekał"
|
||||||
|
- "Literalne 'description'/'keywords' w pp_shop_categories_langs dla kategorii 10 — to dane klienta, nie bug shopPRO; admin uzupełnia w panelu"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "LayoutEngine bug: nadpisywanie pól w $page['language'] musi być KOMPLETNE — partial override powoduje wyciek wartości z poprzedniego stanu (homepage)"
|
||||||
|
- "Test jednostkowy LayoutEngine: require_once pliku w teście (bootstrap nie ładuje \\front\\)"
|
||||||
|
|
||||||
|
duration: ~45min
|
||||||
|
started: 2026-05-13T14:00:00Z
|
||||||
|
completed: 2026-05-13T14:45:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 19 Plan 01: Frontend meta tags fix — Summary
|
||||||
|
|
||||||
|
**LayoutEngine::applyEntityMetaToPage() rozwiązuje wyciek meta_title homepage do stron kategorii/produktu/artykułu — 3 gałęzie + nowa metoda helper + 5 testów regresyjnych.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~45min |
|
||||||
|
| Tasks | 4 z 4 wykonane |
|
||||||
|
| Files modified | 2 (1 zmiana, 1 nowy test) |
|
||||||
|
| Tests added | 5 (18 asercji) |
|
||||||
|
| Total suite | 846 zielone (z 841) |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Diagnostyka — ustalona root cause | Pass | DIAGNOSTICS.md zawiera 4 zapytania SQL + analizę kodu + jednoznaczny wniosek |
|
||||||
|
| AC-2: Strona kategorii pokazuje własny title | Pass | Curl: `/sen-i-otulenie` → `<title>Sen i otulenie | shopPRO 1</title>` |
|
||||||
|
| AC-3: Strona produktu pokazuje własny title | Pass | Curl: `/kocyk-niemowlaka-...` → `<title>Kocyk niemowlaka - Szczeniak z balonikiem - Fuksja | shopPRO 1</title>` |
|
||||||
|
| AC-4: Fallback dla pustego meta_title | Pass | Dla kategorii meta_title=NULL → title=`category.title`; pokryte testem `testHomepageMetaTitleIsClearedWhenEntityHasNoMetaTitle` |
|
||||||
|
| AC-5: Test + cała suita zielona | Pass | LayoutEngineMetaTagsTest (5/18) + 846/846 ogółem |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Zidentyfikowano root cause przez diagnostyczne SQL na produkcyjnej DB (3 hipotezy zweryfikowane, 1 potwierdzona) — bug w `LayoutEngine` linie 156-213, nie pp_routes, nie session, nie tylko dane
|
||||||
|
- Wyodrębniono `applyEntityMetaToPage()` — testowalna pure-function w `\front\LayoutEngine`, używana w 3 gałęziach (category/article/product)
|
||||||
|
- Fix zweryfikowany curl-em na produkcji (auto-upload FTP po edycji): 3 różne `<title>` na 3 stronach, homepage nie wycieka
|
||||||
|
- Boczny issue zidentyfikowany i zostawiony klientowi: literalne 'description'/'keywords' w `pp_shop_categories_langs.id=331` — admin uzupełnia w panelu
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `autoload/front/LayoutEngine.php` | Modified | 3 gałęzie (category line 152, article 174, product 194) zastąpione wywołaniem `applyEntityMetaToPage()`; nowa metoda po `title()` (linie ~430-455) |
|
||||||
|
| `tests/Unit/front/LayoutEngineMetaTagsTest.php` | Created | 5 testów: meta_title encji wygrywa, NULL czyści homepage, all-null product, null entity safe, empty page struct |
|
||||||
|
| `.paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md` | Created | Wyniki 4 zapytań SQL + analiza kodu + wniosek root cause |
|
||||||
|
| `.gitignore` | Modified | Dodano `temp/` (skrypty diagnostyczne z DB password) |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Fix przez extract helper (`applyEntityMetaToPage`) zamiast inline edycji 3 gałęzi | Testowalność (statyczna pure-function), DRY (jedno miejsce z logiką override meta) | Future SEO fixes działają w jednym miejscu |
|
||||||
|
| Zawsze nadpisuj meta_title (nawet NULL), nie tylko gdy wypełnione | Eliminuje wyciek z homepage; semantyka „encja w pełni opisuje swoje meta" | Linia 332 LayoutEngine działa zgodnie z intencją oryginalnego kodu |
|
||||||
|
| Dane klienta (literalne 'description'/'keywords') NIE są częścią fixu | To dane, nie kod; admin uzupełnia przez panel; klient inaczej skomplikowane | Phase 19 zamyka się czysto, nie wlecze tematu DB |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Type | Count | Impact |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Auto-fixed | 1 | `.gitignore` rozszerzony o `temp/` (DB password w skryptach diag) |
|
||||||
|
| Scope additions | 0 | — |
|
||||||
|
| Deferred | 1 | Git commit transition-phase (pattern z faz 15-18) |
|
||||||
|
|
||||||
|
**Total impact:** Plan wykonany bez odchyleń scope. Jeden security micro-fix (.gitignore).
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Security] DB credentials w temp/diag*.php**
|
||||||
|
- **Found during:** Task 1 (diagnostyka)
|
||||||
|
- **Issue:** Skrypty diagnostyczne `temp/diag_meta*.php` zawierają hardcoded credentials produkcyjnej DB
|
||||||
|
- **Fix:** Dodano `temp/` do `.gitignore` (CLAUDE.md i tak nakazuje skrypty pomocnicze w temp/)
|
||||||
|
- **Files:** `.gitignore`
|
||||||
|
- **Verification:** `git status` nie pokazuje temp/* jako trackowane
|
||||||
|
|
||||||
|
### Deferred Items
|
||||||
|
|
||||||
|
- Transition-phase git commit dla Phase 19 — kontynuacja patternu z faz 15/16/17/18 (commit robi `/koniec-pracy` lub user manualnie). Brak negatywnego impactu — kod działa na produkcji już teraz (auto-upload FTP).
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
| Issue | Resolution |
|
||||||
|
|-------|------------|
|
||||||
|
| Pierwsza wersja diag SQL używała `pp_shop_categories_languages` (nie istnieje) | Sprawdzono `SHOW TABLES` — tabele to `*_langs` (skrót). Zaktualizowano zapytania |
|
||||||
|
| Pierwsza wersja używała `shop_category_id` (nie istnieje) | Kolumna to `category_id`. Sprawdzono `SHOW COLUMNS` |
|
||||||
|
| LayoutEngine niedostępny w bootstrap testów | `require_once` w teście (bootstrap PSR-4 nie ładuje `\front\` namespace) |
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Codebase z `applyEntityMetaToPage()` — gotowa do reuse w przyszłych fixach SEO (np. og:title dla kategorii)
|
||||||
|
- Test pattern dla `\front\LayoutEngine` ustalony (require_once + asercje na pure-function)
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- LayoutEngine::show() nadal jest 400+ linijowym monolitem ze statycznymi globalami — dalsze ekstrakcje wskazane, ale poza scope tej fazy
|
||||||
|
- Klienci z istniejącymi instalacjami muszą uzupełnić meta_title/keywords/description przez panel admina (lub zaakceptować że podstrony mają brak meta — co teraz przynajmniej NIE jest niepoprawnym tytułem homepage)
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None.
|
||||||
|
|
||||||
|
## Skill Audit (Phase 19)
|
||||||
|
|
||||||
|
| Expected | Invoked | Notes |
|
||||||
|
|----------|---------|-------|
|
||||||
|
| /feature-dev | ○ | Hotfix z konkretną instrukcją — override per pattern Phase 15-18 |
|
||||||
|
| /koniec-pracy | ○ | Pending — przy zamknięciu sesji jeśli release wchodzi do update package |
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 19-frontend-meta-tags-fix, Plan: 01*
|
||||||
|
*Completed: 2026-05-13*
|
||||||
129
.paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md
Normal file
129
.paul/phases/19-frontend-meta-tags-fix/DIAGNOSTICS.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Phase 19 — DIAGNOSTICS
|
||||||
|
|
||||||
|
**Data:** 2026-05-13
|
||||||
|
**Środowisko:** shoppro.project-dc.pl (produkcja) — DB `host117523_shoppro` na `host117523.hostido.net.pl`
|
||||||
|
|
||||||
|
## Wynik diagnostyczny: ROOT CAUSE w kodzie (LayoutEngine.php)
|
||||||
|
|
||||||
|
`$page['language']['meta_title']` z domyślnej strony (homepage id=6) **nigdy nie jest nadpisywany** w gałęziach kategorii/artykułu/produktu w `LayoutEngine::show()`. Linia 332 priorytetuje `meta_title` nad `title`, więc tytuł homepage wycieka na wszystkie podstrony.
|
||||||
|
|
||||||
|
Dodatkowo: meta_description/meta_keywords dla podstron też nie zachowują się dobrze, bo w DB klient ma literalne zaślepki ("description", "keywords") albo NULL — ale to drugorzędny problem względem bugu w kodzie.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1) pp_routes — działa poprawnie
|
||||||
|
|
||||||
|
```
|
||||||
|
URL: sen-i-otulenie
|
||||||
|
MATCH pattern='^sen-i-otulenie$' dest='index.php?category=10&lang=pl'
|
||||||
|
|
||||||
|
URL: kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja
|
||||||
|
MATCH pattern='^kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja$' dest='index.php?product=522'
|
||||||
|
```
|
||||||
|
|
||||||
|
Hipoteza "pp_routes nie ustawia category=/product=" — **OBALONA**.
|
||||||
|
|
||||||
|
## 2) Meta kategorii 10 (sen-i-otulenie), lang=pl
|
||||||
|
|
||||||
|
```
|
||||||
|
id = 331
|
||||||
|
category_id = 10
|
||||||
|
lang_id = 'pl'
|
||||||
|
title = 'Sen i otulenie'
|
||||||
|
meta_title = NULL
|
||||||
|
meta_description = 'description' ← LITERALNA ZAŚLEPKA w DB
|
||||||
|
meta_keywords = 'keywords' ← LITERALNA ZAŚLEPKA w DB
|
||||||
|
seo_link = 'sen-i-otulenie'
|
||||||
|
category_title = 'Sen i otulenie'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3) Meta produktu 522 (kocyk-niemowlaka...), lang=pl
|
||||||
|
|
||||||
|
```
|
||||||
|
id = 4040
|
||||||
|
product_id = 522
|
||||||
|
lang_id = 'pl'
|
||||||
|
name = 'Kocyk niemowlaka - Szczeniak z balonikiem - Fuksja'
|
||||||
|
meta_title = NULL
|
||||||
|
meta_description = NULL
|
||||||
|
meta_keywords = NULL
|
||||||
|
seo_link = 'kocyk-niemowlaka-szczeniak-z-balonikiem-fuksja'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4) Default page (homepage) — id=6, start=1, lang=pl
|
||||||
|
|
||||||
|
```
|
||||||
|
id = 6
|
||||||
|
start = 1
|
||||||
|
title = 'Home'
|
||||||
|
meta_title = 'Sklep z akcesoriami dla dzieci i niemowląt, kocyki minky, poduszki, ubranka'
|
||||||
|
meta_keywords = '' (puste)
|
||||||
|
meta_description = 'Marianek to sklep internetowy, w którym znajdziecie Państwo artykuły dla dzieci i niemowląt...'
|
||||||
|
```
|
||||||
|
|
||||||
|
To jest źródło "wyciekającego" tytułu na podstronach.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Analiza kodu (autoload/front/LayoutEngine.php)
|
||||||
|
|
||||||
|
### Gałąź kategorii (linie 152-168)
|
||||||
|
```php
|
||||||
|
if ( \Shared\Helpers\Helpers::get( 'category' ) ) {
|
||||||
|
$category = $categoryRepo->frontCategoryDetails(...);
|
||||||
|
|
||||||
|
if ( $category['language']['meta_title'] )
|
||||||
|
$page['language']['title'] = $category['language']['meta_title']; // ← przypisuje do TITLE, nie meta_title
|
||||||
|
else
|
||||||
|
$page['language']['title'] = $category['language']['title'];
|
||||||
|
|
||||||
|
$page['show_title'] = true;
|
||||||
|
$page['language']['meta_keywords'] = $category['language']['meta_keywords']; // OK
|
||||||
|
$page['language']['meta_description'] = $category['language']['meta_description']; // OK
|
||||||
|
// BRAK: $page['language']['meta_title'] = $category['language']['meta_title'];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gałąź produktu (linie 194-213) — identyczny bug
|
||||||
|
|
||||||
|
### Gałąź artykułu (linie 174-189) — identyczny bug
|
||||||
|
|
||||||
|
### Substytucja [TITLE] (linia 332)
|
||||||
|
```php
|
||||||
|
$html = str_replace( '[TITLE]',
|
||||||
|
$page['language']['meta_title']
|
||||||
|
? $page['language']['meta_title'] . ' | ' . $settings['firm_name']
|
||||||
|
: $page['language']['title'] . ' | ' . $settings['firm_name'],
|
||||||
|
$html );
|
||||||
|
```
|
||||||
|
|
||||||
|
`meta_title` z homepage żyje dalej w `$page['language']` (bo nie został zresetowany w gałęzi kategorii/produktu) → wygrywa nad title kategorii/produktu.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wpływ na obserwowane zachowanie
|
||||||
|
|
||||||
|
| URL | Obserwowane `<title>` | Powód |
|
||||||
|
|-----|----------------------|-------|
|
||||||
|
| /sen-i-otulenie | "Sklep z akcesoriami... \| shopPRO 1" | meta_title homepage wycieka |
|
||||||
|
| /kocyk-niemowlaka-... | "Sklep z akcesoriami... \| shopPRO 1" | meta_title homepage wycieka |
|
||||||
|
|
||||||
|
| URL | Obserwowane `<meta description>` | Powód |
|
||||||
|
|-----|---------------------------------|-------|
|
||||||
|
| /sen-i-otulenie | "description" | meta_description kategorii (literalna zaślepka) — POPRAWNE nadpisanie, ale dane w DB są wadliwe |
|
||||||
|
| /kocyk-niemowlaka-... | "" (puste) | meta_description produktu = NULL — POPRAWNE nadpisanie |
|
||||||
|
|
||||||
|
| URL | Obserwowane `<meta keywords>` | Powód |
|
||||||
|
|-----|------------------------------|-------|
|
||||||
|
| /sen-i-otulenie | "keywords" | meta_keywords kategorii (literalna zaślepka) — POPRAWNE nadpisanie, ale dane w DB są wadliwe |
|
||||||
|
| /kocyk-niemowlaka-... | "" (puste) | meta_keywords produktu = NULL — POPRAWNE nadpisanie |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wniosek
|
||||||
|
|
||||||
|
**Bug w kodzie**: `LayoutEngine::show()` w 3 gałęziach (category/article/product) zapisuje meta_title kategorii do `title`, ale nie nadpisuje `$page['language']['meta_title']`. Wartość z homepage zostaje i wygrywa.
|
||||||
|
|
||||||
|
**Dane klienta**: oddzielny issue — meta_keywords/meta_description dla kategorii to literalne zaślepki "keywords"/"description", produkt ma NULL. To NIE jest bug shopPRO — admin musi wypełnić panel.
|
||||||
|
|
||||||
|
**Rekomendacja fixu**: opcja `fix-engine-detection` z planu — naprawić gałęzie kategorii/artykułu/produktu, by zawsze nadpisywały `meta_title` (nawet pustym/NULL), oraz uprościć logikę title żeby była symetryczna.
|
||||||
197
.paul/phases/20-category-edit-mojibake-fix/20-01-PLAN.md
Normal file
197
.paul/phases/20-category-edit-mojibake-fix/20-01-PLAN.md
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
---
|
||||||
|
phase: 20-category-edit-mojibake-fix
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- admin/templates/shop-category/category-edit.php
|
||||||
|
autonomous: false
|
||||||
|
delegation: off
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Etykiety formularza edycji kategorii (`/admin/shop_category/category_edit/id=X`) pokazują poprawne polskie znaki: "Treść", "Język domyślny", "Tytuł kategorii (h1)", "Wyświetlić podkategorie", "Sortowanie produktów", "Blokuj indeksację", "Opis kategorii (rozwinięcie)" — zamiast mojibake `Treść`, `JÄ™zyk domyĹ›lny`, itp.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Mojibake w etykietach UI panelu admina utrudnia korzystanie z formularza. Administrator musi się domyślać znaczenia pól. Naprawia profesjonalny wygląd panelu i poprawia UX uzupełniania kategorii (m.in. SEO).
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- `admin/templates/shop-category/category-edit.php` z poprawnymi polskimi znakami (UTF-8) we wszystkich hardcoded stringach
|
||||||
|
- Weryfikacja wizualna w panelu admina
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
Plik został kiedyś zapisany z UTF-8 zinterpretowanym jako Windows-1252 i ponownie zakodowanym do UTF-8 (classic double-encoding mojibake). `file` raportuje "UTF-8 text" bo bajty są poprawnym UTF-8 — tyle że ich znaczenie po dekodowaniu UTF-8 to bezsensowne kombinacje znaków łacińskich (Ä, Ĺ, Ă itp.).
|
||||||
|
|
||||||
|
Grep `Ä[\x{84}-\x{99}]|Ĺ|Ăł` wskazał, że **tylko ten jeden plik** w całym repo (`admin/templates/`, `templates/`, `autoload/`) jest dotknięty — pozostałe templates mają poprawne UTF-8.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@admin/templates/shop-category/category-edit.php
|
||||||
|
|
||||||
|
## Clarifications
|
||||||
|
- **Objaw** — Mojibake (`Ä€„` zamiast `ą`) w labelkach formularza edycji kategorii
|
||||||
|
→ Odpowiedź: potwierdzone — mojibake (double-encoded UTF-8)
|
||||||
|
- **Pola** — Nie wiem, sprawdź
|
||||||
|
→ Odpowiedź (po inspekcji): WSZYSTKIE hardcoded labelki w pliku `category-edit.php` (9 wystąpień), żadne inne pliki templates nie dotknięte
|
||||||
|
- **Migracja danych** — chodzi o labelki, nie zapisywane dane
|
||||||
|
→ Odpowiedź: plan dotyczy tylko hardcoded stringów w pliku PHP. Dane w bazie (mieszane HTML entities w additional_text) — oddzielny issue, NIE w tym planie
|
||||||
|
|
||||||
|
## Wykryte miejsca mojibake (grep)
|
||||||
|
|
||||||
|
```
|
||||||
|
Line 10: Treść → Treść
|
||||||
|
Line 20: JÄ™zyk domyĹ›lny → Język domyślny
|
||||||
|
Line 48: Opis kategorii (rozwiniÄ™cie) → Opis kategorii (rozwinięcie)
|
||||||
|
Line 87: Sortowanie produktĂłw → Sortowanie produktów
|
||||||
|
Line 96: WyĹ›wietlić podkategorie → Wyświetlić podkategorie
|
||||||
|
Line 107: JÄ™zyk domyĹ›lny → Język domyślny (duplikat)
|
||||||
|
Line 127: TytuĹ‚ kategorii (h1) → Tytuł kategorii (h1)
|
||||||
|
Line 159: Blokuj indeksacjÄ™ → Blokuj indeksację
|
||||||
|
```
|
||||||
|
|
||||||
|
Mapowanie sekwencji (do podmiany):
|
||||||
|
- `ć` → `ć`, `Ä…` → `ą`, `Ä™` → `ę`, `Ĺ‚` → `ł`, `Ĺ›` → `ś`, `Ĺ„` → `ń`, `Ĺş` → `ź`, `Ĺľ` → `ż`
|
||||||
|
- `Ć` → `Ć`, `Ä„` → `Ą`, `Ę` → `Ę`, `Ĺ` → `Ł`, `Ĺš` → `Ś`, `Ĺƒ` → `Ń`, `Ĺ¹` → `Ź`, `Ĺ˝` → `Ż`
|
||||||
|
- `Ăł` → `ó`, `Ă“` → `Ó`
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Brak mojibake w pliku
|
||||||
|
```gherkin
|
||||||
|
Given plik admin/templates/shop-category/category-edit.php po fixie
|
||||||
|
When uruchomię grep regex `Ä[\x{84}-\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć`
|
||||||
|
Then nie ma żadnego dopasowania (0 linii)
|
||||||
|
And plik dalej jest UTF-8 (bez BOM) — sprawdzalne przez `file`
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Labelki formularza renderują się z polskimi znakami
|
||||||
|
```gherkin
|
||||||
|
Given administrator otwiera /admin/shop_category/category_edit/id=10 po deployu
|
||||||
|
When sprawdza nazwy tabów i etykiet pól
|
||||||
|
Then widzi "Treść", "Ustawienia", "SEO" jako nazwy tabów
|
||||||
|
And widzi "Język domyślny", "Tytuł kategorii (h1)", "Sortowanie produktów",
|
||||||
|
"Wyświetlić podkategorie", "Blokuj indeksację", "Opis kategorii (rozwinięcie)"
|
||||||
|
jako etykiety pól
|
||||||
|
And NIE widzi `Ä`, `Ĺ`, `Ă` w żadnym widocznym miejscu na tej stronie
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Brak regresji w innych szablonach
|
||||||
|
```gherkin
|
||||||
|
Given fix dotyczy tylko jednego pliku
|
||||||
|
When uruchomię grep mojibake w admin/templates/ + templates/ + autoload/
|
||||||
|
Then żaden inny plik nie zawiera mojibake (tak jak przed fixem)
|
||||||
|
And cała suita PHPUnit (846 testów) pozostaje zielona
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Podmień double-encoded UTF-8 na właściwe polskie znaki</name>
|
||||||
|
<files>admin/templates/shop-category/category-edit.php</files>
|
||||||
|
<action>
|
||||||
|
Wykonaj globalne podstawienia w pliku z mojibake → UTF-8 polskie znaki:
|
||||||
|
|
||||||
|
Podstawienia całych słów (najbezpieczniejsze — unikamy fałszywych alarmów z `Ä` w innym kontekście):
|
||||||
|
"Treść" → "Treść"
|
||||||
|
"JÄ™zyk domyĹ›lny" → "Język domyślny"
|
||||||
|
"rozwiniÄ™cie" → "rozwinięcie"
|
||||||
|
"Sortowanie produktĂłw" → "Sortowanie produktów"
|
||||||
|
"WyĹ›wietlić podkategorie" → "Wyświetlić podkategorie"
|
||||||
|
"TytuĹ‚ kategorii (h1)" → "Tytuł kategorii (h1)"
|
||||||
|
"Blokuj indeksacjÄ™" → "Blokuj indeksację"
|
||||||
|
|
||||||
|
Po wszystkich podstawieniach zweryfikuj greppem że żadne mojibake już nie zostało.
|
||||||
|
|
||||||
|
Avoid: globalne sekwencyjne `str_replace` typu `ć` → `ć` bez kontekstu — mogłoby przypadkiem złamać poprawne fragmenty w przyszłości (na razie nie ma ryzyka, ale lepiej trzymać się konkretnych słów).
|
||||||
|
Avoid: zmiana encodingu pliku (musi zostać UTF-8 bez BOM, CRLF — jak teraz).
|
||||||
|
Avoid: jakichkolwiek zmian poza podmianami stringów (struktura HTML, logika, imports — bez zmian).
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
grep -P "Ä[\x{84}-\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć|Ĺ„" admin/templates/shop-category/category-edit.php
|
||||||
|
→ 0 dopasowań
|
||||||
|
file admin/templates/shop-category/category-edit.php → UTF-8 text (bez BOM)
|
||||||
|
</verify>
|
||||||
|
<done>AC-1 satisfied: plik bez mojibake, dalej UTF-8</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Weryfikacja braku regresji + odpalenie suity testów</name>
|
||||||
|
<files>(brak modyfikacji — weryfikacja)</files>
|
||||||
|
<action>
|
||||||
|
1. Powtórz globalny grep mojibake w admin/templates/, templates/, autoload/ — powinno być 0 plików (poza tym fixowanym, który po Task 1 też ma 0)
|
||||||
|
2. Uruchom suitę PHPUnit: `php phpunit.phar`
|
||||||
|
3. Sprawdź że nie ma żadnych nowych failów (oczekiwane: 846 OK)
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
grep -rl -P "Ä[\x{84}-\x{99}]|Ĺ" admin/templates/ templates/ autoload/ — brak wyniku
|
||||||
|
php phpunit.phar — exit code 0, 846 tests OK
|
||||||
|
</verify>
|
||||||
|
<done>AC-3 satisfied: brak regresji, suita zielona</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="checkpoint:human-verify" gate="blocking">
|
||||||
|
<what-built>
|
||||||
|
Plik admin/templates/shop-category/category-edit.php z polskimi znakami w UTF-8
|
||||||
|
(auto-upload FTP wysyła zmianę na shoppro.project-dc.pl po zapisie pliku)
|
||||||
|
</what-built>
|
||||||
|
<how-to-verify>
|
||||||
|
1. Otwórz https://shoppro.project-dc.pl/admin/shop_category/category_edit/id=10 (zaloguj się jeśli trzeba)
|
||||||
|
2. Sprawdź nazwy 3 tabów: "Treść", "Ustawienia", "SEO" — powinny być po polsku, bez mojibake
|
||||||
|
3. W tabie "Treść" sprawdź:
|
||||||
|
- tooltip ikony gwiazdki: "Język domyślny"
|
||||||
|
- etykiety pól: "Nazwa kategorii", "Opis kategorii", "Opis kategorii (rozwinięcie)", "Dodatkowy tekst (nad produktami)"
|
||||||
|
4. W tabie "Ustawienia" sprawdź: "Aktywna", "Sortowanie produktów", "Wyświetlić podkategorie"
|
||||||
|
5. W tabie "SEO" sprawdź: "Tytuł kategorii (h1)", "Blokuj indeksację"
|
||||||
|
6. Otwórz inną kategorię (np. id=11) — to samo dla regresji
|
||||||
|
</how-to-verify>
|
||||||
|
<resume-signal>Wpisz "approved" by kontynuować, lub opisz issues</resume-signal>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- Struktura HTML pliku (tagi, klasy CSS, JS scripts)
|
||||||
|
- Logika PHP (if/foreach, wywołania Tpl)
|
||||||
|
- Inne pliki w admin/templates/shop-category/ — nie są dotknięte mojibake
|
||||||
|
- Encoding pliku (musi zostać UTF-8 bez BOM, jak obecnie)
|
||||||
|
- Dane w bazie (HTML entities w `additional_text` to oddzielny issue)
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Plan dotyczy TYLKO pliku `admin/templates/shop-category/category-edit.php`
|
||||||
|
- NIE skanujemy wszystkich szablonów admina pod kątem mojibake (już sprawdzone — pozostałe OK)
|
||||||
|
- NIE migrujemy danych w DB (admin uzupełnia ręcznie jeśli ma encje)
|
||||||
|
- Bez build update package — to robi `/koniec-pracy` po UNIFY
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Przed zamknięciem planu:
|
||||||
|
- [ ] grep mojibake → 0 wyników w category-edit.php
|
||||||
|
- [ ] file potwierdza UTF-8 bez BOM
|
||||||
|
- [ ] Suita PHPUnit 846 zielona
|
||||||
|
- [ ] Human-verify na 2 kategoriach (id=10 i jeszcze jednej) zatwierdzony
|
||||||
|
- [ ] AC-1, AC-2, AC-3 spełnione
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- 9 wystąpień mojibake naprawionych w 1 pliku
|
||||||
|
- Brak regresji w innych szablonach
|
||||||
|
- Suita testów zielona
|
||||||
|
- Wizualna weryfikacja w panelu admina OK
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion: `.paul/phases/20-category-edit-mojibake-fix/20-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
121
.paul/phases/20-category-edit-mojibake-fix/20-01-SUMMARY.md
Normal file
121
.paul/phases/20-category-edit-mojibake-fix/20-01-SUMMARY.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
---
|
||||||
|
phase: 20-category-edit-mojibake-fix
|
||||||
|
plan: 01
|
||||||
|
subsystem: admin-ui
|
||||||
|
tags: [encoding, utf8, mojibake, admin-templates, polish-chars]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: none
|
||||||
|
provides: n/a
|
||||||
|
|
||||||
|
provides:
|
||||||
|
- poprawne polskie znaki w labelkach formularza edycji kategorii
|
||||||
|
- pewność że pozostałe pliki admin/templates/, templates/, autoload/ są wolne od double-encoded UTF-8 mojibake
|
||||||
|
|
||||||
|
affects: []
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Detekcja double-encoded UTF-8: grep `Ä[\\x{84}-\\x{99}]|Ĺ|Ăł|Ĺ›|Ĺ‚|Ä™|Ä…|ć|Ĺ„` znajduje pliki z mojibake"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
modified:
|
||||||
|
- admin/templates/shop-category/category-edit.php
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Fix tylko 1 plik (9 wystąpień) — żaden inny szablon w repo nie ma mojibake"
|
||||||
|
- "Podmiana całych słów zamiast generyczna `ć`→`ć` — unika fałszywych alarmów na przyszłość"
|
||||||
|
- "Brak migracji danych w DB (te są oddzielnym tematem — HTML entities w additional_text)"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Workflow detekcji mojibake: jeden grep regex pokrywa najczęstsze sekwencje Win-1252→UTF-8 double-encoding"
|
||||||
|
|
||||||
|
duration: ~10min
|
||||||
|
started: 2026-05-13T16:30:00Z
|
||||||
|
completed: 2026-05-13T16:40:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 20 Plan 01: Category edit mojibake fix — Summary
|
||||||
|
|
||||||
|
**9 wystąpień double-encoded UTF-8 w `admin/templates/shop-category/category-edit.php` naprawione na poprawne polskie znaki; pozostałe szablony zweryfikowane jako wolne od mojibake.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~10min |
|
||||||
|
| Tasks | 3 z 3 wykonane |
|
||||||
|
| Files modified | 1 |
|
||||||
|
| Mojibake fixed | 9 wystąpień (7 unikalnych fraz) |
|
||||||
|
| Total suite | 846 zielone (bez zmian) |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Brak mojibake w pliku | Pass | grep mojibake → 0 wyników; file → UTF-8 bez BOM |
|
||||||
|
| AC-2: Labelki renderują się z polskimi znakami | Pass | Human-verify approved przez użytkownika |
|
||||||
|
| AC-3: Brak regresji w innych szablonach | Pass | grep w admin/templates/+templates/+autoload/ → 0 plików; suita 846 OK |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Wykryto i naprawiono mojibake w jedynym dotkniętym pliku repo
|
||||||
|
- Etykiety formularza edycji kategorii w panelu admina są czytelne po polsku ("Treść", "Język domyślny", "Sortowanie produktów", "Tytuł kategorii (h1)", "Blokuj indeksację", "Wyświetlić podkategorie", "Opis kategorii (rozwinięcie)")
|
||||||
|
- Auto-upload FTP wysłał plik na produkcję; weryfikacja w przeglądarce potwierdzona
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `admin/templates/shop-category/category-edit.php` | Modified | Podmiana 9 wystąpień double-encoded UTF-8 na poprawne polskie znaki (7 unikalnych fraz: Treść, JÄ™zyk domyĹ›lny x2, rozwiniÄ™cie, Sortowanie produktĂłw, WyĹ›wietlić podkategorie, TytuĹ‚ kategorii, Blokuj indeksacjÄ™) |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Podmiana całych słów zamiast `ć`→`ć` itd. | Bezpieczniej — nie zostawia ryzyka uszkodzenia poprawnych fragmentów przy hipotetycznym przyszłym pojawieniu się tych bajtów w innym kontekście | Edits są precyzyjne, łatwe do code-review |
|
||||||
|
| Fix tylko ten jeden plik | grep pokazał że to jedyny plik z mojibake w całym repo | Scope minimalny, brak ryzyka regresji |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Type | Count | Impact |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Auto-fixed | 0 | — |
|
||||||
|
| Scope additions | 0 | — |
|
||||||
|
| Deferred | 1 | Git commit transition-phase (pattern z faz 15-19) |
|
||||||
|
|
||||||
|
**Total impact:** Plan wykonany dokładnie według planu.
|
||||||
|
|
||||||
|
### Deferred Items
|
||||||
|
|
||||||
|
- Transition-phase git commit dla Phase 20 — pattern z faz 15-19 (commit zrobi `/koniec-pracy` lub user manualnie). Brak negatywnego impactu — auto-upload FTP już ma plik na produkcji.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Pattern detekcji mojibake (regex) udokumentowany — przydatny przy przyszłych audytach encoding
|
||||||
|
- Plik category-edit.php czysty UTF-8
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- Inne pola w bazie (`additional_text` kategorii) mają mieszane HTML entities z polskimi znakami — oddzielny issue, nie blokuje
|
||||||
|
- Brak automatycznego sprawdzania encoding w CI — przyszły fix mógłby wprowadzić nowy mojibake bez wykrycia
|
||||||
|
|
||||||
|
**Blockers:** None.
|
||||||
|
|
||||||
|
## Skill Audit (Phase 20)
|
||||||
|
|
||||||
|
| Expected | Invoked | Notes |
|
||||||
|
|----------|---------|-------|
|
||||||
|
| /feature-dev | ○ | Triviany fix labelek — override per pattern poprzednich faz |
|
||||||
|
| /koniec-pracy | ○ | Pending — uruchomić przy release update package |
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 20-category-edit-mojibake-fix, Plan: 01*
|
||||||
|
*Completed: 2026-05-13*
|
||||||
173
.paul/phases/21-admin-update-view-js-fix/21-01-PLAN.md
Normal file
173
.paul/phases/21-admin-update-view-js-fix/21-01-PLAN.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
---
|
||||||
|
phase: 21-admin-update-view-js-fix
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- admin/templates/update/main-view.php
|
||||||
|
autonomous: false
|
||||||
|
delegation: off
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
## Goal
|
||||||
|
Naprawić niedziałające przyciski na `/admin/update/main_view/`: "Aktualizuj do wyższej wersji" (`#confirm`), "Aktualizuj do najwyższej wersji" (`#confirmUpdateAll`) oraz globalny "Wyczyść cache" (`#clear-cache-btn`) z headera admina.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Na instancjach klientów shopPRO aktualizacja wersji nie była możliwa — zdalny changelog z `shoppro.project-dc.pl/updates/changelog.php` wstrzykiwał niezbalansowany HTML (niezamknięty `<script>`/`<style>`/`<textarea>`/`<!--`), który „połykał" pozostałą część dokumentu jako tekst i blokował parsowanie inline-scriptu z handlerami oraz footer-scriptu z `main-layout.php`. Bez tej naprawy klienci nie mogą aktualizować systemu.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
Zmodyfikowany plik `admin/templates/update/main-view.php`:
|
||||||
|
1. Blok `<script>` z handlerami przeniesiony PRZED sekcję Changelog.
|
||||||
|
2. Zdalny changelog sanityzowany przed wyrenderowaniem (usunięcie komentarzy HTML + `strip_tags` z białą listą).
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
## Project Context
|
||||||
|
@.paul/PROJECT.md
|
||||||
|
@.paul/ROADMAP.md
|
||||||
|
@.paul/STATE.md
|
||||||
|
|
||||||
|
## Source Files
|
||||||
|
@admin/templates/update/main-view.php
|
||||||
|
@change.md
|
||||||
|
|
||||||
|
<clarifications>
|
||||||
|
- **Scope** — Wystarczy fix zgodny z change.md (jeden plik, dwa kroki)?
|
||||||
|
→ Odpowiedź: brak pytań — change.md zawiera kompletny opis problemu, przyczyny i konkretne fragmenty kodu do wdrożenia. Plan = mechaniczne wdrożenie change.md.
|
||||||
|
</clarifications>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<acceptance_criteria>
|
||||||
|
|
||||||
|
## AC-1: Handlery JS działają niezależnie od treści zdalnego changeloga
|
||||||
|
```gherkin
|
||||||
|
Given administrator jest na /admin/update/main_view/ z wersją starszą niż najnowsza
|
||||||
|
And zdalny serwer shoppro.project-dc.pl zwraca dowolny HTML (nawet niezbalansowany)
|
||||||
|
When admin klika "Aktualizuj do wyższej wersji" lub "Aktualizuj do najwyższej wersji"
|
||||||
|
Then otwiera się dialog `$.confirm` (potwierdzenie aktualizacji)
|
||||||
|
And po potwierdzeniu uruchamia się aktualizacja (redirect /admin/update/update/ lub AJAX /admin/update/updateAll/)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-2: Globalny przycisk "Wyczyść cache" działa na podstronie update
|
||||||
|
```gherkin
|
||||||
|
Given administrator jest na /admin/update/main_view/
|
||||||
|
When klika "Wyczyść cache" w headerze admina (`#clear-cache-btn`)
|
||||||
|
Then footer-script z main-layout.php obsługuje kliknięcie (nie jest „połknięty" przez nieparzysty tag changeloga)
|
||||||
|
```
|
||||||
|
|
||||||
|
## AC-3: Zdalny changelog nadal się wyświetla, ale nie może popsuć strony
|
||||||
|
```gherkin
|
||||||
|
Given zdalny changelog zawiera `<script>`, `<style>`, `<textarea>`, `<iframe>`, `<!--...-->` lub niezamknięte tagi strukturalne
|
||||||
|
When szablon main-view.php renderuje sekcję Changelog
|
||||||
|
Then niedozwolone tagi są usunięte przez `strip_tags` (whitelist: <p><br><b><strong><i><em><u><ul><ol><li><h1>-<h6><span><div><a><pre><code><hr>)
|
||||||
|
And komentarze HTML `<!--...-->` są usuwane
|
||||||
|
And treść tekstowa changeloga + dozwolone tagi formatujące są widoczne na stronie
|
||||||
|
```
|
||||||
|
|
||||||
|
</acceptance_criteria>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Reorder + sanitize w main-view.php</name>
|
||||||
|
<files>admin/templates/update/main-view.php</files>
|
||||||
|
<action>
|
||||||
|
Wdrożyć zmianę zgodnie z change.md:
|
||||||
|
|
||||||
|
1. **Przenieść blok `<script type="text/javascript">...</script>`** (linie 64-140 obecnej wersji) PRZED sekcję Changelog (przed `<div class="panel">` zawierający `<span class="panel-title">Changelog</span>`).
|
||||||
|
|
||||||
|
Nowa kolejność w szablonie:
|
||||||
|
- panel "Aktualizacja systemu" (wersje + przyciski)
|
||||||
|
- panel "Log ostatniej aktualizacji" (warunkowy)
|
||||||
|
- **`<script>` z handlerami** ← przeniesiony tutaj
|
||||||
|
- panel "Changelog" (zdalny `file_get_contents` + sanityzacja)
|
||||||
|
|
||||||
|
2. **Zastąpić linię z `file_get_contents`** (obecnie linia 60):
|
||||||
|
```php
|
||||||
|
<?= @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver ); ?>
|
||||||
|
```
|
||||||
|
na blok sanityzacji:
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
$changelog = (string) @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver );
|
||||||
|
$changelog = preg_replace( '/<!--.*?-->/s', '', $changelog );
|
||||||
|
$changelog = strip_tags( $changelog, '<p><br><b><strong><i><em><u><ul><ol><li><h1><h2><h3><h4><h5><h6><span><div><a><pre><code><hr>' );
|
||||||
|
echo $changelog;
|
||||||
|
?>
|
||||||
|
```
|
||||||
|
|
||||||
|
Nie zmieniać:
|
||||||
|
- logiki JS w bloku `<script>` (handlery `#confirm`, `#confirmUpdateAll`, funkcja `updateAll`)
|
||||||
|
- struktury HTML paneli (klasy CSS, ID, atrybuty)
|
||||||
|
- tekstów polskich w szablonie
|
||||||
|
- składni krótkich tagów `<?` (kompatybilność PHP < 8.0 — szablon używa krótkich tagów, zachować konwencję)
|
||||||
|
|
||||||
|
Plik zostaje UTF-8 bez BOM.
|
||||||
|
|
||||||
|
Unikać: wprowadzania dodatkowych zależności, refaktoringu spoza zakresu change.md, zmiany URL zdalnego changeloga.
|
||||||
|
</action>
|
||||||
|
<verify>
|
||||||
|
1. `php -l admin/templates/update/main-view.php` → "No syntax errors"
|
||||||
|
2. Grep: `grep -n "strip_tags" admin/templates/update/main-view.php` → linia z whitelistą obecna
|
||||||
|
3. Grep: blok `<script type="text/javascript">` znajduje się przed `<span class="panel-title">Changelog</span>` w pliku (sprawdzić numery linii)
|
||||||
|
</verify>
|
||||||
|
<done>AC-3 satisfied (sanityzacja whitelist + usunięcie komentarzy HTML); strukturalna baza dla AC-1 i AC-2 (reorder przed changelogiem)</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="checkpoint:human-verify" gate="blocking">
|
||||||
|
<what-built>
|
||||||
|
Reorder bloku `<script>` przed sekcję Changelog + sanityzacja zdalnego changeloga w `admin/templates/update/main-view.php`.
|
||||||
|
</what-built>
|
||||||
|
<how-to-verify>
|
||||||
|
1. Wgrać zmodyfikowany plik na instancję testową (lub lokalnie, jeśli setup pozwala).
|
||||||
|
2. Hard-reload (Ctrl+F5) w przeglądarce.
|
||||||
|
3. Restart PHP-FPM / wyczyścić OPcache (jeśli aktywny).
|
||||||
|
4. Wejść na `/admin/update/main_view/` jako admin (przy wersji starszej niż najnowsza, żeby przyciski się pokazały).
|
||||||
|
5. **AC-1:** Kliknąć "Aktualizuj do wyższej wersji" → dialog `$.confirm` musi się otworzyć. To samo dla "Aktualizuj do najwyższej wersji".
|
||||||
|
6. **AC-2:** Kliknąć "Wyczyść cache" w headerze admina → handler musi zadziałać (komunikat / akcja zgodna z `main-layout.php`).
|
||||||
|
7. **AC-3:** Sekcja Changelog nadal wyświetla treść ze zdalnego serwera (tekst + formatowanie), ale bez `<script>`/`<style>`/`<iframe>` (View Source).
|
||||||
|
8. Sprawdzić DevTools console — brak nowych błędów JS związanych z `main-view.php`.
|
||||||
|
</how-to-verify>
|
||||||
|
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<boundaries>
|
||||||
|
|
||||||
|
## DO NOT CHANGE
|
||||||
|
- Logikę JS handlerów aktualizacji (`#confirm`, `#confirmUpdateAll`, funkcja `updateAll`) — wyłącznie reorder bloku.
|
||||||
|
- `admin/templates/site/main-layout.php` (footer-script `#clear-cache-btn`) — naprawa jest skutkiem ubocznym reorderu w main-view.
|
||||||
|
- URL zdalnego changeloga (`https://shoppro.project-dc.pl/updates/changelog.php`).
|
||||||
|
- Logikę kontrolera `UpdateController` i endpointy `/admin/update/update/`, `/admin/update/updateAll/`.
|
||||||
|
- Inne szablony w `admin/templates/update/`.
|
||||||
|
|
||||||
|
## SCOPE LIMITS
|
||||||
|
- Tylko jeden plik: `admin/templates/update/main-view.php`.
|
||||||
|
- Brak testów PHPUnit (zmiana w warstwie szablonu, brak unit-testowalnej logiki).
|
||||||
|
- Brak zmian w bazie / migracjach.
|
||||||
|
- Brak release update package — to robi `/koniec-pracy` po UNIFY.
|
||||||
|
- Brak zmiany sposobu pobierania changeloga (np. cache, timeout, fallback) — to byłby osobny scope.
|
||||||
|
|
||||||
|
</boundaries>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `php -l admin/templates/update/main-view.php` passes
|
||||||
|
- [ ] Blok `<script>` znajduje się przed sekcją Changelog (kolejność w pliku)
|
||||||
|
- [ ] Sekcja Changelog zawiera `strip_tags` z whitelistą formatowania
|
||||||
|
- [ ] Human-verify checkpoint approved (3 przyciski działają, changelog renderuje się sanityzowany)
|
||||||
|
- [ ] All acceptance criteria met
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
- AC-1, AC-2, AC-3 spełnione i potwierdzone w human-verify
|
||||||
|
- Brak regresji innych funkcji panelu admina
|
||||||
|
- Pełna suita PHPUnit (`./test.ps1`) nadal zielona (846 testów — bez nowych testów w tym planie)
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
124
.paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md
Normal file
124
.paul/phases/21-admin-update-view-js-fix/21-01-SUMMARY.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
phase: 21-admin-update-view-js-fix
|
||||||
|
plan: 01
|
||||||
|
subsystem: admin
|
||||||
|
tags: [template, js, htmlsanitize, update, admin-panel]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: none
|
||||||
|
provides: none
|
||||||
|
provides:
|
||||||
|
- Działające przyciski aktualizacji systemu (`#confirm`, `#confirmUpdateAll`) na /admin/update/main_view/
|
||||||
|
- Działający globalny przycisk "Wyczyść cache" (`#clear-cache-btn`) na tej podstronie
|
||||||
|
- Sanityzacja zdalnego changeloga (whitelist tagów formatujących + usunięcie komentarzy HTML)
|
||||||
|
affects: [admin update workflow, future remote-content includes]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Zdalne file_get_contents w szablonie sanityzować przez strip_tags z whitelistą + usunięcie komentarzy HTML; krytyczne <script> renderować PRZED takim includem"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- admin/templates/update/main-view.php
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Reorder: blok <script> z handlerami PRZED sekcję Changelog (nie po) — odporność na uszkodzony zdalny HTML"
|
||||||
|
- "Whitelist strip_tags ogranicza zdalny changelog do tagów formatujących; <script>/<style>/<textarea>/<iframe> wykluczone"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Sanityzacja zdalnego HTML w szablonach admina: preg_replace('/<!--.*?-->/s', '', $html) + strip_tags(whitelist)"
|
||||||
|
|
||||||
|
duration: ~15min
|
||||||
|
started: 2026-05-13T00:00:00Z
|
||||||
|
completed: 2026-05-13T00:00:00Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 21 Plan 01: Admin update view JS fix — Summary
|
||||||
|
|
||||||
|
**Naprawiono niedziałające przyciski aktualizacji systemu i globalny "Wyczyść cache" na `/admin/update/main_view/` przez reorder bloku `<script>` przed sekcję Changelog + sanityzację zdalnego changeloga w `admin/templates/update/main-view.php`.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Duration | ~15min |
|
||||||
|
| Tasks | 1 auto + 1 checkpoint:human-verify |
|
||||||
|
| Files modified | 1 |
|
||||||
|
| Tests | 846 / 2348 asercji — OK |
|
||||||
|
|
||||||
|
## Acceptance Criteria Results
|
||||||
|
|
||||||
|
| Criterion | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| AC-1: Handlery JS działają niezależnie od treści zdalnego changeloga | Pass | Blok `<script>` w linii 55, przed sekcją Changelog w linii 135 — handlery `#confirm`/`#confirmUpdateAll` podpinają się przed parsowaniem zdalnego HTML |
|
||||||
|
| AC-2: Globalny "Wyczyść cache" działa na podstronie update | Pass | Footer-script z `main-layout.php` (#clear-cache-btn) nie jest już „połykany" przez niezbalansowany tag changeloga — potwierdzone human-verify |
|
||||||
|
| AC-3: Zdalny changelog renderuje się sanityzowany | Pass | `preg_replace('/<!--.*?-->/s', '', ...)` usuwa komentarze HTML, `strip_tags` z whitelistą `<p><br><b><strong><i><em><u><ul><ol><li><h1>-<h6><span><div><a><pre><code><hr>` wycina niedozwolone tagi strukturalne i wykonywalne |
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Klient może aktualizować shopPRO na instancjach — root cause (niezbalansowany zdalny HTML „połykający" inline-script handlerów i footer-script `main-layout.php`) wyeliminowany przez reorder + sanityzację.
|
||||||
|
- Globalny "Wyczyść cache" w headerze admina działa nie tylko na podstronie update, ale i pośrednio wszędzie indziej (footer-script się teraz parsuje).
|
||||||
|
- Dodatkowy zysk bezpieczeństwa: zdalny `shoppro.project-dc.pl/updates/changelog.php` nie może już wstrzyknąć `<script>`/`<style>`/`<iframe>` w panel admina.
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
| File | Change | Purpose |
|
||||||
|
|------|--------|---------|
|
||||||
|
| `admin/templates/update/main-view.php` | Modified | Reorder bloku `<script>` przed sekcję Changelog + sanityzacja zdalnego changeloga (strip_tags whitelist + usunięcie komentarzy HTML) |
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
| Decision | Rationale | Impact |
|
||||||
|
|----------|-----------|--------|
|
||||||
|
| Reorder zamiast np. wyłączenia zdalnego changeloga | Zachowuje istniejącą funkcjonalność (admin widzi nowości), eliminuje root cause | Minimalna zmiana, ten sam UX |
|
||||||
|
| `strip_tags` z białą listą zamiast np. iframe sandbox | Najprostszy, zerowy narzut, działa na PHP 7.4, brak dodatkowych zależności | Zdalny content może być tylko tekstem z formatowaniem — wystarczy do changeloga |
|
||||||
|
| Whitelist obejmuje tagi formatujące + `<div>`/`<span>`/`<a>` | Zachowuje typową strukturę changeloga | Zdalny serwer nie może już strukturalnie popsuć strony |
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Type | Count | Impact |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Auto-fixed | 0 | — |
|
||||||
|
| Scope additions | 0 | — |
|
||||||
|
| Deferred | 0 | — |
|
||||||
|
|
||||||
|
**Total impact:** Plan wykonany dokładnie według change.md, bez odstępstw.
|
||||||
|
|
||||||
|
### Deferred Items
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
| Issue | Resolution |
|
||||||
|
|-------|------------|
|
||||||
|
| `./test.ps1` z CLAUDE.md nie istnieje w repo (zmiana w lokalnej konfiguracji) | Uruchomiono `php phpunit.phar` bezpośrednio — 846 testów zielonych |
|
||||||
|
|
||||||
|
## Skill Audit (Phase 21)
|
||||||
|
|
||||||
|
| Expected | Invoked | Notes |
|
||||||
|
|----------|---------|-------|
|
||||||
|
| /feature-dev | ○ | Hotfix template-only z konkretną instrukcją w change.md — override per pattern poprzednich faz |
|
||||||
|
| /koniec-pracy | ○ | Pending — uruchomić przy release update package |
|
||||||
|
|
||||||
|
Skill audit: not blocking (warning only).
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
**Ready:**
|
||||||
|
- Repo gotowe do `/koniec-pracy` (release update package z nową wersją zawierającą fix `admin/templates/update/main-view.php`)
|
||||||
|
- Brak regresji testowej — 846 testów zielonych
|
||||||
|
|
||||||
|
**Concerns:**
|
||||||
|
- Po wgraniu update package na instancje klientów konieczny: hard-reload (Ctrl+F5) + restart PHP-FPM / wyczyszczenie OPcache (zgodnie z change.md sekcja "Po wgraniu")
|
||||||
|
|
||||||
|
**Blockers:**
|
||||||
|
- None
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 21-admin-update-view-js-fix, Plan: 01*
|
||||||
|
*Completed: 2026-05-13*
|
||||||
File diff suppressed because one or more lines are too long
@@ -2,5 +2,5 @@ projectKey=shopPRO
|
|||||||
serverUrl=https://sonar.project-pro.pl
|
serverUrl=https://sonar.project-pro.pl
|
||||||
serverVersion=26.3.0.120487
|
serverVersion=26.3.0.120487
|
||||||
dashboardUrl=https://sonar.project-pro.pl/dashboard?id=shopPRO
|
dashboardUrl=https://sonar.project-pro.pl/dashboard?id=shopPRO
|
||||||
ceTaskId=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
ceTaskId=33e10a49-4790-400e-bf25-9b40eaed053e
|
||||||
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=646324f5-0b31-4df4-a424-9aa2e5c89d4b
|
ceTaskUrl=https://sonar.project-pro.pl/api/ce/task?id=33e10a49-4790-400e-bf25-9b40eaed053e
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ ob_start();
|
|||||||
?>
|
?>
|
||||||
<div id="settings-tabs">
|
<div id="settings-tabs">
|
||||||
<ul class="resp-tabs-list settings-tabs">
|
<ul class="resp-tabs-list settings-tabs">
|
||||||
<li><i class="fa fa-file"></i>Treść</li>
|
<li><i class="fa fa-file"></i>Treść</li>
|
||||||
<li><i class="fa fa-wrench"></i>Ustawienia</li>
|
<li><i class="fa fa-wrench"></i>Ustawienia</li>
|
||||||
<li><i class="fa fa-globe"></i>SEO</li>
|
<li><i class="fa fa-globe"></i>SEO</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -17,7 +17,7 @@ ob_start();
|
|||||||
<ul class="resp-tabs-list languages-main htabs">
|
<ul class="resp-tabs-list languages-main htabs">
|
||||||
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
|
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
|
||||||
<? if ( $lg['status'] ):?>
|
<? if ( $lg['status'] ):?>
|
||||||
<li><? if ( $lg['id'] == $this->dlang ) echo '<i class="fa fa-star fa-lg text-system" title="Język domyślny"></i> ';?><?= $lg['name'];?></a></li>
|
<li><? if ( $lg['id'] == $this->dlang ) echo '<i class="fa fa-star fa-lg text-system" title="Język domyślny"></i> ';?><?= $lg['name'];?></a></li>
|
||||||
<? endif;?>
|
<? endif;?>
|
||||||
<? endforeach; endif;?>
|
<? endforeach; endif;?>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -45,7 +45,7 @@ ob_start();
|
|||||||
);?>
|
);?>
|
||||||
<?= \Shared\Html\Html::textarea(
|
<?= \Shared\Html\Html::textarea(
|
||||||
array(
|
array(
|
||||||
'label' => 'Opis kategorii (rozwinięcie)',
|
'label' => 'Opis kategorii (rozwinięcie)',
|
||||||
'name' => 'text_hidden[' . $lg['id'] . ']',
|
'name' => 'text_hidden[' . $lg['id'] . ']',
|
||||||
'id' => 'text_hidden_' . $lg['id'],
|
'id' => 'text_hidden_' . $lg['id'],
|
||||||
'value' => $this -> category['languages'][ $lg['id'] ]['text_hidden'],
|
'value' => $this -> category['languages'][ $lg['id'] ]['text_hidden'],
|
||||||
@@ -84,7 +84,7 @@ ob_start();
|
|||||||
);?>
|
);?>
|
||||||
<?= \Shared\Html\Html::select(
|
<?= \Shared\Html\Html::select(
|
||||||
[
|
[
|
||||||
'label' => 'Sortowanie produktĂłw',
|
'label' => 'Sortowanie produktów',
|
||||||
'name' => 'sort_type',
|
'name' => 'sort_type',
|
||||||
'id' => 'sort_type',
|
'id' => 'sort_type',
|
||||||
'values' => is_array( $this -> sort_types ) ? $this -> sort_types : [],
|
'values' => is_array( $this -> sort_types ) ? $this -> sort_types : [],
|
||||||
@@ -93,7 +93,7 @@ ob_start();
|
|||||||
);?>
|
);?>
|
||||||
<?= \Shared\Html\Html::input_switch(
|
<?= \Shared\Html\Html::input_switch(
|
||||||
array(
|
array(
|
||||||
'label' => 'Wyświetlić podkategorie',
|
'label' => 'Wyświetlić podkategorie',
|
||||||
'name' => 'view_subcategories',
|
'name' => 'view_subcategories',
|
||||||
'checked' => $this -> category['view_subcategories'] == 1 ? true : false
|
'checked' => $this -> category['view_subcategories'] == 1 ? true : false
|
||||||
)
|
)
|
||||||
@@ -104,7 +104,7 @@ ob_start();
|
|||||||
<ul class="resp-tabs-list languages-seo htabs">
|
<ul class="resp-tabs-list languages-seo htabs">
|
||||||
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
|
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
|
||||||
<? if ( $lg['status'] ):?>
|
<? if ( $lg['status'] ):?>
|
||||||
<li><? if ( $lg['id'] == $this->dlang ) echo '<i class="fa fa-star fa-lg text-system" title="Język domyślny"></i> ';?><?= $lg['name'];?></a></li>
|
<li><? if ( $lg['id'] == $this->dlang ) echo '<i class="fa fa-star fa-lg text-system" title="Język domyślny"></i> ';?><?= $lg['name'];?></a></li>
|
||||||
<? endif;?>
|
<? endif;?>
|
||||||
<? endforeach; endif;?>
|
<? endforeach; endif;?>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -124,7 +124,7 @@ ob_start();
|
|||||||
);?>
|
);?>
|
||||||
<?= \Shared\Html\Html::input(
|
<?= \Shared\Html\Html::input(
|
||||||
array(
|
array(
|
||||||
'label' => 'Tytuł kategorii (h1)',
|
'label' => 'Tytuł kategorii (h1)',
|
||||||
'name' => 'category_title[' . $lg['id'] . ']',
|
'name' => 'category_title[' . $lg['id'] . ']',
|
||||||
'id' => 'category_title_' . $lg['id'],
|
'id' => 'category_title_' . $lg['id'],
|
||||||
'value' => $this -> category['languages' ][ $lg['id'] ]['category_title']
|
'value' => $this -> category['languages' ][ $lg['id'] ]['category_title']
|
||||||
@@ -156,7 +156,7 @@ ob_start();
|
|||||||
);?>
|
);?>
|
||||||
<?= \Shared\Html\Html::select(
|
<?= \Shared\Html\Html::select(
|
||||||
array(
|
array(
|
||||||
'label' => 'Blokuj indeksacjÄ™',
|
'label' => 'Blokuj indeksację',
|
||||||
'name' => 'noindex[' . $lg['id'] . ']',
|
'name' => 'noindex[' . $lg['id'] . ']',
|
||||||
'id' => 'noindex_' . $lg['id'],
|
'id' => 'noindex_' . $lg['id'],
|
||||||
'values' => array(
|
'values' => array(
|
||||||
|
|||||||
@@ -52,15 +52,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<? endif; ?>
|
<? endif; ?>
|
||||||
|
|
||||||
<div class="panel">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<span class="panel-title">Changelog</span>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<?= @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver ); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
var version_current = <?= $this->ver; ?>;
|
var version_current = <?= $this->ver; ?>;
|
||||||
@@ -138,3 +129,17 @@ $(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<span class="panel-title">Changelog</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<?php
|
||||||
|
$changelog = (string) @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver );
|
||||||
|
$changelog = preg_replace( '/<!--.*?-->/s', '', $changelog );
|
||||||
|
$changelog = strip_tags( $changelog, '<p><br><b><strong><i><em><u><ul><ol><li><h1><h2><h3><h4><h5><h6><span><div><a><pre><code><hr>' );
|
||||||
|
echo $changelog;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -2369,9 +2369,9 @@ class ProductRepository
|
|||||||
$itemNode->appendChild( $doc->createElement( 'g:description', html_entity_decode( strip_tags( $desc ) ) ) );
|
$itemNode->appendChild( $doc->createElement( 'g:description', html_entity_decode( strip_tags( $desc ) ) ) );
|
||||||
|
|
||||||
if ( $product['language']['seo_link'] ) {
|
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 {
|
} 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 ) );
|
$itemNode->appendChild( $doc->createElement( 'link', $link ) );
|
||||||
|
|
||||||
|
|||||||
@@ -691,12 +691,12 @@ class Helpers
|
|||||||
if ( $row2['seo_link'] )
|
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'] ) . '$', '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
|
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'] ) . '$', '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' ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,15 +153,9 @@ class LayoutEngine
|
|||||||
{
|
{
|
||||||
$category = $categoryRepo->frontCategoryDetails( (int)\Shared\Helpers\Helpers::get( 'category' ), $lang_id );
|
$category = $categoryRepo->frontCategoryDetails( (int)\Shared\Helpers\Helpers::get( 'category' ), $lang_id );
|
||||||
|
|
||||||
if ( $category['language']['meta_title'] )
|
$page = self::applyEntityMetaToPage( $page, isset( $category['language'] ) ? $category['language'] : null, isset( $category['language']['title'] ) ? $category['language']['title'] : '' );
|
||||||
$page['language']['title'] = $category['language']['meta_title'];
|
|
||||||
else
|
|
||||||
$page['language']['title'] = $category['language']['title'];
|
|
||||||
|
|
||||||
$page['show_title'] = true;
|
$page['show_title'] = true;
|
||||||
$page['language']['meta_keywords'] = $category['language']['meta_keywords'];
|
$page['language']['page_title'] = !empty( $category['language']['category_title'] ) ? $category['language']['category_title'] : ( isset( $category['language']['title'] ) ? $category['language']['title'] : '' );
|
||||||
$page['language']['meta_description'] = $category['language']['meta_description'];
|
|
||||||
$page['language']['page_title'] = $category['language']['category_title'] ? $category['language']['category_title'] : $category['language']['title'];
|
|
||||||
|
|
||||||
// CANONICAL
|
// CANONICAL
|
||||||
$html = str_replace( '[CANONICAL]', '', $html );
|
$html = str_replace( '[CANONICAL]', '', $html );
|
||||||
@@ -175,14 +169,8 @@ class LayoutEngine
|
|||||||
{
|
{
|
||||||
$article = $articleRepo->articleDetailsFrontend( (int)\Shared\Helpers\Helpers::get( 'article' ), $lang_id );
|
$article = $articleRepo->articleDetailsFrontend( (int)\Shared\Helpers\Helpers::get( 'article' ), $lang_id );
|
||||||
|
|
||||||
if ( $article['language']['meta_title'] )
|
$page = self::applyEntityMetaToPage( $page, isset( $article['language'] ) ? $article['language'] : null, isset( $article['language']['title'] ) ? $article['language']['title'] : '' );
|
||||||
$page['language']['title'] = $article['language']['meta_title'];
|
|
||||||
else
|
|
||||||
$page['language']['title'] = $article['language']['title'];
|
|
||||||
|
|
||||||
$page['show_title'] = false;
|
$page['show_title'] = false;
|
||||||
$page['language']['meta_keywords'] = $article['language']['meta_keywords'];
|
|
||||||
$page['language']['meta_description'] = $article['language']['meta_description'];
|
|
||||||
|
|
||||||
// CANONICAL
|
// CANONICAL
|
||||||
$html = str_replace( '[CANONICAL]', '', $html );
|
$html = str_replace( '[CANONICAL]', '', $html );
|
||||||
@@ -193,16 +181,11 @@ class LayoutEngine
|
|||||||
//
|
//
|
||||||
if ( \Shared\Helpers\Helpers::get( 'product' ) )
|
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'];
|
|
||||||
else
|
|
||||||
$page['language']['title'] = $product['language']['name'];
|
|
||||||
|
|
||||||
|
$page = self::applyEntityMetaToPage( $page, isset( $product['language'] ) ? $product['language'] : null, isset( $product['language']['name'] ) ? $product['language']['name'] : '' );
|
||||||
$page['show_title'] = false;
|
$page['show_title'] = false;
|
||||||
$page['language']['meta_keywords'] = $product['language']['meta_keywords'];
|
|
||||||
$page['language']['meta_description'] = $product['language']['meta_description'];
|
|
||||||
|
|
||||||
// CANONICAL
|
// CANONICAL
|
||||||
if ( $product['language']['canonical'] )
|
if ( $product['language']['canonical'] )
|
||||||
@@ -439,6 +422,35 @@ class LayoutEngine
|
|||||||
] );
|
] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Przepisuje meta encji (kategoria/artykuł/produkt) do $page['language'].
|
||||||
|
*
|
||||||
|
* Dlaczego: domyślne $page jest stroną główną CMS. Jeśli nie nadpiszemy
|
||||||
|
* meta_title encji (nawet pustym), meta_title homepage wycieka do <title>
|
||||||
|
* na podstronie kategorii/produktu (linia podstawienia [TITLE]).
|
||||||
|
*
|
||||||
|
* @param array $page obecne $page (z homepage lub session)
|
||||||
|
* @param array|null $entityLanguage wiersz *_langs encji (może być null)
|
||||||
|
* @param string $fallbackTitle nazwa encji używana jako $page.language.title
|
||||||
|
* @return array zmodyfikowany $page
|
||||||
|
*/
|
||||||
|
public static function applyEntityMetaToPage( $page, $entityLanguage, $fallbackTitle )
|
||||||
|
{
|
||||||
|
if ( !is_array( $page ) ) {
|
||||||
|
$page = [];
|
||||||
|
}
|
||||||
|
if ( !isset( $page['language'] ) or !is_array( $page['language'] ) ) {
|
||||||
|
$page['language'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$page['language']['title'] = $fallbackTitle;
|
||||||
|
$page['language']['meta_title'] = is_array( $entityLanguage ) && isset( $entityLanguage['meta_title'] ) ? $entityLanguage['meta_title'] : null;
|
||||||
|
$page['language']['meta_keywords'] = is_array( $entityLanguage ) && isset( $entityLanguage['meta_keywords'] ) ? $entityLanguage['meta_keywords'] : null;
|
||||||
|
$page['language']['meta_description'] = is_array( $entityLanguage ) && isset( $entityLanguage['meta_description'] ) ? $entityLanguage['meta_description'] : null;
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
public static function alert()
|
public static function alert()
|
||||||
{
|
{
|
||||||
if ( $alert = \Shared\Helpers\Helpers::get_session( 'alert' ) )
|
if ( $alert = \Shared\Helpers\Helpers::get_session( 'alert' ) )
|
||||||
|
|||||||
56
change.md
Normal file
56
change.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Zmiana 3: Naprawa JS na stronie /admin/update/main_view/ (przyciski aktualizacji + Wyczyść cache)
|
||||||
|
|
||||||
|
## Plik
|
||||||
|
`admin/templates/update/main-view.php`
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
Na podstronie `/admin/update/main_view/` nie działały:
|
||||||
|
- przycisk **„Aktualizuj do wyższej wersji"** (`#confirm`)
|
||||||
|
- przycisk **„Aktualizuj do najwyższej wersji"** (`#confirmUpdateAll`)
|
||||||
|
- globalny przycisk **„Wyczyść cache"** (`#clear-cache-btn`) z headera admina
|
||||||
|
|
||||||
|
W konsoli przeglądarki **nie było żadnego błędu JS**. Kliknięcie powodowało jedynie dopisanie `#` do URL-a (`/admin/update/main_view/#`).
|
||||||
|
|
||||||
|
## Przyczyna
|
||||||
|
W szablonie znajdowało się pobieranie zdalnego changeloga przez `file_get_contents` z `https://shoppro.project-dc.pl/updates/changelog.php`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?= @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver ); ?>
|
||||||
|
```
|
||||||
|
|
||||||
|
Odpowiedź zdalnego serwera zawierała niezbalansowany HTML (np. niezamknięty `<script>`, `<!--`, `<style>` albo `<textarea>`), który „połykał" całą resztę dokumentu jako tekst wewnątrz tego nieparzystego tagu. Skutki:
|
||||||
|
- Inline-script z handlerami przycisków aktualizacji (zaraz pod changelogiem) nie był parsowany jako JS.
|
||||||
|
- Footer-script z `main-layout.php` (handler `#clear-cache-btn` i globalne wyszukiwanie) też był „w środku" połkniętego HTML i nigdy się nie uruchamiał na tej podstronie.
|
||||||
|
- Konsola nie pokazywała błędu, bo to nie był błąd JS — to był po prostu HTML, który nigdy nie został wykonany jako skrypt.
|
||||||
|
|
||||||
|
## Co zmieniono
|
||||||
|
|
||||||
|
### 1. Blok `<script>` z handlerami przeniesiony przed sekcję Changelog
|
||||||
|
Wcześniej kolejność w szablonie była: panel z wersjami → log → **changelog (zdalny)** → `<script>`. Po zmianie: panel z wersjami → log → **`<script>`** → changelog (zdalny). Dzięki temu handlery `#confirm` i `#confirmUpdateAll` podpinają się niezależnie od tego, co zwróci zdalny serwer.
|
||||||
|
|
||||||
|
### 2. Sanitizacja odpowiedzi zdalnego changeloga
|
||||||
|
Przed wyrenderowaniem changelog jest czyszczony:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$changelog = (string) @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver );
|
||||||
|
$changelog = preg_replace( '/<!--.*?-->/s', '', $changelog );
|
||||||
|
$changelog = strip_tags( $changelog, '<p><br><b><strong><i><em><u><ul><ol><li><h1><h2><h3><h4><h5><h6><span><div><a><pre><code><hr>' );
|
||||||
|
echo $changelog;
|
||||||
|
```
|
||||||
|
|
||||||
|
- Usuwane są komentarze HTML (`<!--…-->`).
|
||||||
|
- `strip_tags` z wąską białą listą zostawia tylko tagi formatujące — wszystkie tagi strukturalne i mogące „połknąć" treść (`<script>`, `<style>`, `<textarea>`, `<iframe>`, `<body>`, `</html>` itp.) są usuwane.
|
||||||
|
|
||||||
|
### 3. Naprawiony też skutek uboczny
|
||||||
|
Po tych zmianach poprawnie działa również:
|
||||||
|
- footer-script z `main-layout.php` (przycisk **Wyczyść cache** + globalne wyszukiwanie produktów/zamówień + sprawdzanie aktualizacji w menu)
|
||||||
|
|
||||||
|
## Efekt
|
||||||
|
- Przyciski aktualizacji systemu na `/admin/update/main_view/` działają.
|
||||||
|
- Przycisk „Wyczyść cache" działa na tej (i każdej innej) podstronie admina.
|
||||||
|
- Zdalny changelog ze `shoppro.project-dc.pl` nadal się wyświetla, ale nie może już popsuć struktury strony.
|
||||||
|
- Dodatkowy zysk bezpieczeństwa: zdalny serwis nie może wstrzyknąć JS w panel admina.
|
||||||
|
|
||||||
|
## Po wgraniu
|
||||||
|
1. Hard-reload przeglądarki (Ctrl+F5) — stary HTML siedzi w cache klienta.
|
||||||
|
2. Restart PHP-FPM / wyczyszczenie OPcache — inaczej stary skompilowany szablon dalej będzie serwowany.
|
||||||
@@ -2,17 +2,37 @@
|
|||||||
global $lang_id;
|
global $lang_id;
|
||||||
$attributeRepo = new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] );
|
$attributeRepo = new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] );
|
||||||
$attribute_details = $attributeRepo->frontAttributeDetails( (int)$this -> attribute['id'], $lang_id );
|
$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 )
|
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'];?>">
|
<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>
|
<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">
|
<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>
|
<label for="<?= $this -> attribute['id'];?>-<?= $value['id'];?>" order="<?= $this -> order;?>"><?= ( new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] ) )->getAttributeValueById( $value['id'], $lang_id );?></label>
|
||||||
</div>
|
</div>
|
||||||
<? if ( $value['is_default'] ):?>
|
<? if ( $is_active ):?>
|
||||||
<script class="footer" type="text/javascript">
|
<script class="footer" type="text/javascript">
|
||||||
$( function()
|
$( 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
110
tests/Unit/front/LayoutEngineMetaTagsTest.php
Normal file
110
tests/Unit/front/LayoutEngineMetaTagsTest.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
namespace Tests\Unit\Front;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../autoload/front/LayoutEngine.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Phase 19 — fix metatagów na stronach kategorii/produktu/artykułu.
|
||||||
|
*
|
||||||
|
* Bug: domyślne $page jest stroną główną. W gałęziach category/article/product
|
||||||
|
* w LayoutEngine::show() nadpisywany był tylko title, a meta_title homepage
|
||||||
|
* żył dalej w $page['language']['meta_title'] i wygrywał w substytucji [TITLE].
|
||||||
|
*
|
||||||
|
* Fix: applyEntityMetaToPage() zawsze nadpisuje meta_title/meta_keywords/
|
||||||
|
* meta_description encji (nawet pustymi/null), żeby nic z homepage nie wyciekało.
|
||||||
|
*/
|
||||||
|
class LayoutEngineMetaTagsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testHomepageMetaTitleDoesNotLeakWhenEntityHasOwnMetaTitle()
|
||||||
|
{
|
||||||
|
$page = $this->homepagePage();
|
||||||
|
$category = [
|
||||||
|
'meta_title' => 'Sen i otulenie — kocyki minky',
|
||||||
|
'meta_keywords' => 'kocyki, otulacze',
|
||||||
|
'meta_description' => 'Najwyższej jakości kocyki minky',
|
||||||
|
'title' => 'Sen i otulenie',
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = \front\LayoutEngine::applyEntityMetaToPage($page, $category, $category['title']);
|
||||||
|
|
||||||
|
$this->assertSame('Sen i otulenie — kocyki minky', $result['language']['meta_title']);
|
||||||
|
$this->assertSame('Sen i otulenie', $result['language']['title']);
|
||||||
|
$this->assertSame('kocyki, otulacze', $result['language']['meta_keywords']);
|
||||||
|
$this->assertSame('Najwyższej jakości kocyki minky', $result['language']['meta_description']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHomepageMetaTitleIsClearedWhenEntityHasNoMetaTitle()
|
||||||
|
{
|
||||||
|
$page = $this->homepagePage();
|
||||||
|
$category = [
|
||||||
|
'meta_title' => null,
|
||||||
|
'meta_keywords' => 'description',
|
||||||
|
'meta_description' => 'keywords',
|
||||||
|
'title' => 'Sen i otulenie',
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = \front\LayoutEngine::applyEntityMetaToPage($page, $category, $category['title']);
|
||||||
|
|
||||||
|
$this->assertNull(
|
||||||
|
$result['language']['meta_title'],
|
||||||
|
'meta_title homepage nie może wyciekać gdy kategoria nie ma własnego'
|
||||||
|
);
|
||||||
|
$this->assertSame('Sen i otulenie', $result['language']['title']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProductWithAllMetaNullClearsHomepageValues()
|
||||||
|
{
|
||||||
|
$page = $this->homepagePage();
|
||||||
|
$productLang = [
|
||||||
|
'meta_title' => null,
|
||||||
|
'meta_keywords' => null,
|
||||||
|
'meta_description' => null,
|
||||||
|
'name' => 'Kocyk niemowlaka - Szczeniak z balonikiem - Fuksja',
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = \front\LayoutEngine::applyEntityMetaToPage($page, $productLang, $productLang['name']);
|
||||||
|
|
||||||
|
$this->assertNull($result['language']['meta_title']);
|
||||||
|
$this->assertNull($result['language']['meta_keywords']);
|
||||||
|
$this->assertNull($result['language']['meta_description']);
|
||||||
|
$this->assertSame($productLang['name'], $result['language']['title']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNullEntityLanguageDoesNotCrashAndClearsMeta()
|
||||||
|
{
|
||||||
|
$page = $this->homepagePage();
|
||||||
|
|
||||||
|
$result = \front\LayoutEngine::applyEntityMetaToPage($page, null, 'Fallback');
|
||||||
|
|
||||||
|
$this->assertSame('Fallback', $result['language']['title']);
|
||||||
|
$this->assertNull($result['language']['meta_title']);
|
||||||
|
$this->assertNull($result['language']['meta_keywords']);
|
||||||
|
$this->assertNull($result['language']['meta_description']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmptyPageInputCreatesLanguageStructure()
|
||||||
|
{
|
||||||
|
$result = \front\LayoutEngine::applyEntityMetaToPage([], ['meta_title' => 'X'], 'T');
|
||||||
|
|
||||||
|
$this->assertIsArray($result);
|
||||||
|
$this->assertIsArray($result['language']);
|
||||||
|
$this->assertSame('X', $result['language']['meta_title']);
|
||||||
|
$this->assertSame('T', $result['language']['title']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function homepagePage()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => 6,
|
||||||
|
'language' => [
|
||||||
|
'title' => 'Home',
|
||||||
|
'meta_title' => 'Sklep z akcesoriami dla dzieci i niemowląt, kocyki minky, poduszki, ubranka',
|
||||||
|
'meta_keywords' => '',
|
||||||
|
'meta_description' => 'Marianek to sklep internetowy z artykułami dla dzieci...',
|
||||||
|
'page_title' => null,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
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": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
updates/0.30/ver_0.351.zip
Normal file
BIN
updates/0.30/ver_0.351.zip
Normal file
Binary file not shown.
23
updates/0.30/ver_0.351_manifest.json
Normal file
23
updates/0.30/ver_0.351_manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"changelog": "FIX - poprawne metatagi \u003ctitle\u003e/\u003cdescription\u003e/\u003ckeywords\u003e dla stron kategorii i produktow (eliminacja wycieku meta_title homepage)",
|
||||||
|
"version": "0.351",
|
||||||
|
"files": {
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"deleted": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"autoload/front/LayoutEngine.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checksum_zip": "sha256:046d0504accf29a57fea155ecaa2acfe09078379e43118af7bf6c0f4831a3e5f",
|
||||||
|
"sql": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"date": "2026-05-13",
|
||||||
|
"directories_deleted": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
updates/0.30/ver_0.352.zip
Normal file
BIN
updates/0.30/ver_0.352.zip
Normal file
Binary file not shown.
23
updates/0.30/ver_0.352_manifest.json
Normal file
23
updates/0.30/ver_0.352_manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"changelog": "FIX - poprawne polskie znaki w labelkach formularza edycji kategorii w panelu admina (mojibake)",
|
||||||
|
"version": "0.352",
|
||||||
|
"files": {
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"deleted": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"admin/templates/shop-category/category-edit.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checksum_zip": "sha256:4b51cb1508978f6dc9659ce26c143961eaed6c3d3bb27b47623eaea5b4fa4855",
|
||||||
|
"sql": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"date": "2026-05-13",
|
||||||
|
"directories_deleted": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
updates/0.30/ver_0.353.zip
Normal file
BIN
updates/0.30/ver_0.353.zip
Normal file
Binary file not shown.
23
updates/0.30/ver_0.353_manifest.json
Normal file
23
updates/0.30/ver_0.353_manifest.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"changelog": "fix: dziala aktualizacja systemu i Wyczysc cache na /admin/update/main_view/ (sanityzacja zdalnego changeloga + reorder script)",
|
||||||
|
"version": "0.353",
|
||||||
|
"files": {
|
||||||
|
"added": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"deleted": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
"admin/templates/update/main-view.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checksum_zip": "sha256:86706999cd251c2c06e4b4d5875d049164ad510e60963bf8482f9bb8e6e924eb",
|
||||||
|
"sql": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"date": "2026-05-13",
|
||||||
|
"directories_deleted": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,3 +1,18 @@
|
|||||||
|
<b>ver. 0.353 - 13.05.2026</b><br />
|
||||||
|
fix: dziala aktualizacja systemu i Wyczysc cache na /admin/update/main_view/ (sanityzacja zdalnego changeloga + reorder script)
|
||||||
|
<hr>
|
||||||
|
<b>ver. 0.352 - 13.05.2026</b><br />
|
||||||
|
FIX - poprawne polskie znaki w labelkach formularza edycji kategorii w panelu admina (mojibake)
|
||||||
|
<hr>
|
||||||
|
<b>ver. 0.351 - 13.05.2026</b><br />
|
||||||
|
FIX - poprawne metatagi <title>/<description>/<keywords> dla stron kategorii i produktow (eliminacja wycieku meta_title homepage)
|
||||||
|
<hr>
|
||||||
|
<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 />
|
<b>ver. 0.348 - 19.04.2026</b><br />
|
||||||
Dodano przełącznik i edycję etykiet niestandardowych na liście produktów.
|
Dodano przełącznik i edycję etykiet niestandardowych na liście produktów.
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?
|
<?
|
||||||
$current_ver = 348;
|
$current_ver = 353;
|
||||||
|
|
||||||
for ($i = 1; $i <= $current_ver; $i++)
|
for ($i = 1; $i <= $current_ver; $i++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user