530 lines
28 KiB
Markdown
530 lines
28 KiB
Markdown
# NODE.DC Synology deploy
|
||
|
||
Эта папка фиксирует текущий воспроизводимый NAS-deploy для `nodedc-platform` на Synology RS1221RP+.
|
||
|
||
## Правила
|
||
|
||
- Не выполнять `docker stop`, `docker restart`, `docker compose down`, `docker system prune` для старых проектов.
|
||
- Новый compose project: `nodedc-platform`.
|
||
- Новая папка на NAS: `/volume1/docker/nodedc-platform`.
|
||
- Внутренний HTTP edge использует `18080`, AI Workspace Hub — `18081`, Tasker upstream — `18090`, BIM Viewer upstream — `18100`, Ops Agents Gateway upstream — `18190`.
|
||
- Старые порты `9000` и `5678` заняты старым `nodedc-demo` и не используются.
|
||
|
||
## Deploy runner
|
||
|
||
`nodedc-deploy` is managed outside the platform runtime tree. The synced install candidate lives in:
|
||
|
||
```text
|
||
/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy
|
||
```
|
||
|
||
The live root-owned runner is:
|
||
|
||
```text
|
||
/usr/local/sbin/nodedc-deploy
|
||
```
|
||
|
||
`deploy-current.sh` syncs the runner candidate into `runner-install`. Promoting it to live is explicit:
|
||
|
||
```bash
|
||
sudo install -o root -g root -m 0755 \
|
||
/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy \
|
||
/usr/local/sbin/nodedc-deploy
|
||
sudo /usr/local/sbin/nodedc-deploy verify-install
|
||
```
|
||
|
||
## Текущие внешние домены
|
||
|
||
```text
|
||
https://id.nodedc.ru -> Authentik
|
||
https://hub.nodedc.ru -> Launcher / Hub
|
||
https://ops.nodedc.ru -> Tasker / Operational Core
|
||
https://bim.nodedc.tech -> BIM Viewer
|
||
https://ops-agents.nodedc.ru -> Ops Agents Gateway / MCP
|
||
https://ai-hub.nodedc.ru -> AI Workspace Hub / WebSocket relay
|
||
```
|
||
|
||
`id.nodedc.ru` is the user-facing OIDC/login host. Authentik Admin is intentionally not exposed through this public host; `/if/admin/*` returns `404` there.
|
||
|
||
`ai-hub.nodedc.ru` is intentionally routed by Synology DSM Reverse Proxy directly to `172.22.0.222:18081`, because this endpoint must carry WebSocket Upgrade traffic for remote Codex agents.
|
||
|
||
В `Caddyfile.http` эти домены проксируются через локальный HTTP edge, но upstream получает `X-Forwarded-Proto: https` и `X-Forwarded-Port: 443`.
|
||
|
||
`bim.nodedc.tech` can either be routed by DSM directly to the BIM host port `172.22.0.222:18100`, or through the platform HTTP edge `172.22.0.222:18080`. When it goes through the platform edge, `BIM_DOMAIN=bim.nodedc.tech` and `SYNOLOGY_BIM_VIEWER_UPSTREAM=host.docker.internal:18100` keep the same target service.
|
||
|
||
## AI Workspace Hub / Assistant contract
|
||
|
||
`ai-workspace-hub` remains a thin public WebSocket relay. It is the only AI Workspace service exposed through DSM/Nginx as `https://ai-hub.nodedc.ru`.
|
||
|
||
`ai-workspace-assistant` is an internal platform service for per-user executors, selected device, shared threads and installer generation. It must not be exposed as a public route. Launcher, Engine and Tasker use it through Docker networking:
|
||
|
||
```env
|
||
NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082
|
||
PLANE_NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082
|
||
```
|
||
|
||
Installer generation must always point remote Codex workers to the deployed Hub:
|
||
|
||
```env
|
||
AI_WORKSPACE_HUB_PUBLIC_URL=wss://ai-hub.nodedc.ru/api/ai-workspace/hub
|
||
AI_WORKSPACE_HUB_INTERNAL_URL=https://ai-hub.nodedc.ru
|
||
AI_WORKSPACE_HUB_FALLBACK_URLS=
|
||
```
|
||
|
||
Server-side Hub API calls, including executor status checks, use `AI_WORKSPACE_HUB_INTERNAL_URL` and require a token accepted by Hub: `AI_WORKSPACE_HUB_TOKEN`, `NDC_AI_WORKSPACE_HUB_TOKEN`, or the shared `NODEDC_INTERNAL_ACCESS_TOKEN` where that token is intentionally common across platform services.
|
||
|
||
Local NDC SEO Mode development uses this same server-side Hub class through `SEO_AI_WORKSPACE_PROFILE=deployed-hub`, `SEO_AI_WORKSPACE_CONTROL_URL=https://ai-hub.nodedc.ru`, and a Hub-accepted `SEO_AI_WORKSPACE_CONTROL_TOKEN`. The Hub only exposes an Assistant-compatible allowlist proxy for setup/probe/thread dispatch calls behind bearer-token auth; it does not expose unrestricted Assistant, product apps, Authentik, Engine, Ops, or Tasker to the remote Codex worker.
|
||
|
||
AI Workspace Assistant also calls product entitlement adapters before every Codex run. Ops uses the Agent Gateway internal endpoint; the token must match `NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN` from the Ops Agent Gateway deployment:
|
||
|
||
```env
|
||
AI_WORKSPACE_OPS_ENTITLEMENT_URL=http://172.22.0.222:18190/api/internal/v1/ai-workspace/entitlements
|
||
AI_WORKSPACE_OPS_ENTITLEMENT_TOKEN=<same value as Ops NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN>
|
||
AI_WORKSPACE_OPS_ENTITLEMENT_REQUIRED=false
|
||
```
|
||
|
||
## Локальные домены для первичной проверки
|
||
|
||
На Mac для первичной проверки добавить в `/etc/hosts`:
|
||
|
||
```text
|
||
172.22.0.222 auth.nas.nodedc
|
||
172.22.0.222 auth-admin.nas.nodedc
|
||
172.22.0.222 launcher.nas.nodedc
|
||
172.22.0.222 task.nas.nodedc
|
||
```
|
||
|
||
Первичные URL:
|
||
|
||
```text
|
||
http://auth.nas.nodedc:18080
|
||
http://auth-admin.nas.nodedc:18080/if/admin/
|
||
http://172.22.0.222:18080/if/admin/
|
||
http://launcher.nas.nodedc:18080
|
||
http://task.nas.nodedc:18080
|
||
http://task.nas.nodedc:18090
|
||
```
|
||
|
||
`auth-admin.nas.nodedc` is the technical Authentik Admin entrypoint. `172.22.0.222:18080` is a local IP fallback for workstations without `auth-admin.nas.nodedc` DNS. Both keep Authentik access separate from the public `id.nodedc.ru` login entrypoint and do not load NODE.DC auth-flow CSS.
|
||
|
||
## Что входит
|
||
|
||
- `docker-compose.platform-http.yml` поднимает новый Authentik, Launcher, Notification Core, AI Workspace Hub и Caddy edge.
|
||
- `Caddyfile.http` маршрутизирует локальные `auth/auth-admin/launcher/task.nas.nodedc`, IP fallback `172.22.0.222` для Authentik Admin и внешние `id/hub/ops.nodedc.ru`.
|
||
- `deploy-current.sh` синхронизирует compose, Caddyfile, Notification Core source, AI Workspace Hub source и опционально Launcher/BIM source в NAS mount. Authentik templates синхронизируются только при явном `SYNC_AUTHENTIK_TEMPLATES=1`.
|
||
- `backup-current.sh` делает snapshot Launcher runtime/uploads/Auth templates/config, BIM Viewer `server/data` и готовит команду `pg_dump` для Authentik Postgres.
|
||
- Tasker поднимается отдельным compose из `NODEDC_TASKMANAGER/plane-app/docker-compose.yaml` на порту `18090`.
|
||
- Ops Agents Gateway поднимается отдельным compose из `NODEDC_TASKMANAGER_CODEXAPI/docker-compose.synology.yml` на `172.22.0.222:18190`; Synology reverse proxy должен вести `ops-agents.nodedc.ru` на этот порт, а не на `18090`.
|
||
|
||
## Внутренний Authentik API для Launcher
|
||
|
||
Launcher подключен и к platform identity-сети, и к engine-сети. В engine-сети тоже может быть сервис с DNS-именем `authentik-server`, поэтому это имя нельзя использовать для `NODEDC_AUTHENTIK_BASE_URL`: Docker DNS может отдать не тот Authentik, и platform API-token будет получать `403 Token invalid/expired`.
|
||
|
||
Для platform Authentik зафиксирован отдельный alias:
|
||
|
||
```text
|
||
http://nodedc-platform-authentik-server:9000
|
||
```
|
||
|
||
Live `/volume1/docker/nodedc-platform/platform/.env.synology` должен содержать:
|
||
|
||
```env
|
||
NODEDC_AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
|
||
AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
|
||
NODEDC_AUTHENTIK_SERVICE_TOKEN=<server Authentik API token>
|
||
AUTHENTIK_SERVICE_TOKEN=<same token>
|
||
```
|
||
|
||
Быстрая проверка из launcher-контейнера:
|
||
|
||
```bash
|
||
sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc '
|
||
echo "$NODEDC_AUTHENTIK_BASE_URL"
|
||
getent hosts nodedc-platform-authentik-server
|
||
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
||
wget -qSO- \
|
||
--header "Authorization: Bearer $NODEDC_AUTHENTIK_SERVICE_TOKEN" \
|
||
"$NODEDC_AUTHENTIK_BASE_URL/api/v3/core/groups/?search=nodedc_admin" \
|
||
2>&1 | head -n 25 && exit 0
|
||
echo "authentik-api-not-ready attempt=$attempt"
|
||
sleep 10
|
||
done
|
||
exit 1
|
||
'
|
||
```
|
||
|
||
Ожидаемый результат: `HTTP/1.1 200 OK`.
|
||
|
||
После изменения platform Authentik alias пересоздавать нужно `authentik-server`, `authentik-worker` и `launcher`. Один `authentik-server` может временно отдавать `503 Service Unavailable`, пока worker и bootstrap не готовы.
|
||
|
||
## Синхронизация текущего состояния
|
||
|
||
С Mac, при смонтированном `/Volumes/docker`:
|
||
|
||
```bash
|
||
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
|
||
NAS_ROOT=/Volumes/docker/nodedc-platform \
|
||
LAUNCHER_REPO=/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher \
|
||
BIM_REPO=/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_BIM_VIEWER \
|
||
TASKER_REPO=/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER \
|
||
TASKER_CHANGED_BASE=533f8c6 \
|
||
GATEWAY_REPO=/Users/dcconstructions/Downloads/mnt/data/NODEDC_TASKMANAGER_CODEXAPI \
|
||
./infra/synology/deploy-current.sh
|
||
```
|
||
|
||
Скрипт не запускает Docker сам: на NAS `sudo` интерактивный, поэтому команды применения печатаются в конце.
|
||
|
||
По умолчанию sync source-копий на SMB/NAS не сохраняет owner/group/perms/times. Для Docker build важен контент, а macOS/Synology metadata может падать на `utimensat Operation timed out`. Если metadata действительно нужно сохранить для отдельного ручного случая, запускать с `RSYNC_PRESERVE_METADATA=1`.
|
||
|
||
Что синхронизируется:
|
||
|
||
- Platform compose/Caddy.
|
||
- Notification Core source в `/volume1/docker/nodedc-platform/platform/notification-core`.
|
||
- AI Workspace Hub source в `/volume1/docker/nodedc-platform/platform/ai-workspace-hub`.
|
||
- Authentik templates только при `SYNC_AUTHENTIK_TEMPLATES=1`; по умолчанию они не трогаются, чтобы лёгкий Hub deploy не уносил экспериментальную тему/брендинг в prod.
|
||
- Launcher source в `/volume1/docker/nodedc-platform/launcher/source`.
|
||
- BIM Viewer source в `/volume1/docker/nodedc-platform/bim-viewer/source`; `server/data` не синхронизируется и остаётся live runtime-хранилищем моделей, shares, comments и refs.
|
||
- Tasker `plane-app/docker-compose.yaml` и, если задан `TASKER_CHANGED_BASE`, только изменённые source-файлы из диапазона `TASKER_CHANGED_BASE..HEAD`.
|
||
- Ops Agents Gateway source в `/volume1/docker/nodedc-platform/ops-agents`.
|
||
|
||
Полный sync Tasker source по SMB тяжёлый для Plane fork. Использовать его только осознанно:
|
||
|
||
```bash
|
||
TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh
|
||
```
|
||
|
||
Секретные runtime env-файлы не перетираются:
|
||
|
||
- `/volume1/docker/nodedc-platform/platform/.env.synology`
|
||
- `/volume1/docker/nodedc-platform/bim-viewer/source/.env`
|
||
- `/volume1/docker/nodedc-platform/tasker/plane-app/.env.synology`
|
||
- `/volume1/docker/nodedc-platform/ops-agents/.env`
|
||
|
||
Если emergency-fix был сделан прямо на Synology в этих env-файлах, перенести sanitized-значение в `.env.synology.example`/docs, а секрет оставить только в live env.
|
||
|
||
### Gelios: frozen legacy compatibility contour
|
||
|
||
`gelios-postgres` и `gelios-gateway` — уже существующий self-hosted контур с
|
||
собственным persistent Timescale volume. Он остаётся полностью воспроизводимым
|
||
в source/deploy, но не развивается и не используется как шаблон для новых
|
||
провайдеров. Его удаление или миграция требуют отдельного подтверждённого плана;
|
||
обычный Platform/EDP deploy не удаляет volume и не изменяет старый workflow.
|
||
|
||
`GELIOS_UNIT_SCOPE=all` означает **все текущие и будущие units только одной уже
|
||
настроенной пары `GELIOS_TENANT_ID` + `GELIOS_CONNECTION_ID`**. Это не wildcard
|
||
на другие tenants или providers. Provider credential остаётся только в Engine.
|
||
Пропавший из очередного ответа unit не удаляется: его stable provider ID и
|
||
`last_seen_at` сохраняются; видимость на карте — отдельная логика витрины.
|
||
|
||
Перед узким legacy apply включить политику на Synology (скрипт создаёт backup и
|
||
не выводит секреты):
|
||
|
||
```bash
|
||
sudo bash /volume1/docker/nodedc-deploy/inbox/prepare-gelios-all-units-env.sh
|
||
```
|
||
|
||
В plan такого Platform-артефакта должны быть только `gelios-postgres` и
|
||
`gelios-gateway`; общий compose в узкий архив не входит.
|
||
|
||
## EDP publish grant: platform-owned credential
|
||
|
||
`NDC Data Product Writer API` — историческое имя native credential type для
|
||
внутреннего scoped EDP publish grant. Это не Gelios access/refresh token и не
|
||
право записи в Gelios.
|
||
|
||
Целевой путь полностью служебный: control plane NDC по разрешённому connection
|
||
profile генерирует capability внутри native NDC L2 Credentials, передаёт EDP
|
||
только digest для scoped binding и возвращает MCP только opaque compatible
|
||
reference/status.
|
||
Пользователь не читает, не копирует и не вводит этот внутренний секрет.
|
||
|
||
EDP уже имеет localhost-only digest-only managed endpoint. Managed endpoint и
|
||
legacy plaintext provisioning имеют раздельные флаги и по умолчанию выключены.
|
||
Runner-owned provisioner bearer относится только к legacy plaintext routes и
|
||
на managed ensure/revoke намеренно не действует. Managed caller contract —
|
||
Ed25519-signed Engine service request с exact audience, method, request target,
|
||
raw-body SHA-256, timestamp и одноразовым nonce; EDP хранит только public key и
|
||
fail-closed replay cache. Ни bearer, ни signing private key нельзя открывать
|
||
workflow, MCP или переиспользовать как shared credential. В source-кандидате
|
||
Engine добавлен отдельный server-derived plan/apply для exact пары
|
||
`ndcDataProductWriterApi` + custom Publish node; он не расширяет generic HTTP
|
||
safe-ref policy и не принимает provider/scope/credential identity, capability,
|
||
generation или service URL от MCP. До отдельного Engine deploy и runtime proof
|
||
текущий deployed MCP этого контракта не имеет. Поэтому отсутствие
|
||
совместимого reference — платформенный runtime gap, а не действие пользователя.
|
||
Ручной перенос capability из отдельно включаемого legacy endpoint через root/UI допустим только как аварийная
|
||
диагностика self-hosted контура; он не является acceptance-путём и не должен
|
||
закрепляться в пользовательской автоматизации.
|
||
|
||
Compose монтирует read-only trust directory
|
||
`/volume1/docker/nodedc-platform/trust/engine-managed-provisioner` в EDP; в нём
|
||
ожидается один regular, non-symlink файл `public-key.pem` с Ed25519 SPKI public
|
||
key. Файл не должен быть group/world-writable и должен читаться runtime UID
|
||
`11006`. Private key в этот каталог, Platform artifact, `.env` или EDP
|
||
контейнер не попадает. Canonical deploy runner теперь атомарно создаёт или
|
||
проверяет matching Ed25519 pair перед relevant Engine/EDP Compose apply: private
|
||
key остаётся `root:root 0400`, public trust — `root:11006 0440`; public-only
|
||
crash state, mismatch, symlink и неверный тип ключа отклоняются до запуска.
|
||
`EXTERNAL_DATA_PLANE_MANAGED_PROVISIONING_ENABLED` остаётся `false` на staging.
|
||
В отдельно подтверждённом activation window его переводят в `true`
|
||
непосредственно перед Platform EDP artifact; runner принимает deploy только
|
||
если `/healthz` явно вернул managed status `enabled`. Старый Engine в этот
|
||
момент ещё не имеет signer mount, поэтому usable caller появляется лишь после
|
||
следующего отдельно принятого Engine artifact.
|
||
EDP application artifact пересобирает и force-recreate только
|
||
`external-data-plane`. Уже работающий `external-data-plane-postgres` и его
|
||
Timescale volume runner не выбирает и не перезапускает; healthy database —
|
||
обязательная deploy prerequisite.
|
||
Canonical service/key/audience заданы в `.env.synology.example`; wire headers и
|
||
canonical signing payload описаны в `packages/external-provider-contract/README.md`.
|
||
|
||
До появления opaque compatible reference и успешного manual publish proof
|
||
Schedule Trigger не включать. Frozen legacy workflow и его credentials этот
|
||
процесс не изменяет.
|
||
|
||
## AI Hub relay-only deploy
|
||
|
||
Для локального тестирования с внешней Codex-машиной нельзя деплоить Launcher, Engine, Ops, Authentik или Tasker. Единственная допустимая удалённая точка в этой схеме — `ai-workspace-hub`, потому что удалённый worker должен иметь публичный WebSocket/HTTP relay.
|
||
|
||
С Mac, при смонтированном `/Volumes/docker`, синхронизировать только Hub source, compose и узкий apply-script:
|
||
|
||
```bash
|
||
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
|
||
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/sync-ai-hub-relay.sh
|
||
```
|
||
|
||
На Synology применить только `ai-workspace-hub`:
|
||
|
||
```bash
|
||
ssh dctouch@100.109.216.21 'cd /volume1/docker/nodedc-platform/platform && sudo bash apply-ai-hub-relay.sh'
|
||
```
|
||
|
||
Этот путь намеренно делает только:
|
||
|
||
- build `nodedc/ai-workspace-hub:local`;
|
||
- `docker compose up -d --no-deps --force-recreate ai-workspace-hub`;
|
||
- container health check;
|
||
- проверку `/api/ai-workspace/hub/v1/assistant-relays/<relayId>/poll`;
|
||
- public route check через `https://ai-hub.nodedc.ru`.
|
||
|
||
Он не меняет `.env.synology`, не синхронизирует Launcher/Tasker/Ops source, не пересоздаёт Authentik, reverse-proxy, базы, storage или product containers.
|
||
|
||
После успешного relay-only deploy локальная цепочка для теста должна быть такой:
|
||
|
||
```text
|
||
local Launcher/Engine/Ops/Auth/Assistant
|
||
-> deployed AI Hub relay: https://ai-hub.nodedc.ru
|
||
-> remote Codex worker
|
||
-> deployed AI Hub relay
|
||
-> local Assistant relay poll
|
||
-> local product services
|
||
```
|
||
|
||
## Лёгкое обновление Hub / Launcher
|
||
|
||
Для правок только в Launcher/BFF не пересоздавать Authentik, reverse-proxy, Tasker и Ops Agents:
|
||
|
||
```bash
|
||
cd /volume1/docker/nodedc-platform/launcher/source
|
||
sudo /usr/local/bin/docker build --no-cache -t nodedc/launcher:local .
|
||
|
||
cd /volume1/docker/nodedc-platform/platform
|
||
sudo /usr/local/bin/docker compose \
|
||
--env-file /volume1/docker/nodedc-platform/platform/.env.synology \
|
||
-f /volume1/docker/nodedc-platform/platform/docker-compose.platform-http.yml \
|
||
up -d --force-recreate --no-deps ai-workspace-hub launcher
|
||
```
|
||
|
||
После такого deploy проверить `healthz`, запись в launcher storage/uploads и сценарий пользователя без аппрува: сохранение аватара не должно показывать экран `Заявка ожидает подтверждения`. Дополнительно проверить, что live bundle больше не содержит старый pending gate:
|
||
|
||
```bash
|
||
launcher_asset="$(
|
||
curl -k -sS --compressed -H 'Accept: text/html' https://hub.nodedc.ru/ \
|
||
| grep -aoE 'index-[A-Za-z0-9_-]+\.js' \
|
||
| head -n 1
|
||
)"
|
||
test -n "$launcher_asset"
|
||
if curl -k -sS --compressed "https://hub.nodedc.ru/assets/${launcher_asset}" \
|
||
| grep -aq 'Заявка ожидает подтверждения'; then
|
||
echo 'old pending gate still present'
|
||
exit 1
|
||
fi
|
||
echo 'launcher-pending-gate-ok'
|
||
```
|
||
|
||
## BIM Viewer deploy
|
||
|
||
`bim.nodedc.tech` на Synology можно вести напрямую через DSM Reverse Proxy на `172.22.0.222:18100`. В этом режиме Platform Caddy не участвует в публичном BIM-трафике, но `Caddyfile.http` всё равно содержит BIM route как запасной вариант для маршрута через `172.22.0.222:18080`.
|
||
|
||
Canonical BIM deploy now uses `nodedc-deploy` with `component=bim-viewer`; do not deploy BIM by manually running `docker compose up` from the source directory as the normal path.
|
||
|
||
Live BIM root:
|
||
|
||
```text
|
||
/volume1/docker/nodedc-platform/bim-viewer/source
|
||
```
|
||
|
||
Live env stays outside artifacts:
|
||
|
||
```text
|
||
/volume1/docker/nodedc-platform/bim-viewer/source/.env
|
||
```
|
||
|
||
Before the first canonical apply, prepare `.env` from `.env.synology.example` and verify that `NODEDC_INTERNAL_ACCESS_TOKEN` matches `platform/.env.synology`. After that, `.env` must not be included in deploy artifacts.
|
||
|
||
Canonical deploy commands:
|
||
|
||
```bash
|
||
sudo /usr/local/sbin/nodedc-deploy verify-install
|
||
sudo /usr/local/sbin/nodedc-deploy plan /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz
|
||
sudo /usr/local/sbin/nodedc-deploy apply /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz
|
||
```
|
||
|
||
The `bim-viewer` runner component:
|
||
|
||
- applies payload under `/volume1/docker/nodedc-platform/bim-viewer/source`;
|
||
- rejects `.env`, `server/data`, upload/model/comment/share runtime storage, `node_modules`, `.git`, shell hooks and backup files;
|
||
- prepares required live runtime directories under `server/data` before compose;
|
||
- builds `nodedc/bim-converter:local` from `converter/Dockerfile`;
|
||
- recreates only `ndc-beam-viewer` and `nodedc-bim-converter`;
|
||
- healthchecks `http://127.0.0.1:18100/api/auth/session`.
|
||
|
||
Минимальная проверка после apply:
|
||
|
||
```bash
|
||
curl -k -fsS http://127.0.0.1:18100/api/auth/session
|
||
curl -k -sS -o /dev/null -w '%{http_code}\n' https://bim.nodedc.tech/
|
||
```
|
||
|
||
Ожидаемо: `/api/auth/session` возвращает `authRequired: true`, а прямой public root без BIM-сессии отдаёт `302` в Launcher login/launch. Public share `/share/<token>` должен открываться без авторизации и без toolbar.
|
||
|
||
## Tasker / OPS BIM iframe rebuild
|
||
|
||
OPS web bundle получает BIM URL на build-time через `VITE_BEAM_VIEWER_BASE_URL` и `VITE_BEAM_API_BASE_URL`. После смены домена пересобрать только web image:
|
||
|
||
```bash
|
||
cd /volume1/docker/nodedc-platform/tasker/plane-src
|
||
VITE_BEAM_VIEWER_BASE_URL=https://bim.nodedc.tech \
|
||
VITE_BEAM_API_BASE_URL=https://bim.nodedc.tech \
|
||
BUILD_BACKEND=0 BUILD_WEB=1 BUILD_ADMIN=0 \
|
||
sh rebuild-nas-legacy.sh
|
||
```
|
||
|
||
Это пересоздаёт только `web` и не трогает PostgreSQL/MinIO volumes.
|
||
|
||
## Authentik Admin и Brand CSS
|
||
|
||
NODE.DC auth-flow CSS must stay template-scoped. Do not store it in Authentik `Brand.branding_custom_css`: Authentik passes that CSS into Admin/User web component runtime and breaks native controls.
|
||
|
||
After syncing Authentik templates to NAS, recreate `reverse-proxy authentik-server authentik-worker launcher`, then clear existing global Brand CSS in the live DB:
|
||
|
||
```bash
|
||
cd /volume1/docker/nodedc-platform/platform
|
||
sudo bash clear-authentik-brand-css.sh
|
||
```
|
||
|
||
Verify:
|
||
|
||
```bash
|
||
id_admin_status="$(
|
||
curl -k -sS -o /dev/null -w '%{http_code}' https://id.nodedc.ru/if/admin/
|
||
)"
|
||
if [[ "$id_admin_status" != "404" ]]; then
|
||
echo "public id admin is not closed: status=${id_admin_status}"
|
||
exit 1
|
||
fi
|
||
echo 'public-id-admin-closed-ok'
|
||
|
||
auth_admin_page="$(
|
||
curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/admin/
|
||
)"
|
||
printf '%s' "$auth_admin_page" \
|
||
| grep -aE '<style data-id="brand-css"></style>|authentikBrand.branding_custom_css = ""'
|
||
|
||
auth_admin_flow="$(
|
||
curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/flow/default-authentication-flow/
|
||
)"
|
||
if printf '%s' "$auth_admin_flow" | grep -aq '<style data-id="nodedc-auth-login-css">'; then
|
||
echo 'admin host still has NODE.DC auth CSS'
|
||
exit 1
|
||
fi
|
||
echo 'auth-admin-css-ok'
|
||
```
|
||
|
||
## Backup текущего состояния
|
||
|
||
С Mac, при смонтированном `/Volumes/docker`:
|
||
|
||
```bash
|
||
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
|
||
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/backup-current.sh
|
||
```
|
||
|
||
Файловый backup создаётся в `/Volumes/docker/nodedc-platform/backups/platform-current-*`.
|
||
|
||
Для Authentik Postgres dump нужно выполнить напечатанную команду на Synology, потому что Docker доступен через интерактивный `sudo`:
|
||
|
||
```bash
|
||
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-authentik-db-dump-on-synology.sh
|
||
```
|
||
|
||
Для Notification Core Postgres dump:
|
||
|
||
```bash
|
||
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-notification-db-dump-on-synology.sh
|
||
```
|
||
|
||
Если планируются изменения Tasker backend/schema, дополнительно выполнить:
|
||
|
||
```bash
|
||
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-tasker-db-dump-on-synology.sh
|
||
```
|
||
|
||
Если Ops Agents Gateway уже был запущен и там есть production tokens/grants/audit, дополнительно выполнить:
|
||
|
||
```bash
|
||
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-ops-agents-db-dump-on-synology.sh
|
||
```
|
||
|
||
## Что нужно перед запуском
|
||
|
||
- Собрать или загрузить `linux/amd64` images:
|
||
- `nodedc/launcher:local`
|
||
- `nodedc/notification-core:local`
|
||
- `nodedc/plane-frontend:ru`
|
||
- `nodedc/plane-admin:ru`
|
||
- `nodedc/plane-space:ru`
|
||
- `nodedc/plane-live:local`
|
||
- `nodedc/plane-backend:local`
|
||
- `nodedc/plane-proxy:ru`
|
||
- Для Ops Agents Gateway отдельный registry image пока не обязателен: deploy из source repo выполняется через `docker compose --env-file .env -f docker-compose.synology.yml up -d --build`.
|
||
- Создать `.env.synology` из `.env.synology.example` и заменить все `replace-with-*`.
|
||
- Создать `plane.env.synology` для Tasker из `plane.env.staging.example`, но с HTTP URL на `*.nas.nodedc:18080` и портами `18090/18490`.
|
||
|
||
## Обязательные runtime-права
|
||
|
||
Launcher пишет runtime snapshot и uploads под пользователем `node` (`uid=1000`). После создания NAS-папок:
|
||
|
||
```bash
|
||
cd /volume1/docker/nodedc-platform/platform
|
||
sudo mkdir -p ../launcher/server-storage ../launcher/uploads
|
||
sudo chown -R 1000:1000 ../launcher/server-storage ../launcher/uploads
|
||
sudo chmod -R u+rwX,g+rwX ../launcher/server-storage ../launcher/uploads
|
||
```
|
||
|
||
Проверка внутри контейнера:
|
||
|
||
```bash
|
||
sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc \
|
||
'touch /app/server/storage/.write-test /app/server/storage/uploads/.write-test && rm /app/server/storage/.write-test /app/server/storage/uploads/.write-test && echo storage-ok'
|
||
```
|
||
|
||
## Проверки после деплоя
|
||
|
||
```bash
|
||
curl -k -sS --compressed https://id.nodedc.ru/if/flow/default-authentication-flow/ \
|
||
| grep -aE 'hub.nodedc.ru|launcher.local|getLauncherBaseUrl|Запросить доступ'
|
||
```
|
||
|
||
В выводе должны быть `id.nodedc.ru -> hub.nodedc.ru` и не должно быть `launcher.local`.
|