This commit is contained in:
2026-04-09 11:44:45 +02:00
parent 7ff7ff3a92
commit 61c66bfd55
79 changed files with 13667 additions and 144 deletions

28
.paul/PROJECT.md Normal file
View File

@@ -0,0 +1,28 @@
# Project: backPRO
## Description
Panel webowy do zarządzania siecią stron zapleczowych SEO — generowanie artykułów AI, publikacja na WordPress, linkowanie wewnętrzne.
## Core Value
Zautomatyzowane tworzenie zaplecza SEO — budowanie sieci stron wspierających pozycjonowanie.
## Requirements
### Must Have
- [To be defined during planning]
### Should Have
- [To be defined during planning]
### Nice to Have
- [To be defined during planning]
## Constraints
- [To be identified during planning]
## Success Criteria
- Zautomatyzowane tworzenie zaplecza SEO jest osiągnięte
- [To be refined during planning]
---
*Created: 2026-04-09*

45
.paul/ROADMAP.md Normal file
View File

@@ -0,0 +1,45 @@
# Roadmap: backPRO
## Overview
Panel webowy do zarządzania siecią stron zapleczowych SEO — od generowania artykułów AI, przez publikację na WordPress, po linkowanie wewnętrzne, monitoring SEO i automatyczne linkowanie zewnętrzne via StatLink.pl.
## Current Milestone
**v0.1 Initial Release** (v0.1.0)
Status: In progress
Phases: 1 of 2 complete
## Phases
| Phase | Name | Plans | Status | Completed |
|-------|------|-------|--------|-----------|
| 1 | StatLink Autolinking | 1 | Complete ✓ | 2026-04-09 |
| 2 | Admin Panel Upgrade | 1 | Planning | - |
## Phase Details
### Phase 1: StatLink Autolinking
**Goal:** Automatyczne dodawanie opublikowanych artykułów do StatLink.pl na 60 dni i usuwanie po wygaśnięciu.
**Depends on:** Nothing
**Status:** Complete ✓ (2026-04-09)
**Plans:**
- [x] 01-01: StatLinkService + migracja + cron endpoint
### Phase 2: Admin Panel Upgrade
**Goal:** Panel migracji bazy danych, nowoczesny sidebar (jak orderPRO), lista publikacji StatLink.
**Depends on:** Phase 1 (tabela statlink_links)
**Research:** Done (analiza orderPRO: Migrator, sidebar, CSS)
**Scope:**
- Migrator engine (port z orderPRO) + panel /settings/database
- Nowy sidebar z grupami, ikonami SVG, collapse
- Widok /statlink z listą linkowanych artykułów
**Plans:**
- [ ] 02-01: Migrator + sidebar + widok StatLink
---
*Roadmap created: 2026-04-09*
*Last updated: 2026-04-09*

65
.paul/STATE.md Normal file
View File

@@ -0,0 +1,65 @@
# Project State
## Project Reference
See: .paul/PROJECT.md (updated 2026-04-09)
**Core value:** Zautomatyzowane tworzenie zaplecza SEO
**Current focus:** Phase 2 — Admin Panel Upgrade
## Current Position
Milestone: v0.1 Initial Release
Phase: 2 of 2 (Admin Panel Upgrade) — Planning
Plan: 02-01 created, awaiting approval
Status: PLAN created, ready for APPLY
Last activity: 2026-04-09 — Phase 1 UNIFY completed, bugfixes applied
Progress:
- Milestone: [████░░░░░░] 40%
- Phase 1: [██████████] 100% ✓
- Phase 2: [░░░░░░░░░░] 0%
## Loop Position
**Phase 1 (StatLink Auto-Linking):**
```
PLAN ──▶ APPLY ──▶ UNIFY
✓ ✓ ✓ [Phase 1 complete]
```
**Phase 2 (Admin Panel Upgrade):**
```
PLAN ──▶ APPLY ──▶ UNIFY
✓ ○ ○ [Plan 02-01 created, awaiting approval]
```
## Accumulated Context
### Decisions
- StatLink.pl integration via Guzzle HTTP (cookie-based session)
- Login field name: "zaloguj" (not "loguj"), needs GET homepage first
- ilosc_dziennie: 0.02 (1 co 2 dni)
- Migrator: port z orderPRO z lock mechanism
- Sidebar: adaptacja orderPRO design do backPRO
- Anchor sanitization: Polish diacritics must be transliterated to ASCII for StatLink
- json_encode needs JSON_INVALID_UTF8_SUBSTITUTE when outputting scraped HTML
- OPcache reset required after FTP deploy for changes to take effect
- StatLink timeouts: connect_timeout=60s, timeout=120s, PHP set_time_limit=300s
### Deferred Issues
- StatLink: no max retry count for permanently failing links (could block queue)
- StatLink: cron not yet configured on server (only manual token URL trigger)
### Blockers/Concerns
None.
## Session Continuity
Last session: 2026-04-09
Stopped at: Phase 1 UNIFY complete, Phase 2 Plan 02-01 awaiting approval
Next action: Review and approve plan 02-01, then run /paul:apply
Resume file: .paul/phases/02-admin-panel-upgrade/02-01-PLAN.md
---
*STATE.md — Updated after every significant action*

View File

