feat: unify admin identity — SAAS_ADMIN_USER is the email in SaaS mode
In SaaS mode, SAAS_ADMIN_USER must be an email address. It's used as both the Logto username and primaryEmail. No separate SAAS_ADMIN_EMAIL. Installer enforces email format in SaaS mode (moved deployment mode question before admin credentials), accepts any username in standalone. Sign-in form label changed to "Login". Removes SAAS_ADMIN_EMAIL from bootstrap, compose template, installers, and all documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,10 @@ POSTGRES_DB=cameleer_saas
|
||||
CLICKHOUSE_PASSWORD=change_me_in_production
|
||||
|
||||
# Admin user (created by bootstrap)
|
||||
# Email is the primary user identity in SaaS mode. The admin email defaults
|
||||
# to <SAAS_ADMIN_USER>@<PUBLIC_HOST> if not set explicitly.
|
||||
SAAS_ADMIN_USER=admin
|
||||
# In SaaS mode, this must be an email address (primary user identity).
|
||||
# In standalone mode, any username is accepted.
|
||||
SAAS_ADMIN_USER=admin@example.com
|
||||
SAAS_ADMIN_PASS=change_me_in_production
|
||||
# SAAS_ADMIN_EMAIL=admin@example.com
|
||||
|
||||
# SMTP / email connector configuration is managed at runtime via the vendor
|
||||
# admin UI (Email Connector page at /vendor/email). No SMTP env vars needed.
|
||||
|
||||
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
Cameleer SaaS — **vendor management plane** for the Cameleer observability stack. Three personas: **vendor** (platform:admin) manages the platform and provisions tenants; **tenant admin** (tenant:manage) manages their observability instance; **new user** (authenticated, no scopes) goes through self-service onboarding. Tenants can be created by the vendor OR via self-service sign-up (email registration + onboarding wizard). Each tenant gets per-tenant cameleer-server + UI instances via Docker API.
|
||||
|
||||
**Email is the primary user identity** in SaaS mode. All users — including the admin — must have an email address. The admin email defaults to `<SAAS_ADMIN_USER>@<PUBLIC_HOST>` if not set explicitly via `SAAS_ADMIN_EMAIL`. Self-service registration (email + password + verification code) is disabled by default and enabled via the vendor UI after configuring an email connector.
|
||||
**Email is the primary user identity** in SaaS mode. `SAAS_ADMIN_USER` IS the email address — there is no separate `SAAS_ADMIN_EMAIL`. The installer enforces email format in SaaS mode (must contain `@`; auto-appends `@<PUBLIC_HOST>` if missing). The bootstrap uses `SAAS_ADMIN_USER` as both the Logto username and primaryEmail. In standalone mode, any username is accepted. Self-service registration (email + password + verification code) is disabled by default and enabled via the vendor UI after configuring an email connector.
|
||||
|
||||
## Ecosystem
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ Idempotent script run inside the Logto container entrypoint. **Clean slate** —
|
||||
3. Create Logto apps (SPA, Traditional Web App with `skipConsent`, M2M with Management API role + server API role)
|
||||
3b. Create API resource scopes (1 platform + 9 tenant + 3 server scopes)
|
||||
4. Create org roles (owner, operator, viewer with API resource scope assignments) + M2M server role (`cameleer-m2m-server` with `server:admin` scope)
|
||||
5. Create admin user (SaaS admin with Logto console access). Email is the primary user identity in SaaS mode — admin email defaults to `<SAAS_ADMIN_USER>@<PUBLIC_HOST>` if `SAAS_ADMIN_EMAIL` is not set.
|
||||
5. Create admin user (SaaS admin with Logto console access). `SAAS_ADMIN_USER` is the admin's email address in SaaS mode — used as both the Logto username and primaryEmail. No separate `SAAS_ADMIN_EMAIL`.
|
||||
7b. Configure Logto Custom JWT for access tokens (maps org roles -> `roles` claim: owner->server:admin, operator->server:operator, viewer->server:viewer; saas-vendor global role -> server:admin)
|
||||
8. Configure Logto sign-in branding (Cameleer colors `#C6820E`/`#D4941E`, logo from `/platform/logo.svg`)
|
||||
8c. Configure sign-in experience (sign-in only) — sets `signInMode: "SignIn"` with username+password method. Registration is disabled by default; the vendor admin enables it via the Email Connector UI after configuring SMTP delivery.
|
||||
|
||||
@@ -27,9 +27,8 @@ API_RESOURCE_NAME="Cameleer SaaS API"
|
||||
# Users (configurable via env vars)
|
||||
SAAS_ADMIN_USER="${SAAS_ADMIN_USER:-admin}"
|
||||
SAAS_ADMIN_PASS="${SAAS_ADMIN_PASS:-admin}"
|
||||
# Admin email: use provided value, or derive from username@host.
|
||||
# SaaS enforces email as the user identity — admin must have one.
|
||||
SAAS_ADMIN_EMAIL="${SAAS_ADMIN_EMAIL:-${SAAS_ADMIN_USER}@${PUBLIC_HOST:-localhost}}"
|
||||
# In SaaS mode, SAAS_ADMIN_USER is the admin's email address.
|
||||
# Use it as both username and primaryEmail in Logto.
|
||||
|
||||
# No server config — servers are provisioned dynamically by the admin console
|
||||
|
||||
@@ -397,12 +396,12 @@ ADMIN_USER_ID=$(api_get "/api/users?search=$SAAS_ADMIN_USER" | jq -r ".[] | sele
|
||||
if [ -n "$ADMIN_USER_ID" ]; then
|
||||
log "Platform owner exists: $ADMIN_USER_ID"
|
||||
else
|
||||
log "Creating platform owner '$SAAS_ADMIN_USER' (email: $SAAS_ADMIN_EMAIL)..."
|
||||
log "Creating platform owner '$SAAS_ADMIN_USER'..."
|
||||
ADMIN_RESPONSE=$(api_post "/api/users" "{
|
||||
\"username\": \"$SAAS_ADMIN_USER\",
|
||||
\"password\": \"$SAAS_ADMIN_PASS\",
|
||||
\"name\": \"Platform Owner\",
|
||||
\"primaryEmail\": \"$SAAS_ADMIN_EMAIL\"
|
||||
\"primaryEmail\": \"$SAAS_ADMIN_USER\"
|
||||
}")
|
||||
ADMIN_USER_ID=$(echo "$ADMIN_RESPONSE" | jq -r '.id')
|
||||
log "Created platform owner: $ADMIN_USER_ID"
|
||||
|
||||
@@ -441,9 +441,8 @@ Copy `.env.example` to `.env` and configure as needed:
|
||||
| `CAMELEER_SAAS_IDENTITY_SPACLIENTID` | SPA client ID for the frontend | _(empty)_ |
|
||||
| `PUBLIC_HOST` | Public hostname for Traefik, Logto, and SaaS routing | `localhost` |
|
||||
| `PUBLIC_PROTOCOL` | Public protocol (`http` or `https`) | `https` |
|
||||
| `SAAS_ADMIN_USER` | Platform admin username | `admin` |
|
||||
| `SAAS_ADMIN_USER` | Platform admin login (must be an email in SaaS mode) | `admin` |
|
||||
| `SAAS_ADMIN_PASS` | Platform admin password | `admin` |
|
||||
| `SAAS_ADMIN_EMAIL` | Platform admin email (primary identity) | `<SAAS_ADMIN_USER>@<PUBLIC_HOST>` |
|
||||
| `TENANT_ADMIN_USER` | Tenant admin username | `camel` |
|
||||
| `TENANT_ADMIN_PASS` | Tenant admin password | `camel` |
|
||||
|
||||
|
||||
Submodule installer updated: 0da26160c6...21ea9515a2
@@ -2,7 +2,7 @@
|
||||
|
||||
## User identity
|
||||
|
||||
**Email is the primary user identity** in SaaS mode. All users must have an email address — Logto enforces this via `signUp.identifiers: ["email"]` when registration is enabled. The bootstrap creates the admin user with `primaryEmail` set to `SAAS_ADMIN_EMAIL` (defaults to `<SAAS_ADMIN_USER>@<PUBLIC_HOST>`). Self-service registration requires email verification via a configured email connector (vendor UI at `/vendor/email`).
|
||||
**Email is the primary user identity** in SaaS mode. All users must have an email address — Logto enforces this via `signUp.identifiers: ["email"]` when registration is enabled. `SAAS_ADMIN_USER` IS the email address (no separate `SAAS_ADMIN_EMAIL`). The bootstrap creates the admin user with `SAAS_ADMIN_USER` as both username and `primaryEmail`. The installer enforces email format in SaaS mode. Self-service registration requires email verification via a configured email connector (vendor UI at `/vendor/email`).
|
||||
|
||||
## Auth enforcement
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ export function SignInPage() {
|
||||
{/* --- Sign-in form --- */}
|
||||
{mode === 'signIn' && (
|
||||
<form className={styles.fields} onSubmit={handleSignIn} aria-label="Sign in" noValidate>
|
||||
<FormField label="Email or username" htmlFor="login-identifier">
|
||||
<FormField label="Login" htmlFor="login-identifier">
|
||||
<Input
|
||||
id="login-identifier"
|
||||
type="email"
|
||||
|
||||
Reference in New Issue
Block a user