# admin-api — shared management-plane API (Fastify, port 4731) на vds-kzntsv (89.253.255.94). # # STAGING-FIRST. Source-of-truth compose — admin-репо; применяется через Portainer API/UI # (VDS-rule: стеки через Portainer, не ssh+compose). # # Модель: @snolla/admin-api (Fastify, Prisma→MSSQL) — resource-oriented CRUD + ContentTools # (fields[]/Content) + keys-эндпоинты (Bearer PAT sk_…). Общий management-plane инстанс # (один на все тенанты, по дизайну admin-typed-api-design). Читает/пишет MoreThenCms # (mssql.kzntsv.site, user snolla). Первый потребитель — @pilorama98/loader (apps/loader). # # Образ: registry.kzntsv.site/admin-api:ca0dfa3 — собран АДМИНОМ на VDS из victor/snolla # (packages/admin-api/Dockerfile, multi-stage node:22-slim, deps public npm — verdaccio не нужен). # Тег = git-sha snolla master. ca0dfa3 = ESM-фикс (relative imports .js). Healthcheck GET /health (в Dockerfile). # # Домен: admin-api.vds.kzntsv.site (wildcard → VDS). LE cert на первый hit. # # Runtime egress: mssql.kzntsv.site:1433 (traefik TCP), minio.vds.kzntsv.site:443 (theme-files ops). # # Секреты — env на VDS (Portainer stack env), НЕ в образ, НЕ в git. Контракт стека: # DATABASE_URL JWT_SECRET S3_ENDPOINT S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY S3_REGION S3_FORCE_PATH_STYLE THEMES_BUCKET # JWT_SECRET — реальный (не дефолт dev-secret-change-in-production). S3_* — для theme-storage-плагина # (loader'у не нужен, но общий инстанс — заводим сразу). services: admin-api: container_name: admin-api image: registry.kzntsv.site/admin-api:ca0dfa3 restart: unless-stopped mem_limit: 512m # guardrail: admin-api базало ~100-200M; OOM -> restart. environment: NODE_ENV: production TZ: Europe/Moscow # --- runtime-секреты (значения из Portainer stack env; НЕ хранить тут) --- DATABASE_URL: ${DATABASE_URL} JWT_SECRET: ${JWT_SECRET} S3_ENDPOINT: ${S3_ENDPOINT} S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID} S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY} S3_REGION: ${S3_REGION} S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE} THEMES_BUCKET: ${THEMES_BUCKET} networks: - proxy labels: traefik.enable: "true" traefik.http.routers.admin-api.entrypoints: websecure traefik.http.routers.admin-api.rule: Host(`admin-api.vds.kzntsv.site`) traefik.http.routers.admin-api.tls.certresolver: letsEncrypt traefik.http.services.admin-api.loadbalancer.server.port: "4731" networks: proxy: external: true