kstools-license-manager-test / docs /SUPABASE_STORAGE_GUIDE.md
KyrosDev's picture
整理文件結構移至 docs 和 schemas 資料夾
0bca400

Supabase Storage 檔案儲存使用指南

概述

KSTools License Manager 使用 Supabase Storage 來儲存和管理插件發布檔案。系統支援 ZIP、EXE、MSI 三種檔案格式,並自動建立 plugin-releases bucket 用於存放版本檔案。

系統架構流程圖

graph TD
    A[開發者] --> B[準備發布檔案]
    B --> C{選擇檔案格式}
    C --> D[.zip 壓縮包]
    C --> E[.exe 可執行檔]
    C --> F[.msi 安裝程式]

    D --> G[上傳到 Supabase Storage]
    E --> G
    F --> G

    G --> H[獲取公開 URL]
    H --> I[更新 versions 表]
    I --> J[用戶可下載]

    subgraph "Supabase Storage"
        K[plugin-releases bucket]
        L[RLS 政策]
        M[公開 URL]
    end

    G --> K
    K --> L
    L --> M
    M --> H

    subgraph "前端系統"
        N[版本管理頁面]
        O[下載統計]
        P[檔案列表]
    end

    J --> N
    N --> O
    N --> P

    %% 精簡配色 - 只標記關鍵步驟
    style A fill:#e3f2fd
    style G fill:#f3e5f5
    style J fill:#d4edda

發布流程圖

sequenceDiagram
    participant Dev as 開發者
    participant UI as 前端介面
    participant API as 後端 API
    participant Storage as Supabase Storage
    participant DB as Supabase DB
    participant User as 用戶

    Dev->>+UI: 1. 選擇檔案上傳 (.zip/.exe/.msi)
    UI->>UI: 2. 檢測檔案格式
    UI->>+API: 3. POST /api/admin/release (FormData)
    API->>API: 4. 驗證檔案格式和大小
    API->>+Storage: 5. upload(file, filename)
    Storage-->>-API: 6. 返回上傳結果
    API->>+Storage: 7. getPublicUrl(filename)
    Storage-->>-API: 8. 返回公開 URL
    API->>+DB: 9. 插入版本記錄 (含 title, file_type)
    DB-->>-API: 10. 確認記錄已建立
    API-->>-UI: 11. 返回完整發布結果
    UI-->>-Dev: 12. 發布成功通知

    User->>+UI: 13. 查看版本列表
    UI->>+DB: 14. 查詢版本記錄
    DB-->>-UI: 15. 返回版本資料 (含檔案類型)
    UI-->>-User: 16. 顯示版本列表 (顯示檔案格式圖示)
    User->>+Storage: 17. 點擊下載
    Storage-->>-User: 18. 直接下載檔案

    %% 關鍵步驟高亮
    rect rgb(255, 243, 205)
        note over UI,API: 檔案上傳驗證階段
    end

    rect rgb(243, 229, 245)
        note over API,Storage: Storage 處理階段
    end

    rect rgb(212, 237, 218)
        note over API,DB: 資料庫記錄階段
    end

檔案格式決策流程圖

flowchart TD
    Start([開始發布]) --> Choose{選擇檔案格式}
    Choose -->|開發版本| ZIP[ZIP 壓縮包]
    Choose -->|便攜版本| EXE[EXE 可執行檔]
    Choose -->|正式安裝| MSI[MSI 安裝程式]

    ZIP --> CheckZip{檔案完整性}
    EXE --> CheckExe{可執行性測試}
    MSI --> CheckMsi{安裝程式測試}

    CheckZip -->|通過| Upload1[上傳 .zip]
    CheckExe -->|通過| Upload2[上傳 .exe]
    CheckMsi -->|通過| Upload3[上傳 .msi]

    CheckZip -->|失敗| Error[修復並重新打包]
    CheckExe -->|失敗| Error
    CheckMsi -->|失敗| Error

    Upload1 --> Success[發布成功]
    Upload2 --> Success
    Upload3 --> Success

    Error --> Start

    %% 精簡配色 - 只標記關鍵步驟
    style Start fill:#e3f2fd
    style Success fill:#d4edda
    style Error fill:#f8d7da

檔案格式說明

支援的檔案格式

格式 用途 檔案大小 建議使用場景
.zip 壓縮包 開發版本、源碼發布
.exe 可執行檔 便攜版本、免安裝版
.msi 安裝程式 正式發布、企業部署

檔案命名規範

KSTools-v{版本號}.{格式}

範例:
- KSTools-v1.2.0.zip
- KSTools-v1.2.0.exe
- KSTools-v1.2.0.msi

設定步驟

1. 執行 SQL Schema

在你的 Supabase 版本專案中執行 supabase-version-schema.sql,這會:

  • 建立 plugin-releases bucket
  • 建立支援多格式的 versions
  • 設定適當的 RLS 政策
  • 允許公開讀取檔案
  • 允許認證用戶上傳檔案

