Org Onboarding
The Org Onboarding module handles the creation and activation of new organizations in Lacroo Pro. It provides an invite-code-protected setup wizard that walks founding administrators through configuring their organization, connecting Microsoft Entra SSO, and provisioning the initial master admin accounts.
Data Model
Organizations
| Column | Type | Description |
|---|---|---|
id | UUID | Primary key |
name | TEXT | Display name |
slug | TEXT | URL-safe unique identifier |
logo_url | TEXT | Optional logo URL |
erp_source | ENUM | ERP system integration (8 options) |
entra_tenant_id | TEXT | Microsoft Entra tenant |
entra_client_id | TEXT | App registration client ID |
entra_client_secret_encrypted | BYTEA | AES-256-GCM encrypted secret |
sso_configured | BOOL | Set once SSO credentials are saved |
status | ENUM | pending_setup, active, suspended |
Users
| Column | Type | Description |
|---|---|---|
id | UUID | Primary key |
org_id | UUID | Foreign key to organizations |
entra_object_id | TEXT | Microsoft Entra object ID (unique per org when set) |
name | TEXT | Display name |
email | TEXT | Email (unique per org). For SSO users this is their mailbox (Graph mail), not always their sign-in name |
auth_method | ENUM | How the person signs in: sso (Microsoft), password, email_password or none. Routing is per user, not per org |
entra_upn | TEXT | Their Microsoft user principal name, when known |
entra_user_type | TEXT | Member or Guest, as Microsoft reports it |
entra_sign_in_name | TEXT | The name they sign in to Microsoft with; sent as the sign-in hint and shown as “Signs in as” |
role | ENUM | One of 14 roles |
status | ENUM | active, inactive, pending, deleted |
The three entra_* identity columns are kept true by the nightly directory refresh and by each successful Microsoft sign-in. A person’s first successful Microsoft sign-in also moves them from pending to active.
User Roles
master_admin, organisational_manager, project_admin, engineer, senior_supervisor, supervisor, labour, operator, wet_hire_machines, dry_hire_machines, subcontractor, supplier, client, unassigned
API Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /v1/setup/validate-invite | None | Validate invite code |
| POST | /v1/setup/org | SetupToken | Create organization |
| POST | /v1/setup/org/{orgId}/logo | SetupToken | Upload org logo |
| POST | /v1/setup/org/{orgId}/admin | SetupToken | Create founding admin |
| PUT | /v1/setup/org/{orgId}/sso | SetupToken | Store SSO config |
| POST | /v1/setup/org/{orgId}/sso/validate | SetupToken | Validate SSO + list users |
| POST | /v1/setup/org/{orgId}/finalize | SetupToken | Create co-admin + activate |
| GET | /v1/orgs/{orgId}/dashboard | BearerAuth | Get org dashboard |
Security
- Setup tokens are short-lived JWTs (HS256) that bind each wizard session to an invite code and (after org creation) an organization.
- Client secrets are encrypted with AES-256-GCM before storage. The encryption key is configured via
AES_ENCRYPTION_KEYenv var (64-char hex string). - Invite codes gate access to the setup wizard. Each code tracks usage count.
- Internal service auth — All
/v1/auth/*endpoints requireX-Internal-Service-Keyheader. Only the BFF can call them. - Tenant isolation — All user queries include
AND org_id = $N. Dashboard/delete endpoints verify JWTorg_idmatches the requested org. - Double input validation — Zod schemas at the BFF layer + Go struct validation with
net/mailemail parsing and length limits. - Session management via Go API — The BFF never touches PostgreSQL directly. Session creation, validation, and deletion all go through the Go API.
- httpOnly cookies — All
lacroo.*cookies (session_token,org_id,role) are httpOnly to prevent client-side JS access. - Log redaction — Sensitive fields (password, token, secret, etc.) are automatically redacted in structured logs.
- Request body limit — 1MB global max body size to prevent payload abuse.