Skip to content

Nasazení ​

Tahle stránka popisuje, jak se projekt staví a nasazuje — lokálně, na test a na produkci.

Přehled architektury ​

Systém se skládá ze čtyř kontejnerů + jednoho samostatného static buildu:

KomponentaCo to jeKde se buildí
jabcore-platform-apiAPI (/api) + Swagger (/api/docs) + docs (/docs). Panel NENÍ uvnitř.deploy.sh na DEV → push do registry.jabcore.cloud
jabcore-platform-adminAdmin panel (Vue SPA), servírovaný statickybuild.sh přímo na serveru
jabcore-platform-authZitadel Login v2 UI (Next.js)image z registry.jabcore.cloud
jabcore-zitadelZitadel server (OIDC/SAML IdP)oficiální image ghcr.io/zitadel/zitadel
jabcore-postgresJeden PostgreSQL se dvěma databázemi: jabcore-platform-db + zitadelpostgres:16-alpine

Image se pushují do vlastního registry registry.jabcore.cloud (projekt jabcore-registry, běží na lionu). Dev stroj i server potřebují jednou docker login registry.jabcore.cloud (servery účtem deploy).

Klíčové principy:

  • Image je env-agnostický. Tentýž jabcore-platform-api image běží na prod i testu — prostředí vybírá NODE_ENV (→ config/production.yaml / config/test.yaml).
  • Panel se vydává samostatně (často, nezávisle na API), buduje se na serveru z repa jabcore-platform-admin.
  • Panel ↔ API jsou cross-origin (každý na své doméně). CORS je v API otevřený, takže to funguje bez whitelistu.
  • TLS terminuje Caddy na proxy serveru; kontejnery jedou v HTTP.

Domény ​

Produkce (jabcore.cloud) ​

DoménaCíl
zitadel.auth.jabcore.cloudZitadel server (issuer / mgmt API / konzole)
auth.jabcore.cloudLogin v2 UI
api.auth.jabcore.cloudAPI /api + Swagger /api/docs + docs /docs

Swagger a docs jsou v produkci chráněné přes OIDC instanci aplikace auth. Přesný callback a proměnné DOCS_TOKEN_SECRET / DOCS_PUBLIC_BASE_URL jsou popsané v Přístupu k dokumentaci. | admin.auth.jabcore.cloud | Admin panel (static) | | test.admin.auth.jabcore.cloud | Admin panel — test-production build (test FE proti ostrému prod backendu) |

Test (test.jabcore.cloud) ​

DoménaCíl
zitadel.auth.test.jabcore.cloudZitadel server
auth.test.jabcore.cloudLogin v2 UI
api.auth.test.jabcore.cloudAPI + Swagger + docs
admin.auth.test.jabcore.cloudAdmin panel (static)

1) Lokální vývoj ​

docker-compose.yml postaví celý stack lokálně z buildů (ne z hubu) — vlastní postgres (app/app, auto-init z sql/), API, panel i login s build kontexty.

bash
./build.sh            # git pull 3 repa + docker compose up --build
  • API: localhost:3001, Postgres: localhost:5434, Zitadel: localhost:3000/8080
  • NODE_ENV=development → padá na config/default.yaml
  • Panel pro lokální vývoj: npm run dev v repu jabcore-platform-admin (Vite na :5173, proxy /api → localhost:3001)

2) API image — build & push (DEV stroj) ​

API image se staví a pushuje skriptem deploy.sh na vývojářském stroji:

bash
# 1) bump verze (vytvoří git tag vX.Y.Z)
npm version patch        # nebo minor / major

# 2) build + push do registry.jabcore.cloud
./deploy.sh

Co deploy.sh dělá:

  • vyžaduje čistý git tree;
  • docker buildx cross-build pro linux/amd64 (servery jsou x86_64 — na Macu by jinak vznikl arm64 a spadl by „exec format error");
  • build + push v jednom kroku, tagy :vX.Y.Z (z git tagu) a :latest (na main);
  • panel nebuildí (od oddělení panelu) — image obsahuje jen API + docs.

Přebít platformu jde přes PLATFORMS=… ./deploy.sh.

3) Panel — build na serveru ​

