Files
admin/.tasks/bookva-tenant-cutover-prep.md
vitya 4f1a4cf436 tasks(bookva-tenant-cutover-prep): create — 7-step VDS prep после tenant-split dev-side closed
Gitea secrets для PORTAINER_STACK_ID_BOOKVA_* + GITEA_TOKEN, создание
Portainer stacks для bookva-{api,web,scheduler,task-runner,ozon-mcp,
ops-mcp,db,mongo,es,ntfy}, volume create+copy (Mongo/ES/MinIO/configs),
bookva-db login-gate password-replace, DNS bookseller.kzntsv.site,
PWA redirect env в books-web, books-web embedded-api env (pending
step из embed-api handoff).

Dev-side done в victor/books master:
- 5e28fd1 embed-api + zod^4 (root cause: zod 3.x в web shadowed
  root zod 4.x, @nuxt/ui v4.5 silent broke without zod 4 API)
- 4a9cafc ES endpoint per-tenant via custom-environment-variables.json
- c1e58cf PWA redirect banner (user.id=1 modal)
- 88df172 deploy.yml per-tenant (tenant input + per-tenant stack IDs)

Overlay-repos обновлены: bookva-overlay 58d4295 (+ ES env + ntfy
full config), slovo-overlay bca6bbc (+ ES env + ntfy full config).
2026-05-26 08:36:08 +03:00

7.1 KiB
Raw Blame History

bookva-tenant-cutover-prep

Подготовительные ops-шаги на books VDS перед cutover Bookva tenant в отдельный стек на bookseller.kzntsv.site. Code/CI part сделан в victor/books master (см. dev-side ниже).

