agnes-the-ai-analyst/docs/REFACTORING_PLAN.md

22 KiB

Refaktoring AI Data Analyst — Finální plán

Kontext

Platforma vznikla iterativně pro interní Keboola a nyní se má stát produktem pro zákazníky (Groupon aj.). Klíčové problémy z transcriptu ZS+Padák: křehký filesystem stav (JSON soubory, permission konflikty), žádné API (vše SSH+skripty), bezpečnost přes Linux skupiny, složitá instalace (10+ kroků). Systém je navržen pro AI agenty — člověk diskutuje s AI, AI řeší vše (user, admin, dev operace).

UX zůstává stejné. Tooling: uv všude místo pip. Docker + Kamal pro server. CLI (da) jako primární rozhraní pro AI agenty.


Architektura — cílový stav

SERVER (Docker + Kamal):
├── webapp        Flask UI (katalog, login, corporate memory)
├── api           FastAPI (CLI backend, sync manifest, data download)
├── scheduler     APScheduler (nahrazuje 7 systemd timerů)
├── telegram-bot  Telegram notifikace
├── ws-gateway    WebSocket pro desktop app
└── script-runner Sandboxovaný runner pro user skripty

LOKÁLNĚ (analytik):
├── da CLI        Python balíček (uv tool install)
├── DuckDB        Embedded (analytics.duckdb → views na parquety)
└── Parquety      Stažené ze serveru přes da sync

