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
}
¶
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:
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