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).
7.1 KiB
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.mdrev v3 (2026-05-25). - Overlay-репо:
victor/bookva-overlay+victor/slovo-overlay(compose'ы + config-templates). - Code-side done в master:
5e28fd1embed-api в web (server/api/*) + zod^4 fix.4a9cafcES endpoint per-tenant черезcustom-environment-variables.json.c1e58cfBookvaRedirectBanner — PWA handoff modal для user.id=1.88df172deploy.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.ymlbookva-mongo—mongo.compose.ymlbookva-es—elasticsearch.compose.yml(новый, в-stack ES 7.10.0)bookva-api—api.compose.ymlbookva-web—web.compose.ymlbookva-scheduler—scheduler.compose.ymlbookva-task-runner—task-runner.compose.ymlbookva-ozon-mcp—ozon-mcp.compose.ymlbookva-ops-mcp—ops-mcp.compose.ymlbookva-ntfy—ntfy.compose.yml
Env-vars stack-level (Portainer Stack → Environment):
CORE_SHA— последний master tag из registry (напримерmaster-5e28fd1).HOSTNAME_API/HOSTNAME_WEB—bookseller.kzntsv.site(per design v3).HOSTNAME_NTFY—push.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-renamebooks→slovo+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