Separator URL miedzy parami attr-val zmieniony z "/" na "_" w generatorze feedu (ProductRepository::appendCombinationToXml). Wzorzec routingu pp_routes rozszerzony do [0-9_-]+ w Helpers::htacces (oba warianty: seo_link i fallback p-id-name). LayoutEngine konwertuje "_" -> "|" przed wywolaniem ProductRepository::findCached — format DB pozostaje "|". Partial product-attribute.php preselectuje wartosc z permutation_hash URL (forced_value_id), co poprawia UX wejscia z linka feedu. Suita: 834 -> 841 testow (+7), 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. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
169 lines
8.2 KiB
Markdown
169 lines
8.2 KiB
Markdown
---
|
||
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*
|