Контекст dev-source

  • Дизайн: victor/books .wiki/concepts/tenant-split.md rev v3 (2026-05-25).
  • Overlay-репо: victor/bookva-overlay + victor/slovo-overlay (compose'ы + config-templates).
  • Code-side done в master:
    • 5e28fd1 embed-api в web (server/api/*) + zod^4 fix.
    • 4a9cafc ES endpoint per-tenant через custom-environment-variables.json.
    • c1e58cf BookvaRedirectBanner — PWA handoff modal для user.id=1.
    • 88df172 deploy.yml per-tenant (tenant input + per-tenant stack IDs + bookva-overlay clone).

Goal

Bookva стек готов взлететь — все secrets/stacks/volumes/DNS/PWA-redirect на месте. Сам compose up для bookva = последний шаг (отдельная задача bookva-tenant-cutover будет создана когда юзер скажет).

Plan

Step 1 — Gitea secrets (admin via gitea UI или API)

Добавить в repo victor/books settings → Secrets:

PORTAINER_STACK_ID_BOOKVA_API
PORTAINER_STACK_ID_BOOKVA_WEB
PORTAINER_STACK_ID_BOOKVA_SCHEDULER
PORTAINER_STACK_ID_BOOKVA_OPS_MCP
GITEA_TOKEN                       # read-access к victor/bookva-overlay
HEALTHCHECK_BOOKVA_API_URL        # опционально, http healthcheck
HEALTHCHECK_BOOKVA_WEB_URL

Значения stack ID — после Step 2.

После Phase 2 cutover (отдельная задача) — переименовать PORTAINER_STACK_ID_{API,WEB,SCHEDULER,OPS_MCP}PORTAINER_STACK_ID_SLOVO_* для symmetry. До тех пор deploy.yml использует fallback на legacy имена.

Step 2 — Portainer bookva stacks

В Portainer (https://portainer.kzntsv.site) создать stacks из overlay-compose:

  • bookva-db~/projects/bookva-overlay/deploy/db.compose.yml
  • bookva-mongomongo.compose.yml
  • bookva-eselasticsearch.compose.yml (новый, в-stack ES 7.10.0)
  • bookva-apiapi.compose.yml
  • bookva-webweb.compose.yml
  • bookva-schedulerscheduler.compose.yml
  • bookva-task-runnertask-runner.compose.yml
  • bookva-ozon-mcpozon-mcp.compose.yml
  • bookva-ops-mcpops-mcp.compose.yml
  • bookva-ntfyntfy.compose.yml

Env-vars stack-level (Portainer Stack → Environment):

  • CORE_SHA — последний master tag из registry (например master-5e28fd1).
  • HOSTNAME_API / HOSTNAME_WEBbookseller.kzntsv.site (per design v3).
  • HOSTNAME_NTFYpush.bookseller.kzntsv.site.

После создания каждого stack — Portainer присваивает ID → записать в Gitea secrets (Step 1).

Step 3 — Volume create + copy (stateful split)

См. отдельную задачу stateful-split-volume-copy — MariaDB.

Дополнительно для Phase 2 нужны (текущая задача охватывает только MariaDB):

  • bookva-mongo-data — copy с books-job-scheduler-mongo_data через cp -a + deleteMany({'data.idSeller': 2}) для cleanup чужих agenda jobs.
  • bookva-es-data — пустой volume; данные через ES snapshot+restore из shared kzntsv ES в Phase 2.
  • bookva-minio-data ИЛИ FS-rename booksslovo + cp -a slovo bookva в shared MinIO контейнере.
  • Config volumes — bookva-{api,scheduler,task-runner}-config + bookva-web-branding + bookva-ntfy-data (см. README в bookva-overlay для bootstrap).

Step 4 — bookva-db login-gate

После volume copy + bookva-db up:

-- В bookva-db только (slovo-db не трогать!):
UPDATE users SET password = SHA2(UUID(), 256) WHERE id NOT IN (1, 2);

(точная команда — после проверки актуального password storage format в packages/api/server/services/auth/* или embedded packages/web/server/api/auth/login.post.js.)

Эффект: только id=1 (Bookva-учредитель) + id=2 (Slovo-учредитель) могут логиниться в bookseller.kzntsv.site. Остальные user-записи остаются, но без работающего пароля.

Step 5 — DNS

Добавить A-record bookseller.kzntsv.site → books-vds IP (тот же что bookva.kzntsv.site сейчас).

После cutover (отдельная задача) — bookva.kzntsv.site остаётся на тот же IP (роутит на slovo стек).

Step 6 — PWA redirect handoff (за 1-2 недели до cutover)

В Portainer для текущего books-web stack (= future slovo-web после cutover) добавить env:

NUXT_PUBLIC_BOOKVA_REDIRECT_URL=https://bookseller.kzntsv.site

После DEPLOY_AT bump → recreate web container → новый SW bundle подхватывает BookvaRedirectBanner компонент. user.id=1 видит modal «Bookva теперь на bookseller.kzntsv.site → Перейти».

Step 7 — books-web embedded-api env (pending step из embed-api handoff)

В Portainer books-web stack environment:

ADD:

NUXT_AUTH_TOKEN=<значение из books-api.NITRO_AUTH_TOKEN>
NUXT_JWT_SECRET_KEY=<значение из books-api.NITRO_JWT_SECRET_KEY>

CHANGE/REMOVE:

NUXT_PUBLIC_BOOKS_API_URL=/api    # было https://books.kzntsv.site, переключаем на embedded
NUXT_PUBLIC_BOOKS_API_KEY=         # удалить (legacy)

После DEPLOY_AT bump → recreate. Embedded api начнёт обслуживать /api/* (вместо старого books-api стека).

После 24-48ч стабильности — остановить books-api stack (отдельная micro-task).

Acceptance

  • Gitea secrets выставлены (Step 1).
  • Portainer stacks bookva-* созданы (Step 2), stack IDs в Gitea secrets.
  • Volumes bookva-* существуют + data populated (Step 3).
  • bookva-db login-gate применён (Step 4).
  • DNS bookseller.kzntsv.site → books-vds (Step 5).
  • NUXT_PUBLIC_BOOKVA_REDIRECT_URL в books-web env (Step 6) — за 1-2 недели до cutover.
  • books-web env обновлён для embedded api (Step 7).
  • Acceptance не включает compose up bookva-* — это отдельная задача bookva-tenant-cutover (создаётся когда юзер скажет «давай поднимать Bookva»).

Status

ready

Where I stopped

(not started — все code/CI prep на dev-стороне closed, осталась только VDS/Portainer работа)

Next action

Step 1 в Gitea UI: добавить bookva secrets (значения placeholder). Шаги 2-7 — по порядку под maintenance window.

Blocker

Branch

main