DVA DuckDB NA SERVERU:
├── /data/state/system.duckdb      Systémový stav (users, sync_state, knowledge...)
└── /data/analytics/server.duckdb  Views → /data/parquet/** (profiler, remote query, skripty)

JEDEN DuckDB LOKÁLNĚ:
└── user/duckdb/analytics.duckdb   Views → server/parquet/** + user tabulky

Fáze 0: Základ — DuckDB state + repository vrstva

Cíl: Nahradit 10+ JSON souborů DuckDB databází. Eliminovat #1 zdroj outages (file permission konflikty).

Proč DuckDB: Už v stacku, agent může joinovat stav s analytickými daty, lepší než SQLite pro analytické dotazy nad stavem.

Task 0A: DuckDB schema + repository vrstva [INDEPENDENT]

Nové soubory:

  • src/db.py — DuckDB connection management, schema creation, migration system
  • src/repositories/__init__.py
  • src/repositories/sync_state.py — CRUD pro sync stav
  • src/repositories/users.py — CRUD pro uživatele + role
  • src/repositories/knowledge.py — CRUD pro corporate memory
  • src/repositories/table_registry.py — CRUD pro registr tabulek
  • src/repositories/audit.py — audit log
  • src/repositories/notifications.py — telegram links, pending codes, script registry

Schema tabulky (mapování z JSON):

Současný JSON DuckDB tabulka Zdroj soubor
sync_state.json sync_state src/data_sync.py:37-138
sync_settings.json user_sync_settings webapp/sync_settings_service.py:20
knowledge.json knowledge_items webapp/corporate_memory_service.py
votes.json knowledge_votes webapp/corporate_memory_service.py
audit.jsonl audit_log webapp/corporate_memory_service.py
telegram_users.json telegram_links services/telegram_bot/storage.py
pending_codes.json pending_codes services/telegram_bot/storage.py
password_users.json users webapp/password_auth.py
table_registry.json table_registry src/table_registry.py
profiles.json table_profiles src/profiler.py

Přidat navíc: sync_history (posledních 10 syncí per tabulka, ne jen last), script_registry (deployed skripty).

Task 0B: Migrace existujících service souborů na repository [DEPENDS ON 0A]

Soubory k úpravě (nahradit _read_json/_write_json za repository volání):

  • webapp/sync_settings_service.py řádky 40-62
  • webapp/corporate_memory_service.py — 31 JSON operací
  • webapp/telegram_service.py řádky 22-45
  • src/data_sync.py — třída SyncState řádky 37-138
  • src/table_registry.py_load, _atomic_write_json
  • src/profiler.py — uložení profilů
  • services/corporate_memory/collector.py — čtení/zápis knowledge
  • services/telegram_bot/storage.py — 15 JSON operací

Pattern: dual-write (JSON + DuckDB) po přechodnou dobu → ověřit → smazat JSON zápisy.

Task 0C: Migrační skript [DEPENDS ON 0A]

  • scripts/migrate_json_to_duckdb.py — načte všechny JSON, vloží do DuckDB
  • Idempotentní (safe to run multiple times)
  • Validace po migraci (count porovnání)

Co se NEMĚNÍ v Fázi 0

  • Flask routes v webapp/app.py
  • HTML šablony
  • Konektory (connectors/keboola/, connectors/bigquery/, connectors/jira/)
  • src/config.py (čte data_description.md — konfigurace, ne stav)
  • config/loader.py (čte instance.yaml)
  • src/parquet_manager.py

Fáze 1: API vrstva (FastAPI)

Cíl: REST API pro CLI. Všechny operace co dnes vyžadují SSH.

Task 1A: FastAPI základ + auth [INDEPENDENT od 0B, DEPENDS ON 0A]

Nové soubory:

api/
  __init__.py
  app.py              # FastAPI app, middleware, CORS
  auth.py             # JWT vydávání + validace
  dependencies.py     # DI pro DuckDB session, current_user

Auth flow:

  1. POST /api/auth/login — přijme OAuth token z webappu, vydá JWT
  2. POST /api/auth/token — přijme API key, vydá JWT
  3. JWT obsahuje: user_id, email, role, expiry
  4. Middleware validuje JWT na všech /api/* endpoints

Task 1B: Sync + Data endpointy [DEPENDS ON 1A, 0A]

api/routers/
  sync.py             # GET /api/sync/manifest, POST /api/sync/trigger
  data.py             # GET /api/data/{table}/download (parquet stream)
  • /api/sync/manifest — vrátí hashe všech parquetů, docs, rules, profilů (filtrované per-user dle subscription)
  • /api/data/{table}/download — streaming parquet souboru s ETag/If-None-Match
  • /api/sync/trigger — spustí DataSyncManager (reuse src/data_sync.py)

Task 1C: Query + Scripts endpointy [DEPENDS ON 1A, 0A]

api/routers/
  query.py            # POST /api/query (remote query)
  scripts.py          # POST /api/scripts/run, /deploy, /list
  • /api/query — reuse src/remote_query.py, výsledek jako JSON/parquet
  • /api/scripts/run — spustí Python skript v sandboxu na serveru
  • /api/scripts/deploy — nahraje skript + registruje v scheduleru
  • /api/scripts/list — deployed skripty s jejich schedules

Task 1D: User management + Corporate memory endpointy [DEPENDS ON 1A, 0A]

api/routers/
  users.py            # CRUD uživatelů, role, permissions
  settings.py         # GET/PUT sync settings per user
  memory.py           # Corporate memory CRUD, voting, governance
  health.py           # GET /api/health (strukturovaná diagnostika)
  upload.py           # POST sessions, artifacts, CLAUDE.local.md

Task 1E: Odstranění SSH/sudo závislostí [DEPENDS ON 1B, 1D]

Smazat/přepsat:

  • webapp/sync_settings_service.py řádky 128-240 (sudo/rsync-filter kód)
  • webapp/user_service.py — Linux user management (pwd.getpwnam, sudo add-analyst)
  • SSH key validace workflow
  • server/sudoers-webapp, server/sudoers-deploy
  • server/bin/add-analyst

Fáze 2: CLI nástroj (da)

Cíl: Jediné rozhraní pro AI agenty. Nahrazuje SSH+skripty. uv tool install.

Task 2A: CLI základ + auth [INDEPENDENT od 1B-1E, DEPENDS ON 1A]

cli/
  __init__.py
  main.py             # Typer app, global options (--server, --json)
  config.py           # ~/.config/da/ management
  client.py           # HTTP client wrapper (auth, retry, streaming)
  commands/
    auth.py           # da login, da logout, da whoami
  • da login → otevře browser pro OAuth → server vydá JWT → uloží do ~/.config/da/token.json
  • da --json flag na všech příkazech pro strukturovaný output
  • da --server URL override (default z config.yaml)

Task 2B: Sync příkazy [DEPENDS ON 2A, 1B]

cli/commands/
  sync.py             # da sync, da sync --table X, da sync --upload-only

Flow:

  1. GET /api/sync/manifest → porovnej s ~/.config/da/sync_state.json
  2. Download změněné parquety (HTTP streaming s progress barem)
  3. Download docs, rules, profily
  4. Upload sessions, artifacts, CLAUDE.local.md
  5. Rebuild DuckDB views (DROP views, CREATE VIEW per tabulka, zachovej user tabulky)
  6. Update lokální manifest

Přepíše funkci scripts/sync_data.sh (475 řádků).

Task 2C: Query + Scripts příkazy [DEPENDS ON 2A, 1C]

cli/commands/
  query.py            # da query "SQL" [--remote] [--json]
  scripts.py          # da scripts list/run/deploy/undeploy
  explore.py          # da explore {table} — profil tabulky
  • da query — lokální DuckDB default, --remote přes server API
  • da scripts run X — lokálně default, --remote přes server
  • da scripts deploy X --schedule "cron" — upload + registrace na serveru
  • da explore orders — profil z lokálních dat (nebo --remote ze serveru)

Task 2D: Admin + Server příkazy [DEPENDS ON 2A, 1D]

cli/commands/
  admin.py            # da admin add-user/remove-user/list-users
  status.py           # da status [--local] — zdraví systému
  server.py           # da server deploy/rollback/logs/status
  diagnose.py         # da diagnose — AI-friendly diagnostika
  • da status — strukturovaný health report (tabulky, sync stav, služby)
  • da status --local — offline: kdy jsem synkoval, kolik dat mám
  • da diagnose — projde logy, sync stav, konektivitu → root cause
  • da server deploy — wrapper kolem kamal deploy
  • da server logs webapp — wrapper kolem kamal app logs

Task 2E: PyPI distribuce [DEPENDS ON 2A]

  • pyproject.toml pro CLI balíček
  • uv tool install data-analyst nebo uv pip install data-analyst
  • Entry point: [project.scripts] da = "cli.main:app"
  • Minimální dependencies: typer, httpx, duckdb, rich (progress bars)

Fáze 3: Docker + Kamal

Cíl: docker compose up pro dev, kamal deploy pro produkci. Nahrazuje 10+ manuálních kroků.

Task 3A: Dockerfile + docker-compose.yml [INDEPENDENT]

Dockerfile              # python:3.13-slim, uv install, jeden image
docker-compose.yml      # webapp, api, scheduler, telegram-bot, ws-gateway
docker-compose.test.yml # api + test-runner pro integrační testy
  • Jeden image, různý CMD per služba
  • Volume /data sdílený mezi kontejnery
  • profiles: ["full"] pro volitelné služby (telegram, ws-gateway)
  • uv sync místo pip install v Dockerfile

Task 3B: Scheduler služba [DEPENDS ON 0A]

Nový soubor: services/scheduler/__main__.py

  • APScheduler (nebo jednoduchý custom) nahrazuje 7 systemd timerů:
Timer Schedule Funkce
data-refresh 15 min DataSyncManager.sync_scheduled()
catalog-refresh 15 min Catalog refresh
corporate-memory 30 min Knowledge collector
session-collector 6h Session collection (z uploaded dat)
user-scripts per-script cron Script runner
profiler po data-refresh Auto-profile nových dat

Task 3C: Kamal konfigurace [DEPENDS ON 3A]

config/
  deploy.yml           # produkční Kamal config
  deploy.staging.yml   # staging override
  • Kamal Proxy pro auto-SSL (Let's Encrypt)
  • Healthcheck na /api/health
  • Zero-downtime deploy
  • Accessories: scheduler, telegram-bot, ws-gateway, script-runner
  • Environment secrets přes Kamal env management

Task 3D: GitHub Actions CI/CD [DEPENDS ON 3A, 3C]

.github/workflows/
  ci.yml               # test + build na každém push
  deploy.yml           # staging na PR, production na merge do main

Flow: push → pytest → integrační testy (docker compose) → build image → push GHCR → kamal deploy staging (PR) / production (merge)

Task 3E: Smazání starého server infra [DEPENDS ON 3A-3D, ověřeno že nové funguje]

Smazat:

  • server/setup.sh (103 řádků)
  • server/webapp-setup.sh (171 řádků)
  • server/deploy.sh (395 řádků)
  • server/migrate-to-v2.sh (146 řádků)
  • Všechny systemd unit soubory (services/*/systemd/)
  • server/sudoers-*
  • server/bin/add-analyst a related skripty
  • scripts/sync_data.sh (475 řádků)
  • server/webapp.service, server/webapp-nginx.conf