Panel se buduje přímo na serveru z repa jabcore-platform-admin skriptem build.sh. Je to per-env build (build:production / build:test / build:test-production) — build-time hodnoty se berou z příslušného .env.<mode> (hlavně VITE_API_BASE_URL + Zitadel clientId/orgs).

bash
cd /opt/apps/jabcore-platform-admin

./build.sh           # nabídne: 1) production  2) test  3) test-production
./build.sh -q        # production bez dotazu

Tři módy a jejich výstup (verzovaný adresář + symlink latest):

MódEnv souborVýstupDoménaBackend
production.env.productionrelease/latestadmin.auth.jabcore.cloudprod API + prod Zitadel
test.env.testrelease-test/latestadmin.auth.test.jabcore.cloudtest API + test Zitadel
test-production.env.test-productionrelease-test-production/latesttest.admin.auth.jabcore.cloudprod API + prod Zitadel

test-production

Slouží k testování změn pouze ve frontendu proti ostrému produkčnímu backendu. Je shodný s production, liší se jen redirect/logout URI (míří na test.admin.auth.jabcore.cloud) — ta URI musí být povolená v produkční Zitadel aplikaci (Redirect URIs), jinak login selže.

Caddy pak servíruje statiku z latest symlinku:

caddyfile
admin.auth.jabcore.cloud {
    root * /opt/apps/jabcore-platform-admin/release/latest
    try_files {path} /index.html      # SPA fallback
    file_server
}
admin.auth.test.jabcore.cloud {
    root * /opt/apps/jabcore-platform-admin/release-test/latest
    try_files {path} /index.html
    file_server
}
test.admin.auth.jabcore.cloud {
    root * /opt/apps/jabcore-platform-admin/release-test-production/latest
    try_files {path} /index.html
    file_server
}

Produkční client ID

Protože panel nemá runtime config, ZITADEL clientId se zapéká při buildu z panelového .env.production (VITE_ZITADEL_CLIENT_ID). Organization ID se do panelového prostředí už nezapisují: odkazy i směrování auth e-mailů se odvozují z brand.zitadelOrgId načteného přes API.

4) Stack na serveru — pull & up ​

Images (jabcore-platform-api, jabcore-platform-auth) se na server jen tahají z hubu, nebuildí se tam.

Produkce ​

Nasazuje se přes ansible (volá docker compose), nebo ručně:

bash
docker compose -f docker-compose.production.yml --env-file .env.production pull
docker compose -f docker-compose.production.yml --env-file .env.production up -d

Test ​

bash
docker compose -f docker-compose.test.yml --env-file .env.test pull
docker compose -f docker-compose.test.yml --env-file .env.test up -d

