CI / build-and-test (push) Successful in 14m43s
7.3: capturedAt/source au registre + 6 adaptateurs + module provenance.ts + ?debug=1 (search-transport.mjs). 7.4: ProviderHealthService + badge source degradee. 7.6: squelettes par provider + snapshots progressifs + transport NDJSON /api/search. 8.1: ProviderAdapter unifie (search enveloppe + channelContent/channelMeta/capabilities) via getProviderAdapter + test de contrat offline.
217 lines
7.4 KiB
SQL
217 lines
7.4 KiB
SQL
-- NewTube User Management Schema (SQLite)
|
|
-- Timestamps are ISO8601 (UTC). Use PRAGMA foreign_keys = ON;
|
|
|
|
PRAGMA foreign_keys = ON;
|
|
|
|
-- Users & identity -----------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id TEXT PRIMARY KEY,
|
|
username TEXT NOT NULL UNIQUE,
|
|
email TEXT UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
is_active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
last_login_at TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_preferences (
|
|
user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
|
language TEXT DEFAULT 'en',
|
|
default_provider TEXT,
|
|
default_providers TEXT,
|
|
download_languages TEXT,
|
|
theme TEXT DEFAULT 'system',
|
|
video_quality TEXT DEFAULT 'auto',
|
|
region TEXT,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
-- Sessions: refresh tokens are stored hashed; per-device visibility ----------
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
refresh_token_hash TEXT NOT NULL,
|
|
user_agent TEXT,
|
|
device_info TEXT,
|
|
ip_address TEXT,
|
|
is_remember INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
last_seen_at TEXT,
|
|
expires_at TEXT NOT NULL,
|
|
revoked_at TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sessions_lastseen ON sessions(last_seen_at);
|
|
|
|
-- Login audit ---------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS login_audit (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT,
|
|
username TEXT,
|
|
ip_address TEXT,
|
|
user_agent TEXT,
|
|
success INTEGER NOT NULL,
|
|
reason TEXT,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_login_audit_user_time ON login_audit(user_id, created_at DESC);
|
|
|
|
-- Search history ------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS search_history (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
query TEXT NOT NULL,
|
|
filters_json TEXT,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_search_history_user_time ON search_history(user_id, created_at DESC);
|
|
|
|
-- Watch history -------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS watch_history (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
provider TEXT NOT NULL,
|
|
video_id TEXT NOT NULL,
|
|
title TEXT,
|
|
thumbnail TEXT,
|
|
watched_at TEXT NOT NULL,
|
|
progress_seconds INTEGER DEFAULT 0,
|
|
duration_seconds INTEGER DEFAULT 0,
|
|
last_position_seconds INTEGER DEFAULT 0,
|
|
last_watched_at TEXT
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_watch_history_user_video ON watch_history(user_id, provider, video_id);
|
|
CREATE INDEX IF NOT EXISTS idx_watch_history_user_time ON watch_history(user_id, watched_at DESC);
|
|
|
|
-- Transcript history (transcripts générés et conservés) --------------------
|
|
CREATE TABLE IF NOT EXISTS transcript_history (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
provider TEXT NOT NULL,
|
|
video_id TEXT NOT NULL,
|
|
title TEXT,
|
|
thumbnail TEXT,
|
|
lang TEXT NOT NULL,
|
|
languages_json TEXT,
|
|
lines_json TEXT NOT NULL DEFAULT '[]',
|
|
line_count INTEGER NOT NULL DEFAULT 0,
|
|
char_count INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_transcript_history_user_video_lang
|
|
ON transcript_history(user_id, provider, video_id, lang);
|
|
CREATE INDEX IF NOT EXISTS idx_transcript_history_user_time
|
|
ON transcript_history(user_id, updated_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_transcript_history_user_provider
|
|
ON transcript_history(user_id, provider);
|
|
|
|
-- Channels cache & subscriptions --------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS channels (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
provider TEXT NOT NULL,
|
|
external_id TEXT NOT NULL,
|
|
title TEXT,
|
|
handle TEXT,
|
|
avatar_url TEXT,
|
|
url TEXT,
|
|
subs_count INTEGER,
|
|
verified INTEGER DEFAULT 0,
|
|
last_refreshed_at INTEGER,
|
|
banner_url TEXT,
|
|
description TEXT,
|
|
UNIQUE(provider, external_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
|
|
created_at INTEGER NOT NULL,
|
|
UNIQUE(user_id, channel_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_subs_user ON subscriptions(user_id);
|
|
|
|
-- Groupes d'abonnements (façon PocketTube) -----------------------------------
|
|
CREATE TABLE IF NOT EXISTS subscription_groups (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
color TEXT NOT NULL DEFAULT '#ef4444',
|
|
icon TEXT NOT NULL DEFAULT '📁',
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
UNIQUE(user_id, name)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sub_groups_user ON subscription_groups(user_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS subscription_group_members (
|
|
group_id TEXT NOT NULL REFERENCES subscription_groups(id) ON DELETE CASCADE,
|
|
subscription_id INTEGER NOT NULL REFERENCES subscriptions(id) ON DELETE CASCADE,
|
|
added_at INTEGER NOT NULL,
|
|
PRIMARY KEY (group_id, subscription_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sub_group_members_sub ON subscription_group_members(subscription_id);
|
|
CREATE INDEX IF NOT EXISTS idx_sub_group_members_group ON subscription_group_members(group_id);
|
|
|
|
-- Playlists -----------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS playlists (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
thumbnail TEXT,
|
|
is_private INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(user_id, name)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS playlist_items (
|
|
id TEXT PRIMARY KEY,
|
|
playlist_id TEXT NOT NULL REFERENCES playlists(id) ON DELETE CASCADE,
|
|
provider TEXT NOT NULL,
|
|
video_id TEXT NOT NULL,
|
|
title TEXT,
|
|
thumbnail TEXT,
|
|
added_at TEXT NOT NULL,
|
|
position INTEGER NOT NULL,
|
|
UNIQUE(playlist_id, provider, video_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_playlist_items_order ON playlist_items(playlist_id, position);
|
|
|
|
-- Playlist metrics -----------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS playlist_metrics (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
playlist_id TEXT NOT NULL REFERENCES playlists(id) ON DELETE CASCADE,
|
|
action TEXT NOT NULL, -- create|update|delete|add_video|remove_video|reorder
|
|
meta_json TEXT,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_playlist_metrics_user_time ON playlist_metrics(user_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_playlist_metrics_playlist_time ON playlist_metrics(playlist_id, created_at DESC);
|
|
|
|
-- Tags (optional) -----------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS tags (
|
|
id TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
UNIQUE(user_id, name)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS video_tags (
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
provider TEXT NOT NULL,
|
|
video_id TEXT NOT NULL,
|
|
tag_id TEXT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
created_at TEXT NOT NULL,
|
|
PRIMARY KEY (user_id, provider, video_id, tag_id)
|
|
);
|