CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT uuidv7(), email TEXT NOT NULL UNIQUE, password_hash TEXT, google_id VARCHAR(255) UNIQUE, auth_provider VARCHAR(50) NOT NULL DEFAULT 'local', is_deleted BOOLEAN NOT NULL DEFAULT false, token_version INT NOT NULL DEFAULT 1, refresh_token TEXT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS user_profiles ( user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, display_name TEXT, full_name TEXT, avatar_url TEXT, bio TEXT, location TEXT, website TEXT, country_code CHAR(2), phone TEXT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS roles ( id UUID PRIMARY KEY DEFAULT uuidv7(), name TEXT UNIQUE NOT NULL, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS user_roles ( user_id UUID REFERENCES users(id) ON DELETE CASCADE, role_id UUID REFERENCES roles(id) ON DELETE CASCADE, PRIMARY KEY (user_id, role_id) ); CREATE TABLE IF NOT EXISTS medias ( id UUID PRIMARY KEY DEFAULT uuidv7(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, storage_key VARCHAR(255) UNIQUE NOT NULL, original_name VARCHAR(255) NOT NULL, mime_type VARCHAR(100) NOT NULL, size BIGINT NOT NULL, file_metadata JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS user_verifications ( id UUID PRIMARY KEY DEFAULT uuidv7(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, verify_type SMALLINT NOT NULL, content TEXT, is_deleted BOOLEAN NOT NULL DEFAULT false, status SMALLINT NOT NULL DEFAULT 1, reviewed_by UUID REFERENCES users(id), review_note TEXT, reviewed_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS verification_medias ( verification_id UUID REFERENCES user_verifications(id) ON DELETE CASCADE, media_id UUID REFERENCES medias(id) ON DELETE CASCADE, PRIMARY KEY (verification_id, media_id) ); CREATE TABLE IF NOT EXISTS projects ( id UUID PRIMARY KEY DEFAULT uuidv7(), title TEXT NOT NULL, description TEXT, latest_commit_id UUID, project_status SMALLINT NOT NULL DEFAULT 1, locked_by UUID, is_deleted BOOLEAN NOT NULL DEFAULT false, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS entities ( id UUID PRIMARY KEY DEFAULT uuidv7(), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, name TEXT NOT NULL, slug TEXT UNIQUE, description TEXT, status SMALLINT, time_start INT, time_end INT, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS wikis ( id UUID PRIMARY KEY DEFAULT uuidv7(), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, title TEXT, slug TEXT UNIQUE, content TEXT, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS entity_wikis ( entity_id UUID REFERENCES entities(id) ON DELETE CASCADE, wiki_id UUID REFERENCES wikis(id) ON DELETE CASCADE, project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, PRIMARY KEY (entity_id, wiki_id) ); CREATE TABLE IF NOT EXISTS geometries ( id UUID PRIMARY KEY DEFAULT uuidv7(), geo_type SMALLINT NOT NULL DEFAULT 1, draw_geometry JSONB NOT NULL, binding JSONB, time_start INT, time_end INT, bbox GEOMETRY(Polygon, 4326), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS entity_geometries ( entity_id UUID REFERENCES entities(id) ON DELETE CASCADE, geometry_id UUID REFERENCES geometries(id) ON DELETE CASCADE, project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, PRIMARY KEY (entity_id, geometry_id) ); CREATE TABLE IF NOT EXISTS commits ( id UUID PRIMARY KEY DEFAULT uuidv7(), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, snapshot_json JSONB NOT NULL, snapshot_hash TEXT, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, edit_summary TEXT, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS submissions ( id UUID PRIMARY KEY DEFAULT uuidv7(), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, commit_id UUID NOT NULL REFERENCES commits(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, status SMALLINT NOT NULL DEFAULT 1, reviewed_by UUID REFERENCES users(id) ON DELETE SET NULL, reviewed_at TIMESTAMPTZ, review_note TEXT, content TEXT, is_deleted BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS project_members ( project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role SMALLINT NOT NULL DEFAULT 3, invited_by UUID REFERENCES users(id) ON DELETE SET NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (project_id, user_id) ); CREATE TABLE IF NOT EXISTS rag_chunks ( id UUID PRIMARY KEY DEFAULT uuidv7(), source_type VARCHAR(50) NOT NULL, source_id UUID NOT NULL, project_id UUID REFERENCES projects(id) ON DELETE CASCADE, chunk_index INT NOT NULL, content TEXT NOT NULL, embedding vector(3072), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() );