Add OIDC sign-in, group-derived roles and declarative instance configuration
Workspaces, group mappings and sign-in methods now come from a configuration file synchronized at startup; workspaces dropped from it are disabled, never deleted. Instance administrators (a new role) see and help every workspace and may delete disabled ones; workspace administrators and employees are derived from the user's groups at every SSO sign-in or administrator edit, and the employee permission set belongs to the workspace. Self-registration is gone: users come from SSO (only when their groups map) or from the administrator. Break-glass bootstrap accounts get an HMAC-derived hourly password that all replicas agree on. First SSO sign-in links a matching email contact to the user. The demo runs on the same model with a generated per-start password. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
e37d583179
commit
4764f3545f
68 files changed
+7220
-964
No files matched your search
@@ -194,3 +194,22 @@ input[type=date]:not(.native-date),.date-field{max-width:176px;min-width:0}
|
||||
.map-source-card{border:1px solid var(--line);border-radius:7px;padding:10px;margin:8px 0;background:#f8faf9}.map-source-title{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px}.map-source-title>small{margin-left:auto;color:var(--muted)}.map-source-addresses{display:flex;flex-direction:column;gap:4px;margin-top:7px}.map-source-addresses code{font:10px/1.5 Consolas,monospace;overflow-wrap:anywhere;color:#567565}.map-source-card>button{margin-top:6px;padding:3px 0}
|
||||
|
||||
.map-resource-fields{padding:0 12px 12px;border-top:1px solid var(--line)}.map-field-hint{display:block;font-size:10px;line-height:1.5;color:var(--muted);margin-bottom:6px}.map-resource-fields .map-reference>small{flex-basis:auto;margin:0;min-width:15px}.map-resource-fields .map-input-field:last-child{margin-bottom:0}
|
||||
|
||||
.login-form .password-login{display:block}.login-form .password-login>label:first-of-type{margin-top:22px}.login-form .sso-button{display:block;width:100%;margin-top:26px;padding:13px;text-align:center;text-decoration:none;border:1px solid var(--green);border-radius:7px;box-sizing:border-box}
|
||||
.login-divider{display:flex;align-items:center;gap:12px;margin:22px 0 0;color:var(--muted);font-size:12px}.login-divider::before,.login-divider::after{content:"";flex:1;border-top:1px solid var(--line)}
|
||||
.login-error{display:flex;flex-direction:column;gap:6px;margin-top:22px;padding:12px 14px;border:1px solid #e9c6b9;border-radius:7px;background:#fff3ee;color:#a04e34;font-size:13px;line-height:1.5}.login-error small{font-size:11px;user-select:all;color:#8a5f4f}
|
||||
.demo-accounts{list-style:none;margin:8px 0;padding:0;display:flex;flex-direction:column;gap:2px}.demo-account{display:flex;align-items:baseline;gap:10px;padding:2px 0;font-size:11px;text-align:left;border:0;background:none}.demo-account code{min-width:56px;font-weight:700}.demo-password{display:block;margin-top:6px}.demo-password code{user-select:all}.demo-note small{display:block;margin-top:6px;color:#8a977f}
|
||||
a.button{display:inline-block;text-decoration:none;border:1px solid #dbe3de;border-radius:7px;padding:9px 13px;color:inherit}a.button.primary{width:auto;margin-top:12px}
|
||||
.sidebar nav .instance-link{margin-top:6px;border-top:1px solid var(--line);border-radius:0;padding-top:18px}
|
||||
.warning-banner{margin:0 0 20px;padding:14px 16px;border:1px solid #e5c9a8;border-radius:8px;background:#fdf4e3;color:#7d5a1d;font-size:13px;line-height:1.5}
|
||||
.config-summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 24px;margin:12px 0}.config-summary>div{min-width:0}.config-summary dt{font-size:11px;color:var(--muted);margin-bottom:3px}.config-summary dd{margin:0;overflow-wrap:anywhere}
|
||||
.admin-workspace.disabled{background:#faf7f2}.admin-workspace small{display:block;margin-top:3px;overflow-wrap:anywhere}.disabled-note{color:#a17f32}
|
||||
.admin-user small{display:block;margin-top:3px;overflow-wrap:anywhere}.admin-user .badge,.admin-workspace .badge{white-space:nowrap}.admin-user>button,.admin-workspace>button{white-space:nowrap}small.inline{display:inline}
|
||||
.padded{padding:16px}.danger-button{color:#a04e34;border-color:#e9c6b9}.danger-button:hover{background:#fff3ee}.danger-note{background:#fff3ee;color:#a04e34}
|
||||
.role-badge{text-transform:none}.role-badge.admin{background:#e4f1e8;color:#3d7e57}
|
||||
.permission-list{list-style:none;margin:12px 0;padding:0;display:flex;flex-direction:column;gap:6px}.permission-list li{color:var(--muted)}.permission-list li.on{color:var(--ink)}
|
||||
.group-picker{border:1px solid var(--line);border-radius:8px;padding:10px 14px;margin:12px 0 0}.group-picker legend{font-size:12px;color:var(--muted);padding:0 6px}.group-picker .check{margin:6px 0}
|
||||
@media(max-width:700px){.config-summary{grid-template-columns:1fr}.admin-user,.admin-workspace{flex-wrap:wrap}.admin-user>.grow,.admin-workspace>.grow{flex-basis:calc(100% - 60px)}}
|
||||
@media(max-width:700px){.sidebar nav .instance-link{margin:0;border:0;border-radius:6px;padding:6px}.sidebar nav .instance-link>span:not(.nav-icon){position:absolute;width:1px;height:1px;clip-path:inset(50%);overflow:hidden;white-space:nowrap}}
|
||||
.admin-user .badge,.admin-workspace .badge{text-transform:none}.admin-user strong{display:inline}
|
||||
@media(max-width:700px){.sidebar nav .instance-link{padding:6px 2px}.sidebar nav .instance-link .nav-icon{width:16px}}
|
||||
Reference in new issue
Block a user