Files
the-biergarten-app/web/backend/Database/Database.Migrations/schema.dbml

256 lines
7.8 KiB
Plaintext

Project biergarten_app {
database_type: 'SQL Server'
Note: 'Generated from Database.Migrations/scripts/01-schema. Default schema is dbo.'
}
Table UserAccount {
UserAccountID uniqueidentifier [pk, default: `newid()`]
Username varchar(64) [not null, unique]
FirstName nvarchar(128) [not null]
LastName nvarchar(128) [not null]
Email varchar(128) [not null, unique]
CreatedAt datetime [not null, default: `getdate()`]
UpdatedAt datetime
DateOfBirth date [not null]
RowVersion rowversion
}
Table Photo {
PhotoID uniqueidentifier [pk, default: `newid()`]
Hyperlink nvarchar(256) [note: 'storage handled via filesystem/cloud service']
UploadedByID uniqueidentifier [not null]
UploadedAt datetime [not null, default: `getdate()`]
RowVersion rowversion
Note: 'A user account cannot be deleted while it has uploaded photos'
Indexes {
UploadedByID
}
}
Table UserAvatar {
UserAvatarID uniqueidentifier [pk, default: `newid()`]
UserProfileID uniqueidentifier [not null]
PhotoID uniqueidentifier [not null]
ValidFrom "datetime2(3)" [not null, default: `sysutcdatetime()`]
ValidTo "datetime2(3)" [note: 'NULL = currently active']
RowVersion rowversion
Note: 'Deleted when the user profile is deleted. At most one row per profile has ValidTo = NULL.'
Indexes {
UserProfileID [unique, name: 'UX_UserAvatar_ActiveOne', note: 'filtered: WHERE ValidTo IS NULL']
PhotoID [name: 'IX_UserAvatar_Photo']
}
}
Table UserProfile {
UserProfileID uniqueidentifier [pk, default: `newid()`]
Biography "nvarchar(max)" [not null]
UserAccountID uniqueidentifier [not null, unique]
RowVersion rowversion
Note: 'Deleted when the user account is deleted'
}
Table UserVerification {
UserVerificationID uniqueidentifier [pk, default: `newid()`]
UserAccountID uniqueidentifier [not null, unique]
VerificationDateTime datetime [not null, default: `getdate()`]
RowVersion rowversion
Note: 'Deleted when the user account is deleted'
}
Table UserCredential {
UserCredentialID uniqueidentifier [pk, default: `newid()`]
UserAccountID uniqueidentifier [not null]
CreatedAt datetime [not null, default: `getdate()`]
Expiry datetime [not null, default: `dateadd(day, 90, getdate())`]
Hash nvarchar(256) [not null, note: 'argon2 hash']
IsRevoked bit [not null, default: 0]
RevokedAt datetime
RowVersion rowversion
Note: 'Deleted when the user account is deleted'
Indexes {
UserAccountID
(UserAccountID, IsRevoked, Expiry) [name: 'IX_UserCredential_Account_Active', note: 'includes Hash']
}
}
Table UserFollow {
UserFollowID uniqueidentifier [pk, default: `newid()`]
UserAccountID uniqueidentifier [not null]
FollowingID uniqueidentifier [not null]
CreatedAt datetime [not null, default: `getdate()`]
RowVersion rowversion
Note: 'CHECK: UserAccountID != FollowingID (cannot follow own account)'
Indexes {
(UserAccountID, FollowingID)
(FollowingID, UserAccountID)
}
}
Table Country {
CountryID uniqueidentifier [pk, default: `newid()`]
CountryName nvarchar(100) [not null]
ISO3166_1 char(2) [not null, unique]
RowVersion rowversion
}
Table StateProvince {
StateProvinceID uniqueidentifier [pk, default: `newid()`]
StateProvinceName nvarchar(100) [not null]
ISO3166_2 char(6) [not null, unique, note: "e.g. 'US-CA' for California, 'CA-ON' for Ontario"]
CountryID uniqueidentifier [not null]
RowVersion rowversion
Indexes {
CountryID
}
}
Table City {
CityID uniqueidentifier [pk, default: `newid()`]
CityName nvarchar(100) [not null]
StateProvinceID uniqueidentifier [not null]
RowVersion rowversion
Indexes {
StateProvinceID
}
}
Table BreweryPost {
BreweryPostID uniqueidentifier [pk, default: `newid()`]
BreweryName nvarchar(256) [not null]
PostedByID uniqueidentifier [not null]
Description "nvarchar(max)" [not null]
CreatedAt datetime [not null, default: `getdate()`]
UpdatedAt datetime
RowVersion rowversion
Note: 'A user cannot be deleted if they have a post'
Indexes {
PostedByID
}
}
Table BreweryPostLocation {
BreweryPostLocationID uniqueidentifier [pk, default: `newid()`]
BreweryPostID uniqueidentifier [not null, unique]
AddressLine1 nvarchar(256) [not null]
AddressLine2 nvarchar(256)
PostalCode nvarchar(20) [not null]
CityID uniqueidentifier [not null]
Coordinates geography [note: 'spatial index deferred, see schema.sql history']
RowVersion rowversion
Indexes {
BreweryPostID
CityID
}
}
Table BreweryPostPhoto {
BreweryPostPhotoID uniqueidentifier [pk, default: `newid()`]
BreweryPostID uniqueidentifier [not null]
PhotoID uniqueidentifier [not null]
LinkedAt datetime [not null, default: `getdate()`]
RowVersion rowversion
Note: 'All photos linked to a post are deleted if the post is deleted'
Indexes {
(PhotoID, BreweryPostID)
(BreweryPostID, PhotoID)
}
}
Table BeerStyle {
BeerStyleID uniqueidentifier [pk, default: `newid()`]
StyleName nvarchar(100) [not null, unique]
Description "nvarchar(max)"
RowVersion rowversion
}
Table BeerPost {
BeerPostID uniqueidentifier [pk, default: `newid()`]
Name nvarchar(100) [not null]
Description "nvarchar(max)" [not null]
ABV "decimal(4,2)" [not null, note: 'CHECK ABV BETWEEN 0 AND 67']
IBU int [not null, note: 'CHECK IBU BETWEEN 0 AND 120']
PostedByID uniqueidentifier [not null]
BeerStyleID uniqueidentifier [not null]
BrewedByID uniqueidentifier [not null]
CreatedAt datetime [not null, default: `getdate()`]
UpdatedAt datetime
RowVersion rowversion
Indexes {
PostedByID
BeerStyleID
BrewedByID
}
}
Table BeerPostPhoto {
BeerPostPhotoID uniqueidentifier [pk, default: `newid()`]
BeerPostID uniqueidentifier [not null]
PhotoID uniqueidentifier [not null]
LinkedAt datetime [not null, default: `getdate()`]
RowVersion rowversion
Note: 'All photos linked to a beer post are deleted if the post is deleted'
Indexes {
(PhotoID, BeerPostID)
(BeerPostID, PhotoID)
}
}
Table BeerPostComment {
BeerPostCommentID uniqueidentifier [pk, default: `newid()`]
Comment nvarchar(250) [not null]
BeerPostID uniqueidentifier [not null]
CommentedByID uniqueidentifier [not null]
Rating int [not null, note: 'CHECK Rating BETWEEN 1 AND 5']
CreatedAt datetime [not null, default: `getdate()`]
UpdatedAt datetime
RowVersion rowversion
Indexes {
BeerPostID
CommentedByID
}
}
Ref: Photo.UploadedByID > UserAccount.UserAccountID [delete: no action]
Ref: UserAvatar.PhotoID > Photo.PhotoID [delete: no action]
Ref: UserAvatar.UserProfileID > UserProfile.UserProfileID [delete: cascade]
Ref: UserProfile.UserAccountID - UserAccount.UserAccountID [delete: cascade]
Ref: UserVerification.UserAccountID - UserAccount.UserAccountID [delete: cascade]
Ref: UserCredential.UserAccountID > UserAccount.UserAccountID [delete: cascade]
Ref: UserFollow.UserAccountID > UserAccount.UserAccountID [delete: no action]
Ref: UserFollow.FollowingID > UserAccount.UserAccountID [delete: no action]
Ref: StateProvince.CountryID > Country.CountryID
Ref: City.StateProvinceID > StateProvince.StateProvinceID
Ref: BreweryPost.PostedByID > UserAccount.UserAccountID [delete: no action]
Ref: BreweryPostLocation.BreweryPostID - BreweryPost.BreweryPostID [delete: cascade]
Ref: BreweryPostLocation.CityID > City.CityID
Ref: BreweryPostPhoto.BreweryPostID > BreweryPost.BreweryPostID [delete: cascade]
Ref: BreweryPostPhoto.PhotoID > Photo.PhotoID [delete: cascade]
Ref: BeerPost.PostedByID > UserAccount.UserAccountID [delete: no action]
Ref: BeerPost.BeerStyleID > BeerStyle.BeerStyleID
Ref: BeerPost.BrewedByID > BreweryPost.BreweryPostID
Ref: BeerPostPhoto.BeerPostID > BeerPost.BeerPostID [delete: cascade]
Ref: BeerPostPhoto.PhotoID > Photo.PhotoID [delete: cascade]
Ref: BeerPostComment.BeerPostID > BeerPost.BeerPostID
Ref: BeerPostComment.CommentedByID > UserAccount.UserAccountID [delete: no action]