Files
labweb/supabase-stack/docs/DEPLOYMENT_GUIDE.md
zly 1f7a2ed1e4 feat: 迁移 Storage 后端从 MinIO 到文件系统
## 主要变更

### 1. Storage 配置修改
- 修改 docker-compose.yml: STORAGE_BACKEND 从 s3 改为 file
- 注释所有 GLOBAL_S3_* 环境变量
- 启用 FILE_STORAGE_BACKEND_PATH=/var/lib/storage
- 停止使用 MinIO 容器(docker-compose.s3.yml)

### 2. 文档更新
- 新增 docs/STORAGE_FILE_BACKEND_MIGRATION.md - 迁移详细文档
- 新增 docs/STORAGE_TROUBLESHOOTING.md - 故障排查指南
- 更新 README.md - 反映新的架构

### 3. 存储架构变更
- 从 MinIO S3 对象存储 -> 本地文件系统
- 存储路径: volumes/storage/undefined/stub/{bucket}/{file}/{version}
- 不再需要额外的 MinIO 容器

## 测试结果
-  上传文件 - 正常
-  下载文件 - 正常
-  删除文件 - 正常
-  签名 URL - 正常
- ⚠️ 更新文件 - 已知bug(使用删除+上传代替)

## 注意事项
- 旧的 S3 后端数据需要清理数据库元数据
- 文件更新操作有已知bug,需使用删除+重新上传
- 备份文件保存在 *.backup-before-rustfs

## 回滚方法
如需回滚到 MinIO:
```bash
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
docker compose -f docker-compose.s3.yml up -d
docker compose restart storage
```

日期: 2025-12-05
状态:  测试通过 (4/5 功能正常)
2025-12-05 19:44:11 +08:00

8.7 KiB
Raw Blame History

🚀 课题组网站部署指南

📋 最终架构

公网 HTTPS 访问

https://amiap.hzau.edu.cn/
├── /               → MinIO S3 API对象存储
│   └── /stub/      → 默认 bucket
│
├── /group/         → 🎨 Vue 课题组网站(主站)
│   ├── /group/            - 首页
│   ├── /group/members     - 成员介绍
│   ├── /group/research    - 研究方向
│   └── /group/...         - 其他页面
│
├── /supa/          → Supabase 后端 API
│   ├── /supa/auth/v1      - 用户认证
│   ├── /supa/rest/v1      - 数据库 REST
│   └── /supa/storage/v1   - 文件存储
│
└── /ABM/           → ABM 数据库系统

内网访问Tailscale VPN: 100.64.0.2

http://100.64.0.2:18000   → Supabase Dashboard后端管理
http://100.64.0.2:9001    → MinIO ConsoleS3 管理)

🎨 Vue 课题组网站开发

1. 项目配置

vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  base: '/group/',  // ⚠️ 必须配置子路径
  plugins: [vue()],
  server: {
    port: 5173
  }
})

router/index.js

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory('/group/'),  // ⚠️ 必须配置子路径
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('@/views/Home.vue')
    },
    {
      path: '/members',
      name: 'Members',
      component: () => import('@/views/Members.vue')
    },
    {
      path: '/research',
      name: 'Research',
      component: () => import('@/views/Research.vue')
    },
    {
      path: '/publications',
      name: 'Publications',
      component: () => import('@/views/Publications.vue')
    }
  ]
})

export default router

2. Supabase 集成

src/lib/supabase.js

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = 'https://amiap.hzau.edu.cn/supa'
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseKey)

.env

VITE_SUPABASE_ANON_KEY=your-anon-key-here

使用示例

<script setup>
import { ref, onMounted } from 'vue'
import { supabase } from '@/lib/supabase'

const members = ref([])

onMounted(async () => {
  // 查询团队成员
  const { data, error } = await supabase
    .from('members')
    .select('*')
    .order('join_date', { ascending: false })
  
  if (\!error) {
    members.value = data
  }
})

// 上传文件到 Supabase Storage
async function uploadPhoto(file) {
  const { data, error } = await supabase.storage
    .from('photos')
    .upload(`members/${file.name}`, file)
  
  if (\!error) {
    console.log('上传成功:', data.path)
  }
}
</script>

3. 跳转链接配置

<template>
  <div class="admin-panel">
    <h3>管理入口内网访问</h3>
    
    <\!-- Supabase 后端管理 -->
    <a 
      href="http://100.64.0.2:18000" 
      target="_blank"
      class="admin-link"
    >
      <icon>🗄️</icon>
      <span>Supabase Dashboard</span>
      <badge>需要 VPN</badge>
    </a>
    
    <\!-- MinIO 存储管理 -->
    <a 
      href="http://100.64.0.2:9001" 
      target="_blank"
      class="admin-link"
    >
      <icon>💾</icon>
      <span>MinIO Console</span>
      <badge>需要 VPN</badge>
    </a>
    
    <\!-- ABM 数据库 -->
    <router-link to="/external/ABM" class="admin-link">
      <icon>📊</icon>
      <span>ABM 数据库</span>
    </router-link>
  </div>
</template>

<script setup>
// 外部链接处理
function openExternal(url) {
  window.open(url, '_blank')
}
</script>

📦 MinIO S3 存储使用

直接上传到 S3大文件