2. 驗證 Storage 設定

  1. 登入 Supabase Dashboard
  2. 進入你的版本專案
  3. 點選 "Storage" 頁面
  4. 確認看到 plugin-releases bucket

檔案上傳方式

透過後端 API 上傳

系統採用統一的後端 API 上傳方式,確保安全性和一致性。

// 前端版本發布表單提交
async function handleRelease(formData, file) {
    const releaseData = new FormData();
    releaseData.append('version', formData.version);
    releaseData.append('title', formData.title);
    releaseData.append('changelog', formData.changelog);
    releaseData.append('file', file);

    const response = await fetch('/api/admin/release', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${session.access_token}`
        },
        body: releaseData
    });

    if (!response.ok) {
        throw new Error('發布失敗');
    }

    return await response.json();
}

檔案上傳流程

  1. 前端驗證 - 檔案格式、大小檢查
  2. API 呼叫 - 傳送 FormData 到 /api/admin/release
  3. 後端處理 - 檔案上傳到 Supabase Storage
  4. 資料庫更新 - 儲存版本記錄
  5. 返回結果 - 完整的發布資訊

後端 API 實作詳情

FastAPI 端點:/api/admin/release

@router.post("/admin/release")
async def release_version(
    version: str = Form(...),
    title: Optional[str] = Form(None),
    changelog: str = Form(...),
    min_revit_version: Optional[str] = Form(None),
    file: Optional[UploadFile] = File(None),
    current_user = Depends(verify_admin)
):
    """
    發布新版本 - 統一的檔案上傳端點
    支援 .zip, .exe, .msi 三種格式
    """
    # 1. 驗證檔案格式
    allowed_extensions = ['.zip', '.exe', '.msi']
    file_extension = None
    for ext in allowed_extensions:
        if file.filename.lower().endswith(ext):
            file_extension = ext
            break

    if not file_extension:
        raise HTTPException(
            status_code=400,
            detail=f"不支援的檔案格式。支援格式:{', '.join(allowed_extensions)}"
        )

    # 2. 上傳到 Supabase Storage
    file_content = await file.read()
    file_size = len(file_content)
    file_path = f"KSTools-v{version}{file_extension}"

    # 設定正確的 MIME 類型
    content_types = {
        '.zip': 'application/zip',
        '.exe': 'application/octet-stream',
        '.msi': 'application/x-msi'
    }
    content_type = content_types.get(file_extension, 'application/octet-stream')

    final_download_url = await version_db.upload_file(file_path, file_content, content_type)

    # 3. 儲存版本記錄
    version_data = {
        'version': version,
        'title': title,
        'changelog': changelog,
        'min_revit_version': min_revit_version,
        'download_url': final_download_url,
        'file_size': file_size,
        'file_type': file_extension.lstrip('.') if file_extension else None,
        'file_name': f"KSTools-v{version}{file_extension}" if file_extension else None,
        'released_by': current_user.get('email', 'Unknown'),
        'is_active': True
    }

    result = client.table('versions').insert(version_data).execute()
    return {"success": True, "version": result.data[0]}

自動化流程

使用此 API 端點的優勢:

  • 統一入口 - 所有檔案上傳都通過同一個端點
  • 自動驗證 - 檔案格式、大小自動檢查
  • 安全控制 - 管理員權限驗證
  • 完整記錄 - 自動建立資料庫記錄
  • 錯誤處理 - 統一的錯誤回應

資料庫記錄範例

系統會自動建立以下格式的版本記錄:

-- 新增版本記錄(包含檔案格式和標題)
INSERT INTO versions (
    version,
    title,
    release_date,
    is_active,
    download_url,
    file_size,
    file_type,
    file_name,
    changelog,
    min_revit_version,
    released_by
) VALUES (
    '1.2.0',
    '重大功能更新',  -- 版本標題
    NOW(),
    true,
    'https://你的專案ID.supabase.co/storage/v1/object/public/plugin-releases/KSTools-v1.2.0.msi',
    25600000, -- 檔案大小(位元組)
    'msi',    -- 檔案類型
    'KSTools-v1.2.0.msi', -- 檔案名稱
    '- 新功能說明\n- 錯誤修復',
    '2020',
    'KyrosDev'
);

前端顯示檔案類型

// 在版本列表中顯示檔案格式圖示
function getFileTypeIcon(fileType) {
    const icons = {
        'zip': '📦',
        'exe': '⚙️',
        'msi': '💾'
    };
    return icons[fileType] || '📄';
}

function renderVersionList(versions) {
    return versions.map(version => `
        <div class="version-item">
            <span class="version-number">${version.version}</span>
            <span class="file-type">
                ${getFileTypeIcon(version.file_type)}
                ${version.file_type.toUpperCase()}
            </span>
            <span class="file-size">${formatFileSize(version.file_size)}</span>
            <a href="${version.download_url}" class="download-btn">
                下載 ${version.file_name}
            </a>
        </div>
    `).join('');
}

檔案管理操作流程圖

flowchart TD
    A[列出檔案] --> B{選擇操作}

    B --> C[下載]
    B --> D[刪除]
    B --> E[更新]
    B --> F[獲取資訊]

    A --> G[檢查 .zip]
    A --> H[檢查 .exe]
    A --> I[檢查 .msi]

    A --> J[storage.list API]
    C --> K[storage.download API]
    D --> L[storage.remove API]
    E --> M[storage.update API]
    F --> N[storage.getPublicUrl API]

    K --> O[檔案下載完成]
    L --> P[檔案刪除完成]
    M --> Q[檔案更新完成]
    N --> R[獲取URL完成]

    %% 精簡配色 - 只標記關鍵步驟
    style A fill:#e3f2fd
    style D fill:#f8d7da
    style J fill:#f3e5f5
    style K fill:#f3e5f5
    style L fill:#f3e5f5
    style M fill:#f3e5f5
    style N fill:#f3e5f5
    style O fill:#d4edda
    style P fill:#d4edda
    style Q fill:#d4edda
    style R fill:#d4edda

檔案管理

檢視所有檔案(按格式篩選)

// 列出所有檔案
const { data, error } = await supabaseVersion.storage
    .from('plugin-releases')
    .list();

// 按檔案格式篩選
const zipFiles = data.filter(file => file.name.endsWith('.zip'));
const exeFiles = data.filter(file => file.name.endsWith('.exe'));
const msiFiles = data.filter(file => file.name.endsWith('.msi'));

批量操作不同格式檔案

// 刪除特定版本的所有格式檔案
async function deleteVersionAllFormats(version) {
    const formats = ['zip', 'exe', 'msi'];
    const filesToDelete = formats.map(format => `KSTools-v${version}.${format}`);

    const { data, error } = await supabaseVersion.storage
        .from('plugin-releases')
        .remove(filesToDelete);

    return { success: !error, error };
}

檢查檔案完整性

// 驗證檔案是否完整上傳
async function verifyFileIntegrity(fileName, expectedSize) {
    const { data, error } = await supabaseVersion.storage
        .from('plugin-releases')
        .list('', { search: fileName });

    if (error || !data.length) {
        return { valid: false, reason: '檔案不存在' };
    }

    const file = data[0];
    if (file.metadata?.size !== expectedSize) {
        return { valid: false, reason: '檔案大小不符' };
    }

    return { valid: true };
}

權限管理架構圖

graph TB
    subgraph "Supabase RLS 政策"
        A[Public Read Policy]
        B[Authenticated Upload Policy]
        C[Service Role Manage Policy]
    end

    subgraph "用戶角色"
        D[匿名用戶]
        E[登入用戶]
        F[Service Role]
    end

    subgraph "操作權限"
        G[只能下載]
        H[可以上傳+下載]
        I[完整管理權限]
    end

    subgraph "檔案格式支援"
        J[所有格式下載]
        K[所有格式上傳]
        L[所有格式管理]
    end

    D --> A --> G --> J
    E --> B --> H --> K
    F --> C --> I --> L

    %% 精簡配色 - 只標記關鍵權限
    style C fill:#f3e5f5
    style I fill:#f8d7da

安全建議

檔案上傳安全

  1. 檔案格式驗證:確保只允許 .zip、.exe、.msi 格式
  2. 檔案大小限制:設定合理的檔案大小上限
  3. 病毒掃描:建議對 .exe 和 .msi 檔案進行安全掃描
  4. 數位簽章:.exe 和 .msi 檔案應使用程式碼簽章

權限控制

  1. 不要在前端暴露 Service Role Key
  2. 上傳功能建議透過後端 API 處理
  3. 定期檢查並清理舊版本檔案
  4. 對敏感操作實施雙重驗證

疑難排解

常見問題

Q: 版本發布失敗 A: 檢查 API 權限、檔案格式是否正確,查看瀏覽器開發者工具錯誤訊息

Q: 檔案上傳後找不到 A: 確認 Supabase Storage bucket plugin-releases 已正確建立並設定 RLS 政策

Q: 檔案大小限制 A: 系統設定為 100MB 上限,Supabase 免費版單檔限制為 50MB,付費版可達 5GB

Q: 權限驗證失敗 A: 確認登入狀態和管理員權限,檢查 Bearer Token 是否正確傳送

檢查清單

  • SQL Schema 已執行(包含 file_type 欄位)
  • Storage bucket 已建立
  • RLS 政策已設定
  • 檔案命名符合規範
  • 檔案格式驗證功能正常
  • 版本記錄包含檔案類型資訊
  • 下載連結可正常使用
  • 前端顯示檔案格式圖示

相關連結