Backend Go: - Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN. - Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError). - Sécurisation de config.go, CORS, statuts de santé et monitoring. - Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles). - Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés. - Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*. Chat server (Rust): - Refonte du pipeline JWT + sécurité, audit et rate limiting avancé. - Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing). - Nettoyage des panics, gestion d’erreurs robuste, logs structurés. - Migrations chat alignées sur le schéma UUID et nouvelles features. Stream server (Rust): - Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core. - Transactions P0 pour les jobs et segments, garanties d’atomicité. - Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION). Documentation & audits: - TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services. - Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3). - Scripts de reset et de cleanup pour la lab DB et la V1. Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
216 lines
No EOL
7.3 KiB
SQL
216 lines
No EOL
7.3 KiB
SQL
-- 010_auth_and_users.sql
|
|
-- Core Authentication and User Identity Tables (Aligned with ORIGIN)
|
|
|
|
-- === USERS ===
|
|
CREATE TABLE public.users (
|
|
-- Primary Key
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Authentication
|
|
email VARCHAR(255) NOT NULL,
|
|
email_verified_at TIMESTAMPTZ,
|
|
password_hash VARCHAR(255),
|
|
|
|
-- Profile Basic
|
|
username VARCHAR(30) NOT NULL,
|
|
slug VARCHAR(255),
|
|
first_name VARCHAR(100),
|
|
last_name VARCHAR(100),
|
|
display_name VARCHAR(100),
|
|
|
|
-- Legacy Profile fields (kept for Go compatibility, prefer user_profiles)
|
|
avatar TEXT,
|
|
bio TEXT,
|
|
location VARCHAR(100),
|
|
birthdate TIMESTAMPTZ,
|
|
gender VARCHAR(20),
|
|
|
|
-- Role & Status
|
|
role public.user_role NOT NULL DEFAULT 'user',
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
is_verified BOOLEAN NOT NULL DEFAULT false,
|
|
is_banned BOOLEAN NOT NULL DEFAULT false,
|
|
is_admin BOOLEAN DEFAULT false, -- Legacy boolean, prefer role='admin'
|
|
is_public BOOLEAN DEFAULT true, -- Legacy visibility
|
|
|
|
-- Security
|
|
token_version INTEGER NOT NULL DEFAULT 0,
|
|
last_password_change_at TIMESTAMPTZ,
|
|
|
|
-- Tracking
|
|
last_login_at TIMESTAMPTZ,
|
|
login_count INTEGER NOT NULL DEFAULT 0,
|
|
last_login_ip INET,
|
|
username_changed_at TIMESTAMPTZ,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_users_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'),
|
|
CONSTRAINT chk_users_username_format CHECK (username ~* '^[a-zA-Z0-9_]{3,30}$')
|
|
);
|
|
|
|
-- Indexes
|
|
CREATE UNIQUE INDEX idx_users_email ON public.users(email) WHERE deleted_at IS NULL;
|
|
CREATE UNIQUE INDEX idx_users_username ON public.users(username) WHERE deleted_at IS NULL;
|
|
CREATE UNIQUE INDEX idx_users_slug ON public.users(slug) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_users_role ON public.users(role);
|
|
CREATE INDEX idx_users_created_at_desc ON public.users(created_at DESC);
|
|
CREATE INDEX idx_users_deleted_at ON public.users(deleted_at) WHERE deleted_at IS NOT NULL;
|
|
|
|
-- === FEDERATED IDENTITIES (OAuth) ===
|
|
CREATE TABLE public.federated_identities (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
|
|
-- Provider
|
|
provider VARCHAR(50) NOT NULL,
|
|
provider_user_id VARCHAR(255) NOT NULL, -- ORIGIN name
|
|
provider_id TEXT, -- Legacy name (kept for compatibility if needed, else deprecate)
|
|
|
|
-- OAuth Data
|
|
access_token TEXT,
|
|
refresh_token TEXT,
|
|
token_expires_at TIMESTAMPTZ, -- ORIGIN name
|
|
expires_at TIMESTAMPTZ, -- Legacy name
|
|
|
|
-- Profile Data
|
|
provider_email VARCHAR(255),
|
|
provider_username VARCHAR(255),
|
|
provider_avatar_url TEXT,
|
|
provider_profile_data JSONB,
|
|
|
|
-- Legacy fields
|
|
email TEXT, -- Maps to provider_email
|
|
display_name TEXT,
|
|
avatar_url TEXT, -- Maps to provider_avatar_url
|
|
|
|
-- Status
|
|
is_primary BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT uq_federated_identities_provider_user UNIQUE (provider, provider_user_id)
|
|
);
|
|
|
|
CREATE INDEX idx_federated_identities_user_id ON public.federated_identities(user_id);
|
|
CREATE INDEX idx_federated_identities_provider ON public.federated_identities(provider);
|
|
|
|
-- === REFRESH TOKENS ===
|
|
CREATE TABLE public.refresh_tokens (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
|
|
-- Token
|
|
token VARCHAR(255) NOT NULL UNIQUE,
|
|
token_hash VARCHAR(255) NOT NULL,
|
|
|
|
-- Metadata
|
|
device_name VARCHAR(255),
|
|
device_type VARCHAR(50),
|
|
user_agent TEXT,
|
|
ip_address INET,
|
|
|
|
-- Expiration
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
last_used_at TIMESTAMPTZ,
|
|
|
|
-- Status
|
|
is_revoked BOOLEAN NOT NULL DEFAULT false,
|
|
revoked_at TIMESTAMPTZ,
|
|
revoked_reason VARCHAR(255),
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ, -- Legacy soft delete
|
|
|
|
CONSTRAINT chk_refresh_tokens_expires_future CHECK (expires_at > created_at)
|
|
);
|
|
|
|
CREATE INDEX idx_refresh_tokens_user_id ON public.refresh_tokens(user_id);
|
|
CREATE INDEX idx_refresh_tokens_token_hash ON public.refresh_tokens(token_hash);
|
|
CREATE INDEX idx_refresh_tokens_expires_at ON public.refresh_tokens(expires_at);
|
|
CREATE INDEX idx_refresh_tokens_is_revoked ON public.refresh_tokens(is_revoked) WHERE is_revoked = false;
|
|
|
|
-- === PASSWORD RESET TOKENS ===
|
|
CREATE TABLE public.password_reset_tokens (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
|
|
-- Token
|
|
token VARCHAR(255) NOT NULL UNIQUE,
|
|
token_hash VARCHAR(255) NOT NULL,
|
|
|
|
-- Status
|
|
used BOOLEAN NOT NULL DEFAULT false,
|
|
used_at TIMESTAMPTZ,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
|
|
-- Metadata
|
|
ip_address INET,
|
|
user_agent TEXT,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT chk_password_reset_expires CHECK (expires_at > created_at)
|
|
);
|
|
|
|
CREATE INDEX idx_password_reset_tokens_user_id ON public.password_reset_tokens(user_id);
|
|
CREATE INDEX idx_password_reset_tokens_token_hash ON public.password_reset_tokens(token_hash);
|
|
CREATE INDEX idx_password_reset_tokens_expires_at ON public.password_reset_tokens(expires_at);
|
|
|
|
-- === EMAIL VERIFICATION TOKENS ===
|
|
CREATE TABLE public.email_verification_tokens (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
|
|
-- Token
|
|
token VARCHAR(255) NOT NULL UNIQUE,
|
|
token_hash VARCHAR(255) NOT NULL,
|
|
|
|
-- Email
|
|
email VARCHAR(255) NOT NULL,
|
|
|
|
-- Status
|
|
verified BOOLEAN NOT NULL DEFAULT false, -- Legacy used
|
|
used BOOLEAN NOT NULL DEFAULT false, -- Legacy used
|
|
verified_at TIMESTAMPTZ,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
CONSTRAINT chk_email_verification_expires CHECK (expires_at > created_at)
|
|
);
|
|
|
|
CREATE INDEX idx_email_verification_tokens_user_id ON public.email_verification_tokens(user_id);
|
|
CREATE INDEX idx_email_verification_tokens_token_hash ON public.email_verification_tokens(token_hash);
|
|
CREATE INDEX idx_email_verification_tokens_email ON public.email_verification_tokens(email);
|
|
|
|
-- === USER SESSIONS (Legacy/Auth) ===
|
|
CREATE TABLE public.user_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
|
|
session_token VARCHAR(255) NOT NULL UNIQUE,
|
|
|
|
ip_address INET, -- Changed to INET per Origin style
|
|
user_agent TEXT,
|
|
|
|
is_active BOOLEAN DEFAULT true,
|
|
last_activity TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
revoked_at TIMESTAMPTZ,
|
|
|
|
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_user_sessions_user_id ON public.user_sessions(user_id);
|
|
CREATE INDEX idx_user_sessions_expires_at ON public.user_sessions(expires_at);
|
|
CREATE INDEX idx_user_sessions_last_activity ON public.user_sessions(last_activity DESC); |