Schéma Base de Données Veza
Référence complète du schéma PostgreSQL — 60+ tables, UUIDs, soft deletes.
Source : veza-backend-api/internal/models/ (68 fichiers Go) et migrations/ (115 fichiers SQL)
ORM : GORM v1 (mapping uniquement, migrations 100% SQL)
Stratégie de migration
- Migrations SQL pures dans
veza-backend-api/migrations/ (001 à 115+)
- GORM utilisé uniquement pour le mapping Go ↔ PostgreSQL, pas pour la création de schéma
- AutoMigrate() est vide — tout est géré par SQL
- Outil :
go run ./cmd/migrate_tool/main.go up (ou down pour rollback)
- Table
schema_migrations pour le suivi des migrations appliquées
Conventions
- Clés primaires : UUID v4 (
uuid.UUID avec google/uuid)
- Soft delete : Colonne
deleted_at indexée sur 20+ tables
- Timestamps :
created_at, updated_at sur toutes les tables
- JSONB : Utilisé pour les données flexibles (social_links, specs, metadata)
- Enums : Types PostgreSQL custom (user_role, track_status, etc.)
- Foreign keys : Contraintes PostgreSQL natives, toujours actives
A. Utilisateurs & Authentification
users
Table centrale — profil utilisateur.
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
username |
VARCHAR(30) |
NOT NULL |
|
email |
VARCHAR |
NOT NULL, UNIQUE |
|
password_hash |
VARCHAR |
NOT NULL |
Masqué en JSON |
token_version |
INT |
DEFAULT 0 |
Pour révocation de tokens |
first_name |
VARCHAR |
|
|
last_name |
VARCHAR |
|
|
avatar |
TEXT |
|
URL avatar |
banner_url |
TEXT |
|
URL bannière |
bio |
TEXT |
|
|
location |
VARCHAR |
|
|
birthdate |
TIMESTAMP |
NULLABLE |
|
gender |
VARCHAR(20) |
|
|
role |
user_role ENUM |
DEFAULT 'user' |
|
is_active |
BOOL |
DEFAULT true |
|
is_verified |
BOOL |
DEFAULT false |
|
is_banned |
BOOL |
DEFAULT false |
|
is_admin |
BOOL |
DEFAULT false |
|
is_public |
BOOL |
DEFAULT true |
|
last_login_at |
TIMESTAMP |
NULLABLE |
|
login_count |
INT |
DEFAULT 0 |
|
password_changed_at |
TIMESTAMP |
NULLABLE |
|
social_links |
JSONB |
DEFAULT '{}' |
|
created_at |
TIMESTAMP |
|
|
updated_at |
TIMESTAMP |
|
|
deleted_at |
TIMESTAMP |
INDEX |
Soft delete |
Relations : roles (M2M via user_roles), track_likes (has many, CASCADE)
sessions
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users, INDEX |
|
token_hash |
VARCHAR |
UNIQUE INDEX |
Token hashé |
ip_address |
VARCHAR |
|
|
user_agent |
VARCHAR |
|
|
revoked_at |
TIMESTAMP |
NULLABLE |
|
expires_at |
TIMESTAMP |
NOT NULL |
|
created_at |
TIMESTAMP |
|
|
refresh_tokens
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE), NOT NULL, INDEX |
|
token_hash |
VARCHAR |
NOT NULL, INDEX |
|
expires_at |
TIMESTAMP |
NOT NULL |
|
created_at |
TIMESTAMP |
|
|
updated_at |
TIMESTAMP |
|
|
deleted_at |
TIMESTAMP |
|
Soft delete |
roles
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
name |
VARCHAR(50) |
UNIQUE, NOT NULL |
|
display_name |
VARCHAR(100) |
NOT NULL |
|
description |
TEXT |
|
|
is_system |
BOOL |
|
Rôle système (non supprimable) |
is_active |
BOOL |
DEFAULT true |
|
created_at |
TIMESTAMP |
|
|
updated_at |
TIMESTAMP |
|
|
Relations : users (M2M), permissions (M2M)
permissions
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
name |
VARCHAR(100) |
UNIQUE, NOT NULL |
|
resource |
VARCHAR(50) |
NOT NULL |
|
action |
VARCHAR(50) |
NOT NULL |
|
description |
TEXT |
|
|
created_at |
TIMESTAMP |
|
|
user_roles (table pivot)
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE), UNIQUE(user_id, role_id) |
|
role_id |
UUID |
FK → roles (CASCADE) |
|
role |
VARCHAR(50) |
|
Nom du rôle (dénormalisé) |
assigned_at |
TIMESTAMP |
DEFAULT CURRENT_TIMESTAMP |
|
assigned_by |
UUID |
NULLABLE, INDEX |
|
expires_at |
TIMESTAMP |
NULLABLE |
|
is_active |
BOOL |
DEFAULT true |
|
role_permissions (table pivot)
| Colonne |
Type |
Contraintes |
role_id |
UUID |
FK → roles (CASCADE), UNIQUE(role_id, permission_id) |
permission_id |
UUID |
FK → permissions (CASCADE) |
mfa_configs
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
NOT NULL, UNIQUE INDEX |
|
secret |
VARCHAR |
NOT NULL |
Masqué en JSON |
backup_codes |
TEXT |
|
JSON array |
is_enabled |
BOOL |
DEFAULT false |
|
last_used_at |
TIMESTAMP |
NULLABLE |
|
created_at |
TIMESTAMP |
|
|
updated_at |
TIMESTAMP |
|
|
deleted_at |
TIMESTAMP |
|
Soft delete |
recovery_codes
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
INDEX |
code |
VARCHAR |
Masqué |
is_used |
BOOL |
DEFAULT false |
used_at |
TIMESTAMP |
NULLABLE |
expires_at |
TIMESTAMP |
|
created_at |
TIMESTAMP |
|
webauthn_credentials
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
NOT NULL |
|
credential_id |
BYTEA |
UNIQUE, NOT NULL |
|
public_key |
BYTEA |
NOT NULL |
|
attestation_type |
VARCHAR(50) |
DEFAULT 'none' |
|
aaguid |
BYTEA |
|
|
sign_count |
INT |
DEFAULT 0 |
|
name |
VARCHAR(100) |
DEFAULT 'My Passkey' |
|
created_at |
TIMESTAMP |
|
|
last_used_at |
TIMESTAMP |
NULLABLE |
|
federated_identities
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE), INDEX |
|
provider |
VARCHAR |
|
google, github, facebook, twitter |
provider_id |
VARCHAR |
|
|
email |
VARCHAR |
|
|
display_name |
VARCHAR |
|
|
avatar_url |
VARCHAR |
|
|
access_token |
TEXT |
|
Masqué |
refresh_token |
TEXT |
|
Masqué |
expires_at |
TIMESTAMP |
NULLABLE |
|
api_keys
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
INDEX |
name |
VARCHAR(100) |
|
prefix |
VARCHAR(16) |
INDEX |
hashed_key |
VARCHAR(128) |
Masqué |
scopes |
TEXT[] |
PostgreSQL array |
last_used_at |
TIMESTAMP |
NULLABLE |
expires_at |
TIMESTAMP |
NULLABLE |
created_at |
TIMESTAMP |
|
user_settings
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE |
email_notifications |
BOOL |
|
push_notifications |
BOOL |
|
browser_notifications |
BOOL |
|
email_on_follow |
BOOL |
|
email_on_like |
BOOL |
|
email_on_comment |
BOOL |
|
email_on_message |
BOOL |
|
email_on_mention |
BOOL |
|
email_marketing |
BOOL |
|
allow_search_indexing |
BOOL |
|
show_activity |
BOOL |
|
explicit_content |
BOOL |
|
autoplay |
BOOL |
|
user_profiles
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE |
language |
VARCHAR |
DEFAULT 'en' |
timezone |
VARCHAR |
DEFAULT 'UTC' |
theme |
VARCHAR |
DEFAULT 'auto' |
user_presence
| Colonne |
Type |
Contraintes |
Description |
user_id |
UUID |
PK |
|
status |
VARCHAR(20) |
DEFAULT 'offline' |
online/away/busy/offline |
last_seen_at |
TIMESTAMP |
|
|
status_message |
TEXT |
|
|
track_id |
UUID |
NULLABLE |
Piste en écoute |
track_title |
TEXT |
|
|
invisible |
BOOL |
DEFAULT false |
|
updated_at |
TIMESTAMP |
|
|
B. Pistes audio
tracks
Table principale des pistes audio.
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
creator_id |
UUID |
FK → users (CASCADE), INDEX |
|
file_id |
UUID |
NULLABLE |
|
title |
VARCHAR(255) |
NOT NULL |
|
artist |
VARCHAR(255) |
|
|
album |
VARCHAR(255) |
|
|
duration |
INT |
|
Secondes |
genre |
VARCHAR(100) |
|
|
tags |
TEXT[] |
|
PostgreSQL array |
year |
INT |
DEFAULT 0 |
|
bpm |
INT |
NULLABLE |
|
musical_key |
VARCHAR(10) |
|
|
file_path |
VARCHAR(500) |
|
|
file_size |
BIGINT |
|
Octets |
format |
VARCHAR(10) |
|
wav, mp3, flac... |
bitrate |
INT |
|
kbps |
sample_rate |
INT |
|
Hz |
waveform_path |
VARCHAR |
|
|
waveform_url |
VARCHAR |
|
|
cover_art_path |
VARCHAR |
|
|
is_public |
BOOL |
DEFAULT true |
|
status |
track_status ENUM |
|
uploading/processing/completed/failed |
status_message |
TEXT |
|
|
stream_status |
VARCHAR |
DEFAULT 'pending' |
pending/processing/ready/error |
stream_manifest_url |
VARCHAR |
|
URL playlist HLS |
play_count |
BIGINT |
|
Non exposé en API |
like_count |
BIGINT |
|
Non exposé en API |
created_at |
TIMESTAMP |
|
|
updated_at |
TIMESTAMP |
|
|
deleted_at |
TIMESTAMP |
INDEX |
Soft delete |
Relations : user (belongs to), playlists (M2M), likes (has many), shares (has many), versions (has many), hls_streams (has many)
track_versions
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
track_id |
UUID |
FK → tracks (CASCADE), UNIQUE(track_id, version_number) |
version_number |
INT |
|
file_path |
VARCHAR(500) |
|
file_size |
BIGINT |
Octets |
changelog |
TEXT |
|
track_likes
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
FK → users (CASCADE), UNIQUE(user_id, track_id) |
track_id |
UUID |
FK → tracks (CASCADE) |
created_at |
TIMESTAMP |
|
track_plays
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
FK → tracks, INDEX |
|
user_id |
UUID |
FK → users (SET NULL), NULLABLE, INDEX |
Anonyme si non connecté |
duration |
INT |
|
Secondes jouées |
played_at |
TIMESTAMP |
INDEX |
|
device |
VARCHAR(100) |
|
|
ip_address |
VARCHAR(45) |
|
|
track_shares
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
track_id |
UUID |
INDEX |
user_id |
UUID |
INDEX |
share_token |
VARCHAR(255) |
UNIQUE |
permissions |
VARCHAR(50) |
DEFAULT 'read' (read/download) |
expires_at |
TIMESTAMP |
NULLABLE |
access_count |
BIGINT |
DEFAULT 0 |
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
|
user_id |
UUID |
FK → users (CASCADE), INDEX |
|
parent_id |
UUID |
FK → track_comments (CASCADE), NULLABLE |
Réponses |
content |
TEXT |
NOT NULL |
|
timestamp |
FLOAT |
|
Position en secondes |
is_edited |
BOOL |
DEFAULT false |
|
Relations : parent (self-ref), replies (has many self-ref)
track_reposts
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
FK → users (CASCADE), INDEX |
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
created_at |
TIMESTAMP |
INDEX |
track_stems
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
name |
VARCHAR(100) |
|
file_path |
VARCHAR(500) |
|
format |
VARCHAR(10) |
|
size_bytes |
BIGINT |
|
created_at |
TIMESTAMP |
|
deleted_at |
TIMESTAMP |
Soft delete |
track_lyrics
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
track_id |
UUID |
FK → tracks (CASCADE), UNIQUE |
content |
TEXT |
NOT NULL |
track_history
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
INDEX |
|
user_id |
UUID |
FK → users (SET NULL) |
|
action |
ENUM |
INDEX |
created/updated/deleted/published/unpublished/restored |
old_value |
TEXT |
|
|
new_value |
TEXT |
|
|
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
name |
VARCHAR(30) |
UNIQUE |
use_count |
INT |
DEFAULT 0 |
| Colonne |
Type |
Contraintes |
track_id |
UUID |
PK composite |
tag_id |
UUID |
PK composite |
created_at |
TIMESTAMP |
|
genres
| Colonne |
Type |
Contraintes |
slug |
VARCHAR(50) |
PK |
name |
VARCHAR(100) |
|
track_genres (pivot)
| Colonne |
Type |
Contraintes |
track_id |
UUID |
PK composite |
genre_slug |
VARCHAR(50) |
PK composite |
position |
INT |
DEFAULT 0 |
playback_analytics
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
|
user_id |
UUID |
FK → users (CASCADE), INDEX |
|
play_time |
INT |
|
Secondes |
pause_count |
INT |
|
|
seek_count |
INT |
|
|
completion_rate |
DECIMAL(5,2) |
|
0-100% |
started_at |
TIMESTAMP |
|
|
ended_at |
TIMESTAMP |
NULLABLE |
|
C. Playlists
playlists
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE), INDEX |
|
name |
VARCHAR(200) |
|
Titre (colonne DB: name) |
description |
TEXT |
|
|
is_public |
BOOL |
DEFAULT true |
|
cover_url |
VARCHAR(500) |
|
|
track_count |
INT |
DEFAULT 0 |
|
follower_count |
INT |
DEFAULT 0 |
|
is_editorial |
BOOL |
DEFAULT false |
Playlist éditoriale |
is_default_favorites |
BOOL |
DEFAULT false |
Playlist favoris auto |
deleted_at |
TIMESTAMP |
|
Soft delete |
Relations : user (belongs to), tracks (has many PlaylistTrack), collaborators (has many, CASCADE)
playlist_tracks (pivot ordonné)
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
playlist_id |
UUID |
FK → playlists (CASCADE), INDEX |
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
position |
INT |
Ordre dans la playlist |
added_by |
UUID |
|
added_at |
TIMESTAMP |
|
playlist_collaborators
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
playlist_id |
UUID |
FK → playlists, INDEX |
|
user_id |
UUID |
FK → users, INDEX |
|
permission |
VARCHAR(20) |
DEFAULT 'read' |
read/write/admin |
playlist_follows
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
playlist_id |
UUID |
INDEX |
user_id |
UUID |
INDEX |
playlist_share_links
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
playlist_id |
UUID |
INDEX |
user_id |
UUID |
INDEX |
share_token |
VARCHAR(255) |
UNIQUE |
expires_at |
TIMESTAMP |
NULLABLE |
access_count |
BIGINT |
DEFAULT 0 |
playlist_versions
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
playlist_id |
UUID |
INDEX |
|
user_id |
UUID |
FK → users (SET NULL) |
|
version |
INT |
|
|
action |
ENUM |
|
Type de modification |
title |
VARCHAR(200) |
|
|
description |
TEXT |
|
|
is_public |
BOOL |
|
|
cover_url |
VARCHAR(500) |
|
|
tracks_snapshot |
TEXT |
|
JSON des pistes à cette version |
user_genre_follows (pivot)
| Colonne |
Type |
Contraintes |
user_id |
UUID |
PK composite |
genre_slug |
VARCHAR |
PK composite |
user_tag_follows (pivot)
| Colonne |
Type |
Contraintes |
user_id |
UUID |
PK composite |
tag_id |
UUID |
PK composite |
D. Chat & Messagerie
rooms
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
name |
VARCHAR(255) |
|
|
description |
TEXT |
|
|
room_type |
VARCHAR |
DEFAULT 'public' |
public/private/dm |
is_private |
BOOL |
DEFAULT false |
|
creator_id |
UUID |
FK → users (CASCADE) |
|
deleted_at |
TIMESTAMP |
|
Soft delete |
Relations : members (has many, CASCADE), messages (has many, CASCADE)
room_members
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
room_id |
UUID |
FK → rooms (CASCADE) |
user_id |
UUID |
FK → users (CASCADE) |
role |
VARCHAR |
DEFAULT 'member' |
joined_at |
TIMESTAMP |
|
room_invitations
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
room_id |
UUID |
FK → rooms |
inviter_id |
UUID |
FK → users |
invitee_id |
UUID |
NULLABLE |
token |
UUID |
UNIQUE |
status |
VARCHAR(20) |
DEFAULT 'pending' (pending/accepted/expired) |
expires_at |
TIMESTAMP |
|
messages
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
room_id |
UUID |
FK → rooms |
|
sender_id |
UUID |
FK → users |
|
content |
TEXT |
|
|
message_type |
VARCHAR |
DEFAULT 'text' |
text/image/audio/system |
reply_to_id |
UUID |
NULLABLE, self-ref |
Réponse à |
is_edited |
BOOL |
DEFAULT false |
|
is_deleted |
BOOL |
DEFAULT false |
|
is_pinned |
BOOL |
DEFAULT false |
|
edited_at |
TIMESTAMP |
NULLABLE |
|
status |
VARCHAR(20) |
DEFAULT 'sent' |
|
metadata |
JSONB |
NULLABLE |
|
content_tsv |
TSVECTOR |
|
Recherche full-text |
message_reactions
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE(user_id, message_id, emoji) |
message_id |
UUID |
|
emoji |
VARCHAR(50) |
|
read_receipts
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE(user_id, message_id) |
message_id |
UUID |
|
read_at |
TIMESTAMP |
|
delivered_status
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE(user_id, message_id) |
message_id |
UUID |
|
delivered_at |
TIMESTAMP |
|
E. Streaming & Collaboration
hls_streams
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
FK → tracks (CASCADE), INDEX |
|
playlist_url |
VARCHAR(500) |
|
|
segments_count |
INT |
DEFAULT 0 |
|
bitrates |
JSONB |
|
Liste des bitrates disponibles |
status |
VARCHAR(20) |
DEFAULT 'pending', INDEX |
pending/processing/ready/failed |
hls_transcode_queue
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
track_id |
UUID |
INDEX |
|
priority |
INT |
DEFAULT 5 |
|
status |
VARCHAR(20) |
DEFAULT 'pending', INDEX |
pending/processing/completed/failed |
retry_count |
INT |
|
|
max_retries |
INT |
|
|
error_message |
TEXT |
NULLABLE |
|
started_at |
TIMESTAMP |
NULLABLE |
|
completed_at |
TIMESTAMP |
NULLABLE |
|
live_streams
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE) |
|
title |
VARCHAR(200) |
|
|
description |
TEXT |
|
|
category |
VARCHAR(100) |
|
|
thumbnail_url |
VARCHAR(500) |
|
|
stream_key |
VARCHAR(100) |
|
Masqué en JSON |
streamer_name |
VARCHAR(100) |
|
|
is_live |
BOOL |
DEFAULT false |
|
started_at |
TIMESTAMP |
NULLABLE |
|
ended_at |
TIMESTAMP |
NULLABLE |
|
viewer_count |
INT |
DEFAULT 0 |
|
tags |
JSONB |
DEFAULT '[]' |
|
scheduled_at |
TIMESTAMP |
NULLABLE |
|
stream_url |
TEXT |
DEFAULT '' |
|
is_vod |
BOOL |
DEFAULT false |
|
deleted_at |
TIMESTAMP |
|
Soft delete |
co_listening_sessions
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
host_id |
UUID |
FK → users, INDEX |
track_id |
UUID |
FK → tracks, INDEX |
expires_at |
TIMESTAMP |
|
queues
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
UNIQUE |
|
current_track_id |
UUID |
NULLABLE |
|
current_position |
INT |
DEFAULT 0 |
|
is_playing |
BOOL |
DEFAULT false |
|
shuffle |
BOOL |
DEFAULT false |
|
repeat_mode |
VARCHAR(20) |
DEFAULT 'off' |
off/one/all |
volume |
INT |
DEFAULT 100 |
|
queue_items
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
queue_id |
UUID |
FK → queues |
track_id |
UUID |
FK → tracks |
position |
INT |
|
queue_sessions (sessions collaboratives)
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
share_token |
VARCHAR(32) |
UNIQUE |
creator_id |
UUID |
INDEX |
shared_queue_items
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
session_id |
UUID |
INDEX |
track_id |
UUID |
|
position |
INT |
|
F. Fichiers & Stockage
user_files
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users |
|
folder_id |
UUID |
FK → user_folders (SET NULL), NULLABLE |
|
filename |
VARCHAR(255) |
|
|
s3_key |
VARCHAR(500) |
|
Clé MinIO/S3 |
size_bytes |
BIGINT |
DEFAULT 0 |
|
mime_type |
VARCHAR(100) |
DEFAULT 'application/octet-stream' |
|
user_folders
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE) |
|
name |
VARCHAR(255) |
|
|
parent_id |
UUID |
FK → user_folders (CASCADE), NULLABLE |
Hiérarchie |
Relations : parent (self-ref), children (has many), files (has many)
cloud_file_versions
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
file_id |
UUID |
FK → user_files (CASCADE) |
version |
INT |
|
storage_key |
TEXT |
|
size_bytes |
BIGINT |
DEFAULT 0 |
cloud_file_shares
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
file_id |
UUID |
FK → user_files (CASCADE) |
token |
VARCHAR(64) |
UNIQUE |
permissions |
VARCHAR(20) |
DEFAULT 'read' |
expires_at |
TIMESTAMP |
|
user_storage_quotas
| Colonne |
Type |
Contraintes |
Description |
user_id |
UUID |
PK |
|
max_bytes |
BIGINT |
DEFAULT 5368709120 |
~5 Go |
used_bytes |
BIGINT |
DEFAULT 0 |
|
G. Équipement (Gear)
gear_items
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users |
|
name |
VARCHAR(200) |
|
|
category |
VARCHAR(100) |
|
micro, interface, casque... |
brand |
VARCHAR |
|
|
model |
VARCHAR |
|
|
serial_number |
VARCHAR |
|
|
image |
VARCHAR(500) |
|
|
images |
JSONB |
DEFAULT '[]' |
|
status |
VARCHAR(50) |
|
actif, en réparation, vendu |
condition |
VARCHAR(50) |
|
neuf, bon, usé |
purchase_date |
TIMESTAMP |
NULLABLE |
|
purchase_price |
DECIMAL(12,2) |
|
|
currency |
VARCHAR(3) |
DEFAULT 'USD' |
|
vendor |
VARCHAR |
|
|
order_number |
VARCHAR |
|
|
warranty_start |
TIMESTAMP |
NULLABLE |
|
warranty_expire |
TIMESTAMP |
NULLABLE |
|
warranty_type |
VARCHAR |
|
|
warranty_notes |
TEXT |
|
|
support_contact |
VARCHAR |
|
|
specs |
JSONB |
|
Spécifications techniques |
notes |
TEXT |
|
|
documents |
JSONB |
|
|
maintenance_history |
JSONB |
|
|
is_public |
BOOL |
DEFAULT false |
Visible sur le profil |
deleted_at |
TIMESTAMP |
|
Soft delete |
gear_images
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
gear_id |
UUID |
FK → gear_items (CASCADE) |
image_url |
VARCHAR(500) |
|
position |
INT |
DEFAULT 0 |
gear_repairs
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
gear_id |
UUID |
FK → gear_items (CASCADE) |
repair_date |
DATE |
|
description |
TEXT |
|
cost_cents |
INT |
DEFAULT 0 |
currency |
VARCHAR(3) |
DEFAULT 'EUR' |
provider |
VARCHAR(255) |
|
notes |
TEXT |
|
gear_documents
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
gear_id |
UUID |
FK → gear_items (CASCADE) |
type |
VARCHAR(50) |
DEFAULT 'invoice' |
storage_key |
TEXT |
|
filename |
VARCHAR(255) |
|
H. Paiements & Royalties
seller_stripe_accounts
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
user_id |
UUID |
UNIQUE |
stripe_account_id |
VARCHAR(255) |
UNIQUE |
charges_enabled |
BOOL |
|
payouts_enabled |
BOOL |
|
onboarding_completed |
BOOL |
|
kyc_status |
VARCHAR(32) |
DEFAULT 'not_started' |
kyc_verification_session_id |
VARCHAR(255) |
|
kyc_verified_at |
TIMESTAMP |
NULLABLE |
kyc_last_error |
TEXT |
|
royalty_records
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
content_id |
UUID |
INDEX |
|
creator_id |
UUID |
INDEX |
|
period |
VARCHAR |
INDEX |
Période (ex: 2026-03) |
plays |
BIGINT |
|
|
revenue |
FLOAT |
|
|
royalty_amount |
FLOAT |
|
|
royalty_rate |
FLOAT |
|
|
status |
VARCHAR |
DEFAULT 'calculated' |
calculated/paid |
calculated_at |
TIMESTAMP |
|
|
paid_at |
TIMESTAMP |
NULLABLE |
|
royalty_payouts
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
payout_id |
VARCHAR |
UNIQUE |
creator_id |
UUID |
INDEX |
amount |
FLOAT |
|
currency |
VARCHAR |
DEFAULT 'EUR' |
period |
VARCHAR |
INDEX |
status |
VARCHAR |
DEFAULT 'pending' |
payment_method |
VARCHAR |
|
transaction_id |
VARCHAR |
|
processed_at |
TIMESTAMP |
|
estimated_arrival |
TIMESTAMP |
|
notes |
VARCHAR |
|
royalty_rates
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
content_type |
VARCHAR |
UNIQUE |
rate |
FLOAT |
|
description |
VARCHAR |
|
is_active |
BOOL |
DEFAULT true |
creator_royalty_rates
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
creator_id |
UUID |
UNIQUE |
|
rate |
FLOAT |
|
Taux personnalisé |
reason |
VARCHAR |
|
|
is_active |
BOOL |
DEFAULT true |
|
royalty_config
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
platform_fee_rate |
FLOAT |
DEFAULT 0.15 |
15% frais plateforme |
minimum_payout_amount |
FLOAT |
DEFAULT 50.0 |
Seuil minimum versement |
payout_schedule |
VARCHAR |
DEFAULT 'monthly' |
|
processing_delay |
INT |
DEFAULT 3 |
Jours |
currency |
VARCHAR |
DEFAULT 'EUR' |
|
is_active |
BOOL |
DEFAULT true |
|
I. Modération & Administration
reports
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
reporter_id |
UUID |
|
reported_user_id |
UUID |
NULLABLE |
content_type |
VARCHAR(50) |
|
content_id |
UUID |
NULLABLE |
reason |
TEXT |
|
status |
VARCHAR(20) |
DEFAULT 'pending' |
resolved_by |
UUID |
NULLABLE |
resolved_at |
TIMESTAMP |
NULLABLE |
announcements
| Colonne |
Type |
Contraintes |
id |
UUID |
PK |
title |
VARCHAR(200) |
|
content |
TEXT |
|
type |
VARCHAR(20) |
DEFAULT 'info' |
is_active |
BOOL |
DEFAULT true |
starts_at |
TIMESTAMP |
|
ends_at |
TIMESTAMP |
NULLABLE |
created_by |
UUID |
NULLABLE |
notifications
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
FK → users (CASCADE), INDEX |
|
type |
VARCHAR(50) |
INDEX |
follow, like, comment, system... |
title |
VARCHAR(255) |
|
|
content |
TEXT |
|
|
link |
VARCHAR(500) |
|
|
read |
BOOL |
DEFAULT false |
INDEX composite avec user_id |
read_at |
TIMESTAMP |
NULLABLE |
|
created_at |
TIMESTAMP |
INDEX |
|
J. Exports de données
data_exports (RGPD)
| Colonne |
Type |
Contraintes |
Description |
id |
UUID |
PK |
|
user_id |
UUID |
|
|
status |
VARCHAR(20) |
DEFAULT 'pending' |
pending/processing/completed/failed |
s3_key |
TEXT |
NULLABLE |
|
file_size_bytes |
BIGINT |
NULLABLE |
|
expires_at |
TIMESTAMP |
|
|
completed_at |
TIMESTAMP |
NULLABLE |
|
error_message |
TEXT |
NULLABLE |
|
Utilisation de Redis
Redis est optionnel — dégradation gracieuse si indisponible.
| Cas d'usage |
Pattern de clé |
TTL |
Fallback |
| Sessions |
sessions:{token_hash} |
Configurable |
Table sessions |
| Cache HTTP |
http_cache:{sha256(url)} |
5-15 min |
Pas de cache |
| Rate limiting |
ratelimit:{key} |
Variable |
In-memory avec mutex |
| Verrouillage compte |
lockout:{email}:count, lockout:{email}:locked_until |
Configurable |
In-memory map |
| Token blacklist |
token_blacklist:{jti} |
Durée JWT |
Pas de révocation |
| Présence utilisateur |
presence:{user_id} |
Variable |
Table user_presence |
| Cache applicatif |
Via CacheService |
Variable |
Pas de cache |
Headers de cache : X-Cache: HIT ou X-Cache: MISS
Statistiques
| Métrique |
Valeur |
| Fichiers modèles Go |
68 |
| Tables PostgreSQL |
60+ |
| Migrations SQL |
115 |
| Tables avec soft delete |
20+ |
| Tables avec UUIDs |
95%+ |
| Cas d'usage Redis |
6 principaux |
Documents liés