Fáze 4: RBAC + bezpečnost

Cíl: Aplikační RBAC místo Linux skupin. Audit trail. Script sandboxing.

Task 4A: Role + permissions v DuckDB [DEPENDS ON 0A]

Nový soubor: src/rbac.py

class Role(Enum):
    VIEWER = "viewer"       # Katalog, čtení dat
    ANALYST = "analyst"     # Sync, queries, voting, skripty
    ADMIN = "admin"         # Správa uživatelů, schvalování knowledge
    KM_ADMIN = "km_admin"  # Corporate memory governance
  • Dataset-level permissions (kdo má přístup ke kterým datům)
  • Přepsat webapp/auth.py řádky 37-65 (admin_required/km_admin_required)
  • Přepsat webapp/user_service.py celý — DB místo pwd.getpwnam() + sudo

Task 4B: Audit trail [DEPENDS ON 0A]

  • Každý API call logován do audit_log tabulky
  • Struktura: timestamp, user_id, action, resource, params, result, duration
  • Agent může: da query "SELECT * FROM system.audit_log WHERE action='sync_trigger' ORDER BY timestamp DESC LIMIT 10"

Task 4C: Script sandboxing [DEPENDS ON 3A]

  • Script-runner jako izolovaný Docker kontejner
  • Read-only přístup k DuckDB
  • Omezená paměť (512MB), čas (5min), žádný network (kromě notification dispatch)
  • Explicitní whitelist Python balíčků (pandas, duckdb, matplotlib)

