Tmavý režim
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:
| Komponenta | Co to je | Kde se buildí |
|---|---|---|
| jabcore-platform-api | API (/api) + Swagger (/api/docs) + docs (/docs). Panel NENÍ uvnitř. | deploy.sh na DEV → push do registry.jabcore.cloud |
| jabcore-platform-admin | Admin panel (Vue SPA), servírovaný staticky | build.sh přímo na serveru |
| jabcore-platform-auth | Zitadel Login v2 UI (Next.js) | image z registry.jabcore.cloud |
| jabcore-zitadel | Zitadel server (OIDC/SAML IdP) | oficiální image ghcr.io/zitadel/zitadel |
| jabcore-postgres | Jeden PostgreSQL se dvěma databázemi: jabcore-platform-db + zitadel | postgres: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-apiimage 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éna | Cíl |
|---|---|
zitadel.auth.jabcore.cloud | Zitadel server (issuer / mgmt API / konzole) |
auth.jabcore.cloud | Login v2 UI |
api.auth.jabcore.cloud | API /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éna | Cíl |
|---|---|
zitadel.auth.test.jabcore.cloud | Zitadel server |
auth.test.jabcore.cloud | Login v2 UI |
api.auth.test.jabcore.cloud | API + Swagger + docs |
admin.auth.test.jabcore.cloud | Admin 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á naconfig/default.yaml- Panel pro lokální vývoj:
npm run devv repujabcore-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.shCo deploy.sh dělá:
- vyžaduje čistý git tree;
docker buildxcross-build prolinux/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(namain); - 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 dotazuTři módy a jejich výstup (verzovaný adresář + symlink latest):
| Mód | Env soubor | Výstup | Doména | Backend |
|---|---|---|---|---|
| production | .env.production | release/latest | admin.auth.jabcore.cloud | prod API + prod Zitadel |
| test | .env.test | release-test/latest | admin.auth.test.jabcore.cloud | test API + test Zitadel |
| test-production | .env.test-production | release-test-production/latest | test.admin.auth.jabcore.cloud | prod 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 -dTest
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 -dNODE_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íkapp).zitadel— Zitadel si ji vytvoří sám při prvním startu (appje instance admin, vyrobí DB + runtime userazitadel).
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.sqlVš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_PASSWORD | heslo DB app (user-api + Zitadel admin) |
ZITADEL_DB_PASSWORD | heslo Zitadel runtime usera |
ZITADEL_MASTERKEY | klíč, kterým Zitadel šifruje secrety v DB (32 znaků) |
ZITADEL_ADMIN_USER / _PASSWORD | první admin Zitadelu (bootstrap) |
ZITADEL_SERVICE_ACCOUNT_TOKEN | PAT service účtu, kterým API volá Zitadel |
ZITADEL_PROJECT_ORG_ID | Platformní 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_SECRET | ověření příchozích Zitadel Action callů |
INTERNAL_API_KEY | sdílený klíč pro interní service-to-service endpointy |
BRAND_SMTP_KEY | AES 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 versionbump (git tagvX.Y.Z) - [ ] čistý git tree
- [ ]
./deploy.sh→ image v hubu (:vX.Y.Z+:latest)
Panel (server):
- [ ]
.env.production/.env.testmá správnýVITE_API_BASE_URL - [ ] produkční
VITE_ZITADEL_CLIENT_IDdoplněné - [ ] každý user pool má propojenou Zitadel organizaci (admin → User pooly)
- [ ]
./build.sh→release(-test)/latest - [ ] Caddy servíruje z
latestsymlinku
Stack (server):
- [ ]
.env.production/.env.testse secrety (žádné defaultychange-me-*) - [ ]
ZITADEL_MASTERKEYnastaven (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
