refactor: 优化 Docker 部署配置
- 后端使用 uv 管理依赖,镜像内包含所有依赖 - 前端使用生产构建 + serve 提供静态文件 - 添加 WeasyPrint 完整系统依赖 - 修复 PDF 报告 Logo 显示问题 - 添加 .dockerignore 优化构建 - 更新部署文档和 GitHub Actions 工作流 - 前端端口从 5173 改为 3000
This commit is contained in:
parent
db3d8fd9f8
commit
33c4df9645
|
|
@ -115,10 +115,11 @@ jobs:
|
||||||
# 打包 Docker 配置文件
|
# 打包 Docker 配置文件
|
||||||
tar -czf release/xcodereviewer-docker-${{ steps.version.outputs.VERSION }}.tar.gz \
|
tar -czf release/xcodereviewer-docker-${{ steps.version.outputs.VERSION }}.tar.gz \
|
||||||
docker-compose.yml \
|
docker-compose.yml \
|
||||||
Dockerfile \
|
|
||||||
nginx.conf \
|
|
||||||
backend/Dockerfile \
|
backend/Dockerfile \
|
||||||
|
backend/.dockerignore \
|
||||||
frontend/Dockerfile \
|
frontend/Dockerfile \
|
||||||
|
frontend/.dockerignore \
|
||||||
|
frontend/docker-entrypoint.sh \
|
||||||
backend/env.example \
|
backend/env.example \
|
||||||
frontend/.env.example
|
frontend/.env.example
|
||||||
|
|
||||||
|
|
@ -206,12 +207,12 @@ jobs:
|
||||||
- name: 设置 Docker Buildx
|
- name: 设置 Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
# 16. 构建并推送前端 Docker 镜像(生产环境 Nginx)
|
# 16. 构建并推送前端 Docker 镜像
|
||||||
- name: 构建并推送前端 Docker 镜像
|
- name: 构建并推送前端 Docker 镜像
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: ./frontend
|
||||||
file: ./Dockerfile
|
file: ./frontend/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
tags: |
|
tags: |
|
||||||
|
|
|
||||||
35
Dockerfile
35
Dockerfile
|
|
@ -1,35 +0,0 @@
|
||||||
# 多阶段构建 - 构建阶段
|
|
||||||
FROM node:20-alpine AS builder
|
|
||||||
|
|
||||||
# 设置工作目录
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# 安装 pnpm
|
|
||||||
RUN npm install -g pnpm
|
|
||||||
|
|
||||||
# 复制前端项目文件
|
|
||||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# 复制前端源代码
|
|
||||||
COPY frontend/ .
|
|
||||||
|
|
||||||
# 构建应用
|
|
||||||
RUN pnpm build
|
|
||||||
|
|
||||||
# 生产阶段 - 使用 nginx 提供静态文件服务
|
|
||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
# 复制自定义 nginx 配置
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
# 从构建阶段复制构建产物
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
||||||
|
|
||||||
# 暴露端口
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# 启动 nginx
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
|
|
@ -95,7 +95,7 @@ cp backend/env.example backend/.env
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
🎉 **搞定!** 打开 http://localhost:5173 开始体验吧!
|
🎉 **搞定!** 打开 http://localhost:3000 开始体验吧!
|
||||||
|
|
||||||
### 演示账户
|
### 演示账户
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
.venv
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
.env
|
||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
|
uploads/
|
||||||
|
.mypy_cache
|
||||||
|
.ruff_cache
|
||||||
|
|
@ -4,37 +4,45 @@ WORKDIR /app
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV PIP_NO_CACHE_DIR=1
|
# 清除代理设置,避免容器内网络问题
|
||||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
ENV http_proxy=
|
||||||
|
ENV https_proxy=
|
||||||
|
ENV HTTP_PROXY=
|
||||||
|
ENV HTTPS_PROXY=
|
||||||
|
|
||||||
# 安装系统依赖(包含 WeasyPrint 所需的库和中文字体支持)
|
# 安装系统依赖(包含 WeasyPrint 所需的库和中文字体支持)
|
||||||
RUN for i in 1 2 3; do \
|
RUN rm -f /etc/apt/apt.conf.d/proxy.conf 2>/dev/null || true && \
|
||||||
|
unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
gcc \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
# WeasyPrint 依赖
|
curl \
|
||||||
|
# WeasyPrint 完整依赖
|
||||||
libpango-1.0-0 \
|
libpango-1.0-0 \
|
||||||
libpangoft2-1.0-0 \
|
libpangoft2-1.0-0 \
|
||||||
|
libpangocairo-1.0-0 \
|
||||||
libcairo2 \
|
libcairo2 \
|
||||||
libgdk-pixbuf2.0-0 \
|
libgdk-pixbuf-2.0-0 \
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
|
libglib2.0-0 \
|
||||||
shared-mime-info \
|
shared-mime-info \
|
||||||
# 字体支持(中文)
|
# 字体支持(中文)
|
||||||
fonts-noto-cjk \
|
fonts-noto-cjk \
|
||||||
fonts-noto-cjk-extra \
|
fonts-noto-cjk-extra \
|
||||||
fontconfig \
|
fontconfig \
|
||||||
&& fc-cache -fv \
|
&& fc-cache -fv \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
&& break || sleep 5; \
|
|
||||||
done
|
# 安装 uv
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||||
|
|
||||||
# 复制依赖文件
|
# 复制依赖文件
|
||||||
COPY pyproject.toml .
|
COPY pyproject.toml uv.lock ./
|
||||||
COPY requirements.txt .
|
|
||||||
|
|
||||||
# 安装 Python 依赖
|
# 使用 uv 安装依赖(确保无代理)
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||||
|
uv sync --frozen --no-dev
|
||||||
|
|
||||||
# 复制应用代码
|
# 复制应用代码
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
|
||||||
|
|
@ -375,13 +375,18 @@ class ReportGenerator:
|
||||||
"""读取并编码 Logo 图片"""
|
"""读取并编码 Logo 图片"""
|
||||||
try:
|
try:
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
# 回退三级到项目根目录: services -> app -> backend -> root
|
# 尝试多个可能的路径
|
||||||
project_root = os.path.abspath(os.path.join(current_dir, '../../../'))
|
possible_paths = [
|
||||||
logo_path = os.path.join(project_root, 'frontend/public/images/logo_nobg.png')
|
# Docker 容器内路径
|
||||||
|
os.path.join(current_dir, '../../static/images/logo_nobg.png'),
|
||||||
|
# 本地开发路径
|
||||||
|
os.path.abspath(os.path.join(current_dir, '../../../frontend/public/images/logo_nobg.png')),
|
||||||
|
]
|
||||||
|
|
||||||
if os.path.exists(logo_path):
|
for logo_path in possible_paths:
|
||||||
with open(logo_path, "rb") as image_file:
|
if os.path.exists(logo_path):
|
||||||
return base64.b64encode(image_file.read()).decode('utf-8')
|
with open(logo_path, "rb") as image_file:
|
||||||
|
return base64.b64encode(image_file.read()).decode('utf-8')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error loading logo: {e}")
|
print(f"Error loading logo: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 774 KiB |
|
|
@ -21,8 +21,7 @@ services:
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
- backend_uploads:/app/uploads
|
||||||
- ./backend/uploads:/app/uploads
|
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
env_file:
|
env_file:
|
||||||
|
|
@ -32,23 +31,19 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
command: sh -c "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload"
|
command: sh -c ".venv/bin/alembic upgrade head && .venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000"
|
||||||
networks:
|
networks:
|
||||||
- xcodereviewer-network
|
- xcodereviewer-network
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
volumes:
|
|
||||||
- ./frontend:/app
|
|
||||||
- /app/node_modules
|
|
||||||
ports:
|
ports:
|
||||||
- "5173:5173"
|
- "3000:3000"
|
||||||
environment:
|
environment:
|
||||||
- VITE_API_BASE_URL=http://backend:8000/api/v1
|
- VITE_API_BASE_URL=http://localhost:8000/api/v1
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
command: npm run dev -- --host
|
|
||||||
networks:
|
networks:
|
||||||
- xcodereviewer-network
|
- xcodereviewer-network
|
||||||
|
|
||||||
|
|
@ -58,3 +53,4 @@ networks:
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
backend_uploads:
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,10 @@ cp backend/env.example backend/.env
|
||||||
# 编辑 backend/.env,配置 LLM API Key
|
# 编辑 backend/.env,配置 LLM API Key
|
||||||
|
|
||||||
# 3. 启动所有服务
|
# 3. 启动所有服务
|
||||||
docker-compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
# 4. 访问应用
|
# 4. 访问应用
|
||||||
# 前端: http://localhost:5173
|
# 前端: http://localhost:3000
|
||||||
# 后端 API: http://localhost:8000/docs
|
# 后端 API: http://localhost:8000/docs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -89,26 +89,26 @@ LLM_MODEL=gpt-4o-mini
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 3. 启动所有服务
|
# 3. 启动所有服务
|
||||||
docker-compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
# 4. 查看服务状态
|
# 4. 查看服务状态
|
||||||
docker-compose ps
|
docker compose ps
|
||||||
|
|
||||||
# 5. 查看日志
|
# 5. 查看日志
|
||||||
docker-compose logs -f
|
docker compose logs -f
|
||||||
```
|
```
|
||||||
|
|
||||||
### 服务说明
|
### 服务说明
|
||||||
|
|
||||||
| 服务 | 端口 | 说明 |
|
| 服务 | 端口 | 说明 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| `frontend` | 5173 | React 前端应用(开发模式,支持热重载) |
|
| `frontend` | 3000 | React 前端应用(生产构建,使用 serve 提供静态文件) |
|
||||||
| `backend` | 8000 | FastAPI 后端 API |
|
| `backend` | 8000 | FastAPI 后端 API(使用 uv 管理依赖) |
|
||||||
| `db` | 5432 | PostgreSQL 15 数据库 |
|
| `db` | 5432 | PostgreSQL 15 数据库 |
|
||||||
|
|
||||||
### 访问地址
|
### 访问地址
|
||||||
|
|
||||||
- 前端应用: http://localhost:5173
|
- 前端应用: http://localhost:3000
|
||||||
- 后端 API: http://localhost:8000
|
- 后端 API: http://localhost:8000
|
||||||
- API 文档 (Swagger): http://localhost:8000/docs
|
- API 文档 (Swagger): http://localhost:8000/docs
|
||||||
- API 文档 (ReDoc): http://localhost:8000/redoc
|
- API 文档 (ReDoc): http://localhost:8000/redoc
|
||||||
|
|
@ -117,95 +117,70 @@ docker-compose logs -f
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 停止所有服务
|
# 停止所有服务
|
||||||
docker-compose down
|
docker compose down
|
||||||
|
|
||||||
# 停止并删除数据卷(清除数据库)
|
# 停止并删除数据卷(清除数据库)
|
||||||
docker-compose down -v
|
docker compose down -v
|
||||||
|
|
||||||
# 重新构建镜像
|
# 重新构建镜像
|
||||||
docker-compose build --no-cache
|
docker compose build --no-cache
|
||||||
|
|
||||||
# 查看特定服务日志
|
# 查看特定服务日志
|
||||||
docker-compose logs -f backend
|
docker compose logs -f backend
|
||||||
|
|
||||||
# 进入容器调试
|
# 进入容器调试
|
||||||
docker-compose exec backend bash
|
docker compose exec backend sh
|
||||||
docker-compose exec db psql -U postgres -d xcodereviewer
|
docker compose exec db psql -U postgres -d xcodereviewer
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 生产环境部署
|
## 生产环境部署
|
||||||
|
|
||||||
生产环境建议使用 Nginx 提供前端静态文件服务,并配置 HTTPS。
|
Docker Compose 默认配置已适用于生产环境:
|
||||||
|
|
||||||
### 方式一:使用预构建 Docker 镜像
|
- 前端:构建生产版本,使用 serve 提供静态文件服务
|
||||||
|
- 后端:使用 uv 管理依赖,镜像内包含所有依赖
|
||||||
|
- 数据库:使用 Docker Volume 持久化数据
|
||||||
|
|
||||||
```bash
|
### 生产环境安全建议
|
||||||
# 拉取最新镜像
|
|
||||||
docker pull ghcr.io/lintsinghua/xcodereviewer-frontend:latest
|
|
||||||
docker pull ghcr.io/lintsinghua/xcodereviewer-backend:latest
|
|
||||||
|
|
||||||
# 启动后端和数据库
|
1. **修改默认密钥**:务必修改 `SECRET_KEY` 为随机字符串
|
||||||
docker-compose up -d db backend
|
2. **配置 HTTPS**:使用 Nginx 反向代理并配置 SSL 证书
|
||||||
|
3. **限制 CORS**:在生产环境配置具体的前端域名
|
||||||
|
4. **数据库安全**:修改默认数据库密码,限制访问 IP
|
||||||
|
5. **API 限流**:配置 Nginx 或应用层限流
|
||||||
|
6. **日志监控**:配置日志收集和监控告警
|
||||||
|
7. **删除演示账户**:生产环境请删除或禁用 demo 账户
|
||||||
|
|
||||||
# 启动前端(Nginx 生产镜像)
|
### Nginx 反向代理配置(可选)
|
||||||
docker run -d \
|
|
||||||
--name xcodereviewer-frontend \
|
|
||||||
-p 80:80 \
|
|
||||||
--network xcodereviewer-network \
|
|
||||||
ghcr.io/lintsinghua/xcodereviewer-frontend:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方式二:本地构建生产镜像
|
如需使用 Nginx 提供 HTTPS 和统一入口:
|
||||||
|
|
||||||
```bash
|
|
||||||
# 构建前端生产镜像(使用 Nginx)
|
|
||||||
docker build -t xcodereviewer-frontend .
|
|
||||||
|
|
||||||
# 运行前端容器
|
|
||||||
docker run -d \
|
|
||||||
-p 80:80 \
|
|
||||||
--name xcodereviewer-frontend \
|
|
||||||
xcodereviewer-frontend
|
|
||||||
|
|
||||||
# 后端和数据库仍使用 docker-compose
|
|
||||||
docker-compose up -d db backend
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方式三:手动部署
|
|
||||||
|
|
||||||
#### 前端部署
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
pnpm install
|
|
||||||
|
|
||||||
# 构建生产版本
|
|
||||||
pnpm build
|
|
||||||
|
|
||||||
# 将 dist 目录部署到 Nginx/Apache 等 Web 服务器
|
|
||||||
```
|
|
||||||
|
|
||||||
Nginx 配置示例:
|
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name your-domain.com;
|
server_name your-domain.com;
|
||||||
root /var/www/xcodereviewer/dist;
|
return 301 https://$server_name$request_uri;
|
||||||
index index.html;
|
}
|
||||||
|
|
||||||
# 前端路由支持
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name your-domain.com;
|
||||||
|
|
||||||
|
ssl_certificate /path/to/cert.pem;
|
||||||
|
ssl_certificate_key /path/to/key.pem;
|
||||||
|
|
||||||
|
# 前端
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
# API 代理
|
# API 代理
|
||||||
location /api {
|
location /api/ {
|
||||||
proxy_pass http://localhost:8000;
|
proxy_pass http://localhost:8000/api/;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
@ -214,38 +189,6 @@ server {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 后端部署
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd backend
|
|
||||||
|
|
||||||
# 创建虚拟环境
|
|
||||||
python -m venv .venv
|
|
||||||
source .venv/bin/activate
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
# 配置环境变量
|
|
||||||
cp env.example .env
|
|
||||||
# 编辑 .env 文件
|
|
||||||
|
|
||||||
# 初始化数据库
|
|
||||||
alembic upgrade head
|
|
||||||
|
|
||||||
# 使用 Gunicorn 启动(生产环境)
|
|
||||||
gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
### 生产环境安全建议
|
|
||||||
|
|
||||||
1. **修改默认密钥**:务必修改 `SECRET_KEY` 为随机字符串
|
|
||||||
2. **配置 HTTPS**:使用 Let's Encrypt 或其他 SSL 证书
|
|
||||||
3. **限制 CORS**:在生产环境配置具体的前端域名
|
|
||||||
4. **数据库安全**:修改默认数据库密码,限制访问 IP
|
|
||||||
5. **API 限流**:配置 Nginx 或应用层限流
|
|
||||||
6. **日志监控**:配置日志收集和监控告警
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 本地开发部署
|
## 本地开发部署
|
||||||
|
|
@ -259,13 +202,13 @@ gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
||||||
| Node.js | 18+ | 前端运行环境 |
|
| Node.js | 18+ | 前端运行环境 |
|
||||||
| Python | 3.13+ | 后端运行环境 |
|
| Python | 3.13+ | 后端运行环境 |
|
||||||
| PostgreSQL | 15+ | 数据库 |
|
| PostgreSQL | 15+ | 数据库 |
|
||||||
| pnpm | 8+ | 推荐的包管理器 |
|
| pnpm | 8+ | 推荐的前端包管理器 |
|
||||||
| uv | 最新版 | 推荐的 Python 包管理器 |
|
| uv | 最新版 | 推荐的 Python 包管理器 |
|
||||||
|
|
||||||
### 数据库准备
|
### 数据库准备
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 方式一:使用 Docker 启动 PostgreSQL
|
# 方式一:使用 Docker 启动 PostgreSQL(推荐)
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name xcodereviewer-db \
|
--name xcodereviewer-db \
|
||||||
-e POSTGRES_USER=postgres \
|
-e POSTGRES_USER=postgres \
|
||||||
|
|
@ -275,7 +218,6 @@ docker run -d \
|
||||||
postgres:15-alpine
|
postgres:15-alpine
|
||||||
|
|
||||||
# 方式二:使用本地 PostgreSQL
|
# 方式二:使用本地 PostgreSQL
|
||||||
# 创建数据库
|
|
||||||
createdb xcodereviewer
|
createdb xcodereviewer
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -285,25 +227,21 @@ createdb xcodereviewer
|
||||||
# 1. 进入后端目录
|
# 1. 进入后端目录
|
||||||
cd backend
|
cd backend
|
||||||
|
|
||||||
# 2. 创建虚拟环境(推荐使用 uv)
|
# 2. 安装 uv(如未安装)
|
||||||
uv venv
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
source .venv/bin/activate # Linux/macOS
|
|
||||||
# 或 .venv\Scripts\activate # Windows
|
|
||||||
|
|
||||||
# 3. 安装依赖
|
# 3. 同步依赖
|
||||||
uv pip install -e .
|
uv sync
|
||||||
# 或使用 pip
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
# 4. 配置环境变量
|
# 4. 配置环境变量
|
||||||
cp env.example .env
|
cp env.example .env
|
||||||
# 编辑 .env 文件,配置数据库和 LLM 参数
|
# 编辑 .env 文件,配置数据库和 LLM 参数
|
||||||
|
|
||||||
# 5. 初始化数据库
|
# 5. 初始化数据库
|
||||||
alembic upgrade head
|
uv run alembic upgrade head
|
||||||
|
|
||||||
# 6. 启动后端服务(开发模式,支持热重载)
|
# 6. 启动后端服务(开发模式,支持热重载)
|
||||||
uvicorn app.main:app --reload --port 8000
|
uv run uvicorn app.main:app --reload --port 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
### 前端启动
|
### 前端启动
|
||||||
|
|
@ -314,9 +252,8 @@ cd frontend
|
||||||
|
|
||||||
# 2. 安装依赖
|
# 2. 安装依赖
|
||||||
pnpm install
|
pnpm install
|
||||||
# 或 npm install / yarn install
|
|
||||||
|
|
||||||
# 3. 配置环境变量(可选,也可使用运行时配置)
|
# 3. 配置环境变量(可选)
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
|
|
||||||
# 4. 启动开发服务器
|
# 4. 启动开发服务器
|
||||||
|
|
@ -339,10 +276,10 @@ pnpm format
|
||||||
|
|
||||||
# 后端类型检查
|
# 后端类型检查
|
||||||
cd backend
|
cd backend
|
||||||
mypy app
|
uv run mypy app
|
||||||
|
|
||||||
# 后端代码格式化
|
# 后端代码格式化
|
||||||
ruff format app
|
uv run ruff format app
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -364,10 +301,10 @@ XCodeReviewer 采用前后端分离架构,所有数据存储在后端 PostgreS
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 导出 PostgreSQL 数据
|
# 导出 PostgreSQL 数据
|
||||||
docker-compose exec db pg_dump -U postgres xcodereviewer > backup.sql
|
docker compose exec db pg_dump -U postgres xcodereviewer > backup.sql
|
||||||
|
|
||||||
# 恢复数据
|
# 恢复数据
|
||||||
docker-compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
docker compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -380,7 +317,7 @@ docker-compose exec -T db psql -U postgres xcodereviewer < backup.sql
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 检查端口占用
|
# 检查端口占用
|
||||||
lsof -i :5173
|
lsof -i :3000
|
||||||
lsof -i :8000
|
lsof -i :8000
|
||||||
lsof -i :5432
|
lsof -i :5432
|
||||||
|
|
||||||
|
|
@ -391,29 +328,37 @@ lsof -i :5432
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 检查数据库容器状态
|
# 检查数据库容器状态
|
||||||
docker-compose ps db
|
docker compose ps db
|
||||||
|
|
||||||
# 查看数据库日志
|
# 查看数据库日志
|
||||||
docker-compose logs db
|
docker compose logs db
|
||||||
|
|
||||||
# 确保数据库健康检查通过后再启动后端
|
# 确保数据库健康检查通过后再启动后端
|
||||||
docker-compose up -d db
|
docker compose up -d db
|
||||||
docker-compose exec db pg_isready -U postgres
|
docker compose exec db pg_isready -U postgres
|
||||||
docker-compose up -d backend
|
docker compose up -d backend
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Q: 构建时网络问题(代理相关)**
|
||||||
|
|
||||||
|
如果构建时遇到网络问题,检查 Docker Desktop 的代理设置:
|
||||||
|
1. 打开 Docker Desktop → Settings → Resources → Proxies
|
||||||
|
2. 关闭代理或配置正确的代理地址
|
||||||
|
3. 重启 Docker Desktop
|
||||||
|
4. 重新构建:`docker compose build --no-cache`
|
||||||
|
|
||||||
### 后端相关
|
### 后端相关
|
||||||
|
|
||||||
**Q: PDF 导出功能报错(WeasyPrint 依赖问题)**
|
**Q: PDF 导出功能报错(WeasyPrint 依赖问题)**
|
||||||
|
|
||||||
WeasyPrint 需要系统级依赖,Docker 镜像已包含。本地开发时:
|
Docker 镜像已包含 WeasyPrint 所需的系统依赖。本地开发时需要安装:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# macOS
|
# macOS
|
||||||
brew install pango cairo gdk-pixbuf libffi
|
brew install pango cairo gdk-pixbuf libffi
|
||||||
|
|
||||||
# Ubuntu/Debian
|
# Ubuntu/Debian
|
||||||
sudo apt-get install libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf2.0-0
|
sudo apt-get install libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0 libglib2.0-0
|
||||||
|
|
||||||
# Windows - 参见 FAQ.md 中的详细说明
|
# Windows - 参见 FAQ.md 中的详细说明
|
||||||
```
|
```
|
||||||
|
|
@ -435,14 +380,14 @@ LLM_GAP_MS=3000
|
||||||
|
|
||||||
**Q: 前端无法连接后端 API**
|
**Q: 前端无法连接后端 API**
|
||||||
|
|
||||||
检查 `frontend/.env` 中的 API 地址配置:
|
Docker Compose 部署时,前端通过 `http://localhost:8000/api/v1` 访问后端。确保:
|
||||||
|
1. 后端容器正常运行:`docker compose ps backend`
|
||||||
|
2. 后端端口 8000 可访问:`curl http://localhost:8000/docs`
|
||||||
|
|
||||||
|
本地开发时,检查 `frontend/.env` 中的 API 地址配置:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# 本地开发
|
|
||||||
VITE_API_BASE_URL=http://localhost:8000/api/v1
|
VITE_API_BASE_URL=http://localhost:8000/api/v1
|
||||||
|
|
||||||
# Docker Compose 部署
|
|
||||||
VITE_API_BASE_URL=/api
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
.env*
|
||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
|
|
@ -1,23 +1,56 @@
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 安装 pnpm
|
# 清除代理设置
|
||||||
RUN npm install -g pnpm
|
ENV http_proxy=
|
||||||
|
ENV https_proxy=
|
||||||
|
ENV HTTP_PROXY=
|
||||||
|
ENV HTTPS_PROXY=
|
||||||
|
|
||||||
|
# 安装 pnpm(确保无代理)
|
||||||
|
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||||
|
npm install -g pnpm
|
||||||
|
|
||||||
# 复制依赖文件
|
# 复制依赖文件
|
||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
# 安装依赖
|
# 安装依赖(确保无代理)
|
||||||
RUN pnpm install
|
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
# 复制源代码
|
# 复制源代码
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# 暴露端口
|
# 构建时使用占位符,运行时替换
|
||||||
EXPOSE 5173
|
ENV VITE_API_BASE_URL=__API_BASE_URL__
|
||||||
|
|
||||||
# 开发模式启动命令
|
# 构建生产版本
|
||||||
CMD ["pnpm", "dev", "--host"]
|
RUN pnpm build
|
||||||
|
|
||||||
|
# 生产镜像
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 清除代理设置
|
||||||
|
ENV http_proxy=
|
||||||
|
ENV https_proxy=
|
||||||
|
ENV HTTP_PROXY=
|
||||||
|
ENV HTTPS_PROXY=
|
||||||
|
|
||||||
|
# 安装 serve(确保无代理)
|
||||||
|
RUN unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY && \
|
||||||
|
npm install -g serve
|
||||||
|
|
||||||
|
# 复制构建产物
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
|
# 复制启动脚本
|
||||||
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
|
RUN chmod +x /docker-entrypoint.sh
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
|
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# 替换 API 地址占位符
|
||||||
|
API_URL="${VITE_API_BASE_URL:-http://localhost:8000/api/v1}"
|
||||||
|
|
||||||
|
# 在所有 JS 文件中替换占位符
|
||||||
|
find /app/dist -name '*.js' -exec sed -i "s|__API_BASE_URL__|${API_URL}|g" {} \;
|
||||||
|
|
||||||
|
# 执行原始命令
|
||||||
|
exec "$@"
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 处理 SPA 路由
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 代理 API 请求到后端
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://backend:8000/api/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 缓存静态资源
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
38
nginx.conf
38
nginx.conf
|
|
@ -1,38 +0,0 @@
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name localhost;
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# Gzip 压缩配置
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1024;
|
|
||||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
|
|
||||||
|
|
||||||
# 安全头部
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
|
|
||||||
# 处理 React Router 的客户端路由
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 静态资源缓存
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# API 代理(如果需要)
|
|
||||||
# location /api {
|
|
||||||
# proxy_pass http://backend:8000;
|
|
||||||
# proxy_http_version 1.1;
|
|
||||||
# proxy_set_header Upgrade $http_upgrade;
|
|
||||||
# proxy_set_header Connection 'upgrade';
|
|
||||||
# proxy_set_header Host $host;
|
|
||||||
# proxy_cache_bypass $http_upgrade;
|
|
||||||
# }
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue