feat: Add cross-band entity relationship models
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
Schema additions for fediversion multi-band architecture: - SongCanon: Canonical master songs for cross-band linking (e.g., 'Dark Star' links GD, D&C, Billy Strings versions) - UserVerticalPreference: User band display preferences - display_mode: primary/secondary/attribution_only/hidden - priority: Sort order for UI - notify_on_show: Per-band notification settings - Vertical additions: - primary_artist_id: Link to main Artist entity - color: Hex branding color - emoji: Display emoji - Song additions: - canon_id: Link to SongCanon for cross-band tracking
This commit is contained in:
parent
42ede48a70
commit
56f52de7fc
1 changed files with 41 additions and 5 deletions
|
|
@ -61,6 +61,13 @@ class Vertical(SQLModel, table=True):
|
||||||
slug: str = Field(unique=True, index=True)
|
slug: str = Field(unique=True, index=True)
|
||||||
description: Optional[str] = Field(default=None)
|
description: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
|
# Link to primary artist/band for this vertical
|
||||||
|
primary_artist_id: Optional[int] = Field(default=None, foreign_key="artist.id")
|
||||||
|
|
||||||
|
# Theming
|
||||||
|
color: Optional[str] = Field(default=None, description="Hex color for branding")
|
||||||
|
emoji: Optional[str] = Field(default=None, description="Display emoji")
|
||||||
|
|
||||||
shows: List["Show"] = Relationship(back_populates="vertical")
|
shows: List["Show"] = Relationship(back_populates="vertical")
|
||||||
songs: List["Song"] = Relationship(back_populates="vertical")
|
songs: List["Song"] = Relationship(back_populates="vertical")
|
||||||
|
|
||||||
|
|
@ -155,6 +162,18 @@ class Show(SQLModel, table=True):
|
||||||
attendances: List["Attendance"] = Relationship(back_populates="show")
|
attendances: List["Attendance"] = Relationship(back_populates="show")
|
||||||
performances: List["Performance"] = Relationship(back_populates="show")
|
performances: List["Performance"] = Relationship(back_populates="show")
|
||||||
|
|
||||||
|
class SongCanon(SQLModel, table=True):
|
||||||
|
"""Canonical 'master' song independent of band - enables cross-band song linking"""
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
title: str = Field(index=True)
|
||||||
|
slug: str = Field(unique=True, index=True)
|
||||||
|
original_artist: Optional[str] = Field(default=None, description="Original songwriter/band")
|
||||||
|
original_artist_id: Optional[int] = Field(default=None, foreign_key="artist.id")
|
||||||
|
notes: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
|
# All vertical-specific versions of this song
|
||||||
|
versions: List["Song"] = Relationship(back_populates="canon")
|
||||||
|
|
||||||
class Song(SQLModel, table=True):
|
class Song(SQLModel, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
title: str = Field(index=True)
|
title: str = Field(index=True)
|
||||||
|
|
@ -164,11 +183,15 @@ class Song(SQLModel, table=True):
|
||||||
notes: Optional[str] = Field(default=None)
|
notes: Optional[str] = Field(default=None)
|
||||||
youtube_link: Optional[str] = Field(default=None)
|
youtube_link: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
# New Relation
|
# Link to canonical song for cross-band tracking
|
||||||
artist_id: Optional[int] = Field(default=None, foreign_key="artist.id")
|
canon_id: Optional[int] = Field(default=None, foreign_key="songcanon.id")
|
||||||
artist: Optional[Artist] = Relationship(back_populates="songs")
|
canon: Optional[SongCanon] = Relationship(back_populates="versions")
|
||||||
|
|
||||||
vertical: Vertical = Relationship(back_populates="songs")
|
# Artist who wrote/performs this version
|
||||||
|
artist_id: Optional[int] = Field(default=None, foreign_key="artist.id")
|
||||||
|
artist: Optional["Artist"] = Relationship(back_populates="songs")
|
||||||
|
|
||||||
|
vertical: "Vertical" = Relationship(back_populates="songs")
|
||||||
|
|
||||||
class Sequence(SQLModel, table=True):
|
class Sequence(SQLModel, table=True):
|
||||||
"""Named groupings of consecutive songs, e.g. 'Autumn Crossing' = Travelers > Elmeg the Wise"""
|
"""Named groupings of consecutive songs, e.g. 'Autumn Crossing' = Travelers > Elmeg the Wise"""
|
||||||
|
|
@ -346,7 +369,20 @@ class UserPreferences(SQLModel, table=True):
|
||||||
email_on_chase: bool = Field(default=True, description="Email when your chase song is played")
|
email_on_chase: bool = Field(default=True, description="Email when your chase song is played")
|
||||||
email_digest: bool = Field(default=False, description="Weekly digest email")
|
email_digest: bool = Field(default=False, description="Weekly digest email")
|
||||||
|
|
||||||
user: User = Relationship(back_populates="preferences")
|
user: "User" = Relationship(back_populates="preferences")
|
||||||
|
|
||||||
|
class UserVerticalPreference(SQLModel, table=True):
|
||||||
|
"""User preferences for which bands to display prominently vs. attribution-only"""
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
user_id: int = Field(foreign_key="user.id", index=True)
|
||||||
|
vertical_id: int = Field(foreign_key="vertical.id", index=True)
|
||||||
|
display_mode: str = Field(default="primary", description="primary, secondary, attribution_only, hidden")
|
||||||
|
priority: int = Field(default=0, description="Sort order - lower = higher priority")
|
||||||
|
notify_on_show: bool = Field(default=True, description="Notify when this band plays a show")
|
||||||
|
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
|
user: "User" = Relationship()
|
||||||
|
vertical: "Vertical" = Relationship()
|
||||||
|
|
||||||
class Profile(SQLModel, table=True):
|
class Profile(SQLModel, table=True):
|
||||||
"""A user's identity within a specific context or global"""
|
"""A user's identity within a specific context or global"""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue