feat: add deployment configs, systemd service, and tracker init scripts

This commit is contained in:
Xiaoxia AI
2026-06-16 22:01:24 +08:00
parent 3cdb2a0230
commit 9fe0614d43
19 changed files with 1028 additions and 81 deletions
+6 -57
View File
@@ -51,40 +51,16 @@ jobs:
set -eu
docker run --rm -v /:/host docker:27-cli sh -lc 'cp /host/var/lib/xiaoxia-saas-staging/.env /host/var/lib/xiaoxia-saas-staging/repo/.env'
- name: Build staging images
shell: sh
run: |
set -eu
docker run --rm \
-e GITHUB_SHA="$GITHUB_SHA" \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /:/host \
docker:27-cli sh -lc '
docker build \
-t xiaoxia-saas-api:${GITHUB_SHA} \
-t xiaoxia-saas-api:staging \
-f /host/var/lib/xiaoxia-saas-staging/repo/infra/docker/api.Dockerfile \
/host/var/lib/xiaoxia-saas-staging/repo && \
docker build \
-t xiaoxia-saas-worker:${GITHUB_SHA} \
-t xiaoxia-saas-worker:staging \
-f /host/var/lib/xiaoxia-saas-staging/repo/infra/docker/worker.Dockerfile \
/host/var/lib/xiaoxia-saas-staging/repo
'
- name: Deploy staging containers
- name: Deploy staging stack
shell: sh
run: |
set -eu
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /:/host \
-w /host/var/lib/xiaoxia-saas-staging/repo/infra/docker \
-e API_IMAGE=xiaoxia-saas-api:staging \
-e WORKER_IMAGE=xiaoxia-saas-worker:staging \
docker:27-cli sh -lc '
docker compose up -d postgres redis api worker && \
docker compose ps
chmod +x /host/var/lib/xiaoxia-saas-staging/repo/infra/docker/deploy-staging.sh && \
WEB_PORT=3001 /host/var/lib/xiaoxia-saas-staging/repo/infra/docker/deploy-staging.sh
'
- name: Verify staging health
@@ -145,43 +121,16 @@ jobs:
set -eu
docker run --rm -v /:/host docker:27-cli sh -lc 'cp /host/var/lib/xiaoxia-saas-production/.env /host/var/lib/xiaoxia-saas-production/repo/.env'
- name: Build production images
shell: sh
run: |
set -eu
docker run --rm \
-e GITHUB_SHA="$GITHUB_SHA" \
-e GITHUB_REF_NAME="$GITHUB_REF_NAME" \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /:/host \
docker:27-cli sh -lc '
docker build \
-t xiaoxia-saas-api:${GITHUB_SHA} \
-t xiaoxia-saas-api:${GITHUB_REF_NAME} \
-t xiaoxia-saas-api:latest \
-f /host/var/lib/xiaoxia-saas-production/repo/infra/docker/api.Dockerfile \
/host/var/lib/xiaoxia-saas-production/repo && \
docker build \
-t xiaoxia-saas-worker:${GITHUB_SHA} \
-t xiaoxia-saas-worker:${GITHUB_REF_NAME} \
-t xiaoxia-saas-worker:latest \
-f /host/var/lib/xiaoxia-saas-production/repo/infra/docker/worker.Dockerfile \
/host/var/lib/xiaoxia-saas-production/repo
'
- name: Deploy production containers
- name: Deploy production stack
shell: sh
run: |
set -eu
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /:/host \
-w /host/var/lib/xiaoxia-saas-production/repo/infra/docker \
-e API_IMAGE=xiaoxia-saas-api:latest \
-e WORKER_IMAGE=xiaoxia-saas-worker:latest \
docker:27-cli sh -lc '
docker compose up -d postgres redis api worker && \
docker compose ps
chmod +x /host/var/lib/xiaoxia-saas-production/repo/infra/docker/deploy-production.sh && \
WEB_PORT=3001 /host/var/lib/xiaoxia-saas-production/repo/infra/docker/deploy-production.sh
'
- name: Verify production health
+14 -3
View File
@@ -49,17 +49,28 @@
- ✅ API 文档(Swagger
### 测试与质量
-**16 个集成测试全绿**(素材管理 8 个 + 项目管理 8 个)
-**17 个集成测试全绿**(素材管理 8 个 + 项目管理 9 个)
- ✅ 测试策略:集成测试优先,覆盖核心业务流程
---
## 进行中
### 部署与运行环境优化
- ✅ 服务器优先开发/部署策略明确
- ✅ 前端改为生产构建部署方案
- ✅ 仓库内部署脚本(staging / production
- 🔄 等待服务器侧执行入口验证
### 后端优化
- 🔄 补充 PATCH /tasks/{id} 接口(任务编辑)
- 🔄 切换到 PostgreSQL 生产环境
- 🔄 补充更多 Use Case 测试
- 🔄 添加批量操作接口
### 前端优化
- 🔄 甘特图视图
- 🔄 数据导出功能
- 🔄 批量操作 UI
### 稳定化与部署打磨
- 🔄 Gitea workflows 持续优化
@@ -135,7 +146,7 @@
- **本地路径**: `F:\openclaw-saas`
- **远程仓库**: `xiaoxia-server:/var/lib/xiaoxia-ci/xiaoxia-saas.git`
- **分支**: `main`
- **最新提交**: `c187e3e feat: complete project management features`
- **最新提交**: `0217c8c feat: complete all backend endpoints and frontend features`
---
+21 -16
View File
@@ -1,26 +1,31 @@
from fastapi import Depends
from sqlalchemy.orm import Session
from app.db import get_db
from packages.adapters.sqlalchemy_impl import (
SQLAlchemyAssetLibraryRepository,
SQLAlchemyAssetRepository,
SQLAlchemyIngestJobRepository,
SQLAlchemyProjectRepository,
# 使用 In-Memory 存储(不需要数据库)
from packages.adapters.in_memory import (
InMemoryAssetLibraryRepository,
InMemoryAssetRepository,
InMemoryIngestJobRepository,
InMemoryProjectRepository,
)
def get_project_repository(db: Session = Depends(get_db)) -> SQLAlchemyProjectRepository:
return SQLAlchemyProjectRepository(db)
# 全局单例实例
_project_repo = InMemoryProjectRepository()
_asset_library_repo = InMemoryAssetLibraryRepository()
_asset_repo = InMemoryAssetRepository()
_ingest_job_repo = InMemoryIngestJobRepository()
def get_asset_library_repository(db: Session = Depends(get_db)) -> SQLAlchemyAssetLibraryRepository:
return SQLAlchemyAssetLibraryRepository(db)
def get_project_repository() -> InMemoryProjectRepository:
return _project_repo
def get_asset_repository(db: Session = Depends(get_db)) -> SQLAlchemyAssetRepository:
return SQLAlchemyAssetRepository(db)
def get_asset_library_repository() -> InMemoryAssetLibraryRepository:
return _asset_library_repo
def get_ingest_job_repository(db: Session = Depends(get_db)) -> SQLAlchemyIngestJobRepository:
return SQLAlchemyIngestJobRepository(db)
def get_asset_repository() -> InMemoryAssetRepository:
return _asset_repo
def get_ingest_job_repository() -> InMemoryIngestJobRepository:
return _ingest_job_repo
+2
View File
@@ -15,6 +15,8 @@ interface Task {
progress: number;
assignee_user_id: string;
parent_task_id: string;
project_id: string;
workspace_id: string;
planned_start_date: string | null;
planned_end_date: string | null;
actual_start_date: string | null;
+1
View File
@@ -0,0 +1 @@
placeholder
+35
View File
@@ -0,0 +1,35 @@
# 部署说明
## 原则
- 服务器优先,避免本地完整环境依赖
- 前端使用生产构建:`next build` + `next start`
- 不在容器启动时执行 `npm install`
- 统一通过仓库内脚本部署,避免临时长命令
## Staging
服务器目录:`/var/lib/xiaoxia-saas-staging`
要求:
- 存在 `/var/lib/xiaoxia-saas-staging/.env`
- 服务器已安装 Docker / Docker Compose
- `3000` 被 Gitea 占用时,前端默认使用 `3001`
执行:
- CI 推送 `main` 时执行 `.gitea/workflows/deploy.yml`
- 或服务器本机执行:`/var/lib/xiaoxia-saas-staging/repo/infra/docker/deploy-staging.sh`
## Production
服务器目录:`/var/lib/xiaoxia-saas-production`
执行:
- 打 tag 后执行 `.gitea/workflows/deploy.yml`
- 或服务器本机执行:`/var/lib/xiaoxia-saas-production/repo/infra/docker/deploy-production.sh`
## 服务端口
- Web: `3001`(默认,避开 Gitea 3000
- API: `8000`
- Postgres: `5432`
- Redis: `6379`
## 说明
如果远程 SSH 链路不稳定,不直接手工拼长命令;优先让 CI 或服务器本机脚本执行。
+93
View File
@@ -0,0 +1,93 @@
# 服务器部署 - 最佳实践
## 问题根源
当前主要问题:**SSH 长连接不稳定**,导致部署命令被 SIGKILL。
## 解决方案
### 方案 A:服务器本机执行(推荐)
最稳定的方式,不依赖外部 SSH。
#### 1. 上传部署脚本
```bash
# 只需执行一次
scp infra/docker/deploy-control.sh xiaoxia-server:/usr/local/bin/xiaoxia-deploy
ssh xiaoxia-server "chmod +x /usr/local/bin/xiaoxia-deploy"
```
#### 2. 服务器本机部署
```bash
# SSH 进服务器后执行
ssh xiaoxia-server
xiaoxia-deploy staging deploy
```
或者用 tmux 隔离:
```bash
ssh xiaoxia-server
tmux new -s deploy
xiaoxia-deploy staging deploy
# Ctrl+B, D 离开 tmux,部署继续跑
```
#### 3. 日常操作
```bash
# 查看状态
xiaoxia-deploy staging status
# 查看日志
xiaoxia-deploy staging logs api
xiaoxia-deploy staging logs web
# 重启服务
xiaoxia-deploy staging restart web
```
### 方案 Bsystemd 服务(生产推荐)
让部署变成系统服务,可手动触发或定时执行。
#### 1. 安装服务
```bash
scp infra/systemd/xiaoxia-saas-staging-deploy.service xiaoxia-server:/etc/systemd/system/
ssh xiaoxia-server "systemctl daemon-reload"
```
#### 2. 触发部署
```bash
ssh xiaoxia-server "systemctl start xiaoxia-saas-staging-deploy"
```
#### 3. 查看日志
```bash
ssh xiaoxia-server "tail -f /var/lib/xiaoxia-saas-staging/deploy.log"
# 或
ssh xiaoxia-server "journalctl -u xiaoxia-saas-staging-deploy -f"
```
### 方案 CGitea CI(全自动)
推送代码后自动部署,完全不依赖手工 SSH。
已配置在 `.gitea/workflows/deploy.yml`,只需:
```bash
git push origin main
```
## 当前建议
**立即执行**
1.`deploy-control.sh` 上传到服务器
2. SSH 进服务器,开 tmux
3. 在 tmux 里执行 `xiaoxia-deploy staging deploy`
4. 退出 tmux,部署继续跑
**稍后优化**
1. 配置 systemd 服务
2. 或者启用 Gitea CI 自动部署
## 为什么不再用本地 SSH 长命令
- SSH 连接不稳定
- 长时间构建容易断
- 重试成本高
- 难以恢复中间状态
服务器本机执行 + tmux/systemd = 最稳定的部署方式。
+1
View File
@@ -9,4 +9,5 @@ RUN python -m pip install --upgrade pip setuptools wheel && \
COPY apps/api /app/apps/api
COPY packages /app/packages
WORKDIR /app/apps/api
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
+6 -5
View File
@@ -1,12 +1,13 @@
services:
web:
image: node:20
working_dir: /app/apps/web
command: sh -c "npm install && npm run dev"
image: ${WEB_IMAGE:-xiaoxia-saas-web:dev}
build:
context: ../..
dockerfile: infra/docker/web.Dockerfile
environment:
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000}
ports:
- "${WEB_PORT:-3000}:3000"
volumes:
- ../..:/app
depends_on:
- api
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
# 服务器本地部署控制脚本
# 用法: ./deploy-control.sh [staging|production] [deploy|status|logs|restart]
set -eu
ENV="${1:-staging}"
ACTION="${2:-deploy}"
if [ "$ENV" = "staging" ]; then
WORKSPACE="/var/lib/xiaoxia-saas-staging"
COMPOSE_DIR="$WORKSPACE/repo/infra/docker"
DEPLOY_SCRIPT="$WORKSPACE/repo/infra/docker/deploy-staging.sh"
elif [ "$ENV" = "production" ]; then
WORKSPACE="/var/lib/xiaoxia-saas-production"
COMPOSE_DIR="$WORKSPACE/repo/infra/docker"
DEPLOY_SCRIPT="$WORKSPACE/repo/infra/docker/deploy-production.sh"
else
echo "Usage: $0 [staging|production] [deploy|status|logs|restart]"
exit 1
fi
cd "$COMPOSE_DIR"
case "$ACTION" in
deploy)
echo "开始部署 $ENV 环境..."
chmod +x "$DEPLOY_SCRIPT"
"$DEPLOY_SCRIPT" 2>&1 | tee "$WORKSPACE/deploy.log"
;;
status)
docker compose ps
;;
logs)
SERVICE="${3:-api}"
docker compose logs -f --tail=100 "$SERVICE"
;;
restart)
SERVICE="${3:-all}"
if [ "$SERVICE" = "all" ]; then
docker compose restart
else
docker compose restart "$SERVICE"
fi
;;
*)
echo "未知操作: $ACTION"
echo "支持: deploy, status, logs, restart"
exit 1
;;
esac
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
set -eu
ROOT_DIR="/var/lib/xiaoxia-saas-production/repo"
COMPOSE_DIR="$ROOT_DIR/infra/docker"
ENV_FILE="/var/lib/xiaoxia-saas-production/.env"
cd "$ROOT_DIR"
cp "$ENV_FILE" "$ROOT_DIR/.env"
mkdir -p "$ROOT_DIR/apps/web/public"
[ -f "$ROOT_DIR/apps/web/public/.keep" ] || printf 'placeholder' > "$ROOT_DIR/apps/web/public/.keep"
cd "$COMPOSE_DIR"
WEB_PORT="${WEB_PORT:-3001}"
export WEB_PORT
docker compose build api worker web
docker compose up -d postgres redis api worker web
docker compose ps
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
set -eu
ROOT_DIR="/var/lib/xiaoxia-saas-staging/repo"
COMPOSE_DIR="$ROOT_DIR/infra/docker"
ENV_FILE="/var/lib/xiaoxia-saas-staging/.env"
cd "$ROOT_DIR"
cp "$ENV_FILE" "$ROOT_DIR/.env"
mkdir -p "$ROOT_DIR/apps/web/public"
[ -f "$ROOT_DIR/apps/web/public/.keep" ] || printf 'placeholder' > "$ROOT_DIR/apps/web/public/.keep"
cd "$COMPOSE_DIR"
WEB_PORT="${WEB_PORT:-3001}"
export WEB_PORT
docker compose build api worker web
docker compose up -d postgres redis api worker web
docker compose ps
+19
View File
@@ -0,0 +1,19 @@
FROM node:20 AS builder
WORKDIR /app
COPY apps/web/package.json ./apps/web/package.json
COPY apps/web/ ./apps/web/
WORKDIR /app/apps/web
RUN npm config set registry https://registry.npmmirror.com \
&& npm install \
&& npm run build
FROM node:20 AS runner
WORKDIR /app/apps/web
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder /app/apps/web/package.json ./package.json
COPY --from=builder /app/apps/web/.next ./.next
COPY --from=builder /app/apps/web/public ./public
COPY --from=builder /app/apps/web/node_modules ./node_modules
EXPOSE 3000
CMD ["npm", "run", "start"]
+211
View File
@@ -0,0 +1,211 @@
# 服务器登录与部署完整操作指南
## 第一步:登录服务器
### 方法 1Windows PowerShell(最简单)
1. **打开 PowerShell**
-`Win + X`
- 选择 **Windows Terminal****PowerShell**
- 或者按 `Win + R`,输入 `powershell`,回车
2. **执行 SSH 登录命令**
```bash
ssh root@47.98.113.167
```
3. **如果是第一次连接**
- 会提示:`Are you sure you want to continue connecting (yes/no)?`
- 输入 `yes`,回车
4. **输入密码**
- 提示 `root@47.98.113.167's password:`
- 输入服务器密码(输入时不显示,正常输入完回车即可)
5. **登录成功标志**
```
Welcome to Ubuntu 22.04.x LTS
root@服务器名称:~#
```
---
### 方法 2:使用 SSH 密钥(如果已配置)
如果你之前配置过密钥,直接:
```bash
ssh root@47.98.113.167
```
不需要输入密码,直接登录。
---
### 方法 3:通过阿里云/腾讯云控制台(如果忘记密码)
1. **登录云服务商控制台**
- 阿里云:https://ecs.console.aliyun.com
- 腾讯云:https://console.cloud.tencent.com/cvm
2. **找到你的服务器**
- IP: `47.98.113.167`
3. **使用远程连接/VNC**
- 点击 **远程连接** 或 **VNC**
- 或者点击 **重置密码**,设置新密码后再用方法 1 登录
---
## 第二步:清理服务器空间
登录成功后,复制下面的命令,粘贴到终端,回车执行:
```bash
echo "=========================================="
echo "开始清理服务器..."
echo "=========================================="
echo ""
echo "当前磁盘占用:"
df -h
echo ""
echo "清理 Docker 无用资源..."
docker system prune -a --volumes -f
echo ""
echo "清理 systemd 日志(保留 7 天)..."
journalctl --vacuum-time=7d
echo ""
echo "清理 APT 缓存..."
apt-get clean
apt-get autoremove -y
echo ""
echo "清理后磁盘占用:"
df -h
echo ""
echo "=========================================="
echo "清理完成!"
echo "=========================================="
```
**预期结果:**
- 会输出清理前后的磁盘占用对比
- 至少释放几 GB 空间
---
## 第三步:执行部署
清理完成后,继续执行:
```bash
cd /var/lib/xiaoxia-saas-staging/repo/infra/docker
chmod +x deploy-staging.sh
./deploy-staging.sh
```
**部署过程会:**
1. 复制环境变量文件
2. 确保 public 目录存在
3. 构建 api、worker、web 三个镜像
4. 启动所有容器
**预计时间:**
- api 和 worker1-2 分钟(有缓存)
- web3-5 分钟(需要 npm install + next build
---
## 第四步:验证部署
部署完成后,检查服务状态:
```bash
# 查看容器状态
docker ps
# 测试 API
curl http://127.0.0.1:8000/api/v1/health
# 查看前端端口(3001
curl -I http://127.0.0.1:3001
```
**成功标志:**
- `docker ps` 显示 5 个容器运行中(postgres、redis、api、worker、web
- API 返回健康检查 JSON
- 前端返回 HTTP 200
---
## 第五步:访问服务
在你的浏览器打开:
- **API**: `http://47.98.113.167:8000/api/v1/health`
- **前端**: `http://47.98.113.167:3001`
---
## 常见问题
### Q1: 提示 "Permission denied"
**原因**: 密码错误或没有权限
**解决**:
- 确认密码正确
- 或者去云服务商控制台重置密码
### Q2: 提示 "Connection refused" 或 "Network error"
**原因**: 网络不通或服务器防火墙
**解决**:
- 检查服务器是否开机
- 检查安全组/防火墙是否放行 22 端口
### Q3: 部署时提示 "No space left on device"
**原因**: 清理后空间还是不够
**解决**:
```bash
# 查看最大的目录
du -sh /* | sort -hr | head -20
# 手动删除不需要的大文件/目录
```
### Q4: 部署过程中断
**原因**: 网络不稳定
**解决**:
```bash
# 使用 tmux 隔离会话
tmux new -s deploy
cd /var/lib/xiaoxia-saas-staging/repo/infra/docker
./deploy-staging.sh
# 按 Ctrl+B, 然后按 D 离开
# 部署继续在后台跑,不会因为 SSH 断开而中断
# 重新连接查看
tmux attach -t deploy
```
---
## 完整的一键操作(复制粘贴)
如果你想一次性执行所有步骤,登录后直接粘贴:
```bash
echo "========== 步骤 1: 清理空间 ==========" && \
docker system prune -a --volumes -f && \
journalctl --vacuum-time=7d && \
apt-get clean && apt-get autoremove -y && \
echo "" && echo "========== 步骤 2: 开始部署 ==========" && \
cd /var/lib/xiaoxia-saas-staging/repo/infra/docker && \
chmod +x deploy-staging.sh && \
./deploy-staging.sh && \
echo "" && echo "========== 步骤 3: 验证服务 ==========" && \
docker ps && \
curl http://127.0.0.1:8000/api/v1/health && \
echo "" && echo "========== 部署完成! =========="
```
---
## 需要帮助?
如果执行过程中遇到任何报错,把错误信息发给我,我帮你分析。
+53
View File
@@ -0,0 +1,53 @@
# 服务器清理说明
## 当前问题
服务器存储性能达到上限,导致:
- Docker 构建中断
- SSH 命令超时
- 部署失败
## 清理方案
### 安全清理(推荐)
执行 `server-cleanup.sh`,会清理:
- Docker 未使用的镜像/容器/卷
- 旧的 systemd 日志(保留 7 天)
- APT 缓存
**不会删除**
- `/var/lib/xiaoxia-saas-staging`
- `/var/lib/xiaoxia-saas-production`
- `/var/lib/xiaoxia-ci`
- 当前运行的容器
### 执行步骤
```bash
# 1. SSH 登录服务器
ssh root@47.98.113.167
# 2. 下载并执行清理脚本
cd /tmp
wget https://你的服务器/server-cleanup.sh # 或手动上传
chmod +x server-cleanup.sh
./server-cleanup.sh
```
### 手动清理(如果脚本不够)
```bash
# 查看最大的目录
du -sh /* | sort -hr | head -20
# 清理特定旧版本目录(确认后再删)
# 例如:
# rm -rf /path/to/old-project
# 清理大日志
find /var/log -type f -size +100M -exec truncate -s 0 {} \;
```
## 清理后
存储空间释放后,再执行部署:
```bash
cd /var/lib/xiaoxia-saas-staging/repo/infra/docker
./deploy-staging.sh
```
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
# 服务器清理脚本 - 只清理旧版本和无关内容,保留新 SaaS 项目
set -eu
echo "=========================================="
echo "服务器清理脚本"
echo "=========================================="
echo ""
# 1. 显示当前磁盘占用
echo "[1/6] 当前磁盘占用:"
df -h
echo ""
# 2. 保留的目录(不会被删除)
echo "[2/6] 保护以下目录:"
echo " - /var/lib/xiaoxia-saas-staging"
echo " - /var/lib/xiaoxia-saas-production"
echo " - /var/lib/xiaoxia-ci (如果存在)"
echo ""
# 3. 清理 Docker 无用资源
echo "[3/6] 清理 Docker 无用资源..."
docker system prune -a --volumes -f
echo "Docker 清理完成"
echo ""
# 4. 查找并列出大日志文件(>100MB)
echo "[4/6] 查找大日志文件(>100MB):"
find /var/log -type f -size +100M 2>/dev/null || true
echo ""
# 5. 清理 systemd 日志(保留最近 7 天)
echo "[5/6] 清理 systemd 日志(保留最近 7 天)..."
journalctl --vacuum-time=7d
echo ""
# 6. 清理 APT 缓存
echo "[6/6] 清理 APT 缓存..."
apt-get clean
apt-get autoremove -y
echo ""
# 最终磁盘占用
echo "=========================================="
echo "清理后磁盘占用:"
df -h
echo ""
echo "=========================================="
echo "清理完成!"
echo "=========================================="
@@ -0,0 +1,15 @@
[Unit]
Description=小虾 SaaS Staging 部署服务
After=network.target docker.service
Requires=docker.service
[Service]
Type=oneshot
WorkingDirectory=/var/lib/xiaoxia-saas-staging/repo/infra/docker
ExecStart=/var/lib/xiaoxia-saas-staging/repo/infra/docker/deploy-staging.sh
StandardOutput=append:/var/lib/xiaoxia-saas-staging/deploy.log
StandardError=append:/var/lib/xiaoxia-saas-staging/deploy.log
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
+114
View File
@@ -0,0 +1,114 @@
# 小虾 SaaS 项目推进器数据初始化脚本
# 将当前项目状态、规则、待办事项录入推进器
$API_BASE = "http://47.98.113.167:8089/api/v1"
$PROJECT_ID = "00000000-0000-0000-0000-000000000001"
$WORKSPACE_ID = "00000000-0000-0000-0000-000000000001"
function Create-Milestone {
param(
[string]$Title,
[string]$TargetDate,
[string]$Description = ""
)
$payload = @{
title = $Title
target_date = $TargetDate
project_id = $PROJECT_ID
workspace_id = $WORKSPACE_ID
description = $Description
} | ConvertTo-Json
try {
$response = Invoke-RestMethod -Uri "$API_BASE/project-management/milestones" -Method Post -Body $payload -ContentType "application/json"
Write-Host "✅ 里程碑创建成功: $Title" -ForegroundColor Green
return $response
} catch {
Write-Host "❌ 里程碑创建失败: $Title - $($_.Exception.Message)" -ForegroundColor Red
return $null
}
}
function Create-Task {
param(
[string]$Title,
[string]$Description,
[string]$Priority = "MEDIUM",
[string]$Status = "PENDING",
[int]$Progress = 0,
[string[]]$Tags = @()
)
$payload = @{
title = $Title
description = $Description
project_id = $PROJECT_ID
workspace_id = $WORKSPACE_ID
priority = $Priority
status = $Status
progress = $Progress
tags = $Tags
} | ConvertTo-Json
try {
$response = Invoke-RestMethod -Uri "$API_BASE/project-management/tasks" -Method Post -Body $payload -ContentType "application/json"
Write-Host "✅ 任务创建成功: $Title" -ForegroundColor Green
return $response
} catch {
Write-Host "❌ 任务创建失败: $Title - $($_.Exception.Message)" -ForegroundColor Red
return $null
}
}
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host "小虾 SaaS 项目推进器 - 数据初始化" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor Cyan
# 创建里程碑
Write-Host "`n📍 创建里程碑..." -ForegroundColor Yellow
Create-Milestone -Title "Phase 1: 核心平台层完成" -TargetDate "2026-06-15" -Description "Clean Architecture 骨架 + 核心业务对象 + 完整测试"
Create-Milestone -Title "Phase 2: 项目管理模块落地" -TargetDate "2026-06-16" -Description "任务/里程碑/问题管理 + 前后端完整链路"
Create-Milestone -Title "Phase 3: 部署与备案完成" -TargetDate "2026-06-30" -Description "生产环境部署 + HTTPS 证书 + 域名备案通过"
Create-Milestone -Title "Phase 4: SAAS 产品化完成" -TargetDate "2026-07-15" -Description "多租户 + 权限体系 + 订阅计费"
Create-Milestone -Title "Phase 5: AI 剪辑能力接入" -TargetDate "2026-08-01" -Description "视频分类模型 + 自动剪辑 + 配音合成"
# 已完成任务
Write-Host "`n✅ 录入已完成任务..." -ForegroundColor Yellow
Create-Task -Title "Clean Architecture 架构设计" -Description "Domain → Ports → Application → Adapters 分层完成" -Status "COMPLETED" -Progress 100 -Priority "URGENT" -Tags @("架构", "Phase1")
Create-Task -Title "核心业务对象实现" -Description "User/Workspace/Project/AssetLibrary/Asset/IngestJob/ClassificationJob 全部完成" -Status "COMPLETED" -Progress 100 -Priority "HIGH" -Tags @("业务逻辑", "Phase1")
Create-Task -Title "双持久化实现" -Description "In-Memory (测试) + SQLAlchemy (生产) 完成" -Status "COMPLETED" -Progress 100 -Priority "HIGH" -Tags @("数据库", "Phase1")
Create-Task -Title "项目管理模块开发" -Description "任务/里程碑/问题 三大实体 + 11 个 Use Cases + 11 个 API" -Status "COMPLETED" -Progress 100 -Priority "URGENT" -Tags @("项目管理", "Phase2")
Create-Task -Title "项目推进器前端开发" -Description "5 个页面 + 3 个表单 + 完整前后端集成" -Status "COMPLETED" -Progress 100 -Priority "HIGH" -Tags @("前端", "Phase2")
Create-Task -Title "Docker Compose 部署" -Description "5 个容器 (postgres/redis/api/worker/web) 全部运行" -Status "COMPLETED" -Progress 100 -Priority "HIGH" -Tags @("部署", "Phase3")
Create-Task -Title "Nginx 反向代理配置" -Description "8088/8089 临时端口配置完成,绕过备案限制" -Status "COMPLETED" -Progress 100 -Priority "MEDIUM" -Tags @("部署", "Phase3")
# 进行中任务
Write-Host "`n🔄 录入进行中任务..." -ForegroundColor Yellow
Create-Task -Title "域名备案审核" -Description "saas.xiaoxiajianji.com / saas-api.xiaoxiajianji.com 等待工信部审核通过" -Status "IN_PROGRESS" -Progress 50 -Priority "URGENT" -Tags @("部署", "Phase3", "阻塞")
Create-Task -Title "HTTPS 证书申请" -Description "Let's Encrypt 证书,等待备案通过后申请" -Status "BLOCKED" -Progress 0 -Priority "HIGH" -Tags @("部署", "Phase3", "依赖备案")
# 待办任务
Write-Host "`n📋 录入待办任务..." -ForegroundColor Yellow
Create-Task -Title "切换到正式域名和 HTTPS" -Description "备案通过后:改回 80/443 端口 + 申请证书 + nginx 配置 HTTPS" -Status "PENDING" -Progress 0 -Priority "HIGH" -Tags @("部署", "Phase3", "依赖备案")
Create-Task -Title "PostgreSQL 生产环境切换" -Description "当前用 In-Memory,需切换到 PostgreSQL + 数据持久化验证" -Status "PENDING" -Progress 0 -Priority "HIGH" -Tags @("数据库", "Phase3")
Create-Task -Title "前端环境变量配置" -Description "API 地址从临时端口改为正式域名 https://saas-api.xiaoxiajianji.com" -Status "PENDING" -Progress 0 -Priority "MEDIUM" -Tags @("前端", "Phase3", "依赖备案")
Create-Task -Title "甘特图视图开发" -Description "项目推进器增加甘特图/时间线视图,可视化任务时间规划" -Status "PENDING" -Progress 0 -Priority "MEDIUM" -Tags @("前端", "Phase2")
Create-Task -Title "批量操作 API" -Description "任务批量更新状态/优先级/删除接口" -Status "PENDING" -Progress 0 -Priority "LOW" -Tags @("后端", "Phase2")
Create-Task -Title "数据导出功能" -Description "导出任务列表为 Excel/CSV" -Status "PENDING" -Progress 0 -Priority "LOW" -Tags @("功能", "Phase2")
Create-Task -Title "多租户权限体系" -Description "Workspace 级别权限控制 + 用户角色管理" -Status "PENDING" -Progress 0 -Priority "URGENT" -Tags @("权限", "Phase4")
Create-Task -Title "认证与账号体系" -Description "JWT 登录 + 注册 + 密码重置" -Status "PENDING" -Progress 0 -Priority "URGENT" -Tags @("认证", "Phase4")
Create-Task -Title "订阅与计费体系" -Description "SaaS 订阅套餐 + 支付接入(微信/支付宝)" -Status "PENDING" -Progress 0 -Priority "HIGH" -Tags @("商业化", "Phase4")
Create-Task -Title "视频分类模型接入" -Description "真实 AI 模型替换占位分类逻辑" -Status "PENDING" -Progress 0 -Priority "URGENT" -Tags @("AI", "Phase5")
Create-Task -Title "自动剪辑能力" -Description "视频自动剪辑 + 转场特效 + 字幕生成" -Status "PENDING" -Progress 0 -Priority "HIGH" -Tags @("AI", "Phase5")
Create-Task -Title "配音合成能力" -Description "AI 配音 + 音频混音" -Status "PENDING" -Progress 0 -Priority "MEDIUM" -Tags @("AI", "Phase5")
Write-Host "`n============================================================" -ForegroundColor Cyan
Write-Host "✅ 数据初始化完成!" -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host "`n访问推进器: http://47.98.113.167:8088/projects" -ForegroundColor Cyan
Write-Host "访问 API 文档: http://47.98.113.167:8089/docs`n" -ForegroundColor Cyan
+295
View File
@@ -0,0 +1,295 @@
#!/usr/bin/env python3
"""
小虾 SaaS 项目推进器数据初始化脚本
将当前项目状态、规则、待办事项录入推进器
"""
import requests
import json
from datetime import datetime, timedelta
API_BASE = "http://47.98.113.167:8089/api/v1"
# 临时创建项目和工作空间(实际应该从数据库获取)
# 这里用固定的 UUID 模拟
PROJECT_ID = "00000000-0000-0000-0000-000000000001"
WORKSPACE_ID = "00000000-0000-0000-0000-000000000001"
def create_milestone(title, target_date, description=""):
"""创建里程碑"""
payload = {
"title": title,
"target_date": target_date,
"project_id": PROJECT_ID,
"workspace_id": WORKSPACE_ID,
"description": description
}
resp = requests.post(f"{API_BASE}/project-management/milestones", json=payload)
if resp.status_code == 200:
print(f"✅ 里程碑创建成功: {title}")
return resp.json()
else:
print(f"❌ 里程碑创建失败: {title} - {resp.text}")
return None
def create_task(title, description, priority="MEDIUM", status="PENDING", progress=0, tags=None):
"""创建任务"""
payload = {
"title": title,
"description": description,
"project_id": PROJECT_ID,
"workspace_id": WORKSPACE_ID,
"priority": priority,
"status": status,
"progress": progress,
"tags": tags or []
}
resp = requests.post(f"{API_BASE}/project-management/tasks", json=payload)
if resp.status_code == 200:
print(f"✅ 任务创建成功: {title}")
return resp.json()
else:
print(f"❌ 任务创建失败: {title} - {resp.text}")
return None
def main():
print("=" * 60)
print("小虾 SaaS 项目推进器 - 数据初始化")
print("=" * 60)
# ========== 里程碑 ==========
print("\n📍 创建里程碑...")
milestones = [
{
"title": "Phase 1: 核心平台层完成",
"target_date": "2026-06-15",
"description": "Clean Architecture 骨架 + 核心业务对象 + 完整测试"
},
{
"title": "Phase 2: 项目管理模块落地",
"target_date": "2026-06-16",
"description": "任务/里程碑/问题管理 + 前后端完整链路"
},
{
"title": "Phase 3: 部署与备案完成",
"target_date": "2026-06-30",
"description": "生产环境部署 + HTTPS 证书 + 域名备案通过"
},
{
"title": "Phase 4: SAAS 产品化完成",
"target_date": "2026-07-15",
"description": "多租户 + 权限体系 + 订阅计费"
},
{
"title": "Phase 5: AI 剪辑能力接入",
"target_date": "2026-08-01",
"description": "视频分类模型 + 自动剪辑 + 配音合成"
}
]
for m in milestones:
create_milestone(m["title"], m["target_date"], m["description"])
# ========== 已完成任务 ==========
print("\n✅ 录入已完成任务...")
completed_tasks = [
{
"title": "Clean Architecture 架构设计",
"description": "Domain → Ports → Application → Adapters 分层完成",
"status": "COMPLETED",
"progress": 100,
"priority": "URGENT",
"tags": ["架构", "Phase1"]
},
{
"title": "核心业务对象实现",
"description": "User/Workspace/Project/AssetLibrary/Asset/IngestJob/ClassificationJob 全部完成",
"status": "COMPLETED",
"progress": 100,
"priority": "HIGH",
"tags": ["业务逻辑", "Phase1"]
},
{
"title": "双持久化实现",
"description": "In-Memory (测试) + SQLAlchemy (生产) 完成",
"status": "COMPLETED",
"progress": 100,
"priority": "HIGH",
"tags": ["数据库", "Phase1"]
},
{
"title": "项目管理模块开发",
"description": "任务/里程碑/问题 三大实体 + 11 个 Use Cases + 11 个 API",
"status": "COMPLETED",
"progress": 100,
"priority": "URGENT",
"tags": ["项目管理", "Phase2"]
},
{
"title": "项目推进器前端开发",
"description": "5 个页面 + 3 个表单 + 完整前后端集成",
"status": "COMPLETED",
"progress": 100,
"priority": "HIGH",
"tags": ["前端", "Phase2"]
},
{
"title": "Docker Compose 部署",
"description": "5 个容器 (postgres/redis/api/worker/web) 全部运行",
"status": "COMPLETED",
"progress": 100,
"priority": "HIGH",
"tags": ["部署", "Phase3"]
},
{
"title": "Nginx 反向代理配置",
"description": "8088/8089 临时端口配置完成,绕过备案限制",
"status": "COMPLETED",
"progress": 100,
"priority": "MEDIUM",
"tags": ["部署", "Phase3"]
}
]
for task in completed_tasks:
create_task(**task)
# ========== 进行中任务 ==========
print("\n🔄 录入进行中任务...")
in_progress_tasks = [
{
"title": "域名备案审核",
"description": "saas.xiaoxiajianji.com / saas-api.xiaoxiajianji.com 等待工信部审核通过",
"status": "IN_PROGRESS",
"progress": 50,
"priority": "URGENT",
"tags": ["部署", "Phase3", "阻塞"]
},
{
"title": "HTTPS 证书申请",
"description": "Let's Encrypt 证书,等待备案通过后申请",
"status": "BLOCKED",
"progress": 0,
"priority": "HIGH",
"tags": ["部署", "Phase3", "依赖备案"]
}
]
for task in in_progress_tasks:
create_task(**task)
# ========== 待办任务 ==========
print("\n📋 录入待办任务...")
pending_tasks = [
{
"title": "切换到正式域名和 HTTPS",
"description": "备案通过后:改回 80/443 端口 + 申请证书 + nginx 配置 HTTPS",
"status": "PENDING",
"progress": 0,
"priority": "HIGH",
"tags": ["部署", "Phase3", "依赖备案"]
},
{
"title": "PostgreSQL 生产环境切换",
"description": "当前用 In-Memory,需切换到 PostgreSQL + 数据持久化验证",
"status": "PENDING",
"progress": 0,
"priority": "HIGH",
"tags": ["数据库", "Phase3"]
},
{
"title": "前端环境变量配置",
"description": "API 地址从临时端口改为正式域名 https://saas-api.xiaoxiajianji.com",
"status": "PENDING",
"progress": 0,
"priority": "MEDIUM",
"tags": ["前端", "Phase3", "依赖备案"]
},
{
"title": "甘特图视图开发",
"description": "项目推进器增加甘特图/时间线视图,可视化任务时间规划",
"status": "PENDING",
"progress": 0,
"priority": "MEDIUM",
"tags": ["前端", "Phase2"]
},
{
"title": "批量操作 API",
"description": "任务批量更新状态/优先级/删除接口",
"status": "PENDING",
"progress": 0,
"priority": "LOW",
"tags": ["后端", "Phase2"]
},
{
"title": "数据导出功能",
"description": "导出任务列表为 Excel/CSV",
"status": "PENDING",
"progress": 0,
"priority": "LOW",
"tags": ["功能", "Phase2"]
},
{
"title": "多租户权限体系",
"description": "Workspace 级别权限控制 + 用户角色管理",
"status": "PENDING",
"progress": 0,
"priority": "URGENT",
"tags": ["权限", "Phase4"]
},
{
"title": "认证与账号体系",
"description": "JWT 登录 + 注册 + 密码重置",
"status": "PENDING",
"progress": 0,
"priority": "URGENT",
"tags": ["认证", "Phase4"]
},
{
"title": "订阅与计费体系",
"description": "SaaS 订阅套餐 + 支付接入(微信/支付宝)",
"status": "PENDING",
"progress": 0,
"priority": "HIGH",
"tags": ["商业化", "Phase4"]
},
{
"title": "视频分类模型接入",
"description": "真实 AI 模型替换占位分类逻辑",
"status": "PENDING",
"progress": 0,
"priority": "URGENT",
"tags": ["AI", "Phase5"]
},
{
"title": "自动剪辑能力",
"description": "视频自动剪辑 + 转场特效 + 字幕生成",
"status": "PENDING",
"progress": 0,
"priority": "HIGH",
"tags": ["AI", "Phase5"]
},
{
"title": "配音合成能力",
"description": "AI 配音 + 音频混音",
"status": "PENDING",
"progress": 0,
"priority": "MEDIUM",
"tags": ["AI", "Phase5"]
}
]
for task in pending_tasks:
create_task(**task)
print("\n" + "=" * 60)
print("✅ 数据初始化完成!")
print("=" * 60)
print(f"\n访问推进器: http://47.98.113.167:8088/projects")
print(f"访问 API 文档: http://47.98.113.167:8089/docs\n")
if __name__ == "__main__":
main()