veza/fixtures/core/schemas/database.ts
2025-12-03 22:56:50 +01:00

203 lines
No EOL
6.9 KiB
TypeScript

import { z } from 'zod'
/**
* Base schemas for database entities
*/
// User schemas
export const UserRoleSchema = z.enum(['admin', 'user', 'artist', 'producer', 'moderator'])
export const UserStatusSchema = z.enum(['active', 'inactive', 'suspended', 'pending'])
export const UserSchema = z.object({
id: z.string().uuid(),
username: z.string().min(3).max(50),
email: z.string().email(),
firstName: z.string().min(1).max(100),
lastName: z.string().min(1).max(100),
displayName: z.string().max(100).optional(),
role: UserRoleSchema,
status: UserStatusSchema,
avatar: z.string().url().optional(),
bio: z.string().max(1000).optional(),
location: z.string().max(100).optional(),
website: z.string().url().optional(),
isVerified: z.boolean().default(false),
emailVerified: z.boolean().default(false),
preferences: z.object({
language: z.string().default('fr'),
theme: z.enum(['light', 'dark', 'system']).default('system'),
notifications: z.object({
email: z.boolean().default(true),
push: z.boolean().default(true),
desktop: z.boolean().default(false),
}),
privacy: z.object({
profileVisibility: z.enum(['public', 'friends', 'private']).default('public'),
showOnlineStatus: z.boolean().default(true),
allowDirectMessages: z.boolean().default(true),
}),
}),
stats: z.object({
tracksUploaded: z.number().default(0),
playlistsCreated: z.number().default(0),
followersCount: z.number().default(0),
followingCount: z.number().default(0),
totalPlays: z.number().default(0),
}),
lastSeenAt: z.date().optional(),
createdAt: z.date(),
updatedAt: z.date(),
})
// Audio schemas
export const AudioGenreSchema = z.enum([
'rock', 'pop', 'jazz', 'classical', 'electronic', 'hip-hop', 'country',
'blues', 'reggae', 'folk', 'metal', 'punk', 'indie', 'ambient', 'techno'
])
export const AudioFormatSchema = z.enum(['mp3', 'wav', 'flac', 'aac', 'ogg'])
export const AudioQualitySchema = z.enum(['low', 'medium', 'high', 'lossless'])
export const AudioMetadataSchema = z.object({
duration: z.number().positive(), // seconds
bitrate: z.number().positive(), // kbps
sampleRate: z.number().positive(), // Hz
channels: z.number().min(1).max(8),
format: AudioFormatSchema,
quality: AudioQualitySchema,
fileSize: z.number().positive(), // bytes
bpm: z.number().positive().optional(),
key: z.string().optional(), // Musical key
loudness: z.number().optional(), // LUFS
})
export const AudioSchema = z.object({
id: z.string().uuid(),
title: z.string().min(1).max(200),
slug: z.string(),
artist: z.string().min(1).max(100),
albumId: z.string().uuid().optional(),
albumTitle: z.string().max(200).optional(),
genre: AudioGenreSchema,
subgenre: z.string().max(50).optional(),
tags: z.array(z.string()).default([]),
description: z.string().max(2000).optional(),
lyrics: z.string().optional(),
metadata: AudioMetadataSchema,
waveformData: z.array(z.number()).optional(),
fileUrl: z.string().url(),
coverImageUrl: z.string().url().optional(),
uploadedById: z.string().uuid(),
isPublic: z.boolean().default(true),
isExplicit: z.boolean().default(false),
downloadEnabled: z.boolean().default(false),
stats: z.object({
plays: z.number().default(0),
likes: z.number().default(0),
shares: z.number().default(0),
downloads: z.number().default(0),
comments: z.number().default(0),
}),
releaseDate: z.date().optional(),
createdAt: z.date(),
updatedAt: z.date(),
})
// Playlist schemas
export const PlaylistVisibilitySchema = z.enum(['public', 'unlisted', 'private'])
export const PlaylistSchema = z.object({
id: z.string().uuid(),
title: z.string().min(1).max(200),
slug: z.string(),
description: z.string().max(2000).optional(),
coverImageUrl: z.string().url().optional(),
createdById: z.string().uuid(),
visibility: PlaylistVisibilitySchema,
isCollaborative: z.boolean().default(false),
tags: z.array(z.string()).default([]),
trackIds: z.array(z.string().uuid()),
stats: z.object({
followers: z.number().default(0),
plays: z.number().default(0),
shares: z.number().default(0),
}),
createdAt: z.date(),
updatedAt: z.date(),
})
// Conversation schemas
export const ConversationTypeSchema = z.enum(['direct', 'group', 'channel'])
export const MessageTypeSchema = z.enum(['text', 'audio', 'image', 'file', 'system'])
export const MessageStatusSchema = z.enum(['sent', 'delivered', 'read', 'failed'])
export const ConversationSchema = z.object({
id: z.string().uuid(),
name: z.string().max(100).optional(),
description: z.string().max(500).optional(),
type: ConversationTypeSchema,
isPrivate: z.boolean().default(false),
avatarUrl: z.string().url().optional(),
createdById: z.string().uuid(),
participantIds: z.array(z.string().uuid()),
lastMessageId: z.string().uuid().optional(),
lastActivityAt: z.date(),
createdAt: z.date(),
updatedAt: z.date(),
})
export const MessageSchema = z.object({
id: z.string().uuid(),
conversationId: z.string().uuid(),
senderId: z.string().uuid(),
content: z.string(),
type: MessageTypeSchema,
status: MessageStatusSchema,
parentMessageId: z.string().uuid().optional(), // For replies
attachments: z.array(z.object({
id: z.string().uuid(),
type: z.enum(['image', 'audio', 'video', 'file']),
url: z.string().url(),
filename: z.string(),
size: z.number(),
mimeType: z.string(),
})).default([]),
reactions: z.array(z.object({
emoji: z.string(),
userId: z.string().uuid(),
createdAt: z.date(),
})).default([]),
mentions: z.array(z.string().uuid()).default([]),
isEdited: z.boolean().default(false),
isDeleted: z.boolean().default(false),
createdAt: z.date(),
updatedAt: z.date(),
})
// Export all types
export type User = z.infer<typeof UserSchema>
export type UserRole = z.infer<typeof UserRoleSchema>
export type UserStatus = z.infer<typeof UserStatusSchema>
export type Audio = z.infer<typeof AudioSchema>
export type AudioGenre = z.infer<typeof AudioGenreSchema>
export type AudioMetadata = z.infer<typeof AudioMetadataSchema>
export type Playlist = z.infer<typeof PlaylistSchema>
export type PlaylistVisibility = z.infer<typeof PlaylistVisibilitySchema>
export type Conversation = z.infer<typeof ConversationSchema>
export type ConversationType = z.infer<typeof ConversationTypeSchema>
export type Message = z.infer<typeof MessageSchema>
export type MessageType = z.infer<typeof MessageTypeSchema>
export type MessageStatus = z.infer<typeof MessageStatusSchema>
/**
* Validation utilities
*/
export const validateUser = (data: unknown): User => UserSchema.parse(data)
export const validateAudio = (data: unknown): Audio => AudioSchema.parse(data)
export const validatePlaylist = (data: unknown): Playlist => PlaylistSchema.parse(data)
export const validateConversation = (data: unknown): Conversation => ConversationSchema.parse(data)
export const validateMessage = (data: unknown): Message => MessageSchema.parse(data)