112 lines
5.1 KiB
SQL
112 lines
5.1 KiB
SQL
CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY,
|
|
email TEXT NOT NULL COLLATE NOCASE UNIQUE CHECK(length(trim(email)) > 3),
|
|
password_hash TEXT NOT NULL CHECK(length(password_hash) > 0),
|
|
role TEXT NOT NULL CHECK(role IN ('admin', 'editor', 'viewer')),
|
|
is_active INTEGER NOT NULL DEFAULT 1 CHECK(is_active IN (0, 1)),
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
last_login_at TEXT
|
|
);
|
|
|
|
CREATE TABLE projects (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT NOT NULL CHECK(length(trim(name)) > 0),
|
|
slug TEXT NOT NULL COLLATE NOCASE UNIQUE CHECK(length(trim(slug)) > 0),
|
|
description TEXT NOT NULL DEFAULT '',
|
|
is_active INTEGER NOT NULL DEFAULT 1 CHECK(is_active IN (0, 1)),
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
);
|
|
|
|
CREATE TABLE tags (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT NOT NULL CHECK(length(trim(name)) > 0),
|
|
slug TEXT NOT NULL COLLATE NOCASE UNIQUE CHECK(length(trim(slug)) > 0),
|
|
description TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
);
|
|
|
|
CREATE TABLE project_tags (
|
|
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
PRIMARY KEY (project_id, tag_id)
|
|
);
|
|
|
|
CREATE TABLE releases (
|
|
id INTEGER PRIMARY KEY,
|
|
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
version TEXT NOT NULL CHECK(length(trim(version)) > 0),
|
|
build TEXT NOT NULL DEFAULT '',
|
|
filename TEXT NOT NULL CHECK(length(trim(filename)) > 0),
|
|
storage_path TEXT NOT NULL UNIQUE CHECK(length(trim(storage_path)) > 0),
|
|
checksum_sha256 TEXT NOT NULL CHECK(length(checksum_sha256) = 64),
|
|
size_bytes INTEGER NOT NULL CHECK(size_bytes >= 0),
|
|
content_type TEXT NOT NULL DEFAULT 'application/octet-stream',
|
|
release_notes TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
uploaded_by_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
is_active INTEGER NOT NULL DEFAULT 1 CHECK(is_active IN (0, 1)),
|
|
UNIQUE (project_id, version, build)
|
|
);
|
|
|
|
CREATE TABLE api_keys (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT NOT NULL CHECK(length(trim(name)) > 0),
|
|
key_prefix TEXT NOT NULL UNIQUE CHECK(length(trim(key_prefix)) > 0),
|
|
key_hash TEXT NOT NULL UNIQUE CHECK(length(trim(key_hash)) > 0),
|
|
description TEXT NOT NULL DEFAULT '',
|
|
scope_mode TEXT NOT NULL CHECK(scope_mode IN ('all_projects', 'project_allow_list', 'project_deny_list', 'tag_allow_list', 'tag_deny_list')),
|
|
can_download INTEGER NOT NULL DEFAULT 0 CHECK(can_download IN (0, 1)),
|
|
can_upload INTEGER NOT NULL DEFAULT 0 CHECK(can_upload IN (0, 1)),
|
|
can_delete INTEGER NOT NULL DEFAULT 0 CHECK(can_delete IN (0, 1)),
|
|
can_manage_projects INTEGER NOT NULL DEFAULT 0 CHECK(can_manage_projects IN (0, 1)),
|
|
is_active INTEGER NOT NULL DEFAULT 1 CHECK(is_active IN (0, 1)),
|
|
expires_at TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
last_used_at TEXT,
|
|
created_by_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL
|
|
);
|
|
|
|
CREATE TABLE api_key_project_access (
|
|
api_key_id INTEGER NOT NULL REFERENCES api_keys(id) ON DELETE CASCADE,
|
|
project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
PRIMARY KEY (api_key_id, project_id)
|
|
);
|
|
|
|
CREATE TABLE api_key_tag_access (
|
|
api_key_id INTEGER NOT NULL REFERENCES api_keys(id) ON DELETE CASCADE,
|
|
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
PRIMARY KEY (api_key_id, tag_id)
|
|
);
|
|
|
|
CREATE TABLE sessions (
|
|
id INTEGER PRIMARY KEY,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
token_hash TEXT NOT NULL UNIQUE CHECK(length(trim(token_hash)) > 0),
|
|
expires_at TEXT NOT NULL,
|
|
last_seen_at TEXT,
|
|
invalidated_at TEXT,
|
|
ip_address TEXT NOT NULL DEFAULT '',
|
|
user_agent TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
);
|
|
|
|
CREATE TABLE audit_logs (
|
|
id INTEGER PRIMARY KEY,
|
|
actor_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
api_key_id INTEGER REFERENCES api_keys(id) ON DELETE SET NULL,
|
|
action TEXT NOT NULL CHECK(length(trim(action)) > 0),
|
|
target_type TEXT NOT NULL DEFAULT '',
|
|
target_id INTEGER,
|
|
target_identifier TEXT NOT NULL DEFAULT '',
|
|
metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
ip_address TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
);
|