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 export type UserRole = z.infer export type UserStatus = z.infer export type Audio = z.infer export type AudioGenre = z.infer export type AudioMetadata = z.infer export type Playlist = z.infer export type PlaylistVisibility = z.infer export type Conversation = z.infer export type ConversationType = z.infer export type Message = z.infer export type MessageType = z.infer export type MessageStatus = z.infer /** * 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)