505 lines
11 KiB
Markdown
505 lines
11 KiB
Markdown
DATA MODELS
|
|
===========
|
|
|
|
This document describes the key top-level entities this application will be working with and the attributes of each. This is a work-in-progress.
|
|
|
|
Other top-level entities will be introduced to the application as necessary.
|
|
|
|
Representations in this document are in application context; for database structure, see SCHEMA.md in this directory.
|
|
|
|
# Person
|
|
|
|
A Person represents a person! Specifically, a Person is a person who is using/has used the web application. Many applications call this entity a "User". We call them a Person.
|
|
|
|
``` rust
|
|
struct PersonId {
|
|
id: String,
|
|
}
|
|
struct Person {
|
|
id: PersonId,
|
|
remote_id: String,
|
|
name: String,
|
|
handle: Option<String>,
|
|
email: Option<Vec<String>>,
|
|
avatar: Option<String>,
|
|
cover: Option<String>,
|
|
bio: Option<String>,
|
|
is_active: bool,
|
|
is_blocked: bool,
|
|
created_at: chrono::DateTime,
|
|
modified_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
deleted_by: Option<PersonId>,
|
|
last_seen: chrono::DateTime,
|
|
shipping_address: Option<String>,
|
|
}
|
|
```
|
|
|
|
# PersonCredential
|
|
|
|
A PersonCredential is an authentication method associated with a specific Person.
|
|
|
|
``` rust
|
|
struct PersonCredentialId {
|
|
id: String,
|
|
}
|
|
enum PersonCredentialProviderType {
|
|
OAuth2,
|
|
Local,
|
|
}
|
|
struct PersonCredentialProviderId {
|
|
id: String,
|
|
}
|
|
struct PersonCredentialProvider {
|
|
id: PersonCredentialProviderId,
|
|
name: String,
|
|
type: PersonCredentialProviderType,
|
|
config: String,
|
|
}
|
|
struct PersonCredential {
|
|
id: PersonCredentialId,
|
|
person_id: PersonId,
|
|
provider_id: PersonCredentialProviderId,
|
|
provider_user_id: String,
|
|
is_enabled: bool,
|
|
}
|
|
```
|
|
|
|
# Tag
|
|
|
|
A Tag is a classification label that a Person wants to associate to a Label, an Artist, an Album, a Track, or a Playlist, used as a way of grouping entities together via some commonality the context of which is not programmatically relevant.
|
|
|
|
``` rust
|
|
struct Tag {
|
|
host: String,
|
|
name: String,
|
|
}
|
|
impl Tag {
|
|
pub fn new(host: String, name: String) -> Self {
|
|
TagId {
|
|
host,
|
|
name,
|
|
}
|
|
}
|
|
}
|
|
impl fmt::Display for Tag {
|
|
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}::tag::{}", self.host.as_ref(), self.name.as_ref())
|
|
}
|
|
}
|
|
```
|
|
|
|
# Label
|
|
|
|
A Label represents a record label (a group of people who handle promotion and/or distribution for one or more Artists).
|
|
|
|
``` rust
|
|
struct LabelId {
|
|
id: String,
|
|
}
|
|
struct Label {
|
|
id: LabelId,
|
|
name: String,
|
|
description: String,
|
|
website: String,
|
|
is_enabled: bool,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
artists: HashMap<Artist>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
}
|
|
```
|
|
|
|
# LabelContact
|
|
|
|
A LabelContact represents a method for contacting a representative of a Label.
|
|
|
|
``` rust
|
|
struct LabelContactId {
|
|
id: String,
|
|
}
|
|
struct LabelContact {
|
|
id: LabelContactId,
|
|
method: String,
|
|
address: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
sort_order: usize,
|
|
}
|
|
```
|
|
|
|
# Artist
|
|
|
|
An Artist represents a musical artist.
|
|
|
|
``` rust
|
|
struct ArtistId {
|
|
id: String,
|
|
}
|
|
struct Artist {
|
|
id: ArtistId,
|
|
name: String,
|
|
bio: String,
|
|
website: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
is_enabled: bool,
|
|
is_public: bool,
|
|
labels: Option<Vec<LabelId>>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
cover: Option<String>,
|
|
images: Option<Vec<String>>,
|
|
}
|
|
```
|
|
|
|
# Track
|
|
|
|
A Track represents a single piece of work by an Artist that is contained in an audio file.
|
|
|
|
``` rust
|
|
struct TrackId {
|
|
id: String,
|
|
}
|
|
struct Track {
|
|
id: TrackId,
|
|
title: String,
|
|
description: Option<String>,
|
|
duration: chrono::Duration,
|
|
artists: Vec<Artist>,
|
|
is_public: bool,
|
|
is_available: bool,
|
|
preview_source: Option<String>,
|
|
source: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
lyrics: Option<String>,
|
|
cover: Option<String>,
|
|
images: Option<Vec<String>>,
|
|
}
|
|
```
|
|
|
|
# Album
|
|
|
|
An Album represents a work by an Artist that contains one or more Tracks.
|
|
|
|
``` rust
|
|
struct AlbumId {
|
|
id: String,
|
|
}
|
|
struct Album {
|
|
id: AlbumId,
|
|
title: String,
|
|
description: String,
|
|
artists: Vec<Artist>,
|
|
tracks: Vec<Track>,
|
|
is_public: bool,
|
|
is_available: bool,
|
|
preview_source: Option<String>,
|
|
source: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
cover: Option<ImageId>,
|
|
images: Option<Vec<ImageId>>,
|
|
}
|
|
```
|
|
|
|
# Playlist
|
|
|
|
A Playlist represents an ordered collection of Tracks assembled by a Person.
|
|
|
|
``` rust
|
|
struct PlaylistId {
|
|
id: String,
|
|
}
|
|
struct Playlist {
|
|
id: PlaylistId,
|
|
title: String,
|
|
description: Option<String>,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_at: chrono::DateTime,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
is_public: bool,
|
|
cover: Option<ImageId>,
|
|
tracks: Vec<Track>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
}
|
|
```
|
|
|
|
# Article
|
|
|
|
An Article represents a "blog post" style article written by a Person.
|
|
|
|
``` rust
|
|
struct ArticleId {
|
|
id: String,
|
|
}
|
|
struct Article {
|
|
id: ArticleId,
|
|
title: String,
|
|
body: String,
|
|
description: Option<String>,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_at: chrono::DateTime,
|
|
published_at: Option<chrono::DateTime>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
is_public: bool,
|
|
is_draft: bool,
|
|
cover: Option<ImageId>,
|
|
images: Option<Vec<ImageId>>,
|
|
tracks: Option<Vec<Track>>,
|
|
tags: Option<Vec<Tag>>,
|
|
comments: Option<Vec<Comment>>,
|
|
}
|
|
```
|
|
|
|
# Comment
|
|
|
|
A Comment represents a textual comment that a Person wants to attach contextually to an Artist, an Album, a Track, or a Playlist.
|
|
|
|
``` rust
|
|
enum CommentTarget {
|
|
Label(LabelId),
|
|
Artist(ArtistId),
|
|
Album(AlbumId),
|
|
Track(TrackId),
|
|
Playlist(PlaylistId),
|
|
Article(ArticleId),
|
|
Comment(CommentId),
|
|
}
|
|
struct CommentId {
|
|
id: String,
|
|
}
|
|
struct Comment {
|
|
id: CommentId,
|
|
body: String,
|
|
target: CommentTarget,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: Option<PersonId>,
|
|
modified_at: Option<chrono::DateTime>,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
is_public: bool,
|
|
is_approved: bool,
|
|
in_reply_to: Option<CommentId>,
|
|
}
|
|
```
|
|
|
|
# Image
|
|
|
|
An Image represents an image file that a Person wants to reference from a Label, an Artist, an Album, a Track, a Playlist, or an Article.
|
|
|
|
``` rust
|
|
struct ImageId {
|
|
id: String,
|
|
}
|
|
struct Image {
|
|
id: ImageId,
|
|
name: Option<String>,
|
|
path: String,
|
|
url: String,
|
|
width: usize,
|
|
height: usize,
|
|
alt_text: String,
|
|
is_public: bool,
|
|
allow_hotlinking: bool,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
}
|
|
```
|
|
|
|
# Video
|
|
|
|
A Video represents a video file that a Person wants to reference from a Label, an Artist, an Album, a Track, a Playlist, or an Article.
|
|
|
|
``` rust
|
|
struct VideoId {
|
|
id: String,
|
|
}
|
|
struct Video {
|
|
id: VideoId,
|
|
name: Option<String>,
|
|
path: String,
|
|
url: String,
|
|
width: usize,
|
|
height: usize,
|
|
duration: chrono::Duration,
|
|
alt_text: String,
|
|
is_public: bool,
|
|
allow_hotlinking: bool,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
}
|
|
```
|
|
|
|
# Collection
|
|
|
|
A Collection represents one or more Albums, Tracks, and/or OtherProducts that are offered together as a package for Purchase
|
|
|
|
``` rust
|
|
enum CollectionItem {
|
|
Album(AlbumId),
|
|
Track(TrackId),
|
|
OtherProduct(OtherProductId),
|
|
}
|
|
struct CollectionId {
|
|
id: String,
|
|
}
|
|
struct Collection {
|
|
id: CollectionId,
|
|
name: String,
|
|
description: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: Person,
|
|
modified_at: chrono::DateTime,
|
|
is_public: bool,
|
|
is_available: bool,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
collection_items: Option<Vec<CollectionMember>>,
|
|
}
|
|
```
|
|
|
|
# OtherProduct
|
|
|
|
An OtherProduct represents a product that is not a Track, Album, or Collection that is nonetheless for sale as a Purchase.
|
|
|
|
``` rust
|
|
struct OtherProductId {
|
|
id: String,
|
|
}
|
|
struct OtherProduct {
|
|
id: OtherProductId,
|
|
name: String,
|
|
description: String,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
is_public: bool,
|
|
is_available: bool,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
requires_shipping: bool,
|
|
}
|
|
```
|
|
|
|
# Purchase
|
|
|
|
A Purchase represents one or more Tracks, Albums, Collections, and/or OtherProducts that a Person purchases from an Artist or Label through the server.
|
|
|
|
``` rust
|
|
enum PurchaseItemType {
|
|
Album(AlbumId),
|
|
Track(TrackId),
|
|
Collection(CollectionId),
|
|
OtherProduct(OtherProductId),
|
|
}
|
|
struct PurchaseItemId {
|
|
id: String,
|
|
}
|
|
struct SkuId {
|
|
id: String,
|
|
}
|
|
struct Sku {
|
|
id: SkuId,
|
|
item: PurchaseItemType,
|
|
variant: Option<String>,
|
|
description: Option<String>,
|
|
price: rusty_money::Money,
|
|
requires_shipping: bool,
|
|
shipping_charge: Option<rusty_money::Money>,
|
|
}
|
|
struct LineItem {
|
|
id: LineItemId,
|
|
sku: SkuId,
|
|
quantity: usize,
|
|
}
|
|
enum PurchaseState {
|
|
InCart,
|
|
Processing,
|
|
PaymentRejected,
|
|
PaymentCompleted,
|
|
Fulfilled,
|
|
Cancelled,
|
|
Refunded,
|
|
}
|
|
struct Purchase {
|
|
id: String,
|
|
items: Vec<LineItem>,
|
|
state: PurchaseState,
|
|
purchased_by: Person,
|
|
purchased_at: Option<chrono::DateTime>,
|
|
fulfilled_by: Option<Person>,
|
|
fulfilled_at: Option<chrono::DateTime>,
|
|
coupons_applied: Option<Vec<CouponCodeId>>,
|
|
total_charge: rusty_money::Money,
|
|
}
|
|
```
|
|
|
|
# CouponCode
|
|
|
|
A CouponCode represents a code a Person can enter to receive a discount on a PurchateItem or on a Purchase.
|
|
|
|
``` rust
|
|
struct CouponCodeId {
|
|
id: String,
|
|
}
|
|
struct CouponCode {
|
|
id: CouponCodeId,
|
|
name: String,
|
|
code: String,
|
|
uses: usize,
|
|
max_uses: usize,
|
|
expiration: Option<chrono::DateTime>,
|
|
discount_flat: Option<rusty_money::Money>,
|
|
discount_percentage: Option<f32>,
|
|
skus: Option<Vec<SkuId>>,
|
|
is_active: bool,
|
|
created_by: PersonId,
|
|
created_at: chrono::DateTime,
|
|
modified_by: PersonId,
|
|
modified_at: chrono::DateTime,
|
|
deleted_by: Option<PersonId>,
|
|
deleted_at: Option<chrono::DateTime>,
|
|
}
|
|
``` |