## 主要变更
### 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 功能正常)
439 lines
8.7 KiB
Markdown
439 lines
8.7 KiB
Markdown
# 🚀 课题组网站部署指南
|
||
|
||
## 📋 最终架构
|
||
|
||
### 公网 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 Console(S3 管理)
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 Vue 课题组网站开发
|
||
|
||
### 1. 项目配置
|
||
|
||
#### vite.config.js
|
||
```javascript
|
||
import { defineConfig } from 'vite'
|
||
import vue from '@vitejs/plugin-vue'
|
||
|
||
export default defineConfig({
|
||
base: '/group/', // ⚠️ 必须配置子路径
|
||
plugins: [vue()],
|
||
server: {
|
||
port: 5173
|
||
}
|
||
})
|
||
```
|
||
|
||
#### router/index.js
|
||
```javascript
|
||
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
|
||
```javascript
|
||
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
|
||
```bash
|
||
VITE_SUPABASE_ANON_KEY=your-anon-key-here
|
||
```
|
||
|
||
#### 使用示例
|
||
```vue
|
||
<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. 跳转链接配置
|
||
|
||
```vue
|
||
<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(大文件)
|
||
|
||
```javascript
|
||
// 使用 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(小文件)
|
||
|
||
```javascript
|
||
// 推荐用于 < 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. 开发环境
|
||
|
||
```bash
|
||
# 创建 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. 生产部署
|
||
|
||
```bash
|
||
# 构建
|
||
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. 验证部署
|
||
|
||
```bash
|
||
# 访问网站
|
||
curl https://amiap.hzau.edu.cn/group/
|
||
|
||
# 查看日志
|
||
docker logs group-site
|
||
|
||
# 查看状态
|
||
docker ps | grep group-site
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 数据库设计示例
|
||
|
||
### Supabase 表结构
|
||
|
||
```sql
|
||
-- 团队成员表
|
||
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 系统链接
|
||
|
||
---
|
||
|
||
## 🔧 常用命令
|
||
|
||
### 开发调试
|
||
```bash
|
||
npm run dev # 启动开发服务器
|
||
npm run build # 构建生产版本
|
||
npm run preview # 预览生产构建
|
||
```
|
||
|
||
### 服务器管理
|
||
```bash
|
||
# 查看所有服务
|
||
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 - 部署配置
|