diff --git a/docs/README.md b/docs/README.md
index 94464d7a7..d6007fbeb 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -21,7 +21,7 @@ Start a docs server
pnpm nx run @zitadel/docs:dev
# Or serve a production build
-pnpm nx run @zitadel/docs:start
+pnpm nx run @zitadel/docs:prod
```
The site will be available at http://localhost:3100
diff --git a/docs/docs/concepts/structure/managers.mdx b/docs/docs/concepts/structure/managers.mdx
index 3e1318ea5..194a34d7b 100644
--- a/docs/docs/concepts/structure/managers.mdx
+++ b/docs/docs/concepts/structure/managers.mdx
@@ -7,6 +7,7 @@ import ManagerDescription from "./_manager_description.mdx";
+
Notes:
- Read our [guide on Managers](../../guides/manage/console/managers) to learn more about the role concept and how to use Manager roles in ZITADEL.
diff --git a/docs/docs/guides/manage/console/managers.mdx b/docs/docs/guides/manage/console/managers.mdx
index 626768ed9..cc571f7a2 100644
--- a/docs/docs/guides/manage/console/managers.mdx
+++ b/docs/docs/guides/manage/console/managers.mdx
@@ -56,3 +56,12 @@ InternalAuthZ:
- "iam.read"
- "iam.write"
```
+
+import PermissionTable from '@site/src/components/PermissionTable';
+import permissionData from '@site/docs/self-hosting/manage/configure/defaults.yaml';
+
+# Manager Permission Matrix
+
+This table is generated dynamically from our configuration file.
+
+
\ No newline at end of file
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index e8786d161..64dea4eb5 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -450,6 +450,23 @@ module.exports = {
},
};
},
+ function (context, options) {
+ return {
+ name: 'docusaurus-yaml-loader',
+ configureWebpack(config, isServer) {
+ return {
+ module: {
+ rules: [
+ {
+ test: /\.ya?ml$/,
+ use: 'yaml-loader',
+ },
+ ],
+ },
+ };
+ },
+ };
+ },
],
markdown: {
mermaid: true,
diff --git a/docs/package.json b/docs/package.json
index 37398dc80..b86553263 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -29,8 +29,8 @@
"@docusaurus/theme-search-algolia": "^3.8.1",
"@headlessui/react": "^1.7.4",
"@heroicons/react": "^2.0.13",
- "@signalwire/docusaurus-plugin-llms-txt": "^1.2.0",
"@inkeep/cxkit-docusaurus": "^0.5.89",
+ "@signalwire/docusaurus-plugin-llms-txt": "^1.2.0",
"autoprefixer": "^10.4.13",
"clsx": "^1.2.1",
"docusaurus-plugin-image-zoom": "^3.0.1",
@@ -44,7 +44,8 @@
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-google-charts": "^5.2.1",
- "react-player": "^2.15.1"
+ "react-player": "^2.15.1",
+ "unicode-property-aliases-ecmascript": "^2.2.0"
},
"browserslist": {
"production": [
@@ -61,6 +62,7 @@
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.8.1",
"@docusaurus/types": "^3.8.1",
- "tailwindcss": "^3.2.4"
+ "tailwindcss": "^3.2.4",
+ "yaml-loader": "^0.8.1"
}
}
\ No newline at end of file
diff --git a/docs/src/components/PermissionTable/index.jsx b/docs/src/components/PermissionTable/index.jsx
new file mode 100644
index 000000000..75455d896
--- /dev/null
+++ b/docs/src/components/PermissionTable/index.jsx
@@ -0,0 +1,77 @@
+import React, { useMemo } from 'react';
+import styles from './styles.module.css';
+
+// Note: We no longer need 'js-yaml' here because the loader parses it before the component sees it.
+
+export default function PermissionTable({ data }) {
+ const { roles, permissions, matrix } = useMemo(() => {
+ if (!data) return { roles: [], permissions: [], matrix: {} };
+
+ // 1. Identify all sources. The 'data' prop is already a JS Object.
+ const sources = [
+ data?.InternalAuthZ?.RolePermissionMappings,
+ data?.SystemAuthZ?.RolePermissionMappings,
+ ].filter(Boolean).flat();
+
+ // 2. Aggregate Data
+ const roleMap = new Map();
+ const allPermissions = new Set();
+
+ sources.forEach((mapping) => {
+ const roleName = mapping.Role;
+ const rolePerms = mapping.Permissions || [];
+
+ if (!roleMap.has(roleName)) {
+ roleMap.set(roleName, new Set());
+ }
+
+ rolePerms.forEach((perm) => {
+ roleMap.get(roleName).add(perm);
+ allPermissions.add(perm);
+ });
+ });
+
+ // 3. Sort for display
+ const sortedRoles = Array.from(roleMap.keys()).sort();
+ const sortedPermissions = Array.from(allPermissions).sort();
+
+ return {
+ roles: sortedRoles,
+ permissions: sortedPermissions,
+ matrix: roleMap,
+ };
+ }, [data]);
+
+ return (
+
+
+
+
+ | Permission |
+ {roles.map((role) => (
+ {role} |
+ ))}
+
+
+
+ {permissions.map((perm) => (
+
+ | {perm} |
+ {roles.map((role) => {
+ const hasPermission = matrix.get(role).has(perm);
+ return (
+
+ {hasPermission ? 'yes' : 'no'}
+ |
+ );
+ })}
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/docs/src/components/PermissionTable/styles.module.css b/docs/src/components/PermissionTable/styles.module.css
new file mode 100644
index 000000000..eaa711d6d
--- /dev/null
+++ b/docs/src/components/PermissionTable/styles.module.css
@@ -0,0 +1,73 @@
+.container {
+ overflow-x: auto;
+ max-width: 100%;
+ margin: 2rem 0;
+ border: 1px solid var(--ifm-color-emphasis-200);
+ border-radius: 8px;
+ box-shadow: var(--ifm-global-shadow-lw);
+}
+
+.table {
+ border-collapse: separate; /* Required for sticky to work */
+ border-spacing: 0;
+ width: 100%;
+ font-size: 0.85rem;
+}
+
+.table th,
+.table td {
+ padding: 8px 12px;
+ border-bottom: 1px solid var(--ifm-color-emphasis-200);
+ border-right: 1px solid var(--ifm-color-emphasis-200);
+ white-space: nowrap;
+}
+
+/* Sticky Header Row */
+.table thead th {
+ position: sticky;
+ top: 0;
+ background-color: var(--ifm-background-surface-color);
+ z-index: 10;
+ border-bottom: 2px solid var(--ifm-color-emphasis-300);
+ text-align: left;
+ font-weight: bold;
+}
+
+/* Sticky First Column (Permission Name) */
+.table tbody th {
+ position: sticky;
+ left: 0;
+ background-color: var(--ifm-background-surface-color);
+ z-index: 5;
+ border-right: 2px solid var(--ifm-color-emphasis-300);
+ text-align: left;
+ /*font-family: var(--ifm-font-family-monospace);
+ color: var(--ifm-color-primary);*/
+}
+
+/* Top Left Corner Intersection */
+.table thead th:first-child {
+ left: 0;
+ z-index: 20;
+ border-right: 2px solid var(--ifm-color-emphasis-300);
+}
+
+/* Cell Coloring */
+.yes {
+ background-color: rgba(0, 255, 0, 0.1); /* Light green tint */
+ color: var(--ifm-color-success);
+ text-align: center;
+ font-weight: bold;
+}
+
+.no {
+ color: var(--ifm-color-emphasis-400);
+ text-align: center;
+ font-size: 0.8em;
+}
+
+/* Dark mode adjustments automatically handled by Docusaurus CSS vars,
+ but ensuring background opacity works */
+[data-theme='dark'] .yes {
+ background-color: rgba(0, 255, 0, 0.15);
+}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a621126f1..231b4c36e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -140,7 +140,7 @@ importers:
version: 1.0.0
'@vitejs/plugin-react':
specifier: ^4.4.1
- version: 4.7.0(vite@5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0))
+ version: 4.7.0(vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1))
'@zitadel/client':
specifier: workspace:*
version: link:../../packages/zitadel-client
@@ -218,7 +218,7 @@ importers:
version: 5.9.2
vite-tsconfig-paths:
specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.2)(vite@5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0))
+ version: 5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1))
vitest:
specifier: ^2.0.0
version: 2.1.9(@types/node@22.18.1)(jsdom@26.1.0)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)
@@ -538,6 +538,9 @@ importers:
react-player:
specifier: ^2.15.1
version: 2.16.1(react@18.3.1)
+ unicode-property-aliases-ecmascript:
+ specifier: ^2.2.0
+ version: 2.2.0
devDependencies:
'@docusaurus/module-type-aliases':
specifier: ^3.8.1
@@ -548,6 +551,9 @@ importers:
tailwindcss:
specifier: ^3.2.4
version: 3.4.14
+ yaml-loader:
+ specifier: ^0.8.1
+ version: 0.8.1
packages/zitadel-client:
dependencies:
@@ -9541,6 +9547,9 @@ packages:
jasmine-spec-reporter@7.0.0:
resolution: {integrity: sha512-OtC7JRasiTcjsaCBPtMO0Tl8glCejM4J4/dNuOJdA8lBjz4PmWjYQ6pzb0uzpBNAWJMDudYuj9OdXJWqM2QTJg==}
+ javascript-stringify@2.1.0:
+ resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==}
+
jest-diff@30.1.2:
resolution: {integrity: sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
@@ -9594,6 +9603,10 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
jsbn@0.1.1:
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
@@ -12101,7 +12114,7 @@ packages:
puppeteer@22.15.0:
resolution: {integrity: sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==}
engines: {node: '>=18'}
- deprecated: < 24.9.0 is no longer supported
+ deprecated: < 24.15.0 is no longer supported
hasBin: true
qjobs@1.2.0:
@@ -13639,8 +13652,8 @@ packages:
resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==}
engines: {node: '>=4'}
- unicode-property-aliases-ecmascript@2.1.0:
- resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
+ unicode-property-aliases-ecmascript@2.2.0:
+ resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==}
engines: {node: '>=4'}
unicorn-magic@0.1.0:
@@ -14342,6 +14355,10 @@ packages:
yaml-ast-parser@0.0.43:
resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==}
+ yaml-loader@0.8.1:
+ resolution: {integrity: sha512-BCEndnUoi3BaZmePkwGGe93txRxLgMhBa/gE725v1/GHnura8QvNs7c4+4C1yyhhKoj3Dg63M7IqhA++15j6ww==}
+ engines: {node: '>= 14'}
+
yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
@@ -14967,7 +14984,7 @@ snapshots:
dependencies:
'@jsdevtools/ono': 7.1.3
'@types/json-schema': 7.0.15
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
'@asamuzakjp/css-color@3.2.0':
dependencies:
@@ -16852,7 +16869,7 @@ snapshots:
'@types/react-router-config': 5.0.11
combine-promises: 1.2.0
fs-extra: 11.3.1
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
lodash: 4.17.21
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -17336,7 +17353,7 @@ snapshots:
'@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
fs-extra: 11.3.1
joi: 17.13.3
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
lodash: 4.17.21
tslib: 2.8.1
transitivePeerDependencies:
@@ -17361,7 +17378,7 @@ snapshots:
globby: 11.1.0
gray-matter: 4.0.3
jiti: 1.21.7
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
lodash: 4.17.21
micromatch: 4.0.8
p-queue: 6.6.2
@@ -19587,7 +19604,7 @@ snapshots:
colorette: 1.4.0
https-proxy-agent: 7.0.6
js-levenshtein: 1.1.6
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
minimatch: 5.1.6
pluralize: 8.0.0
yaml-ast-parser: 0.0.43
@@ -21054,7 +21071,7 @@ snapshots:
dependencies:
vite: 7.1.5(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.44.0)(yaml@2.8.1)
- '@vitejs/plugin-react@4.7.0(vite@5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0))':
+ '@vitejs/plugin-react@4.7.0(vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1))':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
@@ -21062,7 +21079,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.27
'@types/babel__core': 7.20.5
react-refresh: 0.17.0
- vite: 5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)
+ vite: 7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
@@ -22322,7 +22339,7 @@ snapshots:
cosmiconfig@8.3.6(typescript@5.9.2):
dependencies:
import-fresh: 3.3.1
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
parse-json: 5.2.0
path-type: 4.0.0
optionalDependencies:
@@ -22332,7 +22349,7 @@ snapshots:
dependencies:
env-paths: 2.2.1
import-fresh: 3.3.1
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
parse-json: 5.2.0
optionalDependencies:
typescript: 5.9.2
@@ -25357,6 +25374,8 @@ snapshots:
dependencies:
colors: 1.4.0
+ javascript-stringify@2.1.0: {}
+
jest-diff@30.1.2:
dependencies:
'@jest/diff-sequences': 30.0.1
@@ -25425,6 +25444,10 @@ snapshots:
dependencies:
argparse: 2.0.1
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
+
jsbn@0.1.1: {}
jsdom@26.1.0:
@@ -27144,7 +27167,7 @@ snapshots:
find-up: 5.0.0
glob: 10.4.5
he: 1.2.0
- js-yaml: 4.1.0
+ js-yaml: 4.1.1
log-symbols: 4.1.0
minimatch: 9.0.5
ms: 2.1.3
@@ -30865,11 +30888,11 @@ snapshots:
unicode-match-property-ecmascript@2.0.0:
dependencies:
unicode-canonical-property-names-ecmascript: 2.0.1
- unicode-property-aliases-ecmascript: 2.1.0
+ unicode-property-aliases-ecmascript: 2.2.0
unicode-match-property-value-ecmascript@2.2.1: {}
- unicode-property-aliases-ecmascript@2.1.0: {}
+ unicode-property-aliases-ecmascript@2.2.0: {}
unicorn-magic@0.1.0: {}
@@ -31235,13 +31258,13 @@ snapshots:
- supports-color
- terser
- vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)):
+ vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1)):
dependencies:
debug: 4.4.1(supports-color@5.5.0)
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.2)
optionalDependencies:
- vite: 5.4.20(@types/node@22.18.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)
+ vite: 7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
- typescript
@@ -31272,6 +31295,24 @@ snapshots:
sass: 1.92.1
terser: 5.44.0
+ vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(less@4.1.3)(lightningcss@1.30.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1):
+ dependencies:
+ esbuild: 0.25.9
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.52.3
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 22.18.1
+ fsevents: 2.3.3
+ jiti: 2.5.1
+ less: 4.1.3
+ lightningcss: 1.30.1
+ sass: 1.92.1
+ terser: 5.44.0
+ yaml: 2.8.1
+
vite@7.1.5(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.90.0)(terser@5.44.0)(yaml@2.8.1):
dependencies:
esbuild: 0.25.9
@@ -31734,6 +31775,12 @@ snapshots:
yaml-ast-parser@0.0.43: {}
+ yaml-loader@0.8.1:
+ dependencies:
+ javascript-stringify: 2.1.0
+ loader-utils: 2.0.4
+ yaml: 2.8.1
+
yaml@1.10.2: {}
yaml@2.8.1: {}