Changeset 0.28.0 (#172)
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
-- ==========================================
|
||||
-- Chat Switchboard — 001 Core
|
||||
-- ==========================================
|
||||
-- Users, authentication, platform policies, and global settings.
|
||||
-- Foundation tables with no external FK dependencies.
|
||||
--
|
||||
-- ICD §2 (Auth), §14 (User Profile & Settings), §16 (Platform Admin)
|
||||
-- v0.22.8: Domain-grouped migration (replaces monolith 001 + incrementals)
|
||||
-- Users (with auth fields), refresh tokens, platform policies,
|
||||
-- global settings, user presence.
|
||||
-- Consolidated v0.28.0: merges 001 + 018 (auth_abstraction) + 016 (presence).
|
||||
-- ==========================================
|
||||
|
||||
-- ── Extensions ──────────────────────────────
|
||||
@@ -32,7 +30,7 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(50) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
password_hash TEXT, -- nullable for mTLS/OIDC
|
||||
display_name VARCHAR(100),
|
||||
avatar_url TEXT,
|
||||
role VARCHAR(20) DEFAULT 'user'
|
||||
@@ -40,6 +38,12 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
settings JSONB DEFAULT '{}'::jsonb,
|
||||
|
||||
-- Auth abstraction (v0.24.0)
|
||||
auth_source VARCHAR(20) NOT NULL DEFAULT 'builtin'
|
||||
CHECK (auth_source IN ('builtin', 'mtls', 'oidc')),
|
||||
external_id TEXT,
|
||||
handle VARCHAR(100) NOT NULL,
|
||||
|
||||
-- Vault: per-user encryption key (UEK) for BYOK API keys
|
||||
encrypted_uek BYTEA,
|
||||
uek_salt BYTEA,
|
||||
@@ -51,9 +55,12 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
last_login_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
-- Case-insensitive unique indexes (no bare UNIQUE constraint)
|
||||
-- Case-insensitive unique indexes
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_username_ci ON users (LOWER(username));
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_email_ci ON users (LOWER(email));
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_handle ON users(LOWER(handle));
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_external_id
|
||||
ON users(auth_source, external_id) WHERE external_id IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
@@ -62,6 +69,9 @@ DROP TRIGGER IF EXISTS users_updated_at ON users;
|
||||
CREATE TRIGGER users_updated_at BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
|
||||
|
||||
COMMENT ON COLUMN users.auth_source IS 'builtin=password, mtls=cert, oidc=SSO';
|
||||
COMMENT ON COLUMN users.external_id IS 'IdP subject claim (OIDC) or cert fingerprint (mTLS)';
|
||||
COMMENT ON COLUMN users.handle IS 'Unique @mention handle, auto-generated from username';
|
||||
COMMENT ON COLUMN users.encrypted_uek IS 'UEK encrypted with Argon2id(password)-derived key';
|
||||
COMMENT ON COLUMN users.uek_salt IS 'Argon2id salt for UEK derivation';
|
||||
COMMENT ON COLUMN users.uek_nonce IS 'AES-GCM nonce for UEK wrapping';
|
||||
@@ -96,7 +106,6 @@ CREATE TABLE IF NOT EXISTS platform_policies (
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Secure by default
|
||||
INSERT INTO platform_policies (key, value) VALUES
|
||||
('allow_user_byok', 'false'),
|
||||
('allow_user_personas', 'false'),
|
||||
@@ -131,3 +140,19 @@ INSERT INTO global_settings (key, value) VALUES
|
||||
"generation": { "primary": null, "fallback": null }
|
||||
}'::jsonb)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
|
||||
-- =========================================
|
||||
-- USER PRESENCE (v0.23.1)
|
||||
-- =========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_presence (
|
||||
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||
last_seen TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'online'
|
||||
CHECK (status IN ('online', 'away', 'offline'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_presence_last_seen ON user_presence(last_seen DESC);
|
||||
|
||||
COMMENT ON TABLE user_presence IS 'Heartbeat-driven presence. Rows upserted every 30s by active clients.';
|
||||
|
||||
Reference in New Issue
Block a user