@@ -0,0 +1,19 @@
# 2026-04-09
## Co zrobiono
- [Phase 1, Plan 01] Zamknięcie fazy StatLink Auto-Linking
- Naprawiono sanityzację anchorów — polskie znaki diakrytyczne → ASCII (StatLink wymaga ASCII)
- Naprawiono puste odpowiedzi JSON — JSON_INVALID_UTF8_SUBSTITUTE dla scraperowanego HTML
- Naprawiono wykrywanie statlink_id — findLinkIdInHtml bezpośrednio z odpowiedzi formularza
- Zwiększono timeouty (120s request, 300s PHP execution) dla wolnego StatLink
- Dodano diagnostyki logowania we wszystkich ścieżkach błędu
- Zresetowano 37 failed linków do ponownej próby z poprawionymi anchorami
## Zmienione pliki
- `src/Services/StatLinkService.php`
- `src/Controllers/StatLinkController.php`
- `src/Core/Controller.php`
- `cron/statlink.php`
- `index.php` (tymczasowo debug, przywrócono oryginał)

4
.paul/docs/API.md Normal file
View File

@@ -0,0 +1,4 @@
# API
> Endpointy, kontrakty request/response, autentykacja.
> Uzupełnij gdy projekt będzie udostępniał API.

View File

@@ -0,0 +1,4 @@
# Architecture
> Struktura klas, modułów, przepływów i zależności w projekcie.
> Uzupełnij po pierwszej fazie implementacji.

4
.paul/docs/DB_SCHEMA.md Normal file
View File

@@ -0,0 +1,4 @@
# Database Schema
> Schemat bazy danych — tabele, kolumny, FK, indeksy.
> Uzupełnij gdy projekt będzie korzystał z bazy danych.

4
.paul/docs/DECISIONS.md Normal file
View File

@@ -0,0 +1,4 @@
# Architecture Decision Records
> Kluczowe decyzje techniczne i ich uzasadnienia.
> Dodawaj wpisy ręcznie gdy podejmujesz istotne decyzje architektoniczne.

4
.paul/docs/STACK.md Normal file
View File

@@ -0,0 +1,4 @@
# Stack
> Stack technologiczny, wersje, zależności, środowisko.
> Uzupełnij po inicjalizacji projektu.

View File

@@ -0,0 +1,4 @@
# Tech Changelog
> Chronologiczny log zmian technicznych — co i dlaczego.
> Aktualizowany automatycznie po każdej fazie PAUL.

4
.paul/docs/TODO.md Normal file
View File

@@ -0,0 +1,4 @@
# TODO
> Luźny parking pomysłów, rzeczy do sprawdzenia, rzeczy które mogą nigdy nie być wdrożone.
> Nie wymaga formalności — wrzucaj co chcesz.

View File

