NODEDC_PLATFORM/infra/synology
Codex 31e078d6e5 docs(platform): align connector, EDP, and deploy canon 2026-07-17 18:09:55 +03:00
..
tasker-overlays/logo-link-brand-hotfix OPS - TASKER: capture editable logo link overlay 2026-05-14 16:25:20 +03:00
.env.synology.example feat(deploy): extend canon for managed EDP and Engine grants 2026-07-17 18:09:39 +03:00
Caddyfile.http Add BIM Viewer to Synology deploy canon 2026-06-22 13:54:00 +03:00
README.md docs(platform): align connector, EDP, and deploy canon 2026-07-17 18:09:55 +03:00
apply-ai-hub-relay.sh feat(ai-workspace): add local relay profiles 2026-06-20 12:54:19 +03:00
apply-current-runtime.sh feat(deploy): extend canon for managed EDP and Engine grants 2026-07-17 18:09:39 +03:00
backup-current.sh feat(deploy): register managed platform runtime components 2026-07-16 02:25:31 +03:00
check-ai-workspace-apply-plan.sh Add dynamic AI Workspace run profiles 2026-06-13 17:30:48 +03:00
clear-authentik-brand-css.sh fix(platform): isolate authentik admin styling 2026-05-25 01:08:50 +03:00
deploy-current.sh feat(deploy): register managed platform runtime components 2026-07-16 02:25:31 +03:00
docker-compose.external-data-plane.yml feat(deploy): extend canon for managed EDP and Engine grants 2026-07-17 18:09:39 +03:00
docker-compose.platform-http.yml feat(deploy): extend canon for managed EDP and Engine grants 2026-07-17 18:09:39 +03:00
prepare-ai-workspace-env.sh Add dynamic AI Workspace run profiles 2026-06-13 17:30:48 +03:00
prepare-external-data-plane-env.sh feat(deploy): register managed platform runtime components 2026-07-16 02:25:31 +03:00
prepare-gelios-all-units-env.sh feat(deploy): register managed platform runtime components 2026-07-16 02:25:31 +03:00
sync-ai-hub-relay.sh feat(ai-workspace): add local relay profiles 2026-06-20 12:54:19 +03:00
verify-current-runtime.sh feat(deploy): extend canon for managed EDP and Engine grants 2026-07-17 18:09:39 +03:00

README.md

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:

/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy

The live root-owned runner is:

/usr/local/sbin/nodedc-deploy

deploy-current.sh syncs the runner candidate into runner-install. Promoting it to live is explicit:

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

Текущие внешние домены

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:

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:

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:

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:

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:

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:

http://nodedc-platform-authentik-server:9000

Live /volume1/docker/nodedc-platform/platform/.env.synology должен содержать:

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-контейнера:

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:

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. Использовать его только осознанно:

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 и не выводит секреты):

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:

cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/sync-ai-hub-relay.sh

На Synology применить только ai-workspace-hub:

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 локальная цепочка для теста должна быть такой:

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:

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:

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:

/volume1/docker/nodedc-platform/bim-viewer/source

Live env stays outside artifacts:

/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:

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:

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:

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:

cd /volume1/docker/nodedc-platform/platform
sudo bash clear-authentik-brand-css.sh

Verify:

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:

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 /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-authentik-db-dump-on-synology.sh

Для Notification Core Postgres dump:

bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-notification-db-dump-on-synology.sh

Если планируются изменения Tasker backend/schema, дополнительно выполнить:

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 /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-папок:

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

Проверка внутри контейнера:

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'

Проверки после деплоя

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.