gh_UserManager/docs/IDENTITY_MODEL.md
bermooda-company 54d5891edf user
2026-08-23 23:59:14 +03:30

13 KiB

Identity Model

Purpose

This document describes the central identity model managed by the Identity Platform. It is the single source of truth for who a user is and whether they are authenticated.

UserManager answers:

  • WHO ARE YOU? → User identity (UUID, email, phone)
  • ARE YOU AUTHENTICATED? → Session + token validity
  • IS YOUR IDENTITY VERIFIED? → email_verified, phone_verified, mfa_enabled
  • WHICH ORGANIZATIONS? → Membership (user ↔ Organization)
  • WHICH PRODUCTS? → Product catalog + active context in JWT
  • WHAT SESSIONS? → Session tracking (browser/api/device)

Products answer:

  • WHAT CAN YOU DO HERE? → Product-domain permissions (roles, policies) within a specific context

Entity: User

Definition: The central identity entity. A User is a person whose identity is managed by the Identity Platform. The User's UUID is shared across all products — no product creates a separate user for the same person.

Key Principle: A User's identity is immutable and product-agnostic. A User can be an Owner in one org, an Employee in another, and a Specialist in Hamsoo — all as the same User entity.

User Schema

Field Type Constraints Description
id UUID PK, immutable Globally unique user identifier. Shared across all products.
email EmailField unique, nullable Primary authentication channel. Verified.
phone CharField unique, nullable Secondary authentication channel. Verified.
username SlugField unique, nullable Human-readable identifier.
full_name CharField blank Display name
given_name CharField blank First name
family_name CharField blank Last name
avatar_url URLField blank Profile picture URL
status CharField choices Pending / Active / Suspended / Banned
email_verified BooleanField default False Is email verified
phone_verified BooleanField default False Is phone verified
locale CharField default "fa" Default locale (fa/en)
timezone CharField default "UTC" User's timezone
mfa_enabled BooleanField default False Is MFA enrolled
totp_secret CharField blank TOTP secret (encrypted)
password_reset_token CharField blank Hash of password reset token
password_reset_expires DateTimeField nullable Reset token expiry
last_login_at DateTimeField nullable Last login timestamp
is_active BooleanField default True Django auth active flag
is_staff BooleanField default False Django admin access
created_at DateTimeField auto_now_add Creation timestamp
updated_at DateTimeField auto_now Update timestamp

Removed (previously product-specific):

  • employer / job_seeker global roles → These are product-specific roles, managed by Bermooda/Hamsoo, NOT identity layer.
  • Any product-specific profile fields → Managed by Product layers (BusinessProfile, Workspace, etc.)

Computed Properties

Property Type Description
user_id UUID Alias for id — the canonical user identifier
identity_key str usr_{id_hex} — prefixed identifier for external systems

User Lifecycle

1. Created (status=pending) → User registered, not yet active
2. Verified (status=active) → Email/phone verified, user can authenticate
3. Active → User is fully operational
4. Suspended → Temporarily blocked (self-serve or admin action)
5. Banned → Permanently blocked (admin action)

Key Rules:

  • UUID never changes — even if email/phone changes
  • employer/job_seeker roles are NOT on the User model
  • Product-specific roles come from Membership → Organization → Product mapping
  • A suspended/banned user cannot authenticate (LoginView rejects them)

Entity: Organization

Definition: A generic organization (company, team, workspace). NOT tied to any specific product.

Key Principle: Organization is a generic container. Bermooda.Workspace and Hamsoo.BusinessProfile are product-layer entities that map to an identity.Organization.

Organization Schema

Field Type Constraints Description
id UUID PK Organization identifier
name CharField required Display name
slug SlugField unique, auto-generated URL-safe identifier
description TextField blank Description
logo_url URLField blank Logo
website_url URLField blank Website
status CharField choices (active/inactive) Active/Inactive
created_by FK→User nullable User who created org
created_at / updated_at DateTimeField auto Timestamps

No product-specific fields. A Bermooda Workspace adds fields like industry via a product-layer FK to Organization.

Example: Bermooda → Workspace mapping

# In Bermooda product layer
class Workspace(models.Model):
    org = models.ForeignKey("identity.Organization", on_delete=models.CASCADE)
    industry = models.CharField(max_length=100)
    hiring_settings = JSONField()
    ...

The Workspace is NOT an Organization — it extends one.


Entity: Membership

Definition: The relationship between a User and an Organization. Carries role context.

Key Principle: Roles are contextual — a role on the Membership (org-level owner/admin/member), not a global role on the User. Product-specific roles are in the Product layer.

Membership Schema

Field Type Constraints Description
id UUID PK Membership identifier
user FK→User required User identity
organization FK→Organization required Organization context
role CharField choices (owner/admin/member) Org-level role
status CharField choices (active/invited/pending/deactivated) Membership state
invited_by FK→User nullable Who invited
joined_at DateTimeField nullable When accepted
created_at / updated_at DateTimeField auto Timestamps

Constraints:

  • UniqueConstraint(fields=["user", "organization"]) — a user can have only one membership per organization

Role Context (Key Concept)

User: Ali
Org: ACME
Membership: role=owner → Ali is Owner of ACME (identity-level)

