Appearance
Data Model
Base Classes
All entities inherit audit fields. Aggregate roots additionally get a project-scoped sequence number for public identification.
Entity (base)
| Field | Type | Notes |
|---|---|---|
| Id | Guid (UUIDv7) | Internal only, never exposed to users |
| CreatedAt | DateTime | Auto-set on insert |
| CreatedBy | Guid | Auto-set from current user |
| UpdatedAt | DateTime | Auto-set on insert and update |
| UpdatedBy | Guid | Auto-set from current user |
AggregateRoot : Entity
| Field | Type | Notes |
|---|---|---|
| SequenceNumber | int | Project-scoped public ID (the "42" in VNO-42) |
Entities
Project (Aggregate Root)
| Field | Type | Notes |
|---|---|---|
| Name | string | |
| Description | string | |
| Key | string | Unique across platform, used in public IDs (e.g., "VNO") |
| Visibility | enum | public, unlisted, private |
| Theme | value object | primaryColor, accentColor |
| NextSequenceNumber | int | Atomic DB-side counter for public ID generation |
| OwnerUserId | Guid |
ProjectMember (Entity)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| UserId | Guid | FK to User |
| Role | enum | owner, storyteller, co-creator, player, viewer |
| Status | enum | pending, accepted, declined, revoked, removed, left |
| InvitedBy | Guid | UserId of who sent the invitation |
| InvitedAt | DateTime | |
| JoinedAt | DateTime? | Null until accepted |
TimelineUpdate (Aggregate Root)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| Title | string | |
| Color | enum | red, blue, green, purple, amber |
| Status | enum | published, in-development, concept, legacy |
| Order | int | For drag-and-drop reordering |
Section (Entity)
| Field | Type | Notes |
|---|---|---|
| TimelineUpdateId | Guid | FK to TimelineUpdate |
| Label | string | |
| Order | int | For reordering within a timeline update |
Item (Entity)
| Field | Type | Notes |
|---|---|---|
| SectionId | Guid | FK to Section |
| Name | string | |
| Description | string? | |
| Url | string? | External link for published content |
| IsPending | bool | Planned but not named yet |
| Order | int | For reordering within a section |
| ParentItemId | Guid? | Self-referencing FK for sub-items |
Character (Aggregate Root)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| Name | string | |
| Description | string | |
| ImageUrl | string? | |
| Type | enum | pc, npc |
| Visibility | enum | public, private |
| Metadata | jsonb | Flexible custom fields (clan, generation, class, etc.) |
Relationship (Entity)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| SourceCharacterId | Guid | FK to Character |
| TargetCharacterId | Guid | FK to Character |
| Type | enum | family, social, professional, supernatural, custom |
| Subtype | string | e.g., parent, friend, sire, enemy |
| Strength | int | 1-5 |
| Status | enum | active, ended, secret |
| IsBidirectional | bool | If true, queried from both sides |
| Description | string? | |
| Visibility | enum | public, private |
Faction (Aggregate Root)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| Name | string | |
| Description | string | |
| Type | enum | political, military, religious, criminal, other |
| SymbolUrl | string? | |
| ParentFactionId | Guid? | Self-referencing FK for nested factions |
FactionMembership (Entity)
| Field | Type | Notes |
|---|---|---|
| FactionId | Guid | FK to Faction |
| CharacterId | Guid | FK to Character |
| Rank | string? | Role/rank within the faction |
FactionRelationship (Entity)
| Field | Type | Notes |
|---|---|---|
| ProjectId | Guid | FK to Project |
| SourceFactionId | Guid | FK to Faction |
| TargetFactionId | Guid | FK to Faction |
| Type | enum | allied, enemy, neutral, trade, vassal, custom |
| Strength | int | 1-5 |
| IsSecret | bool | |
| Description | string? |
ChangelogEntry (Entity)
| Field | Type | Notes |
|---|---|---|
| TimelineUpdateId | Guid | FK to TimelineUpdate |
| Date | DateTime | |
| Title | string | |
| Description | string? | |
| NewItems | string[]? | List of added items |
| UpdatedItems | string[]? | List of updated items |
| RemovedItems | string[]? | List of removed items |
Value Objects
Theme
- PrimaryColor: string (hex)
- AccentColor: string (hex)
RelationshipType
- Category: enum (family, social, professional, supernatural, custom)
- Subtype: string
DevelopmentStatus
- Value: enum (published, in-development, concept, legacy)
Entity Classification
| Type | Entities |
|---|---|
| Aggregate Roots | Project, Character, Faction, TimelineUpdate |
| Entities | Section, Item, ProjectMember, FactionMembership, Relationship, FactionRelationship, ChangelogEntry |
| Value Objects | Theme, RelationshipType, DevelopmentStatus |