organizations app
The structural backbone. Every other app's data is scoped through this app's models.
Models (9)
Organization— tenant root; fields: name, slug, type, is_active, primary_color, accepts_account_requestsRegion— optional grouping of chapters within an org; states_covered as textChapter— concrete chapter; FK to org + nullable region; fields: name, designation, university, city, state, founded_date, status (active / inactive / suspended)Membership— joins User to Chapter; fields: role (member / officer / president / advisor), status (pnm / pledge / undergrad / associate / alumni / inactive / disaffiliated), joined_atOrganizationAdmin— promotes a User to org admin; fields: title, is_activeRegionalAdmin— promotes a User to regional admin; fields: role (director / coordinator / advisor), title, is_activeProfileCompletenessConfig— per-org rules for what counts toward member profile completeness scoreStorageConfig— per-org S3 / MinIO config (encrypted credentials)OrganizationConsentTemplate— per-org legal templates (membership agreement, code of conduct, photo release, etc.)
Key endpoints
| URL | Purpose |
|---|---|
GET /api/organizations/ | List orgs (platform admin sees all; others see own) |
GET /api/organizations/<id>/ | Org detail |
PATCH /api/organizations/<id>/ | Update org (name, branding, etc.) |
POST /api/organizations/<id>/admins/ | Invite an org admin |
GET /api/organizations/<id>/regions/ | List regions |
POST /api/organizations/<id>/regions/ | Create a region |
GET /api/organizations/<id>/chapters/ | List chapters |
POST /api/organizations/<id>/chapters/ | Create a chapter |
GET /api/chapters/<id>/members/ | Roster |
POST /api/chapters/<id>/members/ | Add a member |
PATCH /api/memberships/<id>/ | Update role / status |
Permissions
IsNationalAdmin— org-wide CRUDIsRegionalAdmin— region-scoped reads + chapter management within regionIsChapterOfficer— chapter-scoped membership managementIsChapterMember— read-only on own chapter
Background tasks
generate_org_snapshots— periodic stats snapshot for retention analyticsrecalculate_membership_stats— fires on bulk membership changes
Signals
post_saveonMembership— creates the relatedMemberProfileand onboarding records
Notable patterns
Membership statuses control platform access
Membership.PLATFORM_ACCESS_STATUSES is the gate — only users with at least one membership in an "access" status can sign in. Statuses excluded from access:
pnm(Prospective New Member — pre-bid)disaffiliated(terminated)inactive(paused)
One Membership per (User, Chapter)
DB constraint: unique_together = ("user", "chapter"). Transferring a member to another chapter creates a new Membership with the prior one moved to inactive.
Sole-admin protection
_validate_org_admin_deactivation blocks deactivating the last active org admin. Returns 409 Conflict with code: "last_admin".
Org-level branding
Organization.primary_color (HSL string, nullable). When set, the frontend injects it as the --primary CSS var, overriding the platform default #334155.
Per-org module licensing
Lives on the OrganizationModule model in apps/organizations/models.py. Foreign-key on Organization, one row per module.
Code paths
- Models:
backend/apps/organizations/models.py - Views:
backend/apps/organizations/views.py - Permissions referenced:
backend/apps/common/permissions.py - Middleware that scopes queries:
backend/apps/common/middleware.py