Bermooda: maps ACME → Workspace
Bermooda role: Ali's profile in Bermooda's Workspace (e.g., HR Manager) — product-layer

Hamsoo: not connected to ACME
Hamsoo profile: Ali's specialist rating, bio — product-layer

Products read the Membership to know if the user has access to an org, then apply their own product-specific logic for what they can do within it.


Entity: Product

Definition: A registered product in the identity ecosystem. Identity uses this to know which products exist and are active.

Key Principle: Identity knows that bermooda and hamsoo are products. It does NOT store product-domain data (BusinessProfile, projects, payroll). It only stores the product's identity metadata.

Product Schema

Field Type Constraints Description
id UUID PK Product identifier
key SlugField unique Unique product key (bermooda, hamsoo, ...)
name CharField required Human-readable name
description TextField blank Description
logo_url URLField blank Product logo
website_url URLField blank Product website
is_active BooleanField default True Can authenticate against this product
created_by FK→User nullable Who registered
created_at / updated_at DateTimeField auto Timestamps

Entity: Application (OAuth2 Client)

Definition: An OAuth2 client registered against a specific Product. Used for authentication flows.

Relationship to Product

Each Application has a product_key that identifies which product it belongs to. This is for routing/context — not for storing product domain data.


Entity: Session

Definition: A user's authenticated session. Tracks device, IP, and lifecycle.

Session Lifecycle

Created (active) → User logs in
                 → Session created, refresh token issued
                 ↓
Active (active)  → User uses platform
                 ↓
Expired (expired) → Refresh token lifetime (30 days) exceeded
                  ↓
Revoked (revoked) → User logs out, password change, admin action

Session is identity-layer. It tracks that a user authenticated — not what they did in a product.


Entity: SecurityEvent

Definition: An immutable audit event. Every auth action, state change, and security-relevant action is logged.

Event Types

Event Type Severity Description
login_success info Successful login
login_failed medium Failed login attempt
login_locked high Account locked due to brute-force
logout low User logged out
password_change medium Password changed
password_reset medium Password reset completed
email_verified low Email verified
phone_verified low Phone verified
mfa_enabled low MFA enrolled
mfa_disabled low MFA removed
session_revoked medium Session revoked
session_expired low Session expired
session_created low New session created
device_added low New device registered
application_created medium OAuth2 app registered
application_revoked high OAuth2 app revoked

Severity Levels

  • info — Normal operation
  • low — Minor event
  • medium — Worth noting, potential investigation
  • high — Security-relevant, requires action
  • critical — Immediate action required

JWT Token Structure

Access Token (RS256, 15 min lifetime)

{
  "user_id": "uuid",
  "user_status": "active",
  "identity_key": "usr_abc123...",
  "product_key": "bermooda",        // optional — active context
  "organization_id": "uuid",         // optional — active context
  "token_type": "access",
  "exp": 1700000000,
  "iat": 1699999100,
  "iss": "https://id.example.com",
  "jti": "unique-token-id"
}

Claims policy:

  • Always present: user_id, user_status, identity_key, exp, iat, iss, jti
  • Optional (context): product_key, organization_id — only included if login established a context
  • Never present: product-specific roles, permissions, business data

Refresh Token (RS256, 30 day lifetime)

{
  "user_id": "uuid",
  "session_id": "uuid",
  "token_type": "refresh",
  "exp": 1702591100,
  "iat": 1699999100,
  "iss": "https://id.example.com",
  "jti": "unique-token-id"
}

Token rotation: Each refresh issues a new refresh token; the old one is revoked and stored in replaced_by. Products must discard old refresh tokens immediately.

ID Token (OIDC)

{
  "sub": "uuid",
  "name": "User Name",
  "email": "user@acme.com",
  "email_verified": true,
  "preferred_username": "user",
  "locale": "fa",
  "iat": 1699999100,
  "exp": 1700000000,
  "iss": "https://id.example.com",
  "aud": "bermooda-client-id"
}

Verification

Definition: Separate from authentication, verification confirms the authenticity of identity claims.

Authentication: "You have a password to the account."
Verification:    "This email/phone belongs to you. This identity is real."

Verification States

Channel Verified? Verified At
Email boolean timestamp
Phone boolean timestamp

Verification is identity-layer. Future extensions:

  • Email verification → Identity Platform
  • Phone verification → Identity Platform
  • Shahkar (Iran national ID verification) → Identity Platform (verification provider)
  • Manual Verification → Identity Platform (admin override)

In the future, products may request additional verification (e.g., Hamsoo needs business license verified) — but that's a Product-layer concern.


User ID Consistency

Guarantee: A user's UUID is the same across Bermooda, Hamsoo, and all future products.

UserManager:  user_id = UUID(550e8400-e29b-41d4-a716-446655440000)

Bermooda:     user_id = UUID(550e8400-e29b-41d4-a716-446655440000)  ← same
Hamsoo:       user_id = UUID(550e8400-e29b-41d4-a716-446655440000)  ← same

No product creates its own user record.
No product duplicates user identity.

Products reference the identity.User UUID via FK. They never store passwords, sessions, or tokens.