NODE_ENV (production / test) je v compose souboru a vybere config/*.yaml. Hesla a secrety jdou z .env.production / .env.test (gitignored).

Databáze ​

Jeden postgres (jabcore-postgres) drží dvě databáze:

  • jabcore-platform-db — user-api (vlastník app).
  • zitadel — Zitadel si ji vytvoří sám při prvním startu (app je instance admin, vyrobí DB + runtime usera zitadel).

Schéma a seed user-api se aplikují ručně po prvním startu (server nemá repo se sql/):

bash
docker exec -i jabcore-postgres psql -v ON_ERROR_STOP=1 -U app -d jabcore-platform-db < sql/init.sql
docker exec -i jabcore-postgres psql -v ON_ERROR_STOP=1 -U app -d jabcore-platform-db < sql/panel_auth_permissions.sql
docker exec -i jabcore-postgres psql -v ON_ERROR_STOP=1 -U app -d jabcore-platform-db < sql/auth_panel_notifications.sql
docker exec -i jabcore-postgres psql -v ON_ERROR_STOP=1 -U app -d jabcore-platform-db < sql/data.sql

Všechny skripty jsou idempotentní. sql/init.sql je kompletní schéma Jabcore Platform (včetně user poolů) — historie migrací z původního projektu se do Jabcore nepřenáší. Změny schématu od teď přibývají v sql/migrations/ (nový soubor YYYY-MM-DD_popis.sql) a zároveň v sql/init.sql; spouští se přes sql/migrations/db_apply.sh.

sql/init.sql založí platform user pool jabcore. API ho při startu propojí s platformní organizací ZITADEL_PROJECT_ORG_ID. sql/data.sql přidá účty týmu Jabcore do platform poolu a nastaví je jako superadminy.

Login v2 po úspěšné změně profilu volá interní POST /api/internal/auth/profile-sync; používá stejné USER_API_URL a USER_API_INTERNAL_KEY jako registrace. ZITADEL Action může navíc posílat na POST /api/zitadel/webhook event user.updated jako záložní cestu pro změny provedené mimo Login v2. Stejný webhook secret zůstává beze změny.

jabcore-platform-api je zdrojem pravdy: jedna lokální aplikace spravuje jeden vlastní ZITADEL projekt, jednu OIDC SPA aplikaci a callbacky odvozené z instancí. Existující vzdálené objekty nejdřív importujte pomocí jejich project/application/client ID jako unmanaged a teprve po ověření je případně přepněte na managed.

Smazání lokální aplikace smí smazat vzdálený projekt pouze při zitadel_managed = true; u importované unmanaged aplikace se vzdálený stav nemění. Pokud synchronizace nebo vzdálené mazání selže, lokální záznam musí zůstat zachovaný se stavem error a operace se po odstranění příčiny opakuje.

Konfigurace prostředí ​

Hierarchie configu (node-config):

  • config/default.yaml — společné defaulty (+ dev).
  • config/test.yaml (NODE_ENV=test) / config/production.yaml (NODE_ENV=production).
  • config/custom-environment-variables.yaml — mapuje secrety na env proměnné.

Secrety se nikdy necommitují — jdou přes .env.production / .env.test:

ProměnnáVýznam
POSTGRES_PASSWORDheslo DB app (user-api + Zitadel admin)
ZITADEL_DB_PASSWORDheslo Zitadel runtime usera
ZITADEL_MASTERKEYklíč, kterým Zitadel šifruje secrety v DB (32 znaků)
ZITADEL_ADMIN_USER / _PASSWORDprvní admin Zitadelu (bootstrap)
ZITADEL_SERVICE_ACCOUNT_TOKENPAT service účtu, kterým API volá Zitadel
ZITADEL_PROJECT_ORG_IDPlatformní organizace: vlastní managed projekty a drží účty platform user poolu (admin panel). Doplní se po prvním startu Zitadelu; do té doby API jen varuje.
ZITADEL_WEBHOOK_SECRETověření příchozích Zitadel Action callů
INTERNAL_API_KEYsdílený klíč pro interní service-to-service endpointy
BRAND_SMTP_KEYAES klíč pro šifrování per-brand SMTP hesel v DB
EMAIL_SMTP_*globální SMTP fallback (když brand nemá vlastní)

Login kontejner musí dostat USER_API_URL (bez koncového /api) a USER_API_INTERNAL_KEY, jehož hodnota je shodná s INTERNAL_API_KEY user API. Bez USER_API_URL login nezjistí user pool aplikace a přihlášení do registrovaných aplikací odmítne.

Health check ​

bash
curl https://api.auth.jabcore.cloud/api/health     # { status, version, uptime }
curl https://api.auth.jabcore.cloud/api/version     # { version, gitSha, buildMode }

Kontejner app má i Docker healthcheck na /api/health.

Checklist před nasazením ​

API image (DEV):

  • [ ] npm version bump (git tag vX.Y.Z)
  • [ ] čistý git tree
  • [ ] ./deploy.sh → image v hubu (:vX.Y.Z + :latest)

Panel (server):

  • [ ] .env.production / .env.test má správný VITE_API_BASE_URL
  • [ ] produkční VITE_ZITADEL_CLIENT_ID doplněné
  • [ ] každý user pool má propojenou Zitadel organizaci (admin → User pooly)
  • [ ] ./build.sh → release(-test)/latest
  • [ ] Caddy servíruje z latest symlinku

Stack (server):

  • [ ] .env.production / .env.test se secrety (žádné defaulty change-me-*)
  • [ ] ZITADEL_MASTERKEY nastaven (a při migraci DB sedí se starým)
  • [ ] docker compose … pull && up -d
  • [ ] DB inicializována (init.sql + data.sql + pending migrace)
  • [ ] Superadmin spustil POST /api/zitadel/admin/notification-provider/setup
  • [ ] Caddy: 4 domény (zitadel / login / api / panel)
  • [ ] SSL certifikáty platné
  • [ ] Zálohování DB nastaveno

Jabcore Platform — interní dokumentace