diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index ba606d15..594cf5df 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,10 +1,10 @@ -{"id":"panvex-dd0","title":"Deploy Panvex to vpn_senko (panvex.azzazelvpn.ru)","description":"Stand up Panvex control-plane + co-located agent on vpn_senko (144.31.122.180) alongside existing traefik/3x-ui/discord-bot. Decisions captured in memory key panvex-senko-deploy-decisions-2026-04-27. Subtasks: (a) write deploy/senko/docker-compose.senko.yml (CP + agent + Telemt, SQLite storage), (b) write deploy/senko/senko.config.toml.template, (c) add traefik labels for panvex.azzazelvpn.ru:443 → CP :9080, (d) generate gRPC TLS cert for :9443, (e) UFW open :2443/:9443, (f) DNS A record panvex.azzazelvpn.ru → 144.31.122.180, (g) bootstrap admin user, (h) smoke test from local laptop.","acceptance_criteria":"panvex.azzazelvpn.ru loads panel over TLS; agent on vpn_senko reports presence; one Telemt client provisioned end-to-end via UI; deploy/senko/ committed.","notes":"Phase 2.1 COMPLETE (committed in 53934c5):\n ✓ deploy/senko/ scaffolded — docker-compose.senko.yml + config.toml + .env.example + README.md + deploy.sh\n ✓ Cross-arch deploy.sh: buildx linux/amd64 → docker save | ssh | docker load → rsync → compose up + ufw + bootstrap-admin + healthz smoke\n ✓ Two production bugs fixed mid-deploy:\n - Dockerfile: /var/lib/panvex needed pre-creation with panvex:panvex ownership (named volume mount otherwise lands as root:root, non-root user can't write SQLite DB)\n - docker-compose.senko.yml + bootstrap-admin in deploy.sh: ENTRYPOINT already declares the binary; `command:` and `docker compose run` args must list ONLY flags. Repeating the binary name shifts it into argv[1], where Go's flag.Parse stops at the first non-flag and silently drops every flag (including -config), causing fallback to the relative DefaultSQLiteDSN data/panvex.db (unwritable from WORKDIR /app under non-root user)\n ✓ Live verification:\n - https://panvex.azzazelvpn.ru/ → 200 OK (panel HTML)\n - POST /api/auth/login {admin/\u003cgen-pass\u003e} → 200 OK + session cookie\n - 144.31.122.180:9443 → TLSv1.3 + ALPN h2, cert CN=control-plane.panvex.internal, issuer=Panvex Control Plane Root CA (embedded)\n - Backend healthy, all 27 migrations ran clean\n - Admin password (one-shot, change on first login): ca9c7c108cb50d8f0b77d0c79f8156ef\n\nPhase 2.2 PENDING — moved to follow-up issue (see dependent issues).","status":"open","priority":2,"issue_type":"feature","owner":"d.shuvalov@test.com","created_at":"2026-04-27T09:41:38Z","created_by":"d.shuvalov","updated_at":"2026-04-27T11:07:11Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"memory","key":"effective-deepinit-dispatch-pattern-panvex-80-dirs-across","value":"Effective deepinit dispatch pattern (Panvex, ~80 dirs across Go backend + React frontend + infra): 7 parallel oh-my-claudecode:writer agents, one per subtree — (1) cmd/, (2) internal/agent/, (3) internal/controlplane/ (~25 dirs, biggest), (4) backend infra (internal/{dbsqlc,gatewayrpc,loadtest,security} + db/ + proto/ + deploy/ + scripts/ + .github*/ + docs/ + ref_systems root only), (5) web/ shell + features index, (6) web/src/features/* (28 dirs feature-sliced), (7) web/src/{ui,shared,locales,types} + web/tests/. One leaf was missed (web/src/ui/compositions/internal/) — fix-up afterwards. Validation: 'find -type d ... -prune ... | while read d; do [ -f \"$d/AGENTS.md\" ] || echo MISSING: $d; done' + first-line grep for 'Parent:'. Lesson: explicitly tell each writer agent NOT to touch the root AGENTS.md when it's a curated style guide; one agent narrated 'let me update root' but did not actually write — defensive instruction prevented the overwrite."} -{"_type":"memory","key":"panvex-is-a-fork-of-github-com-lost","value":"Panvex is a fork of github.com/lost-coder/panvex — fork note added to CLAUDE.md (lines 3-7) noting changes should stay rebase-friendly against upstream main. ref_systems/telemt vendored at repo root contains full upstream telemt source (Rust + Tokio MTProxy). User SSH host alias: vpn_senko maps to root@144.31.122.180:22 in ~/.ssh/config."} -{"_type":"memory","key":"vpn-senko-server-144-31-122-180-ubuntu","value":"vpn_senko server (144.31.122.180, Ubuntu 24.04, 1.9 GB RAM, 16 GB disk free, key-auth as root) currently runs: traefik v3.6.9 on :80/:443 (vpn-setup compose at /root/vpn-setup), 3x-ui Xray panel on :8080/:8443, discord-bot container, hysteria2 + vk-turn-server systemd. UFW open: 22, 80, 443, 8000, 8443, 8388. Marzban containers exited. Compose project: /root/vpn-setup/docker-compose.yml. Memory tight: 335 Mi free + 1.1 Gi cache, 86 Mi swap used — recommend SQLite mode for any new workload."} -{"_type":"memory","key":"deepinit-completed-for-panvex-on-2026-04-27","value":"Deepinit completed for Panvex on 2026-04-27: 117 total AGENTS.md (116 new + 1 preserved root). Hierarchy validated — every non-root file uses '\u003c!-- Parent: ../AGENTS.md --\u003e'. Coverage scope excludes ref_systems/telemt (vendored upstream — its own AGENTS.md kept intact), web/node_modules, cmd/control-plane/.embedded-ui, .git, .beads, .omc, .veai, .claude, .idea. Root AGENTS.md (curated agent style guide) intentionally NOT regenerated; the only +47 lines on it are pre-existing staged BEADS INTEGRATION block from prior session, working tree clean. CLAUDE.md got a fork-note pointing to github.com/lost-coder/panvex (lines 3-7). All 117 files + CLAUDE.md edit are uncommitted, awaiting user decision on commit timing relative to vpn_senko deploy work."} -{"_type":"memory","key":"panvex-deployment-to-vpn-senko-default-ports-collide","value":"Panvex deployment to vpn_senko: default ports collide with existing services. :443 owned by traefik, :8080 + :8443 owned by 3x-ui. Proposed remap awaiting user approval — Telemt MTProxy :2443, Panvex CP HTTP :9080, Panvex gRPC :9443, Telemt API/metrics on loopback :9091/:9090. Plan: standalone compose under /root/panvex, SQLite storage, no Traefik integration first pass. Pending decisions: port confirmation, domain/subdomain choice, whether deploy artifacts (deploy/docker-compose.senko.yml + senko.config.toml) get committed to repo, deepinit scope."} -{"_type":"memory","key":"panvex-docker-entrypoint-cmd-bug","value":"Panvex Dockerfile sets ENTRYPOINT [\"./panvex-control-plane\"]. Compose 'command:' must list ONLY flags, NEVER repeat the binary name — Docker concatenates ENTRYPOINT+CMD, and a duplicate binary in argv[1] causes Go's flag.Parse to stop at the first non-flag arg, silently dropping every flag (including -config). Symptom: backend restart loop with 'mkdir data: permission denied' because the legacy fallback uses DefaultSQLiteDSN='data/panvex.db' (relative, unwritable from WORKDIR /app under non-root user). Same trap applies to 'docker compose run --rm backend \u003ccmd\u003e' — pass only the subcommand + its flags (e.g. 'backend bootstrap-admin -username ...'), not the binary name. Fixed in deploy/senko/docker-compose.senko.yml + deploy/senko/deploy.sh on 2026-04-27."} +{"id":"panvex-dd0","title":"Deploy Panvex to vpn_senko (panvex.azzazelvpn.ru)","description":"Stand up Panvex control-plane + co-located agent on vpn_senko (144.31.122.180) alongside existing traefik/3x-ui/discord-bot. Decisions captured in memory key panvex-senko-deploy-decisions-2026-04-27. Subtasks: (a) write deploy/senko/docker-compose.senko.yml (CP + agent + Telemt, SQLite storage), (b) write deploy/senko/senko.config.toml.template, (c) add traefik labels for panvex.azzazelvpn.ru:443 → CP :9080, (d) generate gRPC TLS cert for :9443, (e) UFW open :2443/:9443, (f) DNS A record panvex.azzazelvpn.ru → 144.31.122.180, (g) bootstrap admin user, (h) smoke test from local laptop.","acceptance_criteria":"panvex.azzazelvpn.ru loads panel over TLS; agent on vpn_senko reports presence; one Telemt client provisioned end-to-end via UI; deploy/senko/ committed.","notes":"Deploy completed across Phase 2.0–2.2 (commits 53934c5, 8fb9418, c976045 + UI deploys). Live at https://panvex.azzazelvpn.ru/. Topology + endpoints captured in memory project_senko_deploy.md / reference_panvex_endpoints.md.","status":"closed","priority":2,"issue_type":"feature","owner":"d.shuvalov@test.com","created_at":"2026-04-27T09:41:38Z","created_by":"d.shuvalov","updated_at":"2026-04-27T14:59:43Z","closed_at":"2026-04-27T14:59:43Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"memory","key":"panvex-senko-deploy-decisions-2026-04-27","value":"Panvex → vpn_senko deploy decisions (2026-04-27, locked): (1) Ports approved as proposed — Telemt MTProxy :2443 direct, Panvex CP HTTP :9080 (behind traefik, not exposed publicly), Panvex gRPC :9443 direct with own TLS, Telemt API/metrics on loopback :9091/:9090. (2) Panel reached via subdomain panvex.azzazelvpn.ru through existing traefik on :443 with letsencrypt cert. DNS A record for panvex.azzazelvpn.ru → 144.31.122.180 must be added. (3) gRPC :9443 NOT through traefik — bound to 0.0.0.0:9443 with own cert, UFW must open :9443. Agents connect to grpc://panvex.azzazelvpn.ru:9443 (or direct IP). (4) Deploy artifacts committed to repo at deploy/senko/ — docker-compose.senko.yml + senko.config.toml.template (real secrets stay server-side). UFW changes needed: open :2443 (Telemt) + :9443 (gRPC); :443 already open via traefik."} {"_type":"memory","key":"panvex-sqlite-volume-permissions","value":"Panvex Dockerfile control-plane stage runs as USER panvex (uid 100), but the original image did NOT pre-create /var/lib/panvex with that ownership. Docker named-volume mount on /var/lib/panvex therefore lands as root:root drwxr-xr-x — panvex user cannot write the SQLite DB. Fix (committed 2026-04-27): added 'mkdir -p /var/lib/panvex \u0026\u0026 chown -R panvex:panvex /var/lib/panvex' to the alpine-based control-plane stage RUN in Dockerfile. Pre-existing bad volumes need 'docker compose down -v' + 'docker volume rm' before redeploy — the chown only applies on first volume init."} +{"_type":"memory","key":"panvex-docker-entrypoint-cmd-bug","value":"Panvex Dockerfile sets ENTRYPOINT [\"./panvex-control-plane\"]. Compose 'command:' must list ONLY flags, NEVER repeat the binary name — Docker concatenates ENTRYPOINT+CMD, and a duplicate binary in argv[1] causes Go's flag.Parse to stop at the first non-flag arg, silently dropping every flag (including -config). Symptom: backend restart loop with 'mkdir data: permission denied' because the legacy fallback uses DefaultSQLiteDSN='data/panvex.db' (relative, unwritable from WORKDIR /app under non-root user). Same trap applies to 'docker compose run --rm backend \u003ccmd\u003e' — pass only the subcommand + its flags (e.g. 'backend bootstrap-admin -username ...'), not the binary name. Fixed in deploy/senko/docker-compose.senko.yml + deploy/senko/deploy.sh on 2026-04-27."} {"_type":"memory","key":"panvex-phase-2.2-plan-2026-04-27","value":"Phase 2.2 (panvex-39x) execution plan, agreed before coding: (1) Dockerfile — add 'agent' target (cmd/agent → panvex-agent, alpine, state dir /var/lib/panvex-agent). (2) deploy/senko/docker-compose.senko.yml — add two services: telemt (ghcr.io/telemt/telemt:latest, host :2443, loopback api :9091 + metrics :9090, named volume) and panvex-agent (depends on telemt+backend, state volume, PANVEX_GRPC_ENDPOINT=144.31.122.180:9443, PANVEX_TELEMT_API=http://telemt:9091; won't start until bootstrapped). (3) deploy.sh — after admin bootstrap: PUT /api/v1/admin/settings/panel grpc_public_endpoint=144.31.122.180:9443 (CRITICAL — else bootstrap response defaults to :8443 from request Host, see internal/controlplane/server/http_enrollment.go:616 bootstrapGatewayAddress + defaultBootstrapGatewayAddress); login admin → CSRF → POST /api/v1/admin/agents/enrollment-tokens → capture value+ca_pem → docker compose run --rm panvex-agent bootstrap -token \u003cvalue\u003e → docker compose up -d panvex-agent; ufw allow 2443/tcp. (4) Verify: GET /api/v1/agents shows presence_state=online; one client created end-to-end. OPEN QUESTIONS pending user answer: (a) confirm Telemt image ghcr.io/telemt/telemt:latest exists / pin digest, (b) Fake-TLS SNI domain choice (proposed www.cloudflare.com), (c) client provisioning manual via UI or scripted in deploy.sh."} +{"_type":"memory","key":"effective-deepinit-dispatch-pattern-panvex-80-dirs-across","value":"Effective deepinit dispatch pattern (Panvex, ~80 dirs across Go backend + React frontend + infra): 7 parallel oh-my-claudecode:writer agents, one per subtree — (1) cmd/, (2) internal/agent/, (3) internal/controlplane/ (~25 dirs, biggest), (4) backend infra (internal/{dbsqlc,gatewayrpc,loadtest,security} + db/ + proto/ + deploy/ + scripts/ + .github*/ + docs/ + ref_systems root only), (5) web/ shell + features index, (6) web/src/features/* (28 dirs feature-sliced), (7) web/src/{ui,shared,locales,types} + web/tests/. One leaf was missed (web/src/ui/compositions/internal/) — fix-up afterwards. Validation: 'find -type d ... -prune ... | while read d; do [ -f \"$d/AGENTS.md\" ] || echo MISSING: $d; done' + first-line grep for 'Parent:'. Lesson: explicitly tell each writer agent NOT to touch the root AGENTS.md when it's a curated style guide; one agent narrated 'let me update root' but did not actually write — defensive instruction prevented the overwrite."} +{"_type":"memory","key":"panvex-deployment-to-vpn-senko-default-ports-collide","value":"Panvex deployment to vpn_senko: default ports collide with existing services. :443 owned by traefik, :8080 + :8443 owned by 3x-ui. Proposed remap awaiting user approval — Telemt MTProxy :2443, Panvex CP HTTP :9080, Panvex gRPC :9443, Telemt API/metrics on loopback :9091/:9090. Plan: standalone compose under /root/panvex, SQLite storage, no Traefik integration first pass. Pending decisions: port confirmation, domain/subdomain choice, whether deploy artifacts (deploy/docker-compose.senko.yml + senko.config.toml) get committed to repo, deepinit scope."} +{"_type":"memory","key":"vpn-senko-server-144-31-122-180-ubuntu","value":"vpn_senko server (144.31.122.180, Ubuntu 24.04, 1.9 GB RAM, 16 GB disk free, key-auth as root) currently runs: traefik v3.6.9 on :80/:443 (vpn-setup compose at /root/vpn-setup), 3x-ui Xray panel on :8080/:8443, discord-bot container, hysteria2 + vk-turn-server systemd. UFW open: 22, 80, 443, 8000, 8443, 8388. Marzban containers exited. Compose project: /root/vpn-setup/docker-compose.yml. Memory tight: 335 Mi free + 1.1 Gi cache, 86 Mi swap used — recommend SQLite mode for any new workload."} +{"_type":"memory","key":"deepinit-completed-for-panvex-on-2026-04-27","value":"Deepinit completed for Panvex on 2026-04-27: 117 total AGENTS.md (116 new + 1 preserved root). Hierarchy validated — every non-root file uses '\u003c!-- Parent: ../AGENTS.md --\u003e'. Coverage scope excludes ref_systems/telemt (vendored upstream — its own AGENTS.md kept intact), web/node_modules, cmd/control-plane/.embedded-ui, .git, .beads, .omc, .veai, .claude, .idea. Root AGENTS.md (curated agent style guide) intentionally NOT regenerated; the only +47 lines on it are pre-existing staged BEADS INTEGRATION block from prior session, working tree clean. CLAUDE.md got a fork-note pointing to github.com/lost-coder/panvex (lines 3-7). All 117 files + CLAUDE.md edit are uncommitted, awaiting user decision on commit timing relative to vpn_senko deploy work."} +{"_type":"memory","key":"panvex-is-a-fork-of-github-com-lost","value":"Panvex is a fork of github.com/lost-coder/panvex — fork note added to CLAUDE.md (lines 3-7) noting changes should stay rebase-friendly against upstream main. ref_systems/telemt vendored at repo root contains full upstream telemt source (Rust + Tokio MTProxy). User SSH host alias: vpn_senko maps to root@144.31.122.180:22 in ~/.ssh/config."} diff --git a/web/src/ui-kit.css b/web/src/ui-kit.css index 4ce976b4..db502903 100644 --- a/web/src/ui-kit.css +++ b/web/src/ui-kit.css @@ -134,6 +134,21 @@ } } +/* WCAG 2.3.3 / Apple HIG reduced-motion: collapse every animation and + transition to a single tick. Each --animate-* keyframe above (breathe, + blink, beacon-glow, led-blink, alert-pulse) ends at its visible + state, so iteration-count:1 lands users on a sane static frame. */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.001ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.001ms !important; + scroll-behavior: auto !important; + } +} + /* ─── Back-compat aliases for raw `var(--color-*)` consumers ────────────── The pre-v4 CSS exposed --color-bg, --color-fg, etc. at :root so hand-written CSS could reference them directly (e.g. the body rule here,