feat: 4-role model — owner, operator, viewer + vendor-seed
Redesign the role model from 3 roles (platform-admin, admin, member) to 4 clear personas: - owner (org role): full tenant control — billing, team, apps, deploy - operator (org role): app lifecycle + observability, no billing/team - viewer (org role): read-only observability - saas-vendor (global role, hosted only): cross-tenant platform admin Bootstrap changes: - Rename org roles: admin→owner, member→operator, add viewer - Remove platform-admin global role (moved to vendor-seed) - admin user gets owner role, camel user gets viewer role - Custom JWT maps: owner→server:admin, operator→server:operator, viewer→server:viewer, saas-vendor→server:admin New docker/vendor-seed.sh for hosted SaaS environments only. Remove sidebar user/logout link (TopBar handles logout). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
11
CLAUDE.md
11
CLAUDE.md
@@ -59,7 +59,8 @@ Separate Vite+React SPA replacing Logto's default sign-in page. Visually matches
|
||||
- Tenant isolation enforced by `TenantIsolationInterceptor` (a single `HandlerInterceptor` on `/api/**` that resolves JWT org_id to TenantContext and validates `{tenantId}`, `{environmentId}`, `{appId}` path variables; fail-closed, platform admins bypass)
|
||||
- 13 OAuth2 scopes on the Logto API resource (`https://api.cameleer.local`): 10 platform scopes + 3 server scopes (`server:admin`, `server:operator`, `server:viewer`), served to the frontend from `GET /platform/api/config`
|
||||
- Server scopes map to server RBAC roles via JWT `scope` claim (SaaS platform path) or `roles` claim (server-ui OIDC login path)
|
||||
- Org role `admin` gets `server:admin`, org role `member` gets `server:viewer`
|
||||
- 4-role model: `saas-vendor` (global, hosted only), org `owner` → `server:admin`, org `operator` → `server:operator`, org `viewer` → `server:viewer`
|
||||
- `saas-vendor` global role injected via `docker/vendor-seed.sh` (not standard bootstrap) — has `platform:admin` + all tenant scopes
|
||||
- Custom `JwtDecoder` in `SecurityConfig.java` — ES384 algorithm, `at+jwt` token type, split issuer-uri (string validation) / jwk-set-uri (Docker-internal fetch), audience validation (`https://api.cameleer.local`)
|
||||
- Logto Custom JWT (Phase 7b in bootstrap) injects a `roles` claim into access tokens based on org roles and global roles — this makes role data available to the server without Logto-specific code
|
||||
|
||||
@@ -89,16 +90,16 @@ Idempotent script run via `logto-bootstrap` init container. Phases:
|
||||
2. Get Management API token (reads `m-default` secret from DB)
|
||||
3. Create Logto apps (SPA, Traditional with `skipConsent`, M2M with Management API role)
|
||||
3b. Create API resource scopes (10 platform + 3 server scopes)
|
||||
4. Create roles (platform-admin, org admin/member with API resource scope assignments)
|
||||
5. Create users (SaaS admin with platform-admin role + Logto console access, tenant admin)
|
||||
6. Create organization, add users with org roles
|
||||
4. Create org roles (owner, operator, viewer with API resource scope assignments)
|
||||
5. Create users (platform owner with Logto console access, viewer for testing read-only OIDC)
|
||||
6. Create organization, add users with org roles (owner + viewer)
|
||||
7. Configure cameleer3-server OIDC (`rolesClaim: "roles"`, `audience`, `defaultRoles: ["VIEWER"]`)
|
||||
7b. Configure Logto Custom JWT for access tokens (maps org roles → `roles` claim: admin→server:admin, member→server:viewer)
|
||||
8. Configure Logto sign-in branding (Cameleer colors `#C6820E`/`#D4941E`, logo from `/platform/logo.svg`)
|
||||
9. Cleanup seeded Logto apps
|
||||
10. Write bootstrap results to `/data/logto-bootstrap.json`
|
||||
|
||||
SaaS admin credentials (`SAAS_ADMIN_USER`/`SAAS_ADMIN_PASS`) work for both the SaaS platform and the Logto console (port 3002).
|
||||
Platform owner credentials (`SAAS_ADMIN_USER`/`SAAS_ADMIN_PASS`) work for both the SaaS platform and the Logto console (port 3002). The `saas-vendor` global role (hosted only) is created separately via `docker/vendor-seed.sh`.
|
||||
|
||||
## Related Conventions
|
||||
|
||||
|
||||
Reference in New Issue
Block a user