p24-infra — Strategia Rozwoju 2026
Synteza analizy krytycznej · Architektura docelowa · Plan wdrożenia Wersja: 2026-06-27
TL;DR — Co teraz robić
| Priorytet | Działanie | Czas | Efekt |
|---|---|---|---|
| 🔴 P1 | Uruchom restore drill MongoDB | 4 h | Zamknięcie 4-miesięcznego długu bezpieczeństwa |
| 🔴 P1 | Dodaj nightly n8n workflow export → git | 2 h | Utrata definitons = niemożliwa |
| 🔴 P1 | Zainstaluj node_exporter na bms-1/2/3 | 1 d | MTTD dla prod z 24 h → 2 min |
| 🟡 P1 | Uruchom bms-3 jako 3. node agentów | 1 d | Pojemność z 7 → 11 agentów bez nowego serwera |
| 🟡 P2 | Skróć notifikacje Discord (tylko zmiana stanu) | 2 h | Koniec spam-fatigeu |
| 🟡 P2 | Dodaj dev_r_ops_events (change log serwera) | 1 d | Korelacja alertów z operacjami możliwa |
| 🟡 P2 | Fix socat-supabase watchdog na bms-4 | 3 h | Koniec cascade-failure przez tunel |
| 🟢 P2 | Extend kolejkę: cost columns + billing tier | 3 d | Gotowość na SaaS billing |
| 🟢 P3 | DuckDB reporting pipeline (ETL nightly) | 3 d | Raporty bez obciążania Supabase |
| 🟢 P3 | SaaS AI metering service (ai-worker) | 2 tyg | BrandPilot AI queuing i billing |
1. Krytyczny przegląd procedur
1.1 Audit zdarzeń i zmian — stan obecny 🟡
Co działa:
docs/secrets-rotation-log.md— jedyny solidny log zmian w systemie (timestampowane wpisy + per-consumer potwierdzenie)- Git commit history — pełna historia kodu i konfiguracji
audit.runsw Supabase — historia wykonań audit-engine- GH issue history — kontekst incydentów z śladem rozumowania agentów
Krytyczne luki:
Brak ustrukturyzowanego change logu serwera. Jeśli ktoś uruchamia docker restart n8n przez SSH lub edytuje /opt/p24-infra/monitoring/.env bezpośrednio — ta akcja nie pozostawia żadnego śladu w żadnym systemie. Brak auditd na węzłach VPS, brak bazy operacji ręcznych.
Niemożliwa korelacja alertów z operacjami. Alert o 03:15, restart kontenera o 03:10 — połączenie tych faktów wymaga ręcznego zestawienia czasów w Discord, komentarzach GitHub Issues i docker logs. Nie ma wspólnego event store.
Log rotacji ma lukę weryfikacyjną. Wpisy z “Confirmed in sync” nie mają timestamp weryfikacji każdego konsumenta. Wzorzec “partial — DEFERRED” + późniejszy wpis “Complete” pojawia się wielokrotnie — log może zawierać otwarte wpisy wyglądające jak zamknięte.
Rekomendacja — dodać tabelę dev_r_ops_events:
CREATE TABLE dev_r_ops_events (
id BIGSERIAL PRIMARY KEY,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
actor TEXT NOT NULL, -- 'claude-runner@bms-4', 'hourly-triage', 'human:radieu'
action_type TEXT NOT NULL, -- 'container_restart', 'config_reload', 'secret_deploy'
target TEXT NOT NULL, -- 'monitoring-n8n-1', 'secrets/monitoring.env.sops'
server_node TEXT, -- 'bms-4', 'vps-i1'
outcome TEXT NOT NULL, -- 'success', 'failure', 'partial'
gh_issue_id INT, -- powiązany issue jeśli istnieje
notes TEXT
);Hourly triage, Tier 1 auto-fix i health-check.yml piszą do tej tabeli na każdym działaniu. Grafana ma timeline view. Korelacja alertów z operacjami staje się trywialna.
1.2 Monitorowanie — krytyczna ocena 🟡
4-warstwowy system jest komplementarny, nie redundantny — ale ma jeden poważny błąd projektowy:
| Warstwa | Funkcja | Problem |
|---|---|---|
| Prometheus (ciągły) | Metryki progowe | ✅ Działa, 22 pliki reguł |
| GitHub Actions co 2h | HTTP probe z zewnątrz | ⚠️ Spamuje Discord przy każdym uruchomieniu (12×/dobę) |
| Nightly AI triage 00:30 UTC | 11-fazowe sprawdzenie SSH | ⚠️ Pass/fail nie jako metryka Prometheus — historia gubi się |
| Hourly AI triage | Klasyfikacja issues | ⚠️ Gdy bms-4 pada — tier 4 znika bez powiadomienia |
MTTD dla awarii produkcji — porównanie:
| Serwer / usługa | MTTD (obecnie) | MTTD (po poprawkach) |
|---|---|---|
| vps-i1 kontener crash | 30 s | 30 s (bez zmian) |
| vps-i1 host down | 2 h (health-check.yml) | 2 h (bez zmian) |
| bms-1 dysk/RAM | 24 h (nightly triage SSH) | 2 min (node_exporter + Prometheus) |
| bms-2/3 MongoDB | 24 h (nightly triage) | 2 min (po node_exporter) |
| WAHA sesja degradacja | Brak metryki | 5 min (po blackbox probe) |
Naprawy priorytetowe:
node_exporterna bms-1, bms-2, bms-3 — Ansible role, 1 dzień pracy- Prometheus gauge
p24_nightly_triage_result{phase, result}— push po każdym runie - health-check.yml — Discord tylko przy zmianie stanu (2 h pracy, nie tydzień)
- Thanos upload alert:
thanos_objstore_bucket_last_successful_upload_seconds_ago > 7200
1.3 Playbooki — ocena jakości 🟡
108 playbooki = dobre pokrycie, ale problemy strukturalne:
- ~40% to rotacje credentiali (jeden plik na typ klucza). Razem z
credential-rotation.yml(automatyka) te pliki są fallback manualnym — warto skonsolidować do jednego “manual-rotation-fallback.md” + wyjątki per-usługa. - Brak
last_verifieddate w żadnym playbooku — nie wiadomo które są aktualne po decommission Infisical CE, usunięciu claude-proxy, włączeniu ufw na bms-2/3. infra_docs_checksprawdza czy playbook istnieje, nie czy jest aktualny.
Potwierdzone brakujące playbooki (krytyczne):
| Brakujący playbook | Ryzyko |
|---|---|
disaster-recovery.md | Brak DR runbooka narusza infrastructure-standard §4 |
bms1-total-failure.md | 24 kontenery prod, brak hot standby, brak procedury |
mongodb-rs0-divergence.md | Split-brain + data divergence podczas partycji sieci |
vps-i1-rebuild.md | Całkowita utrata monitoring stack — jak odbudować < 30 min |
pinbox24-rollback.md | Rollback kontenera v42 → v41 na bms-1 |
supabase-project-suspended.md | Platforma zależy od Supabase — co gdy projekt zawieszony? |
loki-retention-setup.md | Retencja Loki niezdefiniowana — nigdy nie skonfigurowana |
agents-capacity-exhausted.md | Wszystkie 4 sloty bms-4 zajęte + P1 issue wymaga agenta |
1.4 Samoleczenie — luki mechanizmów 🟡
Tier 2 (AI-Dev spawning) nie ma idempotency guard. Jeśli hourly triage odpala się dwukrotnie dla tego samego otwartego issue (np. issue nie zamknięte gdy następna godzina uderza), można dostać 2 agentów pracujących na tym samym zadaniu. Fix: dodać label ai-dev-spawned na issue przed spawnem, sprawdzać w triage.
Playwright OAuth re-auth detection — skrypt Playwright re-authu uruchamia się reagując na awarie SSH. Gdy Playwright fail — Discord alert. Ale brak automatycznej detekcji, że “Playwright uruchomił się i zawiódł po raz 2.” Efektywnie: ludzki tier eskalacji jest wykrywany przez ludzkie oczy, nie przez automat.
n8n-OOM masking: health-check.yml restartuje n8n co 2h jeśli jest crashnięty. Jeśli n8n crashuje co 25 min z OOM — restart się “udaje”, leci kolejny crash. OOM jest maskowany przez auto-restart. Fix: alert na pattern n8n_restart_count > 3 in 6h → wymuś diagnozę zamiast restart.
2. Analiza kolejki — decyzja architektoniczna
2.1 Co tak naprawdę mamy
Po analizie kodu (infra-src/meta-dispatcher/, queue-dispatcher-loop.py, spawn-worker.sh):
CF Worker dispatcher + Supabase dev_r_worker_queue to zaawansowany system kolejkowania — nie uproszczony hack. Zawiera:
- Wave planning z topologicznym sortowaniem (algorytm Kahn) → zapobiega race condition na tych samych plikach
- Role classification (
classify.ts) — dekoupled od dispatchu - Server affinity + RAM-aware spawn (
systemd-run --scope MemoryMax=) - Distributed lock via partial unique index na
dev_r_orchestrator_runs - Heartbeat tracking (60s curl PATCH) — detekcja stallujących agentów
- Spawn_failures vs. retry_count separacja
- Night-task time gating (20:00–02:59 UTC)
- Dedup guards
Wniosek: nie zastępować. Rozszerzyć.
RabbitMQ — decommissioned za brak konsumentów. BullMQ — Redis na bms-4 jest SPOF dla n8n i nie nadaje się na drugi backend. Temporal — overkill. CF Queues — beta.
Wystarczy: dodać kolumny cost metering + billing tier + SaaS job types + bms-3 jako 3. dispatch node.
2.2 Plan rozszerzenia kolejki
Faza 1 — Cost attribution (2 dni):
-- Dodać do dev_r_worker_queue:
ALTER TABLE dev_r_worker_queue
ADD COLUMN client_id TEXT,
ADD COLUMN project_id TEXT,
ADD COLUMN billing_tier TEXT NOT NULL DEFAULT 'internal'
CHECK (billing_tier IN ('client-paid', 'client-free', 'internal')),
ADD COLUMN tokens_in INTEGER,
ADD COLUMN tokens_out INTEGER,
ADD COLUMN cost_usd NUMERIC(10,6),
ADD COLUMN model_used TEXT;Workers piszą token_tick events przez istniejący heartbeat curl — ten sam mechanizm, nowy endpoint.
Faza 2 — Priority tiers dla SaaS (1 dzień):
// W classify.ts — computePriority():
const tierAdj = billingTier === 'client-paid' ? -20
: billingTier === 'client-free' ? -10
: 0;
return waveNumber * 10 + labelAdj + sizeAdj + tierAdj;Dispatcher ORDER BY priority ASC → client-paid jobs wychodzą pierwsze.
Faza 3 — Skala do 12 agentów (1 dzień):
bms-3 ma 8 vCPU / 32 GB RAM — większość zajmowana przez MongoDB PRIMARY (~21 GB) i staging (10 kontenerów, ~6 GB). Dostępne headroom: ~4 GB RAM i ~2 vCPU — wystarczy na 3-4 lekkich agentów.
# Na bms-3: zainstalować claude-runner + spawn-worker.sh
# Dodać do dev_r_server_capacity:
INSERT INTO dev_r_server_capacity VALUES
('bms-3', '51.68.155.224', 3, 6, 2, 'claude-runner');Dispatcher iteruje SERVERS z env — to zmiana konfiguracyjna, nie code change.
Faza 4 — Visibility Grafana (1 dzień):
# queue-exporter/app.py — nowe metryki:
P24_JOB_COST = Gauge('p24_job_cost_usd_total', 'Cost per client', ['client_id', 'project_id'])
P24_AGENTS_ACTIVE = Gauge('p24_agents_active', 'Active agents per server', ['server_node', 'weight'])
P24_QUEUE_BY_TIER = Gauge('p24_queue_depth_by_tier', 'Queue depth by billing tier', ['billing_tier'])Docelowa architektura kolejki (po rozszerzeniu):
ENQUEUE (CF Worker — bez zmian oprócz nowych kolumn billing):
SaaS Apps / n8n → POST /queue-issue → Supabase dev_r_worker_queue
wave planning + role classify + billing_tier + priority
DISPATCH (Python, cron co 2 min, na każdym serwerze):
├─ bms-4 (54.36.123.110) — max 6 slotów: n8n + 4-6 agentów
├─ bms-3 (51.68.155.224) — max 3 sloty: nowy node [NOWY]
└─ vps-i1 (217.154.82.162) — max 2-3 sloty: lekkie taski
EXECUTION:
spawn-worker.sh → claude -p
Heartbeat 60s → PATCH status + token_tick events
CAPACITY TOTAL: ~11-12 równoległych agentów bez nowego serwera
Uwaga: Jeśli bms-3 CPU okaże się niewystarczający (MongoDB PRIMARY + staging + agenty) → wtedy zakup nowego serwera. Testować pod obciążeniem przez 2 tygodnie przed decyzją o bms-5.
3. Architektura SaaS AI Metering
3.1 Pozycjonowanie
Nowy serwis ai-worker jest odrębny od CF Worker dispatcha (który obsługuje dev-issues/infra taski). Inne semantyki: sub-sekundowa admisja, auth per-project, billing, różne typy job.
Client Apps (BrandPilot, Art Agency, future SaaS)
│
│ POST /ai/jobs (X-AI-API-Key header)
▼
Supabase Edge Function (admission layer):
1. Weryfikacja klucza API → resolve project_id, client_id
2. Rate limit check (ai_rate_limits)
3. Budget check (ai_usage month aggregate)
4. INSERT ai_jobs
5. Redis LPUSH → BullMQ queue notification
Returns: {job_id, status: "queued"}
│
▼
BullMQ queues (Redis bms-4):
ai:strategy — concurrency 1 (Claude Opus, 5-min timeout)
ai:article — concurrency 3 (Claude Sonnet, 2-min timeout)
ai:script — concurrency 5 (Claude Sonnet, 1-min timeout)
ai:heygen — concurrency 10 (async poll, near-instant)
ai:batch — concurrency 3 (Claude Sonnet, 2-min per item)
ai:analysis — concurrency 2 (Playwright + Claude, 10-min timeout)
│
▼
FastAPI Worker Service (bms-4 :8200):
1. Claim job (SELECT FOR UPDATE SKIP LOCKED z ai_jobs)
2. Call AI API (Anthropic/HeyGen/Playwright)
3. Capture token usage z API response
4. Upload wynik → Wasabi ai-results/{project_id}/{job_id}
5. INSERT ai_usage (tokens, cost_usd)
6. UPDATE ai_rate_limits (counters)
7. Fire webhook do klienta
8. Log events → ai_job_events
│
▼
Klient: webhook lub polling GET /ai/jobs/:id
3.2 Typy zadań i timeouty
| Job type | Model | Timeout | Retry | Delivery |
|---|---|---|---|---|
marketing_strategy | claude-opus-4-8 | 5 min | 2× | Wasabi PDF |
article | claude-sonnet-4-6 | 2 min | 3× | Wasabi MD + HTML |
video_script | claude-sonnet-4-6 | 1 min | 3× | Wasabi MD |
heygen_video | heygen-v2 | Submit: 30 s / Poll: 30 min | 1× | Wasabi MP4 URL |
batch_articles | claude-sonnet-4-6 | 2 min/elem | 3× | Wasabi ZIP |
competitive_analysis | claude-sonnet-4-6 | 10 min | 2× | Wasabi PDF |
3.3 Kalkulacja kosztów
# Ceny modeli (USD per 1M tokenów):
MODELS = {
'claude-opus-4-8': {'input': 15.00, 'output': 75.00},
'claude-sonnet-4-6': {'input': 3.00, 'output': 15.00},
'claude-haiku-3-5': {'input': 0.80, 'output': 4.00},
'heygen-v2': {'flat_per_call': 0.30}, # ~$0.30-0.50 za wideo
}
# W workerze po każdym call do Claude API:
usage = message.usage
cost_usd = (usage.input_tokens / 1_000_000) * model['input'] \
+ (usage.output_tokens / 1_000_000) * model['output']3.4 Kluczowe tabele (DDL)
Pełne DDL w osobnym pliku: supabase/migrations/048_ai_job_queue.sql
Podsumowanie tabel:
ai_models— rejestr modeli z kosztami per 1M tokenówai_jobs— kolejka zadań z maszyną stanów (queued → processing → completed/failed/awaiting_external)ai_job_events— append-only log zdarzeń per job (submitted, claimed, started, completed, failed, webhook_sent)ai_usage— jeden wiersz per completed job z tokenami i cost_usd (billing source of truth)ai_rate_limits— limity per projekt/klient z atomowymi counterami
3.5 2-tygodniowy plan MVP (BrandPilot)
Tydzień 1 (równolegle):
[A] Migration 048: DDL ai_jobs, ai_usage, ai_models, ai_rate_limits
[B] Scaffold ai-worker (FastAPI + BullMQ) na bms-4 :8200 + Traefik route
[C] Extend queue-exporter: dodaj ai_jobs do QUEUES + 3 nowe Gauge
[D] Claude article worker: claim → Anthropic API → upload MD → Wasabi → done
[E] Edge Function: POST /ai/jobs (admission + rate limit + insert + Redis notify)
[F] Edge Function: GET /ai/jobs/:id (status polling)
Tydzień 2:
[G] Cost recording: INSERT ai_usage po każdym Claude call (potrzebuje A+D)
[H] Rate limiting w Edge Function (potrzebuje A+E)
[I] Webhook delivery z workera (potrzebuje D)
[J] Integracja BrandPilot: zastąp bezpośrednie Anthropic calls przez POST /ai/jobs
[K] Grafana dashboard: queue depth + cost panels (potrzebuje C+G)
[L] Migration 049: ai_api_keys + provisioning dla BrandPilot
Human-action (GH issues, nie blokują):
[H1] HeyGen API key → secrets/n8n-bms4.env.sops
[H2] Zatwierdzenie Traefik route dla :8200
4. Analiza pojemności — plan sprzętowy
4.1 Obecne obciążenie (podstawa planowania)
| Serwer | RAM wolne (szacunek) | CPU headroom | Rola |
|---|---|---|---|
| vps-i1 | ~1 GB | minimal | NA GRANICY — nie dodawać nic |
| vps-h1 | ~5 GB | moderate | Frozen — WAHA only |
| bms-1 | ~10 GB | moderate | Pinbox24 prod — nie dotykać |
| bms-2 | ~26 GB | moderate | MongoDB rs0 PRIMARY (voting member, priority 1) — brak agentów |
| bms-3 | ~4 GB | tight | MongoDB rs0 SECONDARY (21.7 GB) + staging |
| bms-4 | ~26 GB | moderate | n8n + 4 agenty + Redis |
4.2 Wymagania rozbudowy
| Komponent | RAM | CPU burst | Gdzie |
|---|---|---|---|
| Playwright × 4 | 2.5–3.5 GB | 4 vCPU | bms-4 |
| SaaS AI worker + BullMQ | 1–3 GB | 5 vCPU | bms-4 |
| 4 nowe agenty na bms-3 | 1.5 GB | 2 vCPU | bms-3 |
| ai-worker serwis FastAPI | 0.3 GB | minimal | bms-4 |
bms-4 po rozbudowie: ~13 GB / 32 GB RAM (40%) — OK
bms-4 CPU burst: ~14 vCPU vs. 8 fizycznych — potencjalna contention
4.3 Decyzja sprzętowa
Etap 1 (teraz, 0 PLN):
→ Uruchom Playwright × 4 + SaaS microservices na bms-4
→ Uruchom 3-4 dodatkowych agentów na bms-3
→ Monitoruj CPU bms-4 pod obciążeniem przez 2 tygodnie
Etap 2 (jeśli CPU bms-4 saturuje się):
→ Zakup OVH Kimsufi ECO-4 (8 vCPU, 32 GB SSD) ~€60-70/mies
→ Lub OVH Rise-3 (16 vCPU, 64 GB NVMe) ~€140-160/mies (headroom na lata)
→ Dedykowany bms-5 jako "agent farm + SaaS overflow"
Docelowy split pojemności (Etap 2):
bms-4: n8n + WAHA + Playwright × 4 + SaaS microservices + 4 agenty
bms-3: MongoDB PRIMARY + staging + 3-4 agenty (jeśli CPU pozwala)
bms-2: MongoDB rs0 PRIMARY (voting, brak agentów — nie obciążać)
bms-5: 8 agentów (dedykowany)
vps-i1: monitoring + 2-3 agenty
TOTAL: 21-27 równoległych agentów
4.4 GPU — rekomendacja
Nie kupować dedykowanego serwera GPU.
Workloady AI (Whisper, SDXL, embeddings) są burstowe i nieciągłe. RunPod Serverless pokrywa potrzeby:
| Use case | Provider | Koszt/mies |
|---|---|---|
| Whisper (transkrypcja) | RunPod Serverless A10G | ~$10 |
| SDXL (generacja obrazów) | RunPod Spot RTX 4090 | ~$8 |
| 32B LLM (raporty audit) | RunPod A100 80GB | ~$160 max |
| Łącznie | $10-160 zmienny |
Architektura nightly GPU batch już udokumentowana w docs/ai-batch-gpu-operations.md. PR #583 gotowy — uruchomić gdy pojawi się pierwszy use case.
4.5 MongoDB — kiedy skalować
| Trigger | Akcja | Kiedy |
|---|---|---|
| mongod RSS na bms-3 > 26 GB | Planuj migrację do serwera 64 GB | Monitoruj miesięcznie |
| Read QPS > 500/s | Dodaj read replica (nowy węzeł) — bms-2 jest już full voting member | Na demand |
| Single collection > 100 GB | Rozważ sharding | Nie teraz |
Teraz: Przenieś Pinbox24 staging z bms-3 na bms-4 → wolni ~3-4 GB RAM dla MongoDB na bms-3.
5. Reporting — pipeline oparty na plikach
5.1 Architektura (DuckDB + Parquet na Wasabi)
Dlaczego DuckDB: Zero nowego serwera. Działa jako biblioteka Python. Czyta Parquet bezpośrednio z S3 przez httpfs. Supabase dostaje tylko bounded SELECT raz na dobę. Storage: ~180 MB/rok, koszt Wasabi < $0.002/mies.
Nightly ETL (01:00 UTC, cron na vps-i1):
scripts/nightly-etl/
export_supabase.py → dev_r_services, agent_tasks, ai_usage, incidents
export_prometheus.py → metryki kosztów, uptime, alert history (Thanos Query API)
export_github.py → issues, PRs, resolution times
export_n8n.py → execution history (SSH + psql na bms-4)
export_atrax.py → p24_gps_daily_stats, p24_driver_ecodriving_daily,
p24_atrax_drivers_daily (+ anomalie paliwowe, patrz #6138)
run_etl.sh → orchestruje wszystko, push metric do pushgateway
→ Wasabi: reporting/{table}/{YYYY-MM-DD}.parquet
→ Wasabi: reporting/atrax/{table}/{YYYY-MM-DD}.parquet
Report Query API (FastAPI sidecar vps-i1 :9230):
GET /query?sql=SELECT... → DuckDB query na S3 Parquet → JSON
Grafana "Infinity" datasource → bez pluginu → wyniki w dashboardzie
Miesięczny raport PDF (1. każdego miesiąca):
export_monthly_billing.py → DuckDB aggregation → Jinja2 → pdf-service :8100 → Wasabi → email Mailgun
(reuse 100% z report_scheduler.py — tylko swap fetch_cars() → duck_query())
5.2 Eksportowane dane
| Źródło | Tabele/metryki | Retencja Parquet |
|---|---|---|
| Supabase | agent_tasks, audit.runs, incidents, dev_r_services, ai_usage | 2 lata |
| Prometheus/Thanos | koszty, uptime, alert history | 1 rok |
| GitHub | issues, PRs, resolutions | bezterminowo |
| n8n | executions, error rate | 1 rok |
| secrets-rotation-log.md | parsowany Markdown → JSON | bezterminowo |
| Atrax (fuel/ecodriving) | p24_gps_daily_stats, p24_driver_ecodriving_daily, p24_atrax_drivers_daily, anomalie paliwowe — patrz #6138 (blocked na #5921) | 10 lat (spójne z atrax-archival.py) |
5.3 Nowe alerty Prometheus (ETL health)
# monitoring/rules/reporting-etl.yml
- alert: ReportingETLStale
expr: time() - etl_last_success_timestamp > 86400
labels: {severity: warning}
annotations:
summary: "Reporting ETL nie uruchomił się od >24h — raporty mogą być nieaktualne"6. Najsłabsze elementy — plan naprawy
6.1 Ranking słabości (posortowane po blast radius × detection time)
| # | Element | Blast radius | MTTD | MTTR | Fix | Effort | Priorytet |
|---|---|---|---|---|---|---|---|
| 1 | bms-1 Ubuntu 20.04 EOL | Pinbox24 prod down + CVE | Dni–tygodnie | Dni | Distro upgrade per playbook #1683 | 1 dzień (human) | 🔴 P1 |
| 2 | n8n workflows nie w git | Utrata wszystkich definitons jeśli bms-4 DB padnie | Natychmiastowy | Dni (manual) | Nightly n8n export:workflow --all → git push | 2 h | 🔴 P1 |
| 3 | MongoDB restore >4 mies. | Silent backup corruption → katastrofa przy restore | Nigdy | Nieznany | Drill teraz, automat kwartalny | 4 h | 🔴 P1 |
| 4 | bms-1/2/3 bez Prometheus | MTTD dla prod disk/RAM = 24 h | 24 h | 30 min | Ansible role node_exporter na 3 serwerach | 1 dzień | 🔴 P1 |
| 5 | bms-4 role overload | n8n + Redis + arbiter + agenty = 4 SPoF w 1 | 5–26 h | 30 min | Przenieś arbiter na vps-i1 (lekka usługa) | 1 dzień | 🟡 P2 |
| 6 | socat-supabase tunnel na bms-4 | Cascade failure: n8n + triage + raporty | < 5 min | 15 min (ręczny restart) | Watchdog cron co 5 min — auto-restart przed awarią | 3 h | 🟡 P2 |
| 7 | ANTHROPIC_API_KEY/OAuth collision | Każdy nowy skrypt na bms-4 może użyć API key zamiast OAuth | Potencjalnie nigdy (silent) | N/A | Izoluj n8n env w Docker-scope, nie sourcować do claude-runner shell | 1 dzień | 🟡 P2 |
| 8 | Claude runner OAuth expiry | Nightly triage stop | 26 h | 15 min | Pre-expiry refresh cron o godz. 7 | 4 h | 🟡 P2 |
| 9 | GitHub jako jedyny control plane | GitHub outage = wszystko autonomiczne zatrzymuje się | 15 min (brak probe) | N/A (zewnętrzne) | GitHub API heartbeat probe co 15 min → Discord alert < 15 min | 2 h | 🟡 P2 |
| 10 | secrets-sync.yml silent failure | Serwery z przeterminowanymi credentialami | Potencjalnie zero (stary klucz działa) | Minuty | Alert: brak infra_operations row dla deploy w 48h po SOPS commit | 3 h | 🟡 P2 |
| 11 | vps-h1 WAHA jako SPoF | WhatsApp gateway kompletnie down | 5 min | 30 min–kilka godzin | Blackbox external probe + warm standby runbook na vps-i1 | 1 dzień | 🟡 P2 |
| 12 | bms-2 secondary monitoring stack | Konflikty portów jeśli ktoś edytuje sieć bms-2 | Nigdy (nieznany stan) | Nieznany | SSH audit: docker ps na bms-2 → decommission lub zarejestruj | 2 h | 🟢 P3 |
| 13 | Tier 2 duplikat agent spawn | 2 agenty na tym samym issue → konflikt PR | Nigdy (silent) | Manualna kasacja | Label ai-dev-spawned before spawn, check in triage | 2 h | 🟢 P3 |
6.2 3 systemowe luki architektury
1. GitHub jako jedyny control plane Każdy mechanizm autonomii (secrets-sync, CI, issue queue, agent spawn przez GH API) zależy od GitHub. Jedna awaria zatrzymuje wszystko bez ostrzeżenia. Fix: GitHub heartbeat probe co 15 min → Discord alert w < 15 min. Long-term: lokalny fallback scheduler na bms-4 z offline queue (dla zadań pilnych).
2. socat-supabase zombie crash-loop na bms-4 Tunel między n8n a Supabase PostgreSQL przez lokalny socat na porcie 15432 to ukryta zależność. Gdy zombie process trzyma socket — n8n, nightly triage, raporty i routing alertów padają jednocześnie, wyglądając jak 4 niezwiązane alarmy. Playbook istnieje, ale brak watchdoga który wykryje problem w 5 min zamiast w moment gdy n8n workflow krzyknie timeout.
3. ANTHROPIC_API_KEY/OAuth scope collision
.env na bms-4 zawiera ANTHROPIC_API_KEY dla n8n workflows. Shell claude-runnera może odziedziczyć tę zmienną i użyć API key zamiast OAuth — cicho, bez błędu, ale z kosztem i risk rate-limit. Każdy nowy skrypt na bms-4 może wpaść w tę pułapkę jeśli deweloper nie wie o niej. Systemowe rozwiązanie: env n8n wyłącznie w Docker-compose scope (.env file), nigdy sourced do claude-runner environment.
7. Mapa wdrożenia
Faza 1 — Stabilizacja (Tydzień 1, ~8 dni pracy)
Natychmiast (równolegle, < 1 dzień):
[1] Restore drill MongoDB na bms-2 — uruchom verify-backup-restore.sh
[2] Nightly n8n workflow export → git (cron na bms-4 + GH push)
[3] Fix health-check.yml Discord spam (notifikacja tylko przy zmianie stanu)
[4] Fix socat-supabase watchdog (cron co 5 min, auto-restart)
Tydzień 1 (po stabilizacji):
[5] node_exporter na bms-1/2/3 (Ansible role)
[6] Prometheus gauge: nightly triage pass/fail per phase
[7] Tabela dev_r_ops_events (DDL + writer w hourly triage)
[8] Label ai-dev-spawned guard w hourly triage
[9] GitHub heartbeat probe → Discord alert
[10] Izolacja ANTHROPIC_API_KEY do Docker-scope na bms-4
Faza 2 — Skala kolejki (Tydzień 2, ~5 dni pracy)
[11] bms-3 jako dispatch node (Ansible + dev_r_server_capacity insert)
[12] Cost attribution columns w dev_r_worker_queue
[13] Billing tier priority w classify.ts
[14] SaaS job types w queue (job_type check + spawn-worker.sh cases)
[15] Grafana: queue depth by tier + cost per client dashboard
Faza 3 — SaaS AI Metering (Tydzień 3-4, ~10 dni pracy)
[16] Migration 048: ai_jobs, ai_usage, ai_models, ai_rate_limits (DDL)
[17] ai-worker FastAPI scaffold na bms-4 :8200
[18] Claude article worker (claim → API → Wasabi → done)
[19] Supabase Edge Function: POST /ai/jobs (admission)
[20] Cost recording po każdym Claude call
[21] Rate limiting w admission
[22] Webhook delivery z workera
[23] BrandPilot integracja
[24] Grafana AI cost dashboard
Faza 4 — Reporting + DR (Tydzień 5-6, ~8 dni pracy)
[25] DuckDB reporting ETL (export_supabase.py, export_prometheus.py, run_etl.sh)
[26] report-query-api na vps-i1 :9230 (FastAPI + DuckDB)
[27] Grafana Infinity datasource → raporty compliance
[28] Miesięczny PDF raport (Jinja2 + pdf-service)
[29] DR playbooks: disaster-recovery.md, bms1-total-failure.md, vps-i1-rebuild.md
[30] Playbook audit: dodaj last_verified do wszystkich 108 playbooki
Faza 5 — Hardware (Tydzień 7+, decyzja po testach)
[31] Ocena CPU bms-4 po 2 tygodniach z Playwright × 4 + SaaS
[32] Jeśli saturacja: zakup bms-5 (OVH ECO-4 lub Rise-3)
[33] Migracja Pinbox24 staging z bms-3 na bms-4 → wolni RAM dla MongoDB
[34] RunPod setup dla GPU batch (PR #583 gotowy)
8. Metryki sukcesu
| KPI | Teraz | Cel (8 tyg.) |
|---|---|---|
| MTTD bms-1 disk/RAM | 24 h | < 2 min |
| Liczba równoległych agentów | 6-7 | 11-12 |
| Restore drill MongoDB | Overdue | Miesięcznie (automatyczny) |
| Pokrycie playbooki | 108 (brak DR) | +8 nowych, wszystkie z last_verified |
| Discord false-positive rate | ~12 notif/dobę | ~1-2 na dobę (state-change only) |
| Change tracking | git + rotation log | + dev_r_ops_events (real-time) |
| AI job billing | Brak | cost_usd per job, dashboard per projekt |
| Reporting | Manual / Supabase | Nightly Parquet ETL + DuckDB query API |
9. Pliki do stworzenia (backlog)
| Plik | Typ | Faza |
|---|---|---|
supabase/migrations/048_ai_job_queue.sql | DDL | 3 |
infra-src/ai-worker/ | FastAPI service | 3 |
supabase/functions/ai-jobs/index.ts | Edge Function | 3 |
monitoring/rules/ai-jobs.yml | Alert rules | 3 |
scripts/nightly-etl/run_etl.sh | ETL orchestrator | 4 |
infra-src/report-query-api/ | FastAPI + DuckDB | 4 |
docs/ai-worker-operations.md | Workbook | 3 |
docs/reporting-etl-operations.md | Workbook | 4 |
docs/playbooks/disaster-recovery.md | Playbook | 4 |
docs/playbooks/bms1-total-failure.md | Playbook | 4 |
docs/playbooks/vps-i1-rebuild.md | Playbook | 4 |
docs/playbooks/pinbox24-rollback.md | Playbook | 4 |
docs/playbooks/supabase-project-suspended.md | Playbook | 4 |
docs/playbooks/agents-capacity-exhausted.md | Playbook | 4 |
Dokument wygenerowany na podstawie 5-agentowej równoległej analizy. 2026-06-27. Następna aktualizacja: po ukończeniu Fazy 1 (~ Tydzień 1).