Task 4D: Corporate memory push model [DEPENDS ON 1D]

  • Uživatelé pushují CLAUDE.local.md přes da sync --upload-only
  • Server nikdy nečte /home/*/ jako root
  • Corporate memory collector zpracovává uploaded data z DB

Dependency graf pro multi-agenty

Fáze 0:
  0A (DuckDB schema) ─────────────────────┐
  0C (migrační skript) ← závisí na 0A     │
  0B (migrace services) ← závisí na 0A    │
                                           │
Fáze 1:                                   │
  1A (FastAPI základ) ← závisí na 0A ─────┤
  1B (sync/data EP) ← závisí na 1A, 0A    │
  1C (query/scripts EP) ← závisí na 1A    │
  1D (users/memory EP) ← závisí na 1A     │
  1E (remove SSH) ← závisí na 1B, 1D      │
                                           │
Fáze 2:                                   │
  2A (CLI základ) ← závisí na 1A          │
  2B (sync cmd) ← závisí na 2A, 1B        │
  2C (query/scripts cmd) ← závisí na 2A   │
  2D (admin/server cmd) ← závisí na 2A    │
  2E (PyPI) ← závisí na 2A               │
                                           │
Fáze 3:                                   │
  3A (Dockerfile) ← INDEPENDENT ──────────┘
  3B (scheduler) ← závisí na 0A
  3C (Kamal) ← závisí na 3A
  3D (CI/CD) ← závisí na 3A, 3C
  3E (cleanup) ← závisí na 3A-3D verified

Fáze 4:
  4A (RBAC) ← závisí na 0A
  4B (audit) ← závisí na 0A
  4C (sandbox) ← závisí na 3A
  4D (push model) ← závisí na 1D

Paralelní agenty — optimální rozložení

AGENT 1: DuckDB + Repositories    AGENT 2: FastAPI           AGENT 3: Docker + Kamal
─────────────────────────────      ─────────────────          ──────────────────────
0A: DuckDB schema                  (čeká na 0A)               3A: Dockerfile + compose
0C: migrační skript                1A: FastAPI základ          3B: scheduler služba
0B: migrace services               1B: sync/data EP           3C: Kamal konfigurace
4A: RBAC                           1C: query/scripts EP       3D: CI/CD workflow
4B: audit trail                    1D: users/memory EP        4C: script sandbox
                                   1E: remove SSH deps

AGENT 4: CLI + Skills              AGENT 5: Integrace + Cleanup
─────────────────────               ───────────────────────────
(čeká na 1A)                        (čeká na agents 1-4)
2A: CLI základ + auth               End-to-end testování
2B: sync příkazy                    3E: smazání starého infra
2C: query/scripts příkazy           4D: corporate memory push
2D: admin/server příkazy            5A: CLAUDE.md template update
2E: PyPI distribuce                 Dokumentace update
5B: CLI skills (help/docs)
5C: da setup (interactive)
5D: da diagnose
5E: da infra (multi-customer)

Znovupoužité vs. přepsané soubory

Beze změny (business logika zachována)

  • src/config.py — TableConfig, Config parsing (625 řádků)
  • src/parquet_manager.py — Parquet conversion engine
  • connectors/keboola/adapter.py + client.py
  • connectors/bigquery/adapter.py + client.py
  • connectors/jira/ — celý connector
  • connectors/llm/ — LLM abstrakce
  • connectors/openmetadata/ — katalog enrichment
  • webapp/config.py, config/loader.py
  • webapp/templates/ — všechny HTML šablony
  • src/remote_query.py — query logika (zabalená API)
  • src/profiler.py — profiling logika (output do DuckDB)

Přepojené na DuckDB (logika zachována, I/O vrstva vyměněna)

  • webapp/corporate_memory_service.py
  • webapp/sync_settings_service.py
  • webapp/telegram_service.py
  • src/data_sync.py (SyncState třída)
  • src/table_registry.py
  • services/corporate_memory/collector.py
  • services/telegram_bot/storage.py

Přepsané

  • webapp/user_service.py — DB místo Linux users
  • webapp/auth.py řádky 37-65 — RBAC místo Linux skupin

Nové

  • src/db.py, src/repositories/, src/rbac.py
  • api/ — celý FastAPI server
  • cli/ — celý CLI nástroj
  • Dockerfile, docker-compose*.yml, config/deploy*.yml
  • services/scheduler/__main__.py
  • .github/workflows/ci.yml, .github/workflows/deploy.yml

Smazané

  • server/setup.sh, server/webapp-setup.sh, server/deploy.sh
  • server/migrate-to-v2.sh
  • server/sudoers-*, server/bin/add-analyst
  • scripts/sync_data.sh
  • Všechny services/*/systemd/ soubory
  • server/webapp.service, server/webapp-nginx.conf

