diff --git a/memory-bank/creative/creative-tenant-settings-ui.md b/memory-bank/creative/creative-tenant-settings-ui.md new file mode 100644 index 0000000..10f55ed --- /dev/null +++ b/memory-bank/creative/creative-tenant-settings-ui.md @@ -0,0 +1,77 @@ +# Creative: Tenant Settings UI (CP-1) + +📌 **CREATIVE PHASE START: Tenant Settings Module** +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +## 1️⃣ PROBLEM + +**Description:** Tenant-настройки (`global_settings`, `/v1/settings`) разбросаны: вкладка «Система» в Operations и форма BIRD на `/network`. `/settings` зарезервирован под frontend (токен, тема). Нужен отдельный модуль без смешения с browser settings. + +**Requirements:** +- Один route для всех tenant KV (BIRD, revision retention, custom) +- Роли: viewer — read; operator — PATCH +- Переиспользовать существующие схемы (`bird-settings.schema`, `revision-settings.schema`, `settings-api.ts`) +- Убрать дубли из Operations и Network + +**Constraints:** +- Контракт API не менять на UI-фазе +- shadcn-svelte, Svelte 5 runes, superforms +- WEB-16: ConfirmDialog для удаления custom keys + +## 2️⃣ OPTIONS + +| Option | Описание | +|--------|----------| +| **A** | Одна страница `/tenant-settings` с Tabs: BIRD / Ревизии / Дополнительно | +| **B** | Три отдельных route: `/tenant-settings/bird`, `/revision`, `/extra` | +| **C** | Accordion на одной длинной странице без tabs | +| **D** | Оставить BIRD на Network, перенести только revision+KV | + +## 3️⃣ ANALYSIS + +| Criterion | A Tabs | B Multi-route | C Accordion | D Partial | +|-----------|--------|---------------|-------------|-----------| +| Discoverability | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | +| Соответствие плану | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐ | +| Меньше дублирования | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ | +| Сложность реализации | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | +| Консистентность с Monitoring/Ops tabs | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐ | + +**Key insights:** +- Monitoring уже использует `Tabs` (`system` / `postgres`) — паттерн знаком оператору. +- BIRD и revision логически связаны с pipeline/bundles — держать вместе усиливает «единый центр tenant config». +- Отдельные routes (B) дают deep links, но избыточны для ~10 полей. + +## 4️⃣ DECISION + +**Selected: Option A** — `/tenant-settings` с тремя вкладками. + +**Navigation:** +- **mainNav** (не bottom): новый пункт **`Параметры`** → `/tenant-settings`, icon `SlidersHorizontal` +- **bottomNav** `/settings` — без изменений семантики («Настройки интерфейса») +- **Network:** Card «BIRD (кратко)» + кнопка «Изменить параметры» → `/tenant-settings?tab=bird` +- **Operations:** удалить tab `system`; в quick actions / empty state — ссылка на `/tenant-settings` + +**Tab structure:** + +| Tab value | Label | Компонент | Сохранение | +|-----------|-------|-----------|------------| +| `bird` | BIRD | `TenantBirdSettingsCard` (из `BirdSettingsForm`) | PATCH known bird_* | +| `revision` | Ревизии | `TenantRevisionSettingsCard` | PATCH `revision_retention_minutes` | +| `additional` | Дополнительно | `TenantAdditionalSettingsCard` | PATCH custom KV, operator | + +**URL:** `?tab=bird|revision|additional` (как Operations `?tab=jobs`). + +**Rationale:** минимальный diff, один mental model «параметры tenant», переиспользование tabs-паттерна Monitoring. + +## 5️⃣ IMPLEMENTATION NOTES + +- `web/src/routes/tenant-settings/+page.svelte` — PageHeader + Tabs +- Вынести карточки в `web/src/lib/components/tenant-settings/` +- Общий `loadSettings()` / `patchSettings()` из `settings-api.ts` +- PageHeader description: «Параметры control plane для текущего tenant (API /v1/settings)» +- Не показывать на этой странице token/theme +- После миграции: удалить `OperationsSystemSettingsTab`, упростить `network/+page.svelte` + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +📌 **CREATIVE PHASE END: Tenant Settings UI** diff --git a/memory-bank/tasks.md b/memory-bank/tasks.md index b326bad..4f54a34 100644 --- a/memory-bank/tasks.md +++ b/memory-bank/tasks.md @@ -2,31 +2,362 @@ ## Current Task -**[Не определена]** — пользователь вызвал `/van` без описания задачи. +**settings-ui-and-runtime-logs** -## Status +| Поле | Значение | +|------|----------| +| **Task ID** | `settings-ui-and-runtime-logs` | +| **Complexity** | **Level 4** | +| **Status** | **PLAN complete** → `/creative` | +| **Дата VAN** | 2026-06-12 | +| **Дата PLAN** | 2026-06-12 | -- [x] VAN: platform detection -- [x] VAN: Memory Bank verification & creation -- [x] VAN: baseline project context -- [ ] Task definition (от пользователя) -- [ ] Complexity determination (Level 1–4) -- [ ] Implementation plan -- [ ] Execution -- [ ] Documentation / reflect +--- -## Candidate Context (из git, не подтверждено) +## Resolved Decisions (от заказчика) -Возможное продолжение работы над **Maintenance Policies UI**: +| # | Вопрос | Решение | +|---|--------|---------| +| 1 | `/settings` vs tenant | **`/settings` — только frontend** (токен, тема, localStorage). **Tenant-настройки — отдельный модуль** (новый route + nav). | +| 2 | Очистка больших логов | **Синхронно** (HTTP 200/4xx/5xx), без `jobs.Registry` / 202. | +| 3 | Где FS API | **Только `evobgp-all`** с bind-mount volume на runtime-logs. На `evobgp-api` — `503` или отсутствие маршрута. | +| 4 | Audit очистки | **Да** — персистентный audit в PostgreSQL (и sqlite для паритета). | -- `MaintenancePoliciesTab.svelte` — вкладка политик в мониторинге -- `policy-schedule.ts` — редактор cron-расписания (5-field, UTC) +--- -## Requirements +## Requirements Summary -_Ожидается формулировка задачи от пользователя._ +### A. Web UI — два независимых модуля -Пример: +| Модуль | Route (план) | Данные | Роль | +|--------|--------------|--------|------| +| **Frontend settings** | `/settings` (существует) | localStorage, theme | любой пользователь UI | +| **Tenant settings** | `/tenant-settings` (новый) | `GET/PATCH /v1/settings` → `global_settings` | viewer read / operator write | + +**Tenant module** объединяет сейчас разрозненное: +- `OperationsSystemSettingsTab` → revision + custom KV (убрать из Operations) +- `BirdSettingsForm` → BIRD keys (убрать с `/network` или оставить read-only summary + ссылка) + +**`/settings` не трогать семантически** — только polish (заголовки, пояснения что это настройки браузера). + +### B. Runtime logs — FS + +- Корень: `EVOBGP_RUNTIME_LOGS_DIR` (prod default: `/opt/evobgp/runtime-logs`) +- Источник файлов: sidecar `stack-runtime-logs` (без изменений) +- API: list / stat / tail / cleanup (sync) +- Audit: каждая операция cleanup → запись в БД + +--- + +## Technology Validation + +| Технология | Версия / статус | Примечание | +|------------|-----------------|------------| +| Go stdlib `os`, `path/filepath` | 1.24 | FS read/truncate; без новых deps | +| PostgreSQL + sqlite миграции | 000026 | audit table | +| OpenAPI 3.1 | `docs/openapi.yaml` | новые paths под tag `RuntimeLogs` | +| SvelteKit 5 + shadcn | web/ | новые routes/components | +| Compose bind mount | `deploy/compose/*` | volume на `evobgp-all` | + +**PoC не требуется** — паттерны audit и settings уже в репозитории. + +--- + +## Architecture Overview + +```mermaid +flowchart TB + subgraph web [Web UI] + FS["/settings
frontend only"] + TS["/tenant-settings
BIRD + revision + KV"] + MON["/monitoring?tab=runtime-logs"] + end + + subgraph api [evobgp-all only] + H[httpapi handlers] + RL[internal/runtimelogs] + ST[store.Backend] + end + + subgraph data [Data] + PG[(global_settings)] + AUD[(runtime_log_cleanup_audit)] + VOL["/opt/evobgp/runtime-logs/*.log"] + end + + FS --> localStorage + TS --> H + MON --> H + H --> ST + H --> RL + ST --> PG + ST --> AUD + RL --> VOL ``` -/van Доработать MaintenancePoliciesTab: валидация cron и тесты + +--- + +## Phased Implementation Plan + +### Phase 0 — Creative (обязательно перед BUILD) + +Документы в `memory-bank/creative/`: + +| ID | Тип | Тема | Вопросы | +|----|-----|------|---------| +| CP-1 | uiux | Tenant settings module | Структура вкладок: BIRD / Ревизии / Дополнительно; nav label | +| CP-2 | uiux | Runtime logs UI | Вкладка в Monitoring vs отдельный route | +| CP-3 | algorithm | Cleanup semantics | `truncate` (обнулить файл) vs `delete`; max tail bytes/lines | +| CP-4 | architecture | Path safety | Allowlist имён файлов `*.log`, запрет `..`, symlink policy | + +**Уже решено (не обсуждать в creative):** sync cleanup, evobgp-all only, audit yes, settings split. + +--- + +### Phase 1 — Contract & persistence (OpenAPI + migrations + store) + +**Цель:** контракт и audit до FS-логики. + +| # | Действие | Файлы | +|---|----------|-------| +| 1.1 | OpenAPI: `RuntimeLogs` tag | `docs/openapi.yaml` | +| 1.2 | Схемы: `RuntimeLogFile`, `RuntimeLogTail`, `RuntimeLogCleanupAudit` | `docs/openapi.yaml` | +| 1.3 | Paths (см. ниже) | `docs/openapi.yaml` | +| 1.4 | Миграция `000026_runtime_log_cleanup_audit` | `migrations/postgres/`, `migrations/sqlite/` | +| 1.5 | Типы + `store.Backend` методы | `internal/store/runtime_logs.go`, `backend.go` | +| 1.6 | Postgres + Memory реализации | `internal/repository/postgres_runtime_logs.go`, `internal/store/memory_runtime_logs.go` | + +**OpenAPI paths (черновик):** + ``` +GET /v1/runtime-logs/files # list + size/mtime +GET /v1/runtime-logs/files/{filename} # tail (?lines= | ?bytes=, ?grep=) +DELETE /v1/runtime-logs/files/{filename} # cleanup (?mode=truncate|delete), operator+, sync 200 +GET /v1/runtime-logs/cleanup-audit # cursor/limit, viewer+ +``` + +**Audit table `runtime_log_cleanup_audit`:** + +| Column | Type | Note | +|--------|------|------| +| id | TEXT PK | UUID | +| tenant_id | TEXT | из auth | +| actor_prefix | TEXT | API key prefix | +| filename | TEXT | basename only | +| action | TEXT | `truncate` \| `delete` | +| size_before | BIGINT | bytes | +| size_after | BIGINT | nullable | +| detail_json | JSONB | optional (grep stats, error) | +| created_at | TIMESTAMPTZ | | + +**Checklist Phase 1:** +- [ ] `npx @redocly/cli lint docs/openapi.yaml` +- [ ] `scripts/check-migrations-pair.sh` +- [ ] store interface + memory tests + +--- + +### Phase 2 — FS layer & config (evobgp-all only) + +**Цель:** безопасное чтение/очистка файлов. + +| # | Действие | Файлы | +|---|----------|-------| +| 2.1 | `EVOBGP_RUNTIME_LOGS_DIR` в config | `internal/config/config.go`, `docs/access.md` | +| 2.2 | Guard: FS enabled iff dir non-empty **and** `EVOBGP_SERVICE=evobgp-all` | `internal/runtimelogs/guard.go` | +| 2.3 | ListDir, Stat, Tail, Cleanup | `internal/runtimelogs/fs.go` | +| 2.4 | Path hardening: basename allowlist `[a-z0-9_.-]+\.log` | `internal/runtimelogs/safe.go` | +| 2.5 | Unit tests (temp dir) | `internal/runtimelogs/*_test.go` | + +**Поведение при отключённом FS:** +- `GET` → `503` problem+json `runtime_logs_unavailable` +- `DELETE` → `503` + +**Cleanup flow (sync):** +1. Stat file → `size_before` +2. Truncate or Remove +3. `AppendRuntimeLogCleanupAudit(...)` +4. Return `200` + audit id + sizes + +**Checklist Phase 2:** +- [ ] `go test ./internal/runtimelogs/... -race` +- [ ] path traversal tests (`../`, symlinks) + +--- + +### Phase 3 — HTTP handlers + +| # | Действие | Файлы | +|---|----------|-------| +| 3.1 | Регистрация маршрутов | `internal/httpapi/routes.go` или `routes_runtime_logs.go` | +| 3.2 | Handlers | `internal/httpapi/handlers_runtime_logs.go` | +| 3.3 | `actorPrefix(a)` как в maintenance | reuse from `routes_maintenance.go` | +| 3.4 | Handler tests | `internal/httpapi/handlers_runtime_logs_test.go` | + +**Роли:** list/tail/audit — `viewer+`; cleanup — `operator+`. + +**Checklist Phase 3:** +- [ ] `go test ./internal/httpapi/... -race` +- [ ] `scripts/lint-httpapi.sh` + +--- + +### Phase 4 — Deploy (compose) + +| # | Действие | Файлы | +|---|----------|-------| +| 4.1 | Bind mount runtime-logs → evobgp-all | `deploy/compose/stack.microvps-full.yaml`, `docker-compose.microvps-full.yaml` | +| 4.2 | Env `EVOBGP_RUNTIME_LOGS_DIR=/opt/evobgp/runtime-logs` | compose env | +| 4.3 | `EVOBGP_SERVICE=evobgp-all` (если ещё не задан) | compose | +| 4.4 | Комментарий в quickstart / manual | `docs/quickstart.md` или `docs/manual.md` | + +**Пример mount:** +```yaml +volumes: + - ${EVOBGP_RUNTIME_LOGS_HOST_DIR:-./runtime-logs}:/opt/evobgp/runtime-logs:rw +environment: + EVOBGP_RUNTIME_LOGS_DIR: /opt/evobgp/runtime-logs +``` + +**Checklist Phase 4:** +- [ ] dev: `./runtime-logs` рядом с compose +- [ ] prod: `/opt/evobgp/runtime-logs` на хосте + +--- + +### Phase 5 — Web UI: Tenant settings module + +**Цель:** отдельный модуль tenant-настроек; `/settings` остаётся frontend-only. + +| # | Действие | Файлы | +|---|----------|-------| +| 5.1 | Новый route | `web/src/routes/tenant-settings/+page.svelte` | +| 5.2 | Компонент-обёртка с Tabs | `web/src/lib/components/tenant-settings/TenantSettingsPage.svelte` | +| 5.3 | Перенос логики из Operations | refactor `OperationsSystemSettingsTab` → `TenantRevisionSettingsCard.svelte` | +| 5.4 | Перенос BIRD | refactor `BirdSettingsForm` → `TenantBirdSettingsCard.svelte` | +| 5.5 | Custom KV card | `TenantAdditionalSettingsCard.svelte` | +| 5.6 | Nav: добавить пункт (main или bottom) | `web/src/lib/ui/app/layout/nav.ts` | +| 5.7 | Убрать tab `system` из Operations | `web/src/routes/operations/+page.svelte` | +| 5.8 | Network: заменить форму на Card-summary + link | `web/src/routes/network/+page.svelte` | +| 5.9 | Обновить ссылки в docs strings / empty states | grep `tab=system`, `BirdSettingsForm` | + +**Структура tenant module (предложение для creative CP-1):** +``` +/tenant-settings + ├─ BIRD (bird_*) + ├─ Ревизии (revision_retention_minutes) + └─ Дополнительно (custom KV, operator) +``` + +**Checklist Phase 5:** +- [ ] `npm run check && npm run lint` +- [ ] `/settings` без tenant-форм + +--- + +### Phase 6 — Web UI: Runtime logs + +| # | Действие | Файлы | +|---|----------|-------| +| 6.1 | API client | `web/src/lib/runtime-logs/runtime-logs-api.ts` | +| 6.2 | Tab в Monitoring | `web/src/lib/components/monitoring/RuntimeLogsTab.svelte` | +| 6.3 | Подключить tab | `web/src/routes/monitoring/+page.svelte` | +| 6.4 | Таблица файлов (size, mtime) | `AppDataTable` | +| 6.5 | Preview dialog | `ScrollPreBlock` + tail API | +| 6.6 | Cleanup | `ConfirmDialog` + DELETE sync | +| 6.7 | Sub-tab или section: Cleanup audit | таблица `GET /v1/runtime-logs/cleanup-audit` | +| 6.8 | 503 empty state | «Доступно только на evobgp-all с volume» | + +**Checklist Phase 6:** +- [ ] `npm run check && npm run lint` + +--- + +### Phase 7 — Integration, docs, QA + +| # | Действие | +|---|----------| +| 7.1 | `docs/api.md` — новые endpoints | +| 7.2 | `docs/manual.md` — tenant-settings + runtime logs | +| 7.3 | `go test ./... -race -count=1` | +| 7.4 | E2E manual: list → tail → truncate → audit row | + +--- + +## Dependency Graph + +```mermaid +graph TD + P0[Phase 0 Creative] --> P1[Phase 1 OpenAPI+store] + P1 --> P2[Phase 2 FS layer] + P2 --> P3[Phase 3 HTTP] + P3 --> P4[Phase 4 Deploy] + P0 --> P5[Phase 5 Tenant UI] + P3 --> P6[Phase 6 Runtime logs UI] + P4 --> P6 + P5 --> P7[Phase 7 QA] + P6 --> P7 +``` + +**Параллелизация:** Phase 5 (tenant UI) можно начинать после Phase 0, не дожидаясь runtime logs backend. + +--- + +## Risks & Mitigations + +| Risk | Impact | Mitigation | +|------|--------|------------| +| Path traversal | Critical | basename only, allowlist, `filepath.Clean` + root check | +| Sync cleanup блокирует HTTP worker | Medium | лимит размера файла для DELETE; timeout context; документировать | +| evobgp-api без volume | Low | 503 + UI empty state | +| Дублирование settings forms | Medium | Phase 5 удаляет старые вхождения | +| reference compose (не all) | Low | FS API disabled; документировать | + +--- + +## Creative Phases Required + +- [x] **CP-1 uiux** — `creative-tenant-settings-ui.md` ✅ Tabs `/tenant-settings`, nav «Параметры» +- [ ] **CP-2 uiux** — `creative-runtime-logs-ui.md` +- [ ] **CP-3 algorithm** — `creative-runtime-logs-cleanup.md` (truncate default vs delete) +- [ ] **CP-4 architecture** — `creative-runtime-logs-path-safety.md` + +--- + +## Acceptance Criteria + +- [ ] `/settings` — только frontend (токен, тема) +- [ ] `/tenant-settings` — все tenant KV (BIRD + revision + custom) +- [ ] Operations без tab `system`; Network без полной BIRD-формы (summary + link) +- [ ] Runtime logs: list, tail, sync cleanup на evobgp-all +- [ ] Audit cleanup в БД + просмотр в UI +- [ ] `EVOBGP_RUNTIME_LOGS_DIR`, volume в compose +- [ ] redocly lint, go test -race, web check+lint + +--- + +## Status Checklist + +- [x] VAN +- [x] PLAN +- [ ] CREATIVE (4 docs) +- [ ] BUILD Phase 1–7 +- [ ] REFLECT +- [ ] ARCHIVE + +--- + +## Key Files (reference) + +**Settings today:** +- `web/src/routes/settings/+page.svelte` — keep frontend-only +- `web/src/lib/components/operations/OperationsSystemSettingsTab.svelte` — migrate out +- `web/src/lib/components/network/BirdSettingsForm.svelte` — migrate out +- `internal/httpapi/routes_crud.go` — settings handlers (unchanged contract) + +**Runtime logs today:** +- `deploy/compose/stack.microvps-full.yaml` — `stack-runtime-logs`, `./runtime-logs` + +**Patterns:** +- `internal/httpapi/routes_maintenance.go` — audit list, actor_prefix +- `migrations/postgres/000025_*` — config audit table shape