kstools-license-manager / supabase-version-schema.sql
KyrosDev's picture
移除版本刪除外鍵約束限制
218d422
/*
KSTools 版本管理系統 - Supabase Schema
Project 2: kstools-public (版本系統)
這個 schema 應該在第二個 Supabase Project 中執行
主要用於儲存版本資訊、下載記錄和檔案存儲
*/
-- 啟用必要的擴展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ================================
-- 移除現有外鍵約束(如果存在)
-- ================================
-- 安全移除外鍵約束,不影響現有資料
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.table_constraints
WHERE constraint_name = 'fk_version'
AND table_name = 'download_logs'
) THEN
ALTER TABLE download_logs DROP CONSTRAINT fk_version;
END IF;
END $$;
-- ================================
-- 版本管理表(安全建立,如果不存在)
-- ================================
-- 版本表
CREATE TABLE IF NOT EXISTS versions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
version VARCHAR(20) NOT NULL UNIQUE,
title VARCHAR(255),
release_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
is_active BOOLEAN DEFAULT true,
download_url TEXT NOT NULL,
file_size BIGINT,
file_type VARCHAR(10) CHECK (file_type IN ('zip', 'exe', 'msi')) DEFAULT 'zip',
file_name TEXT NOT NULL,
changelog TEXT,
min_revit_version VARCHAR(10),
released_by VARCHAR(255),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 下載記錄表
CREATE TABLE IF NOT EXISTS download_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
version VARCHAR(20),
license_key VARCHAR(255),
action VARCHAR(20) CHECK (action IN ('download', 'update_check', 'install')),
user_agent TEXT,
ip_address INET,
downloaded_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- ================================
-- 索引優化
-- ================================
-- 版本表索引
CREATE INDEX IF NOT EXISTS idx_versions_version ON versions(version);
CREATE INDEX IF NOT EXISTS idx_versions_release_date ON versions(release_date DESC);
CREATE INDEX IF NOT EXISTS idx_versions_is_active ON versions(is_active);
-- 下載記錄表索引
CREATE INDEX IF NOT EXISTS idx_download_logs_version ON download_logs(version);
CREATE INDEX IF NOT EXISTS idx_download_logs_downloaded_at ON download_logs(downloaded_at DESC);
CREATE INDEX IF NOT EXISTS idx_download_logs_action ON download_logs(action);
-- ================================
-- Row Level Security (RLS) 政策
-- ================================
-- 啟用 RLS(如果尚未啟用)
DO $$
BEGIN
ALTER TABLE versions ENABLE ROW LEVEL SECURITY;
EXCEPTION
WHEN OTHERS THEN NULL;
END $$;
DO $$
BEGIN
ALTER TABLE download_logs ENABLE ROW LEVEL SECURITY;
EXCEPTION
WHEN OTHERS THEN NULL;
END $$;
-- 安全建立 RLS 政策(先刪除再建立)
DO $$
BEGIN
-- 版本表政策
DROP POLICY IF EXISTS "Public read versions" ON versions;
CREATE POLICY "Public read versions" ON versions
FOR SELECT USING (true);
DROP POLICY IF EXISTS "Service role insert versions" ON versions;
CREATE POLICY "Service role insert versions" ON versions
FOR INSERT WITH CHECK (auth.role() = 'service_role');
DROP POLICY IF EXISTS "Service role update versions" ON versions;
CREATE POLICY "Service role update versions" ON versions
FOR UPDATE USING (auth.role() = 'service_role');
-- 下載記錄表政策
DROP POLICY IF EXISTS "Service role all download_logs" ON download_logs;
CREATE POLICY "Service role all download_logs" ON download_logs
FOR ALL USING (auth.role() = 'service_role');
END $$;
-- ================================
-- Storage Bucket 設定
-- ================================
-- 安全建立 Storage Bucket(如果不存在)
DO $$
BEGIN
INSERT INTO storage.buckets (id, name, public)
VALUES ('plugin-releases', 'plugin-releases', true);
EXCEPTION
WHEN unique_violation THEN NULL; -- Bucket 已存在
END $$;
-- Storage RLS 政策設定(安全建立)
DO $$
BEGIN
-- 1. 允許公開讀取發布檔案
DROP POLICY IF EXISTS "Public read plugin releases" ON storage.objects;
CREATE POLICY "Public read plugin releases" ON storage.objects
FOR SELECT USING (bucket_id = 'plugin-releases');
-- 2. 允許 Service Role 管理檔案(上傳、更新、刪除)
DROP POLICY IF EXISTS "Service role manage plugin releases" ON storage.objects;
CREATE POLICY "Service role manage plugin releases" ON storage.objects
FOR ALL USING (auth.role() = 'service_role' AND bucket_id = 'plugin-releases');
-- 3. 允許認證用戶上傳檔案(可選,如果需要讓登入用戶上傳)
DROP POLICY IF EXISTS "Authenticated users upload plugin releases" ON storage.objects;
CREATE POLICY "Authenticated users upload plugin releases" ON storage.objects
FOR INSERT WITH CHECK (
bucket_id = 'plugin-releases' AND
auth.role() = 'authenticated'
);
END $$;
-- ================================
-- 觸發器:自動更新 updated_at
-- ================================
-- 建立更新時間觸發器函數
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
-- 安全建立觸發器(先刪除再建立)
DO $$
BEGIN
DROP TRIGGER IF EXISTS update_versions_updated_at ON versions;
CREATE TRIGGER update_versions_updated_at
BEFORE UPDATE ON versions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
END $$;
-- ================================
-- 有用的查詢視圖
-- ================================
-- 安全建立視圖(先刪除再建立)
DROP VIEW IF EXISTS latest_version;
CREATE VIEW latest_version AS
SELECT *
FROM versions
WHERE is_active = true
ORDER BY release_date DESC
LIMIT 1;
DROP VIEW IF EXISTS version_stats;
CREATE VIEW version_stats AS
SELECT
v.version,
v.release_date,
COUNT(dl.id) as download_count,
COUNT(CASE WHEN dl.action = 'download' THEN 1 END) as actual_downloads,
COUNT(CASE WHEN dl.action = 'update_check' THEN 1 END) as update_checks
FROM versions v
LEFT JOIN download_logs dl ON v.version = dl.version
WHERE v.is_active = true
GROUP BY v.id, v.version, v.release_date
ORDER BY v.release_date DESC;
-- ================================
-- 資料表註解
-- ================================
COMMENT ON TABLE versions IS '插件版本資訊表';
COMMENT ON COLUMN versions.version IS '版本號,格式:x.y.z';
COMMENT ON COLUMN versions.title IS '版本標題,簡短描述版本特色';
COMMENT ON COLUMN versions.download_url IS '下載連結URL';
COMMENT ON COLUMN versions.file_size IS '檔案大小(位元組)';
COMMENT ON COLUMN versions.file_type IS '檔案類型:zip, exe, msi';
COMMENT ON COLUMN versions.file_name IS '檔案名稱,包含副檔名';
COMMENT ON COLUMN versions.changelog IS '更新日誌(Markdown格式)';
COMMENT ON COLUMN versions.min_revit_version IS '最小支援的Revit版本';
COMMENT ON TABLE download_logs IS '下載記錄表';
COMMENT ON COLUMN download_logs.action IS '操作類型:download, update_check, install';