Fáze 5: Agent Skills (CLAUDE.md + CLI skills)

Cíl: AI agent má vestavěné znalosti pro nasazení, administraci, diagnostiku a vývoj. Nemusí nic googlit — vše je v skills.

Task 5A: CLAUDE.md template pro analytiky [INDEPENDENT]

Aktualizovat docs/setup/claude_md_template.md:

  • Instrukce pro da CLI místo SSH/rsync
  • da sync jako povinný start session
  • Jak pracovat s lokálním DuckDB
  • Jak vytvářet a deployovat skripty
  • Jak používat corporate memory
  • Notifikační vzory (lokální vs serverové)

Task 5B: Admin/Deploy skills v CLI [DEPENDS ON 2D]

da CLI bude obsahovat vestavěné skills — dlouhé help texty s domain knowledge, které AI agent přečte přes da <command> --help nebo da skills <topic>:

da skills list                    # seznam všech dostupných skills
da skills setup                   # kompletní průvodce setup nové instance
da skills troubleshoot            # diagnostické postupy
da skills connectors              # jak přidat nový data source
da skills notifications           # jak fungují notifikace
da skills corporate-memory        # governance, approval flow
da skills security                # RBAC, permissions, audit
da skills backup-restore          # disaster recovery
da skills upgrade                 # jak upgradovat verzi

