Campaigns and Members
Campaigns are the core ownership boundary for most application data. A campaign has one DM role at a time, optional player memberships, static offline members, settings, cover art, and many child resources.
Backend
Primary files:
server/app/routers/campaigns.pyserver/app/models.py(Campaign,Membership,Invite)server/app/lib/access.pyserver/app/lib/campaign_clone.pyserver/app/serializers.pyserver/app/schemas.py
Campaign endpoints cover create/list/detail/update/delete, member management, static members, character details, DM transfer, campaign duplication, and cover image upload.
Frontend
Primary files:
web/src/screens/Campaigns.tsxweb/src/screens/CreateCampaign.tsxweb/src/screens/CampaignDetail.tsxweb/src/components/CampaignOverview.tsxweb/src/components/PartyRoster.tsxweb/src/components/CharacterForm.tsx
CampaignDetail loads the campaign shell and renders top-level tabs. Campaign
tab visibility depends on role, active session state, and AI access.
Membership Rules
- Creating a campaign makes the creator the DM.
- DM-only mutations must call
require_dm. - Player-facing reads should use
require_member. - Static members represent offline players and do not have user accounts.
- DM handover can keep the outgoing DM as a player or remove them.
Campaign Duplication
Campaign duplication copies prep assets but intentionally excludes live people and historical activity.
Copied:
- Campaign settings.
- Core-rule opt-ins.
- Campaign documents with chunks/embeddings.
- Extracted monsters/items.
- NPCs and relationships.
- Codex entities.
- Encounters, with session links stripped.
Excluded:
- Players and static members.
- Sessions, polls, invites, combat state.
- Rules-chat history.
- Recap extractions.
Change Checklist
- Keep serializer and frontend DTOs synchronized.
- Enforce DM/member scope in every campaign route.
- Update campaign navigation if tabs or visibility rules change.
- Update the Features page for user-visible behavior.