513 lines
11 KiB
Markdown
513 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 CommentTargetType {
|
|
Label,
|
|
Artist,
|
|
Album,
|
|
Track,
|
|
Playlist,
|
|
Article,
|
|
Comment,
|
|
}
|
|
struct CommentTargetId {
|
|
label_id: Option<LabelId>,
|
|
artist_id: Option<ArtistId>,
|
|
album_id: Option<AlbumId>,
|
|
track_id: Option<TrackId>,
|
|
playlist_id: Option<PlaylistId>,
|
|
article_id: Option<ArticleId>,
|
|
comment_id: Option<CommentId>,
|
|
}
|
|
struct CommentId {
|
|
id: String,
|
|
}
|
|
struct Comment {
|
|
id: CommentId,
|
|
body: String,
|
|
target_type: CommentTargetType,
|
|
target_id: CommentTargetId,
|
|
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 and/or Tracks that are offered together as a package for Purchase
|
|
|
|
``` rust
|
|
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>,
|
|
albums: Option<Vec<Album>>,
|
|
tracks: Option<Vec<Track>>,
|
|
other_products: Option<Vec<OtherProduct>>,
|
|
}
|
|
```
|
|
|
|
# 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 or Albums that a Person purchases from an Artist or Label through the server.
|
|
|
|
``` rust
|
|
enum PurchaseItemType {
|
|
Album,
|
|
Track,
|
|
Collection,
|
|
OtherProduct,
|
|
}
|
|
struct PurchaseItemId {
|
|
id: String,
|
|
}
|
|
struct SkuId {
|
|
id: String,
|
|
}
|
|
struct Sku {
|
|
id: SkuId,
|
|
album_id: Option<AlbumId>,
|
|
track_id: Option<TrackId>,
|
|
collection_id: Option<CollectionId>,
|
|
other_product_id: Option<OtherProductId>,
|
|
variant: Option<String>,
|
|
description: Option<String>,
|
|
price: Option<rusty_money::Money>,
|
|
requires_shipping: bool,
|
|
}
|
|
struct PurchaseItem {
|
|
id: PurchaseItemId,
|
|
type: PurchaseItemType,
|
|
sku: Option<SkuId>,
|
|
quantity: usize,
|
|
}
|
|
enum PurchaseState {
|
|
InCart,
|
|
Processing,
|
|
PaymentRejected,
|
|
PaymentCompleted,
|
|
Fulfilled,
|
|
Cancelled,
|
|
Refunded,
|
|
}
|
|
struct Purchase {
|
|
id: String,
|
|
items: Vec<PurchaseItem>,
|
|
state: PurchaseState,
|
|
purchased_by: Person,
|
|
purchased_at: Option<chrono::DateTime>,
|
|
fulfilled_by: Option<Person>,
|
|
fulfilled_at: Option<chrono::DateTime>,
|
|
}
|
|
```
|
|
|
|
# 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>,
|
|
}
|
|
``` |