Každý skill = markdown soubor v cli/skills/ který se zobrazí přes da skills <name>.

Task 5C: Interaktivní setup skill [DEPENDS ON 2D, 1A]

da setup                          # AI agent spustí interaktivní setup

Flow (agent řídí):

  1. da setup init → vygeneruje instance.yaml z konverzace s uživatelem
  2. da setup test-connection → ověří credentials (Keboola/BigQuery)
  3. da setup deploydocker compose up nebo kamal deploy
  4. da setup first-sync → triggeruje první data sync
  5. da setup verify → healthcheck, počet tabulek, sample query
  6. da setup add-user → přidá prvního analytika

Každý krok vrací strukturovaný JSON → agent ví co dělat dál.

Task 5D: Diagnose skill [DEPENDS ON 2D, 1D]

da diagnose                       # kompletní diagnostika
da diagnose --symptom "data not updating"    # cílená diagnostika
da diagnose --component scheduler            # diagnostika jedné služby

Output (strukturovaný pro agenta):

{
  "overall": "degraded",
  "checks": [
    {"name": "api", "status": "ok", "latency_ms": 12},
    {"name": "scheduler", "status": "ok", "last_run": "2026-03-27T08:00"},
    {"name": "data_freshness", "status": "warning",
     "detail": "table 'orders' last synced 26h ago, expected 15min",
     "suggested_action": "da server logs scheduler | grep orders"},
    {"name": "disk", "status": "ok", "usage": "45%"},
    {"name": "duckdb", "status": "ok", "tables": 47, "total_rows": "12.3M"}
  ],
  "suggested_actions": [
    "Check scheduler logs for 'orders' sync failures",
    "Run: da server logs scheduler --since 24h | grep -i error"
  ]
}

Task 5E: Operační skills pro multi-customer [DEPENDS ON 3C]

da infra list                     # seznam zákaznických instancí
da infra provision --customer acme --cloud gcp --region europe-west1
da infra status acme              # zdraví zákaznické instance
da infra deploy acme              # deploy na zákaznický server
da infra backup acme              # snapshot dat

Budoucí rozšíření — Terraform pod kapotou pro provision, Kamal pro deploy.


Verifikace

Per-fáze

  1. Fáze 0: pytest tests/ zelený, webapp funguje identicky s DuckDB backendem
  2. Fáze 1: curl /api/health → ok, curl /api/sync/manifest → manifest, parquet download funguje
  3. Fáze 2: da login && da sync vytvoří identickou strukturu jako sync_data.sh, da query funguje offline
  4. Fáze 3: docker compose up → všechny služby běží, kamal deploy -d staging → staging funguje
  5. Fáze 4: viewer nemůže triggerovat sync, admin může spravovat uživatele, skripty běží v sandboxu

End-to-end test (celý flow)

  1. docker compose up -d (nebo kamal deploy)
  2. Přes webapp: přihlásit se, vybrat datasety
  3. da login && da sync → parquety lokálně
  4. da query "SELECT count(*) FROM orders" → výsledek offline
  5. da scripts run sales_alert → lokální exekuce
  6. da scripts deploy sales_alert --schedule "0 8 * * MON" → serverová exekuce
  7. da sync --upload-only → sessions/artifacts na serveru
  8. Corporate memory: knowledge items viditelné ve webappu
  9. Telegram notifikace doručeny
  10. da diagnose → strukturovaný health report