Skip to content

Orgs — models

Responsibilities

The orgs app models the organizational structure and membership layer of the system.

It is responsible for:

  • the Organization tenant model
  • hierarchical parent/child org structure
  • org-level settings inheritance
  • branding and document identity configuration
  • internal user membership in organizations
  • customer user membership in customer organizations
  • links between internal orgs and customer orgs

This app is the main multi-tenancy and role container for the backend.

It does not model user identity itself. That remains in accounts.
Instead, orgs answers questions like:

  • which organization is the user acting in
  • what role does the user have in that organization
  • which customer organizations are linked to which internal organizations
  • what branding/settings are effective for this org

Main models

Organization

Represents an organizational tenant and, optionally, a node in the org tree.

This is the central model of the app.

  • Fields
  • Core identity
    • name
    • slug
    • org_type
    • parent
    • settings
  • Branding / legal identity
    • legal_name
    • display_name
  • Address / contact
    • address_line1
    • address_line2
    • postal_code
    • city
    • state_region
    • country
    • phone
    • email
    • website
  • Legal / registration
    • vat_number
    • coc_number
  • Branding assets
    • logo
    • logo_pdf
    • brand_primary
    • brand_text
    • brand_muted
  • PDF/document options
    • pdf_footer_note
    • pdf_show_legal_ids
    • pdf_show_contact_details
  • Lifecycle
    • is_active
    • created_at
  • Audit/history
    • history
  • Constraints
  • slug is unique
  • parent is protected on delete
  • Tree behavior is managed via MPTTModel
  • Relationships
  • Optional parent organization via parent
  • One-to-many child organizations via children
  • One-to-many internal memberships via memberships
  • One-to-many customer memberships via customer_memberships
  • One-to-many outgoing customer links via linked_customers
  • One-to-many incoming customer links via linked_to_internal_orgs

Key derived behavior

effective_settings()

Combines inherited JSON settings from ancestors to the current org.

Rule: - parent settings form the base - child settings override matching keys

display_name_effective

Returns: 1. display_name 2. else legal_name 3. else name

logo_pdf_url

Returns the preferred branding file URL: 1. logo_pdf 2. else logo

address_single_line

Builds a one-line address string from the address fields.

effective_branding()

Builds a resolved branding/document payload using: - explicit org fields first - inherited settings as fallback - sensible defaults when neither exists

This makes Organization both a tenant model and a branding/document configuration source.


OrgMembership

Represents an internal user’s membership in an internal organization.

This is the main role-based authorization anchor used across the project.

  • Fields
  • user
  • org
  • role
  • is_active
  • joined_at
  • history
  • Constraints
  • Unique per (user, org)
  • Relationships
  • Foreign key to accounts.User
  • Foreign key to Organization

Role values

  • owner
  • admin
  • manager
  • engineer
  • viewer

These roles are used by application logic to determine whether a user may: - manage members - manage invites - access organization-level functionality - act in administrative workflows


Represents a relationship between an internal organization and a customer organization.

This allows the system to model customer-facing access without mixing internal and customer tenants directly.

  • Fields
  • internal_org
  • customer_org
  • is_active
  • created_at
  • Constraints
  • Unique per (internal_org, customer_org)
  • Relationships
  • Foreign key to Organization as internal_org
  • Foreign key to Organization as customer_org

This model is the bridge that enables internal orgs to work with customer orgs in a controlled way.


CustomerMembership

Represents a customer user’s membership inside a customer organization.

This is intentionally separate from OrgMembership so internal roles and customer roles do not get mixed together.

  • Fields
  • user
  • customer_org
  • role
  • is_active
  • joined_at
  • Constraints
  • Unique per (user, customer_org)
  • Relationships
  • Foreign key to accounts.User
  • Foreign key to Organization as customer_org

Role values

  • customer_admin
  • customer_user

This model is used for portal/customer-side access where internal staff roles should not apply.


Relationship overview

flowchart TD
    User[User]
    Organization[Organization]

    OrgMembership[OrgMembership]
    CustomerMembership[CustomerMembership]
    CustomerLink[CustomerLink]

    Organization -->|parent/children tree| Organization

    User -->|1:N| OrgMembership
    Organization -->|1:N| OrgMembership

    User -->|1:N| CustomerMembership
    Organization -->|1:N customer_org| CustomerMembership

    Organization -->|internal_org| CustomerLink
    Organization -->|customer_org| CustomerLink

Model boundaries and design notes

Why Organization is broader than a simple tenant table

Organization currently combines three concerns: • tenant identity • hierarchy/inheritance • branding/document configuration

That is acceptable in this system because branding and org identity are tightly linked in operational workflows such as: • PDF generation • customer-facing reports • organization settings screens

If these concerns become significantly more complex later, branding could be split into a dedicated model.


Why memberships are split into two models

The project distinguishes between: • internal workforce memberships • customer user memberships

That separation is important because: • role sets differ • permissions differ • workflows differ • mixing them would make authorization logic harder to reason about

So: • OrgMembership = internal tenant role • CustomerMembership = customer tenant role


A customer org is still an Organization, but not every org should automatically be related to every other org.

CustomerLink makes the relationship explicit and manageable: • internal org can link to customer org • link can be activated/deactivated • downstream access can depend on that link