# BackPRO - Konfiguracja CRON

## Opis
Skrypt `cron/publish.php` jest uruchamiany automatycznie co godzinę przez CRON serwera. Odpowiada za sprawdzenie, czy któraś ze stron wymaga nowej publikacji, i jeśli tak - generuje artykuł z obrazkiem i publikuje go na WordPressie.

## Algorytm działania

```
1. Załaduj konfigurację (.env) i autoloader (vendor/autoload.php)
2. Pobierz wszystkie aktywne strony (is_active = 1)
3. Filtruj: zostaw strony, gdzie:
   - last_published_at IS NULL (nigdy nie publikowano)
   - LUB NOW() - last_published_at >= publish_interval_days dni
4. Sortuj po last_published_at ASC (NULL first = najwyższy priorytet)
5. Weź PIERWSZĄ stronę z listy (tylko jedna publikacja na uruchomienie)
6. TopicBalancer → wybierz temat z najmniejszą liczbą artykułów
7. Pobierz ostatnie 20 tytułów artykułów z tego tematu
8. OpenAIService → wygeneruj artykuł (prompt zawiera istniejące tytuły)
9. ImageService → wygeneruj/pobierz obrazek
10. WordPressService → upload obrazka jako media
11. WordPressService → utwórz post z featured image i kategorią
12. Zapisz artykuł w bazie (tabela articles, status=published)
13. Zaktualizuj topics.article_count (+1)
14. Zaktualizuj sites.last_published_at = NOW()
15. Zaloguj wynik do storage/logs/publish_YYYY-MM-DD.log
```

**Ważne:** Skrypt publikuje MAKSYMALNIE 1 artykuł na uruchomienie. Dzięki temu:
- Nie obciążamy API zbyt wieloma zapytaniami naraz
- Mamy lepszą kontrolę nad tempem publikacji
- W razie błędu tracimy tylko 1 artykuł, nie całą partię

## Konfiguracja CRON na Hostido

### Panel DirectAdmin / cPanel
W panelu hostingu dodaj zadanie CRON:

```
# Co godzinę (minuta 0 każdej godziny)
0 * * * * /usr/bin/php /home/username/public_html/cron/publish.php >> /home/username/public_html/storage/logs/cron.log 2>&1
```

Lub jeśli dostępny jest `php` w PATH:
```
0 * * * * php /home/username/public_html/cron/publish.php >> /home/username/public_html/storage/logs/cron.log 2>&1
```

### Alternatywne interwały
```
# Co 2 godziny
0 */2 * * * php /path/to/cron/publish.php

# Co 6 godzin
0 */6 * * * php /path/to/cron/publish.php

# Raz dziennie o 8:00
0 8 * * * php /path/to/cron/publish.php

# Dwa razy dziennie (8:00 i 20:00)
0 8,20 * * * php /path/to/cron/publish.php
```

## Zabezpieczenia

### Blokada dostępu HTTP
Plik `cron/.htaccess`:
```apache
Deny from all
```
Skrypty CRON są uruchamiane z linii komend (CLI), nie przez HTTP.

### Blokada wielokrotnego uruchomienia
Skrypt używa pliku lockfile (`storage/logs/publish.lock`):
- Na początku sprawdza czy lockfile istnieje
- Jeśli tak i nie jest starszy niż 30 minut → kończy działanie (inny proces w toku)
- Jeśli nie → tworzy lockfile
- Na końcu (lub w razie błędu) → usuwa lockfile

## Logowanie

Logi zapisywane w `storage/logs/publish_YYYY-MM-DD.log`:

```
[2026-02-15 10:00:01] INFO: Rozpoczynam publikację
[2026-02-15 10:00:01] INFO: Wybrano stronę: example.com (ID: 3)
[2026-02-15 10:00:01] INFO: Wybrany temat: Ogrodnictwo (ID: 7)
[2026-02-15 10:00:05] INFO: Wygenerowano artykuł: "10 roślin idealnych na balkon"
[2026-02-15 10:00:08] INFO: Wygenerowano obrazek (Freepik)
[2026-02-15 10:00:10] INFO: Upload mediów na WP: media_id=142
[2026-02-15 10:00:12] INFO: Opublikowano post: wp_post_id=523
[2026-02-15 10:00:12] INFO: Zakończono pomyślnie
```

## Ręczne uruchomienie

### Z linii komend
```bash
php /path/to/cron/publish.php
```

### Z panelu BackPRO
Przycisk "Opublikuj teraz" na dashboardzie wywołuje `PublishController@run`, który uruchamia ten sam proces co CRON, ale synchronicznie z poziomu przeglądarki.

## Monitoring

### Sprawdzanie statusu
- Dashboard BackPRO pokazuje datę ostatniej publikacji dla każdej strony
- Lista artykułów z filtrem po statusie (published/failed)
- Logi w `storage/logs/`

### Typowe problemy
| Problem | Przyczyna | Rozwiązanie |
|---------|-----------|-------------|
| Brak publikacji | CRON nie uruchomiony | Sprawdź konfigurację CRON w panelu |
| Status: failed | Błąd API | Sprawdź error_message w artykule i logi |
| Lockfile blokuje | Poprzedni proces nie zakończył się | Usuń `storage/logs/publish.lock` |
| 401 z WordPress | Złe dane API | Sprawdź api_user/api_token w konfiguracji strony |
| 429 z OpenAI | Rate limit | Zwiększ interwał CRON lub poczekaj |

## Miesieczna synchronizacja metryk SEO (SEMSTORM + DataForSEO)

Dodaj osobne zadanie CRON uruchamiane raz w miesiacu:

```bash
0 3 1 * * php /path/to/cron/semstorm.php >> /path/to/storage/logs/cron_semstorm.log 2>&1
```

Skrypt:
- pobiera aktywne strony (`sites.is_active = 1`),
- pobiera metryki z SEMSTORM dla domeny strony,
- pobiera liczbe zaindeksowanych stron (zapytanie `site:domena`) z DataForSEO,
- zapisuje dane do `site_seo_metrics` dla biezacego miesiaca,
- pomija rekord, jesli miesiac jest juz zapisany (idempotencja).