// 使用 AWS SDK
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'

const s3Client = new S3Client({
  endpoint: 'https://amiap.hzau.edu.cn',  // 根路径
  region: 'stub',
  credentials: {
    accessKeyId: import.meta.env.VITE_S3_ACCESS_KEY,
    secretAccessKey: import.meta.env.VITE_S3_SECRET_KEY
  },
  forcePathStyle: true  // ⚠️ 必须启用路径风格
})

async function uploadLargeFile(file) {
  await s3Client.send(new PutObjectCommand({
    Bucket: 'stub',
    Key: `publications/${file.name}`,
    Body: file,
    ContentType: file.type
  }))
  
  // 文件 URL: https://amiap.hzau.edu.cn/stub/publications/file.pdf
  return `https://amiap.hzau.edu.cn/stub/publications/${file.name}`
}

使用 Supabase Storage小文件

// 推荐用于 < 50MB 的文件
const { data, error } = await supabase.storage
  .from('documents')
  .upload('research/paper.pdf', file)

// 获取公开 URL
const { data: { publicUrl } } = supabase.storage
  .from('documents')
  .getPublicUrl('research/paper.pdf')

🚀 部署流程

1. 开发环境

# 创建 Vue 项目
npm create vite@latest group-website -- --template vue

cd group-website

# 安装依赖
npm install @supabase/supabase-js
npm install @aws-sdk/client-s3  # 如果需要直接访问 S3

# 配置 vite.config.js 和 router见上面

# 本地开发
npm run dev
# 访问: http://localhost:5173/group/

2. 生产部署

# 构建
npm run build

# 部署到服务器
scp -r dist/* user@server:/vol1/1000/docker_server/traefik/web/group-site/dist/

# 或直接在服务器上
cd /vol1/1000/docker_server/traefik/web/group-site
rm -rf dist/*
# 复制构建产物到 dist/

# 重启服务
docker compose restart

3. 验证部署

# 访问网站
curl https://amiap.hzau.edu.cn/group/

# 查看日志
docker logs group-site

# 查看状态
docker ps | grep group-site

📊 数据库设计示例

Supabase 表结构

-- 团队成员表
CREATE TABLE members (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  name VARCHAR(100) NOT NULL,
  title VARCHAR(100),
  email VARCHAR(100),
  photo_url TEXT,
  bio TEXT,
  research_interests TEXT[],
  join_date DATE,
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP DEFAULT NOW()
);

-- 研究成果表
CREATE TABLE publications (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  title TEXT NOT NULL,
  authors TEXT[],
  journal VARCHAR(200),
  year INTEGER,
  doi VARCHAR(100),
  pdf_url TEXT,
  abstract TEXT,
  created_at TIMESTAMP DEFAULT NOW()
);

-- 研究项目表
CREATE TABLE projects (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  name VARCHAR(200) NOT NULL,
  description TEXT,
  status VARCHAR(50),
  start_date DATE,
  end_date DATE,
  funding_source VARCHAR(200),
  created_at TIMESTAMP DEFAULT NOW()
);

🎨 页面布局建议

首页 (/)

  • 课题组介绍
  • 最新动态
  • 研究领域概览
  • 快速链接

成员介绍 (/members)

  • 导师信息
  • 博士生/硕士生
  • 校友网络

研究方向 (/research)

  • 主要研究领域
  • 正在进行的项目
  • 技术路线

论文成果 (/publications)

  • 按年份/类别分类
  • 搜索和筛选
  • 下载链接

管理入口(仅内网)

  • Supabase Dashboard 链接
  • MinIO Console 链接
  • ABM 系统链接

🔧 常用命令

开发调试

npm run dev          # 启动开发服务器
npm run build        # 构建生产版本
npm run preview      # 预览生产构建

服务器管理

# 查看所有服务
docker ps | grep -E '(minio|group|supabase)'

# 重启服务
cd /vol1/1000/docker_server/traefik/web/group-site
docker compose restart

# 查看日志
docker logs -f group-site

# 更新代码
cd /vol1/1000/docker_server/traefik/web/group-site
git pull  # 如果使用 git
docker compose restart

📞 故障排查

Vue 网站 404

  • 检查 base: '/group/' 配置
  • 检查 Nginx try_files 配置
  • 清除浏览器缓存

静态资源加载失败

  • 确认 vite.config.js 中 base 设置
  • 检查文件权限:chmod -R 755 dist/

Supabase API 调用失败

  • 检查 CORS 配置
  • 验证 API Key
  • 查看浏览器控制台错误

S3 上传失败

  • 确认 forcePathStyle: true
  • 检查 credentials
  • 验证 bucket 存在

🎉 最终检查清单

部署前确认:

  • vite.config.js 配置 base: '/group/'
  • router 配置 createWebHistory('/group/')
  • Supabase client 配置正确
  • 环境变量已设置
  • 测试所有路由
  • 测试文件上传
  • 测试 Supabase 查询
  • 内网链接可访问
  • 响应式设计检查
  • 浏览器兼容性测试

架构设计:
配置完成:
开发就绪:

开始开发你的课题组网站吧! 🚀

有任何问题,参考:

  • FINAL_ARCHITECTURE_v2.md - 架构说明
  • web/group-site/README.md - 部署配置