Tmavý režim
User pooly — oddělení uživatelů per aplikace
Jabcore Platform slouží jako základ pro SaaS produkty i zakázkové aplikace pro klienty. Uživatel, který se zaregistruje do jedné aplikace, proto nesmí být automaticky uživatelem jiné — u zakázek je správcem osobních údajů klient a my zpracovatel, u SaaS se účel zpracování liší produkt od produktu.
User pool je oddělená množina uživatelských účtů:
- každá aplikace patří do právě jednoho poolu,
- nová aplikace dostane vlastní pool — její uživatelé jsou jen její,
- aplikace, které mají uživatele sjednocené (jedno přihlášení, jeden profil), se dají do stejného poolu — jen tam, kde to výslovně nastavíme,
- platform pool
jabcoredrží tým Jabcore a všechny, kdo se přihlašují do administračního panelu.
Účet = pool + e-mail
Stejná e-mailová adresa ve dvou poolech jsou dva nezávislé účty: vlastní heslo a MFA, vlastní ověření e-mailu, vlastní profil, role, notifikace i souhlasy. Deaktivace nebo smazání v jednom poolu se druhého netýká.
pool „onlybrain“ (OnlyBrain, OnlyBrain Desktop) pool „klient-x“ (Navigace areálu)
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ jan@firma.cz heslo A, profil │ │ jan@firma.cz heslo B, profil │
│ eva@firma.cz │ │ petr@klient.cz │
└───────────────────────────────┘ └───────────────────────────────┘
↑ jedno SSO pro obě aplikace poolu ↑ úplně jiný účetJak je oddělení vynucené
| Vrstva | Co dělá |
|---|---|
| Zitadel | Každý pool = jedna organizace. Účty poolu vznikají jen v ní. |
Login (jabcore-platform-auth) | Z client_id OIDC requestu zjistí pool aplikace (GET /api/zitadel/login-brand). Účty hledá a registruje jen v organizaci poolu, znovu použije jen session z téhož poolu a odmítne dokončit přihlášení účtem z jiné organizace (createCallback). Když API neodpoví, přihlášení neproběhne (fail-closed). |
| API | Pool tokenu = organizace, která vlastní uživatele (sub) — z claimu urn:zitadel:iam:user:resourceowner:id, jinak dotazem do Zitadelu. Token účtu mimo jakýkoli pool nebo vydaný klientovi aplikace z jiného poolu je odmítnut (401). |
| API — aplikační endpointy | /profile/me/check*, preference, notifikace, feedback aj. pro aplikaci X vyžadují, aby účet volajícího patřil do poolu aplikace X (jinak 403). Inbox a /profile/me/apps vrací jen aplikace poolu volajícího. |
| API — administrace | Superadmin, app admin a práva aplikace auth platí jen pro účty platform poolu. Uživatel aplikace se stejným e-mailem jako administrátor žádná admin práva nemá. |
| Kontrola oprávnění | POST /api/check (backend → API) kontroluje účet (pool aplikace, email). Superadmin a app admin mají „bypass“ jen v aplikacích platform poolu. |
Co to znamená pro aplikaci
- Nic nového v kódu aplikace. Aplikace se dál přihlašuje přes OIDC a volá API s JWT nebo
x-internal-api-keysemail+app. Pool se odvozuje sám. - Role se přiřazují v rámci aplikace (
/users/:email/apps/:appCode/roles) — přiřazení platí pro účet s tímto e-mailem v poolu aplikace. - Profil sdílí jen aplikace stejného poolu. Jméno nebo jazyk změněný v jedné aplikaci se projeví v ostatních aplikacích poolu, jinde ne.
- Registrace probíhá v loginu vždy do organizace poolu aplikace.
Správa v administraci
Menu User pooly:
- přehled poolů, jejich aplikací, počtu účtů a propojené Zitadel organizace,
- Nový pool — založí pool i Zitadel organizaci (potřebuje
zitadel.serviceAccountToken); bez něj pool zůstane „nepropojeno“ a do jeho aplikací se nikdo nepřihlásí, dokud organizaci nepropojíte, - brand e-mailů — vzhled ověřovacích e-mailů a resetu hesla účtů poolu.
U aplikace (Aplikace → Nová / Upravit):
- Vlastní pool (výchozí) — oddělení uživatelé,
- Sdílet s poolem … — sjednocení s jinými aplikacemi.
Přesun existující aplikace do jiného poolu vyžaduje globální právo applications.manage (edit): do aplikace se pak přihlásí jen účty nového poolu a přiřazené role budou platit pro účty se stejným e-mailem v novém poolu.
U uživatelů je v seznamu sloupec User pool a detail účtu se otevírá s ?pool=<code>.
API
| Endpoint | Popis |
|---|---|
GET /api/admin/user-pools | Seznam poolů s aplikacemi a počtem účtů |
POST /api/admin/user-pools | Nový pool (code, name, description, brandId) + Zitadel organizace |
PUT /api/admin/user-pools/:code | Název, popis, brand |
POST /api/admin/user-pools/:code/zitadel/sync | Vytvořit organizaci, nebo propojit existující (zitadelOrgId) |
DELETE /api/admin/user-pools/:code | Smazat prázdný pool (bez aplikací a účtů) |
POST /api/applications | userPoolCode — sdílet existující pool; bez něj vlastní pool |
PUT /api/applications/:appCode | userPoolCode — přesun do jiného poolu |
GET /api/users?pool=<code> | Účty jednoho poolu (bez parametru všechny, s userPoolCode) |
GET /api/users/:email?pool=<code> | Souhrn účtu; bez pool = platform pool |
GET /api/admin/users/:email/detail?pool=<code> | Detail účtu |
Datový model
sql
user_pools (id, code, name, is_platform, brand_id, zitadel_org_id, …)
applications.user_pool_id → user_pools.id
users PRIMARY KEY (user_pool_id, email)
user_profiles UNIQUE (user_pool_id, email)
user_application_activity, user_activity_events → users (user_pool_id, email)Tabulky vázané na aplikaci (user_app_roles, app_admins, user_resource_permissions, notifications, user_app_preferences …) zůstávají klíčované e-mailem + aplikací — aplikace patří do jednoho poolu, takže pool je jednoznačný.
Platform pool
Pool jabcore (is_platform = true) vzniká v sql/init.sql. Jeho organizací je platformní organizace (zitadel.projectOrgId / ZITADEL_PROJECT_ORG_ID), kterou API propojí při startu. Patří do něj aplikace auth (administrační panel) a interní aplikace Jabcore, které sdílejí účty týmu.
