Skip to content

Teams — models

Responsibilities

The Teams app models how users are grouped within an organization to support: - Operational collaboration (who works together) - Responsibility structures (team leads vs members) - Workforce segmentation for planning, reporting, and permissions

It provides: - Teams scoped to an organization - Memberships linking users to teams - Primary team designation per user


Main models

Team

Represents a logical group of users within an organization.

Fields - id — Primary key - org — FK → Organization - name — Team name (unique per org) - is_active — Soft-deletion / lifecycle flag - created_at — Timestamp

Constraints - unique_together (org, name) → team names must be unique within an organization

Relationships - Belongs to one Organization - Has many TeamMemberships - Indirectly connects to Users via memberships


TeamMembership

Represents a user’s membership in a team.

Fields - id — Primary key - team — FK → Team - user — FK → User - role — Enum: - lead - deputy - member - specialist - trainee - is_primary — Whether this is the user’s primary team - is_active — Active membership flag - joined_at — Timestamp

Constraints - unique_together (team, user) → user cannot join same team twice - UniqueConstraint(user, is_primary=True) → only one primary team per user

Relationships - Belongs to one Team - Belongs to one User - Indirectly linked to Organization via Team


Model relationships (diagram)

erDiagram
    ORGANIZATION ||--o{ TEAM : contains
    TEAM ||--o{ TEAM_MEMBERSHIP : has
    USER ||--o{ TEAM_MEMBERSHIP : belongs_to

    ORGANIZATION {
        int id
        string name
        string slug
    }

    TEAM {
        int id
        int org_id
        string name
        bool is_active
    }

    TEAM_MEMBERSHIP {
        int id
        int team_id
        int user_id
        string role  "lead|deputy|member|specialist|trainee"
        bool is_primary
        bool is_active
    }

    USER {
        int id
        string email
        string username
    }

Key design notes

1. Teams are scoped to orgs

  • No cross-org teams
  • Enforced via FK (team.org)

2. Membership is explicit (no implicit inclusion)

  • Users only belong to teams via TeamMembership
  • Enables:
  • fine-grained permissions
  • multiple team assignments

3. Primary team constraint

  • Each user can have only one primary team
  • Enforced at DB level:
UniqueConstraint(fields=["user"], condition=Q(is_primary=True))

3. Primary team constraint

  • Each user can have only one primary team
  • Enforced at DB level:
  • UniqueConstraint(user, is_primary=True)

  • Used for:

  • defaults in planning
  • UI shortcuts
  • workforce grouping

4. Soft lifecycle via is_active

  • Teams and memberships are not deleted
  • Allows:
  • audit/history
  • safe deactivation

5. Separation from org roles

  • Org-level roles → OrgMembership
  • Team-level roles → TeamMembership

This separation allows: - A user can be: - Admin in org - Member in team - Cleaner permission layering


6. Expanded team role system

Team roles now support a richer structure: - lead — primary responsible - deputy — secondary lead / backup - member — standard team member - specialist — domain-specific role - trainee — learning / onboarding role

Important: - Roles are currently descriptive, not permission-enforcing within this app - No strict hierarchy is enforced yet - Future iterations may introduce: - role-based permissions - role hierarchy rules