Skip to content

Customer Admin Component

Overview

The customer_admin component is a component that manages everything related to company administrators (admins) at Alan. It provides a centralized, country-agnostic interface for handling admin user management across Alan's multi-country platform (France πŸ‡«πŸ‡·, Belgium πŸ‡§πŸ‡ͺ, Spain πŸ‡ͺπŸ‡Έ and Canada πŸ‡¨πŸ‡¦/global).

Purpose

This component was created to:

  • Centralize admin management logic - Consolidate scattered admin-related code into a single, dedicated component
  • Provide a unified interface - Abstract away country-specific implementations behind a common API
  • Support multi-entity hierarchies - Handle complex relationships between accounts, companies, and operational scopes
  • Manage admin permissions - Track admin responsibilities and access rights across different entities

Core Concepts

Admin Types

Admins are categorized by their level of access:

  • Account Admin - Has access to all companies within an account
  • Company Admin - Has access to specific companies only
  • Operational Scope Admin - Has access to specific operational scopes within companies

πŸ“ Operational scope admin have further access restrictions: they cannot access pro dashboard pages like the admin management, contracts or invoices pages.

This corresponds to the three types of entities:

  • Account - Top-level organization unit - defines the Alan x customer relationship
  • Company - Mid-level unit (belongs to an account) - mostly defined by the contractual setup mostly (= contracts' are tied to a company)
  • Operational Scope - Lowest level unit (belongs to a company) - not all customers use this level, it's used to accommodate customers' more complex needs

πŸ“ Most of the component API is designed to operate in a specific account context to best match users mental model (both customers and Alaners).

AdminedEntitiesForest

A hierarchical tree structure representing all entities an admin has access to:

  • Contains both direct admin relationships and transitive relationships
  • Account admins automatically have access to all companies in their account
  • Efficient querying of admin permissions across entity hierarchies

Note: Forest wording is used to flag that an admin might be admin in several accounts which translated to several indepdendant trees.

This data structure contains 2 kind of nodes:

  • context_account: regroups all entities of a given account as children = under a single tree
  • entity: corresponds to a specific entity the user is admin of (either directly or transitively)

Admin Responsibilities

Note

⚠️ This is FR specific for now and should be replaced at some point with a finer grained access control model. Admins can have different responsibilities for different entities and these only impact the emails received (= all admins get full admin dashboard access, except scope admins): - The plan is to not fully support responsibilities in the global code for now, and directly go for the finer grained access control model, to then migrate FR to that. Rationale: existing responsibilities are confusing admins as they expect responsibilities to limit access to the different part of the pro dashboard.

  • contract_manager - Manages contracts
  • people_manager - Manages people/employees
  • payroll_manager - Manages payroll
  • invoice_manager - Manages invoices
  • wellbeing_referent - Wellbeing responsibilities

AccountOrgTreeQueryApi

This is a global API that abstract away the country-specific data model of the accounts entity setup = which company is linked to which account and which operational scope is linked to which company. This allows customer_admin component to avoid directly relying on each country Account, Company and OperationalScope models by instead relying on the dependency inversion pattern (CustomerAdminDependency interface implemented in each country) The main data structure returned by this API is AccountOrgTree which is a tree structure of all the entities in a given account. This is particularly useful for admin rights business logic as admin rights are transitive (ex: an account admin is also admin of all the companies in that account)

Architecture

Current state

Warning

🚧 The component is an ongoing work. As of Jan 2026:

  • Different patterns and some legacy data models are still used. The most up to date code is the one based on the global CustomerAdmin data model.
  • The admin invitation is fully global + Canada use the global admin management stack end to end (data model + business logic). Other countries are yet to be migrated to global stack.

High level recap table

Aspect France πŸ‡«πŸ‡· Belgium πŸ‡§πŸ‡ͺ Spain πŸ‡ͺπŸ‡Έ Global/Canada πŸ‡¨πŸ‡¦
Global admin invite stack ❌ βœ… βœ… βœ…
Global admin stack ❌ ❌ ❌ βœ…
Data models Local FrCompanyAdmin Local BeAccountAdmin, BeCompanyAdmin Local EsAccountAdmin, EsCompanyAdmin Global CustomerAdmin, CustomerAdminToEntity
Responsibilities avaiable Yes No No No
Operational Scopes βœ… ❌ ❌ Not yet

Public API

  • CustomerAdminReadService is the public entrypoint to query admin data. It's a higher level API that abstracts away country-specific data model and exposes a unified interface.
  • For the write part, we use plain functions stored in public/actions.py

Global data Model

CustomerAdmin

The core model representing an admin user and denormalize some profile data:

class CustomerAdmin:
    profile_id: UUID  # Links to global profile
    first_name: str  # First name (encrypted), mainly for display and search purpose
    last_name: str  # Last name (encrypted), mainly for display and search purpose
    customer_admin_to_entities  # Relationship to entities

CustomerAdminToEntity

Represents the relationship between an admin and an entity they manage:

class CustomerAdminToEntity(Historizable):
    customer_admin_id: UUID  # Reference to CustomerAdmin

    entity_id: str  # ID of the managed entity
    entity_type: EntityType  # account/company/operational_scope
    parent_account_id: str  # Context account

    start_date: date  # When admin role began
    end_date: date  # When admin role ended

    user_id: str  # Country-specific user ID 

    # other fields for specific use case exists but are omitted for clarity

Key features:

  • Historizable - Tracks start/end dates for admin relationships
  • Multi-entity support - An admin can manage multiple entities

Interaction with other components

Depends on:

  • the onboarding component for the admin invite flow
  • some countries components (fr, be, es) to bridge with country-specific data models and logic. This is a transition state only
  • global_profile to get a profile_id from a local user_id + react to profile merge and name update events.

Used by:

  • ca (Canada) for customer authorization logic
  • contracting - work in progress - the direction is to centralize admin management from contracting into customer admin (ex: acccount hub should be powered by this component API long term)
  • global_customer_dashboard to display admins in the customer dashboard

Design Pattern for backward compatibility

The component uses a delegation pattern to handle country-specific logic and bridge with local data models when needed:

  1. Public API methods receive requests
  2. Determine the current application context (FR/BE/ES)
  3. Delegate to country-specific implementations using match/case statements
  4. Return standardized entities from the public API

Info

🚧 This pattern is being phased out in favor of a repository based pattern to reduce dependencies on local code and data model.

The component also makes uses of dependency inversion pattern β§‰ to call country-specific code from the global component.

How It Works

Permission Checking

Authorization is checked separately before the following logic:

  1. Component builds AdminedEntitiesForest for the user
  2. Tree includes direct relationships + transitive relationships
  3. Controllers check if requested entity is in the admin's tree

For pro dashboard use cases, read the following documentation β§‰

Admin Invitation Flow

High level overview of how the global stack works

flowchart TD
    subgraph dash [Pro dashboard]
        A[Admin invite new admin]
    end
    A -->|global_customer_dashboard API calls| B
    subgraph onb [Onboarding component]
        B[Invitation created + email is sent]
        B -->|Invited user click on invite link| C
        subgraph invited [Invited user]
            C[Deep link in Alan web app is opened]
            C --> E[Invitee signs up]
        end
    end
    E -->|admin onboarding completed handler called| F
    subgraph customer_admin [Customer_adminΒ component]
        F[Admin rights created]
    end
Hold "Alt" / "Option" to enable pan & zoom
  • Admin rights created = rows in CustomerAdmin and CustomerAdminToEntity DB tables are created and user gets access to the pro dashboard as a result.
  • There's an alternative flow that allows directly creating admin rights for an existing employee (add admin by the user name instead of invite email in the invite form). Keyword in the code: "promote admin"

Admin lifecycle

  • Admin rights are automatically ended when the admin is also an employee and they leave the company.
  • Aside from that case, admin management is manual and is done by other admins who add, update and remove admins from the pro dashboard.

Frontend Integration

The component works with the customer-admin-management frontend module, which handles:

  • Displaying admins in the customer dashboard
  • Admin invitation UI
  • Admin removal and rights update workflows

Component Tags: Customer Admin, Authorization, Multi-Country, Admin Management