9.6 KiB
9.6 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-statlink-autolinking | 01 | execute | 1 |
|
true | off |
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)
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
<acceptance_criteria>
AC-1: Login do StatLink
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
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
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
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
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>
Task 1: Migracja SQL + Model śledzenia StatLink migrations/013_statlink_tracking.sql 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_TIMESTAMPIndeksy: (article_id), (status, expires_at), (site_id)
SQL jest poprawny składniowo, tabela zawiera wszystkie kolumny
AC-5 satisfied: tabela statlink_links gotowa do śledzenia linków
Task 2: StatLinkService — login, dodawanie, usuwanie linków
src/Services/StatLinkService.php
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).
Klasa kompiluje się bez błędów, metody mają prawidłowe sygnatury
AC-1, AC-2, AC-3 satisfied: serwis loguje się, dodaje i usuwa linki
Task 3: Cron endpoint + integracja z routerem
src/Controllers/SettingsController.php, src/Core/Router.php
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.
Endpoint /cron/statlink odpowiada JSON-em z podsumowaniem
AC-4 satisfied: cron endpoint do automatycznego zarządzania linkami StatLink
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
<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>