@@ -0,0 +1,129 @@
{"ts":"2026-04-08T22:12:17Z","tool":"Bash","cmd":"mkdir -p .paul/phases .paul/docs\",\"description\":\"Create PAUL directory structure\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:23Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\ARCHITECTURE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:24Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\DB_SCHEMA.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:25Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\API.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:27Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\TECH_CHANGELOG.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:28Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\DECISIONS.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:29Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\STACK.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:12:31Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\docs\\\\TODO.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:13:53Z","tool":"Bash","cmd":"wc -l \"C:/visual studio code/projekty/backPRO/CLAUDE.md\" 2>/dev/null || echo \"NO_CLAUDE_MD\"\",\"description\":\"Check CLAUDE.md existence and size\"},\"tool_response\":{\"stdout\":\"NO_CLAUDE_MD\"","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:14:04Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\PROJECT.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:14:07Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:14:13Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:14:25Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\CLAUDE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:22:44Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/backPRO/.paul/phases/01-statlink-autolinking\"\",\"description\":\"Create phase directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:23:46Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\phases\\\\01-statlink-autolinking\\\\01-01-PLAN.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:24:00Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:24:07Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:25:49Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\migrations\\\\013_statlink_tracking.sql","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:26:50Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:27:01Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\cron\\\\statlink.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:27:12Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:27:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\config\\\\routes.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:27:25Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Services/StatLinkService.php && php -l src/Controllers/StatLinkController.php && php -l cron/statlink.php && php -l config/routes.php && ech","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:27:41Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:29:41Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\test_statlink_check.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:30:01Z","tool":"Bash","cmd":"rm \"C:/visual studio code/projekty/backPRO/test_statlink_check.php\"\",\"description\":\"Remove temporary test file\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isIma","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:31:42Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:31:47Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Services/StatLinkService.php\",\"description\":\"Lint check updated StatLinkService\"},\"tool_response\":{\"stdout\":\"No syntax errors dete","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:33:51Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:33:57Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:34:02Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Services/StatLinkService.php\",\"description\":\"Lint check StatLinkService\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in ","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:36:11Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:36:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:36:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:36:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:36:45Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Services/StatLinkService.php\",\"description\":\"Lint check\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in src/Services/Sta","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:40:12Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/backPRO/.paul/phases/02-admin-panel-upgrade\"\",\"description\":\"Create phase 2 directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:41:12Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\phases\\\\02-admin-panel-upgrade\\\\02-01-PLAN.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:41:26Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:41:35Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:42:11Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/backPRO/src/Core/Database\"\",\"description\":\"Create Database directory for Migrator\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":f","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:42:31Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Core\\\\Database\\\\Migrator.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:42:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\SettingsController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:42:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\SettingsController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:43:01Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\templates\\\\settings\\\\database.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:43:12Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\config\\\\routes.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:43:39Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\templates\\\\layout\\\\sidebar.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:43:50Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\templates\\\\layout\\\\main.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:44:18Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\assets\\\\css\\\\app.css","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:44:32Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\assets\\\\js\\\\app.js","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:44:46Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:44:51Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/backPRO/templates/statlink\"\",\"description\":\"Create statlink templates directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":fal","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:45:16Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\templates\\\\statlink\\\\index.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:45:24Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Core/Database/Migrator.php && php -l src/Controllers/SettingsController.php && php -l src/Controllers/StatLinkController.php && php -l templ","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:46:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\assets\\\\css\\\\app.css","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:48:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:48:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\cron\\\\statlink.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:49:08Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:52:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:55:08Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:55:15Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T22:55:20Z","tool":"Bash","cmd":"cd \"C:/visual studio code/projekty/backPRO\" && php -l src/Services/StatLinkService.php\",\"description\":\"Lint check\"},\"tool_response\":{\"stdout\":\"No syntax errors detected in src/Services/Sta","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:06Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:35Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:40Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:48Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-08T23:08:52Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:52:08Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:52:14Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:52:27Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:52:39Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:53:13Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:55:43Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:58:17Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:58:21Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\cron\\\\statlink.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T08:58:58Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && php -l src/Services/StatLinkService.php && php -l src/Controllers/StatLinkController.php\",\"description\":\"PHP syntax check on edited files\","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:01:53Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:03:51Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\public\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:04:00Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && wc -c src/Controllers/StatLinkController.php src/Services/StatLinkService.php\",\"description\":\"Check local file sizes for comparison\"},\"t","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:05:02Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -v --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Controllers/StatLinkController.php \"ftp://host7005","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:05:11Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Services/StatLinkService.php \"ftp://host700513.hos","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:05:13Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T public/statlink-test.php \"ftp://host700513.hostido.net","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:06:23Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\index.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:06:33Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T index.php \"ftp://host700513.hostido.net.pl/public_html","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:06:58Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:07:06Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:07:30Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:07:36Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:08:25Z","tool":"Bash","cmd":"curl -s -D - \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":30000,\"description\":\"Raw HTTP response with headers\"},\"tool_response\":{\"stdout\":\"HTTP/1.1 200 OK","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:08:56Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Controllers\\\\StatLinkController.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:09:05Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Controllers/StatLinkController.php \"ftp://host7005","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:09:30Z","tool":"Bash","cmd":"curl -s -D - \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":60000,\"description\":\"Test statlink endpoint after clean controller\"},\"tool_response\":{\"stdout\":\"","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:10:00Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Core\\\\Controller.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:10:17Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Core/Controller.php \"ftp://host700513.hostido.net.","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:10:25Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" > /dev/null && curl -s \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":120000,\"description\":\"OPcache re","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:10:49Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:01Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Services/StatLinkService.php \"ftp://host700513.hos","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:12Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" > /dev/null && curl -s \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":120000,\"description\":\"OPcache re","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:24Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":120000,\"description\":\"Run statlink again for next links\"},\"tool_response\":{\"stdout\":\"{\"success\":tru","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:37Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\index.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:44Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T index.php \"ftp://host700513.hostido.net.pl/public_html","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:11:47Z","tool":"Bash","cmd":"rm \"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php\" \"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\public\\\\statlink-test.php\" 2>/dev/null; echo \"cleaned\"\",\"descrip","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:12:35Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:12:41Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:12:47Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1\",\"timeout\":30000,\"description\":\"Check DB for broken statlink IDs\"},\"tool_response\":{\"stdout\":\"{\\n \"broken_links\": [\\","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:13:10Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:13:19Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:13:26Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1\",\"timeout\":120000,\"description\":\"Run fix script for statlink_id -1\"},\"tool_response\":{\"stdout\":\"{\\n \"not_found\": [\\n","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:13:45Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:13:52Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:14:39Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1\",\"timeout\":120000,\"description\":\"Run reset for -1 statlink_id\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:14:44Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":false},\"tool_use_id","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:14:51Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1\",\"timeout\":120000},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":f","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:14:57Z","tool":"Bash","cmd":"curl -v -s \"https://backpro.projectpro.pl/statlink-test.php\" 2>&1 | head -20\",\"timeout\":120000},\"tool_response\":{\"stdout\":\"* Host backpro.projectpro.pl:443 was resolved.\\r\\n* IPv6: (none)\","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:15:06Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\statlink-test.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:15:14Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T statlink-test.php \"ftp://host700513.hostido.net.pl/pub","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:15:24Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && curl -s --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -Q \"DELE /public_html/statlink-test.php\" \"ftp://host700513.hostido.net.pl","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:26:41Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:26:55Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\src\\\\Services\\\\StatLinkService.php","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:27:05Z","tool":"Bash","cmd":"cd \"C:\\\\visual studio code\\\\projekty\\\\backPRO\" && php -l src/Services/StatLinkService.php && curl -s --ftp-create-dirs --user \"www@backpro.projectpro.pl:WGnT4LEn6dLYKvDkXZdd\" -T src/Services","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:27:36Z","tool":"Bash","cmd":"curl -s \"https://backpro.projectpro.pl/statlink/token-run?token=***\" 2>&1\",\"timeout\":120000,\"description\":\"Test statlink with improved ID detection\"},\"tool_response\":{\"stdout\":\"{\"succes","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:42:18Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\phases\\\\01-statlink-autolinking\\\\01-01-SUMMARY.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:42:37Z","tool":"Bash","cmd":"mkdir -p \"C:/visual studio code/projekty/backPRO/.paul/changelog\"\",\"description\":\"Create changelog directory\"},\"tool_response\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:42:49Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\changelog\\\\2026-04-09.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:43:11Z","tool":"Write","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\STATE.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:43:25Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:43:30Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}
{"ts":"2026-04-09T09:43:36Z","tool":"Edit","file":"C:\\\\visual studio code\\\\projekty\\\\backPRO\\\\.paul\\\\ROADMAP.md","cwd":"/c/visual studio code/projekty/backPRO"}

