Skip to main content

Data Model

server/app/models.py is the database source of truth. Alembic migrations in server/alembic/versions/ apply model changes to PostgreSQL.

Main Entity Groups

GroupModels
AccountsUser, EmailVerificationToken, PasswordResetToken
Campaign coreCampaign, Membership, Invite
Sessions and schedulingSession, AvailabilityPoll, AvailabilityOption, AvailabilityResponse
Encounters and combatEncounter, EncounterMonster, Combat, Combatant
NPCsNPC, NpcSession, NpcRelationship
CodexCampaignEntity, CampaignEntitySession, RecapExtraction
Documents and RAGCoreRule, CampaignCoreRule, CampaignDocument, IngestionSetting, Chunk, Monster, Item, RulesChatMessage

Design Choices

Enums are often stored as strings and validated in Pydantic or service logic. This keeps migrations lighter and allows feature iteration without repeated enum DDL churn.

Serializers shape API responses. Do not expose raw ORM objects to the frontend. Computed fields such as campaign counts, session labels, difficulty badges, NPC appearance counts, and AI access should be added in serializers or query helpers.

Campaign Scope

Most tables are scoped by campaignId. Always include scope checks in queries for campaign-owned data. This is both a security rule and a correctness rule: IDs alone are not enough to prove the current user can access a row.

Document Scope

Document chunks can belong to either:

  • Core rules, through coreRuleId.
  • Campaign documents, through campaignDocumentId and campaignId.

Retrieval applies campaign scope in SQL. Required core books are always visible, optional core books are visible only when enabled by CampaignCoreRule, and tool-only books are never returned as chat sources.

Migration Workflow

When changing models:

cd server
uv run alembic revision --autogenerate -m "describe change"
uv run alembic upgrade head
uv run pytest

Review generated migrations before committing. Add indexes for foreign keys and common filters. Update server/seed.py when sample data would otherwise stop covering a new feature.