tasks(NEXT_SESSION): session-close — tenant scheduler seller-pinning live

Scheduler seller-pinning выкачен на slovo+bookva (16 джоб, idSeller/ch
per-tenant), task-runner добавлен в auto-deploy, wiki ingested. Открытые
треки: slovo-overlay deploy не активен (legacy bundled compose), docs-commit
триггерит лишний redeploy, bookva compose без DEPLOY_AT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 22:22:52 +03:00
parent 8238ef46a8
commit feeba28433

View File

@@ -1,89 +1,58 @@
---
_last_updated_: 2026-05-27T01:30:00+03:00
session_id: 2026-05-26-bookva-tenant-deep-debug
_last_updated_: 2026-05-26T22:00:00+03:00
session_id: 2026-05-26-tenant-scheduler-seller-pinning
---
# Next session handoff
## Recent commits
- `victor/books 1da3093` — fix(jobs.post): bypass agenda.db.collection → MongoClient (idempotency check fix for embed-api)
- `victor/books e083b71` — fix(files): composite agenda jobId — strip :timestamp before ObjectId.isValid (display fix)
- `victor/books 60382bf` — fix(deploy): books-web-config mount (slovo embed-api Mongo endpoint was stale external)
- `victor/books fc33ea5` — fix(deploy): scheduler — job-scheduler↔scheduler naming bridge tenant-aware
- `victor/books f5f295b` — feat(ops-mcp): multi-tenant pools — MariaDB/Mongo per tenant (0.0.1 → 0.1.0)
- `victor/books ae3ab14` — feat(deploy): ops-mcp host-promote — drop tenant pipeline
- `victor/bookva-overlay 8c104f7` — fix(scheduler): add RECONCILER_ENABLED/TASK_RUNNER_URL/DOCKER_HOST envs
- `victor/bookva-overlay 60e39e5` — fix(deploy): bookva-scheduler healthcheck (mirror slovo's 58b13e0)
- `victor/bookva-overlay a9063f0` — fix(deploy): bookva mount paths /app → /usr/src/app
- `victor/bookva-overlay 4635305` — fix(deploy): bookva-api/web pass NITRO_*/NUXT_* auth env in compose
- `victor/bookva-overlay b6f9144` — fix(web): bookva-web-config volume mount — DB/Mongo/S3 leak fix
- `victor/bookva-overlay 50f5bbb` — chore(deploy): drop ops-mcp.compose.yml (host-promoted)
- `victor/bookva-overlay 437d024` — fix(deploy): bookva-ops-mcp idle-stub (obsolete после delete)
- `.admin × 2` — host-stacks/books-vds/ops-mcp.compose.yml multi-tenant env + task closure + handoff
- `~/projects/.wiki fe3ae78` — ingest concepts/tenant-overlay-config-volume-mount-path-pitfall (shared)
- `victor/books d1054bd` — wiki(ingest): tenant-scheduler-seller-pinning + task-runner auto-deploy
- `victor/books 81e0f29` — ci(deploy): task-runner добавлен в auto-deploy matrix (+ secret PORTAINER_STACK_ID_BOOKVA_TASK_RUNNER=48)
- `victor/books 519d8dc` — feat(tenant-split): tasks.json per-tenant defaults + Group C idSeller filter (job-scheduler 1.6.0, task-runner 0.4.0, tasks 0.1.0)
- `victor/slovo-overlay f8b7bc5` — scheduler tasks.json template (slovo=2) + mount-path fix /app→/usr/src/app
- `victor/bookva-overlay c49afd7` — scheduler tasks.json template (bookva=1)
## What's LIVE сейчас
## Что сделано / LIVE сейчас
**Both tenants полностью изолированы (final audit pass):**
Scheduler seller-pinning **выкачен на оба tenant'а**, verified в живых контейнерах:
- 16 джоб запинены: slovo `idSeller=2`/`salesChannels=[2]`, bookva `idSeller=1`/`[1]`. Zero cross-tenant leakage (проверено node-скриптом в обоих job-scheduler контейнерах).
- Group C code-патчи (idSeller-фильтр в 4 handler'ах) + удалены 3 latent-бага: hardcoded `idSeller:1` (loadSellersPrices), `salesChannels:[1]` (load-products-to-ozon), cross-seller хардкод (withdrawProductsFromSale). 13/13 тестов green.
- Все 4 контейнера (`books-job-scheduler`, `books-task-runner`, `bookva-scheduler`, `bookva-task-runner`) на `master-519d8dc`+, healthy.
- task-runner теперь в auto-deploy pipeline — будущие code-changes раскатываются без ручных шагов. Деталь: slovo tr бандлен в job-scheduler стек, bookva tr = отдельный Portainer-стек 48.
- Wiki: concept [tenant-scheduler-seller-pinning] + source ingested в books/.wiki.
- `bookseller.kzntsv.site` → bookva-web@master-1da3093 → bookva-{db,mongo,es,minio,api,scheduler,task-runner}. Auth `2f2e96e2-25f5-4653-930d-fd307a170543`.
- `bookva.kzntsv.site` → books-web@master-1da3093 (slovo) → books-{db,job-scheduler-mongo,...}. Auth `81e123d0-8edd-...` (slovo's original, не менял).
- bookva-scheduler reconciler **registered** all handlers (`load products to warehouse` ровно processed файл 2674 в `2026-05-26 14:20:45`).
- books-web embed-api (`POST /api/jobs`) теперь без 500 — idempotency через MongoClient.
- 11 Portainer stacks LIVE на books VDS: books-{api,web,job-scheduler,task-runner,db,ntfy} (slovo) + bookva-{api,web,scheduler,task-runner,db,mongo,es,minio,ntfy} + books-ops-mcp host-level + books-docker-proxy{,-ro} + traefik/portainer/registry/mongo/minio/imgproxy и т.д.
bookva volume tasks.json залит (md5-verified), backup на VDS `/tmp/bookva-tasks-live-backup-20260526-212259.json`.
## Open треки
## Открытые треки
| Трек | Готовность | Entry-point |
|---|---|---|
| ~~`ops-mcp-multi-tenant-stack-activate`~~**DONE same session** — stack 26 PUT с pullImage:true + `BOOKVA_MARIADB_PASSWORD` env. Container `books-ops-mcp@master-f5f295b` running. Smoke: `ops.mariadb.query tenant=slovo`АФО2/Главная26/НК11 (slovo data); `tenant=bookva` → Главная26/Ира/НК11 (bookva data); `ops.mongo.count tenant=bookva collection=agendaJobs` → 2818. | n/a |
| `books-api-shutdown` (ранее заведённая micro-task) | 24-48h soak with bookva LIVE — нужно проверить если still applicable (books-api всё ещё нужен для slovo на bookva.kzntsv.site fallback пути?). | TBD |
| `bookva-ozon-mcp-image-build` | image отсутствует в registry, bookva-ozon-mcp stack не создан. Если service не используется — skip навсегда. | TBD |
| `bookva-mongo-cleanup` ⚪ (user-deferred) | 2817 agendaJobs в bookva-mongo from cp-a — user сказал «8 не трогай не стирай». Когда будет готов rotate — отдельная таска. | TBD |
| `bookva-ozon-credentials-audit` ⚪ (user-deferred) | bookva ozonSeller.clientId=50542+94191 = slovo's. Финансовый риск. User сказал «сам подумаю об утечках». | TBD |
| `stateful-split-volume-copy` ⚪ | bookva-side done; slovo-side scope deferred. | `.tasks/stateful-split-volume-copy.md` |
| `infra-inventory` ⚪ | books VDS теперь 14+ stacks — момент удачный для ingest factsheet. | `.tasks/infra-inventory.md` |
| `books-bookva-user-whitelist-gathering` ⚪ | login-gate уже applied — таска только для verification списка post-cutover. | `.tasks/books-bookva-user-whitelist-gathering.md` |
| `books-vds-bookva-bootstrap` 🔵 blocked on Phase 4 (Rusonyx или другой VDS для Bookva billing) | long-term — bookva сейчас на shared books VDS. | `.tasks/books-vds-bookva-bootstrap.md` |
| `books-dns-cutover-bookva` 🔵 blocked on books-vds-bookva-bootstrap | | `.tasks/books-dns-cutover-bookva.md` |
| **slovo-overlay deploy НЕ активен** ⚪ | slovo сейчас работает на **legacy** bundled compose (`books-job-scheduler` стек = mongo+proxy+task-runner+scheduler в одном, bind-mount только `default.json`). slovo-overlay `deploy/*.compose.yml` (named volumes, mount-path fix) — **подготовлены, но не задеплоены**. Миграция = отдельная таска (parity audit с bookva). | `slovo-overlay/deploy/` |
| **docs-commit → лишний redeploy** ⚪ | `.wiki/`-only push триггерит build→skip→deploy.yml workflow_run→полный redeploy (idempotent, но шумно). Можно добавить `.wiki/`+`docs/` в skip-pattern detect-changes в build.yml, либо guard в deploy workflow_run. | `books/.gitea/workflows/build.yml` |
| **bookva compose без DEPLOY_AT** ⚪ | bookva-overlay compose используют `${CORE_SHA}` → recreate только при смене digest (не force). slovo использует `__TAG__`+`__DEPLOY_AT__`. Для re-deploy того же тега bookva не пересоздаётся. Норма для нашего flow (новый код = новый digest), но асимметрия. | `bookva-overlay/deploy/*.compose.yml` |
| `books-api-shutdown` (из прошлой сессии) | soak с bookva LIVE — проверить всё ещё ли books-api нужен для slovo fallback. | TBD |
| `bookva-ozon-credentials-audit` ⚪ (user-deferred) | bookva ozonSeller.clientId = slovo's (cp-a). Финансовый риск. User: «сам подумаю». | TBD |
| `bookva-mongo-cleanup` ⚪ (user-deferred) | 2817 agendaJobs из cp-a. User: «не трогай не стирай». | TBD |
## Спроси user'а
- **`ops-mcp-multi-tenant-stack-activate`** — finish сейчас (PUT stack 26 + add env) или взять отдельной таской?
- **Manual heads-up учредителю Bookva** — Bookva теперь на `https://bookseller.kzntsv.site`, login те же. Когда отправляешь?
- **`books-api-shutdown`** — поверка: books-api всё ещё нужен для legacy paths fallback на bookva.kzntsv.site? Если нет — shutdown candidate.
- **slovo-overlay parity audit** — slovo's compose файлы (book/deploy/) могут страдать от тех же багов что были у bookva (mount path, RECONCILER_ENABLED). Сейчас работает только потому что slovo's mount был через `/opt/...` bind (не named volume), который случайно совпал с правильным WORKDIR. Audit перед follow-up cutover?
- **bookva-minio creds rotation** — сейчас AKIA same as books-minio. Rotate в отдельную task'у когда стабилизируется?
- **slovo→slovo-overlay миграция** — мигрировать slovo на slovo-overlay deploy (named volumes, как bookva) или оставить legacy bundled compose? Сейчас работает, но parity нарушен (mount-path fix в репо не применён к live).
- **docs-redeploy guard** — фиксить пайплайн чтобы `.wiki/`-коммиты не триггерили redeploy?
- **withdrawProductsFromSale** — была cross-seller логика (snять seller2 если seller1 снял тот же offer_id). Я её удалил (single-seller). Если бизнес-смысл cross-coordination всё ещё нужен между Ozon-аккаунтами — пересмотреть.
## Не делать (preemptive guards)
- **Не trust деплой "успех" без end-to-end smoke** — этот session показал 6 багов одной природы которые passed CI но broke runtime. После любого tenant infra изменения: login + write + verify tenant DB + processing-job + UI status.
- **Не stop bookva-{db,mongo,es,minio,api,web,scheduler,task-runner,ntfy}** — LIVE на bookseller.kzntsv.site, любой stop = production outage.
- **Не editing config volumes через alpine напрямую** — source of truth = `bookva-overlay/config-templates/` (для api/scheduler/task-runner) + host-mounted (для web). Edit → commit → push → re-populate.
- **Не stop books-api** до явного soak end + user sign-off.
- **Не push без grant в next session** — auto-push grant был session-only. Этот session был grant'нут.
- **`ops_ro` password в обоих tenant'ах identical** (cp -a). Если будут rotate'ить — оба MariaDB одновременно.
- **bookva-mongo.agendaJobs 2817 docs from slovo cp-a НЕ ТРОГАТЬ** — user explicit "8 не трогай не стирай".
- **Не stop** `bookva-*` / `books-*` контейнеры (`db,mongo,es,minio,api,web,scheduler,task-runner,ntfy`) — production на bookseller.kzntsv.site + slovo URL.
- **Не push без grant в next session** — auto-push был session-only (этот session был grant'нут).
- **task-runner для bookva** — теперь авто-деплоится (стек 48). НЕ нужно руками. Но если меняешь bookva-task-runner стек руками — помни что pipeline его перезапишет.
- **bookva-mongo agendaJobs 2817 docs** — user explicit «не трогай не стирай».
- **Не trust деплой «успех» без smoke** — bookva compose без DEPLOY_AT может не пересоздать контейнер при том же digest; проверяй APP_VERSION/uptime после деплоя.
## Memory updates / wiki ingests
## Memory updates за сессию
Ingested в shared wiki `~/projects/.wiki/concepts/`:
- `tenant-overlay-config-volume-mount-path-pitfall` — 6-bug post-mortem из этого session'а. Includes audit checklist + Lesson о mandatory end-to-end smoke.
Local memory updates (books-specific, не ingested):
- `agenda.db.collection` populated только после `await agenda.start()`. В web/api контейнерах start не вызывается (worker logic в scheduler) → idempotency findOne fails. Используй отдельный MongoClient.
- `composite agenda jobId` (`<bare>:<dispatch_ts>`) пишется через `job-scheduler/lib/handlers/http.js`. ObjectId.isValid возвращает false на 38-char composite — fix: split на `:` перед `.isValid`.
- bookva-scheduler нужны 3 envs для full operation: `RECONCILER_ENABLED=true`, `TASK_RUNNER_URL=http://bookva-task-runner:3000`, `DOCKER_HOST=tcp://books-docker-proxy:2375`.
- bookva auth: NITRO_AUTH_TOKEN/NUXT_AUTH_TOKEN/NITRO_JWT_SECRET_KEY/NUXT_JWT_SECRET_KEY = `2f2e96e2-25f5-4653-930d-fd307a170543` / `5e5ef0460549f36d9ab276882b490b2b77a266e41dc8a6478415869768c1ee36`. Stored in Portainer stack 45 (api) + 46 (web) Env. **Slovo's auth не трогали** (81e123d0/505172e5).
- `_loadFiles` cron в config.jobs больше **нигде не handle'ится** (deprecated после tasksConfig.json migration). File uploads requires manual trigger "Запустить обработку" UI button → POST /api/jobs.
- mongo-shell command на bookva-mongo container — image `mongo:4.2`, use `docker exec bookva-mongo mongo --quiet --eval '...'` (legacy mongo client, NOT mongosh).
- books-db root password в pass `books-vds/full-env` как `BOOKS_DB_ROOT_PASSWORD`. Same для bookva-db (cp-a).
## Pass / Reference
- pass `books-vds/full-env` — VDS root SSH key path (`~/.ssh/id_ed25519_books_ops`), Portainer URL+API key, books-db root password.
- pass `gitea/victor-books-ci-bookva-overlay` — PAT (read:repository) backup для BOOKVA_OVERLAY_TOKEN secret.
- Backups на books VDS — `/backups/books-{db,mongo}-pre-split-20260526-*.tar.gz` (auto-cleanup post 7 дней).
- Shared wiki concept ingested this session: [tenant-overlay-config-volume-mount-path-pitfall](~/projects/.wiki/concepts/tenant-overlay-config-volume-mount-path-pitfall.md).
- **Reference task:** [[books-ops-mcp-host-promote]] (closed) — все 5 design Qs locked + 10-step playbook executed.
- **idSeller == idSalesChannel** маппинг (канон): bookva=1, slovo=2. User-fixed, без проверки БД.
- Deploy-механика: slovo job-scheduler чит tasks.json из **image built-in** (bind только default.json), bookva — из **named volume** (shadow'ит image).
- `deploy.yml` auto-deploy покрывает api/web/task-runner/job-scheduler (task-runner добавлен 2026-05-26). slovo tr бандлен в scheduler-стек, bookva tr отдельный стек 48.
- books CI build path-filter: `tasks.json` триггерит web+scheduler ребилд; `packages/tasks` или `packages/task-runner` → task-runner ребилд.
- Креды: `pass books-vds/full-env` (SSH key `id_ed25519_books_ops`, Portainer URL+key), `pass gitea/admin-token` (Gitea API).