Files
DocNest/k3s/configmap.yaml
M1ngdaXie afb04e5cd3 feat: migrate realtime-collab from Docker Compose to k3s
Add k3s manifests for postgres, redis, and backend

Fix users table constraint and init.sql
2026-03-25 01:19:00 +00:00

179 lines
7.8 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-init-sql
data:
init.sql: |
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE TABLE IF NOT EXISTS documents (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
type VARCHAR(50) NOT NULL CHECK (type IN ('editor', 'kanban')),
yjs_state BYTEA,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_documents_type ON documents(type);
CREATE INDEX idx_documents_created_at ON documents(created_at DESC);
CREATE TABLE IF NOT EXISTS document_updates (
id SERIAL PRIMARY KEY,
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
update BYTEA NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_updates_document_id ON document_updates(document_id);
CREATE INDEX idx_updates_created_at ON document_updates(created_at DESC);
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
avatar_url TEXT,
provider VARCHAR(50) NOT NULL CHECK (provider IN ('google', 'github', 'guest')),
provider_user_id VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
last_login_at TIMESTAMPTZ,
UNIQUE(provider, provider_user_id)
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_provider ON users(provider, provider_user_id);
CREATE TABLE IF NOT EXISTS sessions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token_hash VARCHAR(64) NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
user_agent TEXT,
ip_address VARCHAR(45),
UNIQUE(token_hash)
);
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
CREATE INDEX idx_sessions_token_hash ON sessions(token_hash);
CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
ALTER TABLE documents ADD COLUMN IF NOT EXISTS owner_id UUID REFERENCES users(id) ON DELETE SET NULL;
CREATE INDEX IF NOT EXISTS idx_documents_owner_id ON documents(owner_id);
CREATE TABLE IF NOT EXISTS document_shares (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
permission VARCHAR(20) NOT NULL CHECK (permission IN ('view', 'edit')),
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
UNIQUE(document_id, user_id)
);
CREATE INDEX idx_shares_document_id ON document_shares(document_id);
CREATE INDEX idx_shares_user_id ON document_shares(user_id);
CREATE INDEX idx_shares_permission ON document_shares(document_id, permission);
ALTER TABLE documents ADD COLUMN IF NOT EXISTS share_token VARCHAR(255);
ALTER TABLE documents ADD COLUMN IF NOT EXISTS is_public BOOLEAN DEFAULT false NOT NULL;
CREATE INDEX IF NOT EXISTS idx_documents_share_token ON documents(share_token) WHERE share_token IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_documents_is_public ON documents(is_public) WHERE is_public = true;
ALTER TABLE documents ADD CONSTRAINT check_public_has_token
CHECK (is_public = false OR (is_public = true AND share_token IS NOT NULL));
ALTER TABLE documents ADD COLUMN IF NOT EXISTS share_permission VARCHAR(20) DEFAULT 'edit' CHECK (share_permission IN ('view', 'edit'));
CREATE INDEX IF NOT EXISTS idx_documents_share_permission ON documents(share_permission) WHERE is_public = true;
CREATE TABLE IF NOT EXISTS oauth_tokens (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
provider VARCHAR(50) NOT NULL,
access_token TEXT NOT NULL,
refresh_token TEXT,
token_type VARCHAR(50) DEFAULT 'Bearer',
expires_at TIMESTAMPTZ NOT NULL,
scope TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT oauth_tokens_user_id_provider_key UNIQUE (user_id, provider)
);
CREATE INDEX idx_oauth_tokens_user_id ON oauth_tokens(user_id);
CREATE TABLE IF NOT EXISTS document_versions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
yjs_snapshot BYTEA NOT NULL,
text_preview TEXT,
version_number INTEGER NOT NULL,
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
version_label TEXT,
is_auto_generated BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT unique_document_version UNIQUE(document_id, version_number)
);
CREATE INDEX idx_document_versions_document_id ON document_versions(document_id, created_at DESC);
CREATE INDEX idx_document_versions_created_by ON document_versions(created_by);
ALTER TABLE documents ADD COLUMN IF NOT EXISTS version_count INTEGER DEFAULT 0;
ALTER TABLE documents ADD COLUMN IF NOT EXISTS last_snapshot_at TIMESTAMPTZ;
CREATE OR REPLACE FUNCTION get_next_version_number(p_document_id UUID)
RETURNS INTEGER AS $$
DECLARE
next_version INTEGER;
BEGIN
SELECT COALESCE(MAX(version_number), 0) + 1
INTO next_version
FROM document_versions
WHERE document_id = p_document_id;
RETURN next_version;
END;
$$ LANGUAGE plpgsql;
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE oauth_tokens ENABLE ROW LEVEL SECURITY;
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE document_updates ENABLE ROW LEVEL SECURITY;
ALTER TABLE document_shares ENABLE ROW LEVEL SECURITY;
ALTER TABLE document_versions ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow all operations on users" ON users FOR ALL USING (true);
CREATE POLICY "Allow all operations on sessions" ON sessions FOR ALL USING (true);
CREATE POLICY "Allow all operations on oauth_tokens" ON oauth_tokens FOR ALL USING (true);
CREATE POLICY "Allow all operations on documents" ON documents FOR ALL USING (true);
CREATE POLICY "Allow all operations on document_updates" ON document_updates FOR ALL USING (true);
CREATE POLICY "Allow all operations on document_shares" ON document_shares FOR ALL USING (true);
CREATE POLICY "Allow all operations on document_versions" ON document_versions FOR ALL USING (true);
CREATE TABLE IF NOT EXISTS stream_checkpoints (
document_id UUID PRIMARY KEY REFERENCES documents(id) ON DELETE CASCADE,
last_stream_id TEXT NOT NULL,
last_seq BIGINT NOT NULL DEFAULT 0,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_stream_checkpoints_updated_at ON stream_checkpoints(updated_at DESC);
CREATE TABLE IF NOT EXISTS document_update_history (
id BIGSERIAL PRIMARY KEY,
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
stream_id TEXT NOT NULL,
seq BIGINT NOT NULL,
payload BYTEA NOT NULL,
msg_type TEXT,
server_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS uniq_update_history_document_stream_id ON document_update_history(document_id, stream_id);
CREATE UNIQUE INDEX IF NOT EXISTS uniq_update_history_document_seq ON document_update_history(document_id, seq);
CREATE INDEX IF NOT EXISTS idx_update_history_document_seq ON document_update_history(document_id, seq);