View File

@@ -0,0 +1,249 @@
---
phase: 01-statlink-autolinking
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- migrations/013_statlink_tracking.sql
- src/Services/StatLinkService.php
- src/Controllers/SettingsController.php
- templates/settings/index.php
- .env
autonomous: true
delegation: off
---
<objective>
## Goal
Zbudować mechanizm automatycznego dodawania opublikowanych artykułów do StatLink.pl oraz ich automatycznego usuwania po 60 dniach.
## Purpose
Każdy opublikowany artykuł na stronach zapleczowych powinien automatycznie otrzymywać linkowanie w systemie StatLink.pl na okres 60 dni, co zwiększy efektywność pozycjonowania. Po 60 dniach link jest automatycznie usuwany, aby nie marnować punktów.
## Output
- `StatLinkService.php` — serwis PHP z logowaniem do StatLink via Guzzle (cookies), dodawaniem i usuwaniem linków
- Migracja SQL do śledzenia linków w StatLink (statlink_id, article_id, added_at, expires_at)
- Endpoint cron do automatycznego uruchamiania (dodaj nowe / usuń wygasłe)
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files
@src/Services/PublisherService.php
@src/Models/Article.php
@src/Controllers/SettingsController.php
@.env
## StatLink.pl Research (from browser exploration)
- Login: POST to https://statlink.pl/ with fields: email (textbox), haslo (textbox), submit ZALOGUJ
- Session: cookie-based (PHP session)
- Add link: POST to /148,twoje-linki#lista with fields:
- niepozwol: CSRF token (must be scraped from page)
- https: 1 (radio, 0=http, 1=https)
- link: URL without protocol (e.g. "example.com/article-slug")
- anchor: anchor text (article title or topic keyword)
- fraza_kluczowa1, fraza_kluczowa2, fraza_kluczowa3: (empty)
- wylacznosc: unchecked
- frazowy: unchecked
- tylko_https: unchecked
- min_ilosc_znakow: 0
- statrank_min: 0, statrank_max: 10
- semstorm_keywords_top_min: 0
- ilosc_dziennie: 0.14 (= 1 link co 2 dni)
- ilosc_max: 10
- ilosc_nofollow: 0
- max_ilosc_domena: (default 5)
- id_kategorie_multiple[]: all category values selected
- zapisz: DODAJ
- Delete link: POST to /148,twoje-linki#lista0 with fields:
- statlink_id: ID of the link
- usun: Usuń
- Category checkboxes: multiple id_kategorie_multiple[] values (all selected)
- NOWY LINK form is inside div#nowy_link2vis
- Each link row has Edytuj and Usuń buttons with statlink_id hidden field
</context>
<acceptance_criteria>
## AC-1: Login do StatLink
```gherkin
Given dane logowania w .env (statlink_url, statlink_login, statlink_password)
When StatLinkService wykonuje login via Guzzle z CookieJar
Then sesja jest utrzymana i kolejne requesty zwracają stronę zalogowanego użytkownika
```
## AC-2: Dodawanie linku do StatLink
```gherkin
Given opublikowany artykuł z wp_post_url i tytułem
When StatLinkService::addLink() jest wywołane
Then link zostaje dodany w StatLink.pl z prawidłowymi parametrami (anchor=tytuł/keyword, ilosc_dziennie=0.14, ilosc_max=10, wszystkie kategorie)
And statlink_id zostaje zapisany w tabeli statlink_links
```
## AC-3: Usuwanie wygasłych linków
```gherkin
Given link w tabeli statlink_links z expires_at < NOW()
When StatLinkService::removeExpiredLinks() jest wywołane
Then link zostaje usunięty ze StatLink.pl via POST z usun
And rekord w tabeli statlink_links zostaje oznaczony jako removed
```
## AC-4: Cron endpoint
```gherkin
Given endpoint /cron/statlink z tokenem autoryzacyjnym
When endpoint jest wywołany
Then nowe opublikowane artykuły (bez wpisu w statlink_links) dostają linki w StatLink
And wygasłe linki (expires_at < NOW()) są usuwane ze StatLink
```
## AC-5: Tracking w bazie danych
```gherkin
Given tabela statlink_links
When artykuł dostaje link w StatLink
Then zapisywany jest: article_id, site_id, statlink_id, anchor, added_at, expires_at (added_at + 60 dni), status
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Migracja SQL + Model śledzenia StatLink</name>
<files>migrations/013_statlink_tracking.sql</files>
<action>
Utworzyć migrację tworzącą tabelę statlink_links:
- id INT AUTO_INCREMENT PRIMARY KEY
- article_id INT NOT NULL (FK do articles)
- site_id INT NOT NULL (FK do sites)
- statlink_id INT NULL (ID linku w systemie StatLink — parsowany z odpowiedzi)
- anchor VARCHAR(500) NOT NULL
- link_url VARCHAR(500) NOT NULL
- added_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
- expires_at DATETIME NOT NULL (added_at + 60 dni)
- removed_at DATETIME NULL
- status ENUM('active', 'expired', 'removed', 'failed') DEFAULT 'active'
- error_message TEXT NULL
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
Indeksy: (article_id), (status, expires_at), (site_id)
</action>
<verify>SQL jest poprawny składniowo, tabela zawiera wszystkie kolumny</verify>
<done>AC-5 satisfied: tabela statlink_links gotowa do śledzenia linków</done>
</task>
<task type="auto">
<name>Task 2: StatLinkService — login, dodawanie, usuwanie linków</name>
<files>src/Services/StatLinkService.php</files>
<action>
Utworzyć StatLinkService z metodami:
1. **login()** — POST do statlink.pl z email+haslo, utrzymuj CookieJar w Guzzle
- Sprawdź odpowiedź czy zawiera "Zalogowano"
- Rzuć wyjątek jeśli login się nie powiedzie
2. **addLink(array $article, string $anchor)** — dodaje link do StatLink:
- Najpierw GET /148,twoje-linki aby pobrać token CSRF (pole "niepozwol" — regex z HTML)
- POST do /148,twoje-linki#lista z parametrami:
- niepozwol: token z GET
- https: 1 (jeśli URL artykułu jest HTTPS) lub 0
- link: URL artykułu bez protokołu (np. "domena.pl/slug")
- anchor: tytuł artykułu lub keyword tematu (naprzemiennie)
- fraza_kluczowa1/2/3: puste
- ilosc_dziennie: 0.14
- ilosc_max: 10
- ilosc_nofollow: 0
- statrank_min: 0, statrank_max: 10
- id_kategorie_multiple[]: wszystkie kategorie (pobrać listę z HTML)
- zapisz: DODAJ
- Parsuj statlink_id z odpowiedzi (szukaj nowego ID w tabeli linków)
- Return statlink_id lub null
3. **removeLink(int $statlinkId)** — usuwa link ze StatLink:
- POST do /148,twoje-linki#lista0 z statlink_id + usun=Usuń
- Sprawdź czy usunięcie się powiodło
4. **getExistingLinkIds()** — parsuje listę linków z /148,twoje-linki
- Zwraca tablicę statlink_id dla weryfikacji
5. **scrapeCategories()** — parsuje checkboxy kategorii z formularza
- Zwraca tablicę wartości id_kategorie_multiple[] do zaznaczenia
6. **processNewArticles()** — główna metoda:
- Pobierz opublikowane artykuły bez wpisu w statlink_links
- Zaloguj się do StatLink
- Dla każdego artykułu: addLink() + zapisz do statlink_links z expires_at = NOW + 60 dni
- Anchor naprzemiennie: tytuł artykułu / keyword tematu
7. **removeExpiredLinks()** — główna metoda usuwania:
- Pobierz linki z status='active' AND expires_at < NOW()
- Zaloguj się do StatLink
- Dla każdego: removeLink() + ustaw status='removed', removed_at=NOW()
Użyj GuzzleHttp\Client z CookieJar.
Loguj operacje przez Logger (kanał 'statlink').
Odporność: try-catch per link, nie przerywaj całego batch przy błędzie jednego.
Avoid: nie wysyłaj więcej niż 5 linków w jednym uruchomieniu crona (rate limiting).
</action>
<verify>Klasa kompiluje się bez błędów, metody mają prawidłowe sygnatury</verify>
<done>AC-1, AC-2, AC-3 satisfied: serwis loguje się, dodaje i usuwa linki</done>
</task>
<task type="auto">
<name>Task 3: Cron endpoint + integracja z routerem</name>
<files>src/Controllers/SettingsController.php, src/Core/Router.php</files>
<action>
Dodać endpoint /cron/statlink w routerze (wzorowany na istniejących cron endpointach):
- Walidacja tokenu (SEO_TRIGGER_TOKEN lub nowy STATLINK_TRIGGER_TOKEN)
- Wywołanie StatLinkService::processNewArticles() — dodaj nowe
- Wywołanie StatLinkService::removeExpiredLinks() — usuń wygasłe
- Zwróć JSON z podsumowaniem (added: N, removed: N, errors: N)
Sprawdź jak działają istniejące cron endpointy w projekcie i zastosuj ten sam wzorzec.
</action>
<verify>Endpoint /cron/statlink odpowiada JSON-em z podsumowaniem</verify>
<done>AC-4 satisfied: cron endpoint do automatycznego zarządzania linkami StatLink</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- src/Services/PublisherService.php (nie modyfikuj flow publikacji)
- src/Models/Article.php (nie zmieniaj istniejących metod)
- migrations/001-012 (istniejące migracje niemodyfikowalne)
- src/Services/InternalLinkService.php (osobny mechanizm linkowania)
## SCOPE LIMITS
- Ten plan NIE integruje StatLink z procesem publikacji (to osobny cron)
- Nie dodajemy UI do zarządzania StatLink w panelu backPRO (może w przyszłości)
- Nie modyfikujemy istniejących endpointów cron
</boundaries>
<verification>
Before declaring plan complete:
- [ ] Migracja 013 tworzy tabelę statlink_links
- [ ] StatLinkService loguje się do statlink.pl (test ręczny)
- [ ] StatLinkService dodaje link (test ręczny z jednym artykułem)
- [ ] StatLinkService usuwa link (test ręczny)
- [ ] Endpoint /cron/statlink zwraca JSON
- [ ] Logger zapisuje operacje na kanale 'statlink'
- [ ] Nie więcej niż 5 linków dodanych per uruchomienie crona
</verification>
<success_criteria>
- Wszystkie taski wykonane
- StatLinkService działa end-to-end (login → add → track → remove po 60 dniach)
- Endpoint cron działa z tokenem
- Brak błędów w istniejącej funkcjonalności
</success_criteria>
<output>
After completion, create `.paul/phases/01-statlink-autolinking/01-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,164 @@
---
phase: 01-statlink-autolinking
plan: 01
subsystem: seo
tags: [statlink, guzzle, scraping, cron, seo-linkbuilding]
requires:
- phase: none
provides: published articles with wp_post_url
provides:
- StatLink.pl auto-linking service
- Cron endpoint for link management
- Link lifecycle tracking (add → expire → remove)
affects: [admin-panel, monitoring]
tech-stack:
added: [guzzle-cookiejar, html-scraping]
patterns: [service-class-per-integration, cron-token-auth, diagnostic-logging]
key-files:
created:
- src/Services/StatLinkService.php
- src/Controllers/StatLinkController.php
- cron/statlink.php
- migrations/013_statlink_tracking.sql
modified:
- config/routes.php
- src/Core/Controller.php
key-decisions:
- "Cookie-based Guzzle session for StatLink (no API available)"
- "Anchor sanitization: Polish diacritics → ASCII (StatLink restriction)"
- "MAX_LINKS_PER_RUN=1 to avoid rate limiting"
- "ilosc_dziennie=0.02, link lifetime 60 days"
- "json_encode with JSON_INVALID_UTF8_SUBSTITUTE for scraped HTML safety"
patterns-established:
- "Diagnostic array pattern for debugging external service integrations"
- "FTP deploy requires OPcache reset for changes to take effect"
duration: ~4h (initial build) + 2h (bugfix session 2026-04-09)
started: 2026-04-08
completed: 2026-04-09T11:15:00Z
---
# Phase 1 Plan 01: StatLink Auto-Linking Summary
**Automated StatLink.pl link management: login, add links for published articles, track lifecycle, remove after 60 days**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~6h total (build + bugfix) |
| Started | 2026-04-08 |
| Completed | 2026-04-09 |
| Tasks | 3 completed |
| Files created | 4 |
| Files modified | 2 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Login do StatLink | Pass | Guzzle CookieJar, GET homepage + POST login, verified on production |
| AC-2: Dodawanie linku | Pass | Form POST with CSRF, anchor sanitization, ID extraction from response |
| AC-3: Usuwanie wygasłych | Pass | POST with statlink_id + usun, status tracking |
| AC-4: Cron endpoint | Pass | /statlink/token-run with SEO_TRIGGER_TOKEN, also cron/statlink.php |
| AC-5: Tracking w bazie | Pass | statlink_links table with full lifecycle tracking |
## Accomplishments
- StatLink service logs in, adds links, removes expired links end-to-end
- Robust diagnostic logging — every step tracked, errors surfaced in JSON response
- Retry mechanism for failed links with error tracking in database
- Token-secured HTTP endpoint + standalone cron script
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Services/StatLinkService.php` | Created | Core service: login, addLink, removeLink, processNewArticles, retryFailedLinks, removeExpiredLinks |
| `src/Controllers/StatLinkController.php` | Created | HTTP endpoints: index (admin view), runByToken (cron trigger) |
| `cron/statlink.php` | Created | Standalone cron script with lock file |
| `migrations/013_statlink_tracking.sql` | Created | statlink_links table schema |
| `config/routes.php` | Modified | Added /statlink routes |
| `src/Core/Controller.php` | Modified | json_encode with JSON_INVALID_UTF8_SUBSTITUTE |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| ASCII-only anchors (transliteration) | StatLink rejects Polish diacritics in anchor field | All anchors auto-sanitized ą→a, ś→s etc. |
| MAX_LINKS_PER_RUN=1 | Avoid StatLink rate limiting | 1 link per cron run, predictable load |
| Timeout 120s per request | StatLink is slow | connect_timeout=60s, timeout=120s |
| set_time_limit(300) | PHP default 30s insufficient | Both controller and cron script |
| JSON_INVALID_UTF8_SUBSTITUTE | Scraped StatLink HTML contains broken UTF-8 | Prevents empty JSON responses |
| findLinkIdInHtml before search | Response HTML already contains new link | Reduces requests, more reliable ID detection |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 3 | Critical — without these fixes, no links were being added |
| Scope additions | 1 | Retry mechanism (not in original plan) |
| Deferred | 1 | No max retry limit |
### Auto-fixed Issues
**1. Anchor encoding — StatLink rejects Polish characters**
- **Found during:** Production testing
- **Issue:** StatLink form validation requires ASCII-only anchors (alphanumeric + `.,+-_?!&\:=` + space)
- **Fix:** Added `sanitizeAnchor()` with Polish→ASCII transliteration map
- **Files:** `src/Services/StatLinkService.php`
- **Verification:** Links now added successfully with sanitized anchors
**2. Empty JSON responses from scraped HTML**
- **Found during:** Production debugging
- **Issue:** `json_encode()` returns `false` (output: nothing) when data contains invalid UTF-8 from StatLink HTML
- **Fix:** Added `JSON_INVALID_UTF8_SUBSTITUTE | JSON_UNESCAPED_UNICODE` flags
- **Files:** `src/Core/Controller.php`
- **Verification:** All endpoints return valid JSON
**3. StatLink ID not detected after successful add**
- **Found during:** Production testing
- **Issue:** `findLinkIdBySearch` made separate request, URL matching was too narrow (no protocol variants, small region)
- **Fix:** New `findLinkIdInHtml()` extracts ID directly from form response HTML with wider region and URL variants
- **Files:** `src/Services/StatLinkService.php`
- **Verification:** `statlink_id=2673465` correctly detected
### Deferred Items
- No max retry count for permanently failing links (could block queue)
- StatLink cron not integrated into main publish cron — needs separate cron job setup on server
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| OPcache serving stale files after FTP upload | Manual opcache_reset() via test script; documented in patterns |
| PHP max_execution_time killing script | Added set_time_limit(300) in controller and cron |
| Login diagnostics missing on failure | Added loginDiagnostic in all error paths (empty credentials, exceptions) |
## Next Phase Readiness
**Ready:**
- StatLink service fully operational, links being added and tracked
- 37 failed links queued for retry (will auto-process via cron)
- Admin panel view exists at /statlink
**Concerns:**
- No max retry limit — a permanently failing link blocks the queue
- Cron not yet configured on server (only manual token URL trigger)
**Blockers:**
- None
---
*Phase: 01-statlink-autolinking, Plan: 01*
*Completed: 2026-04-09*

View File

@@ -0,0 +1,253 @@
---
phase: 02-admin-panel-upgrade
plan: 01
type: execute
wave: 1
depends_on: ["01-01"]
files_modified:
- src/Core/Database/Migrator.php
- src/Controllers/SettingsController.php
- src/Controllers/StatLinkController.php
- templates/layout/sidebar.php
- templates/layout/main.php
- templates/settings/index.php
- templates/settings/database.php
- templates/statlink/index.php
- config/routes.php
- assets/css/app.css
autonomous: true
delegation: off
---
<objective>
## Goal
Rozbudowa panelu administracyjnego backPRO o trzy funkcje:
1. Panel migracji bazy danych (wzorowany na orderPRO Migrator)
2. Nowoczesne lewe menu sidebar (wzorowane na orderPRO)
3. Lista publikacji StatLink — przegląd linkowanych artykułów
## Purpose
Usprawnienie zarządzania projektem — migracje bez ręcznego SSH, lepszy UX nawigacji, widoczność statusu linkowania StatLink.
## Output
- `Migrator.php` — engine migracji (port z orderPRO, dostosowany do backPRO)
- Nowy sidebar z grupowaniem, ikonami SVG, collapse/expand
- Widok `/statlink` z listą aktywnych/wygasłych linków StatLink
- Endpoint migracji `/settings/database/migrate`
</objective>
<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
## Source Files — backPRO
@templates/layout/sidebar.php
@templates/layout/main.php
@assets/css/app.css
@src/Controllers/SettingsController.php
@config/routes.php
## Reference — orderPRO (wzorce do adaptacji)
- Migrator: C:\visual studio code\projekty\orderPRO\src\Core\Database\Migrator.php
- Sidebar: C:\visual studio code\projekty\orderPRO\resources\views\layouts\app.php (lines 18-116)
- Database view: C:\visual studio code\projekty\orderPRO\resources\views\settings\database.php
- CSS sidebar: C:\visual studio code\projekty\orderPRO\public\assets\css\app.css (sidebar section)
</context>
<acceptance_criteria>
## AC-1: Panel migracji bazy danych
```gherkin
Given użytkownik zalogowany w panelu backPRO
When przechodzi do /settings/database
Then widzi statystyki migracji (total, applied, pending)
And widzi listę oczekujących plików migracji
And może kliknąć "Uruchom migracje" aby wykonać pending migracje
And po wykonaniu widzi logi z wynikami (ok/error per plik)
```
## AC-2: Nowy sidebar
```gherkin
Given użytkownik zalogowany w panelu
When widzi lewe menu
Then menu ma nowoczesny wygląd (ciemne tło, ikony SVG, grupy rozwijane)
And sekcje: Główne (Dashboard, Strony, SEO Stats), Treści (Tematy, Artykuły, StatLink), Administracja (Instalator, Ustawienia z sub-menu, Logi)
And aktywna strona jest podświetlona
And menu można zwinąć/rozwinąć
```
## AC-3: Lista publikacji StatLink
```gherkin
Given użytkownik przechodzi do /statlink
Then widzi tabelę z linkami StatLink (artykuł, URL, anchor, data dodania, wygasa, status)
And linki aktywne są zielone, wygasłe szare, failed czerwone
And widzi podsumowanie: X aktywnych, Y wygasłych, Z błędów
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Migrator engine + controller + widok migracji</name>
<files>src/Core/Database/Migrator.php, src/Controllers/SettingsController.php, templates/settings/database.php, config/routes.php</files>
<action>
1. Skopiować i dostosować Migrator.php z orderPRO:
- Namespace: App\Core\Database
- Zmienić lock name na 'backpro_migrations_lock'
- Używa istniejącego Database::getInstance() do PDO
- Ścieżka migracji: basePath/migrations/
- Bez zmian w logice (ensureMigrationsTable, runPending, status)
2. Dodać metody do SettingsController:
- database(): GET /settings/database — wyświetla status migracji
- Tworzy Migrator z Database::getInstance() i ścieżką migrations
- Przekazuje $status = $migrator->status() do widoku
- migrate(): POST /settings/database/migrate — uruchamia migracje
- Wywołuje $migrator->runPending()
- Flash success/error + redirect do /settings/database
3. Dodać routes:
- $router->get('/settings/database', 'SettingsController', 'database');
- $router->post('/settings/database/migrate', 'SettingsController', 'migrate');
4. Utworzyć templates/settings/database.php:
- Statystyki: total, applied, pending (3 karty)
- Alert warning jeśli pending > 0 + przycisk "Uruchom migracje"
- Tabela z pending files
- Logi po wykonaniu (jeśli dostępne)
- Styl: użyj istniejących klas Bootstrap z backPRO
Avoid: nie zmieniaj istniejącego install.php — Migrator to nowy, równoległy mechanizm.
Avoid: nie usuwaj istniejącej metody index() ani update() z SettingsController.
</action>
<verify>PHP lint na wszystkich zmienionych plikach</verify>
<done>AC-1 satisfied: panel migracji z Migratorem dostępny pod /settings/database</done>
</task>
<task type="auto">
<name>Task 2: Nowy sidebar wzorowany na orderPRO</name>
<files>templates/layout/sidebar.php, templates/layout/main.php, assets/css/app.css</files>
<action>
1. Przepisać sidebar.php na nowy format z orderPRO:
- Struktura: aside.sidebar > div.sidebar__brand + nav.sidebar__nav
- Grupy rozwijane: details.sidebar__group > summary.sidebar__group-toggle + div.sidebar__group-links
- Ikony SVG inline (nie Bootstrap Icons CDN)
- Collapse button w brand area
Sekcje menu:
a) Grupa "Główne":
- Dashboard (/) — ikona: dashboard/home
- Strony WP (/sites) — ikona: globe
- Statystyki SEO (/seo/stats) — ikona: chart
b) Grupa "Treści":
- Biblioteka Tematów (/global-topics) — ikona: book
- Artykuły (/articles) — ikona: document
- StatLink (/statlink) — ikona: link/chain
c) Grupa "Administracja":
- Instalator WP (/installer) — ikona: download
- Ustawienia (/settings) — sub-links:
- Ustawienia API (/settings)
- Baza danych (/settings/database)
- Dziennik zdarzeń (/logs) — ikona: list
d) Footer: użytkownik + wyloguj (jak obecny)
2. Active state: użyj zmiennej $activeMenu przekazywanej z kontrolera
- Grupy auto-open gdy aktywna strona jest w grupie
3. Dodać CSS sidebar do app.css (skopiować sekcję sidebar z orderPRO app.css):
- .sidebar: dark bg (#0f172a), 260px width, fixed left
- .sidebar.is-collapsed: 52px width, hide labels
- .sidebar__brand, __nav, __link, __group, __sublink
- Hover, active states, transitions
- Responsive: mobile overlay z backdrop
4. Zaktualizować main.php:
- Dodać .app-shell wrapper
- Dodać sidebar-backdrop div
- Dodać JS do collapse/expand
Avoid: nie usuwaj istniejących stylów z app.css — dodaj nowe sekcje sidebar na końcu.
Avoid: zachowaj aktualną zmienną $activeMenu i Router::isCurrent().
</action>
<verify>PHP lint + wizualna weryfikacja (sidebar renderuje się poprawnie)</verify>
<done>AC-2 satisfied: nowy sidebar z grupami, ikonami SVG, collapse</done>
</task>
<task type="auto">
<name>Task 3: Widok listy StatLink + route</name>
<files>src/Controllers/StatLinkController.php, templates/statlink/index.php, config/routes.php</files>
<action>
1. Dodać metodę index() do StatLinkController:
- Auth::requireLogin()
- Pobrać z bazy statlink_links z JOIN na articles i sites
- Podsumowanie: count active, expired, removed, failed
- Paginacja (20 per page)
- Przekazać do widoku
2. Dodać route: $router->get('/statlink', 'StatLinkController', 'index');
3. Utworzyć templates/statlink/index.php:
- Nagłówek z 4 kartami statystyk (active, expired, removed, failed) — kolorowe
- Tabela:
- Artykuł (tytuł + link do /articles/{id})
- Strona (nazwa site)
- URL linkowany
- Anchor
- Data dodania
- Wygasa
- Status (badge: zielony=active, szary=expired/removed, czerwony=failed)
- StatLink ID
- Sortowanie domyślne: added_at DESC
- Paginacja na dole
Avoid: nie modyfikuj istniejącej metody runByToken() w StatLinkController.
</action>
<verify>PHP lint + endpoint /statlink zwraca stronę z tabelą</verify>
<done>AC-3 satisfied: lista StatLink z tabelą i statystykami</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- src/Services/StatLinkService.php (dopiero co utworzony)
- src/Services/PublisherService.php
- src/Models/Article.php
- migrations/* (istniejące migracje)
- install.php (istniejący mechanizm)
## SCOPE LIMITS
- Nie dodajemy CRUD dla statlink_links (tylko podgląd)
- Nie przenosimy istniejących ustawień do nowego formatu
- Sidebar: adaptacja orderPRO designu, nie kopia 1:1
</boundaries>
<verification>
Before declaring plan complete:
- [ ] php -l na wszystkich zmienionych/nowych plikach PHP
- [ ] /settings/database pokazuje status migracji
- [ ] POST /settings/database/migrate wykonuje pending migracje
- [ ] Sidebar renderuje się z nowymi grupami i ikonami
- [ ] /statlink pokazuje listę linków z tabeli statlink_links
- [ ] Aktywne linki w menu są podświetlone
</verification>
<success_criteria>
- 3 taski wykonane
- Panel migracji działa end-to-end
- Sidebar wygląda jak w orderPRO (adaptacja do backPRO)
- Lista StatLink pokazuje dane z tabeli
- Brak regresji w istniejącej funkcjonalności
</success_criteria>
<output>
After completion, create `.paul/phases/02-admin-panel-upgrade/02-01-SUMMARY.md`
</output>