Update DESIGN.md and OPS_MANUAL.md for domain and subpath deployment

- Add www.ityb.me domain info and /careerbot subpath architecture docs
- Document BASE_PATH routing prefix mechanism in DESIGN.md
- Update all URLs from IP to domain in OPS_MANUAL.md
- Update Nginx config section to reflect subpath proxy
- Update new project deployment guide with subpath pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ln0422 2026-04-07 22:13:31 +08:00
parent 501f8985ec
commit 2c1688b4bb
2 changed files with 85 additions and 28 deletions

View File

@ -7,6 +7,14 @@ CareerBot 是一个个人职业展示网站,集成了 AI 智能对话助手。
- **访问者(招聘方)**:浏览候选人的职业背景,通过 AI 对话深入了解候选人,上传 JD 进行匹配分析
- **管理员(候选人)**:管理个人资料、教育/工作经历、技能等内容,配置 LLM管理访问令牌查看招聘意向消息生成定制简历
### 线上地址
| 用途 | 地址 |
|------|------|
| 主页 | `http://www.ityb.me/careerbot/` |
| 管理后台 | `http://www.ityb.me/careerbot/admin/login` |
| Gitea 代码仓库 | `http://www.ityb.me:3000` |
### 技术栈
| 层级 | 技术 |
@ -19,6 +27,7 @@ CareerBot 是一个个人职业展示网站,集成了 AI 智能对话助手。
| 认证 | JWT (管理员) / Cookie (访问者) |
| 密码加密 | bcrypt |
| 文件处理 | python-docx, PyPDF2, Pillow |
| 反向代理 | Nginx (子路径部署) |
---
@ -28,8 +37,8 @@ CareerBot 是一个个人职业展示网站,集成了 AI 智能对话助手。
CareerBot/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 应用入口,启动初始化
│ ├── config.py # Pydantic Settings 配置
│ ├── main.py # FastAPI 应用入口,路由挂载,启动初始化
│ ├── config.py # Pydantic Settings 配置(含 BASE_PATH
│ ├── database.py # SQLAlchemy 引擎、Session、init_db
│ ├── models.py # 全部 ORM 模型定义
│ ├── routers/
@ -125,6 +134,39 @@ CareerBot/
└─────────────────────┘
```
### 3.1 子路径部署架构BASE_PATH
CareerBot 部署在域名的 `/careerbot` 子路径下,通过 `BASE_PATH` 配置实现全局路径前缀管理:
```
浏览器请求: http://www.ityb.me/careerbot/api/profile
Nginx (:80)
location /careerbot/ → proxy_pass http://127.0.0.1:8000/careerbot/
FastAPI (uvicorn :8000)
app.include_router(public.router, prefix="/careerbot")
→ 匹配路由: @router.get("/api/profile")
→ 实际路径: /careerbot/api/profile
```
**前缀注入机制:**
| 层级 | 方式 | 说明 |
|------|------|------|
| Python 路由 | `app.include_router(prefix=BASE)` | 所有路由自动加前缀,路由装饰器不变 |
| 静态文件 | `app.mount(f"{BASE}/static", ...)` | CSS/JS/图片通过 `/careerbot/static/` 访问 |
| Jinja2 模板 | `templates.env.globals["base"]` | 模板中用 `{{ base }}` 引用前缀 |
| 前端 JS | `window.BASE_PATH` | 在模板中注入JS 文件通过全局变量使用 |
| RedirectResponse | `url=f"{BASE}/login"` | Python 重定向使用完整路径 |
| DB 存储路径 | `photo_url = f"{BASE}/uploads/..."` | 持久化数据中的 URL 包含前缀 |
**配置位置:**
- `app/config.py``BASE_PATH: str = "/careerbot"`
- 修改此值即可将应用迁移到其他子路径
---
## 4. 数据模型(类图)
@ -641,8 +683,11 @@ data: {"content": "", "done": true} ← 结束标记
### 前端处理逻辑 (chat.js)
```javascript
// 0. BASE_PATH 由模板注入: window.BASE_PATH = "{{ base }}"
const BASE_PATH = window.BASE_PATH || '';
// 1. POST FormData (session_id + message + file?)
const response = await fetch('/api/chat', { method: 'POST', body: formData });
const response = await fetch(BASE_PATH + '/api/chat', { method: 'POST', body: formData });
// 2. 读取 ReadableStream
const reader = response.body.getReader();
@ -696,3 +741,5 @@ while (true) {
| BackgroundTask 做意图检测 | 避免阻塞 SSE 流或导致连接异常 |
| 意图检测用独立 DB Session | BackgroundTask 执行时请求级 Session 已关闭 |
| FAB 按钮用内层 span flex | Chrome 对 button 元素的 flex 布局有渲染 bug |
| 子路径部署 + BASE_PATH | 支持同域名多项目部署,一处配置全局生效 |
| Jinja2 globals + window.BASE_PATH | 模板和静态 JS 统一获取路径前缀,避免硬编码 |

View File

@ -6,6 +6,7 @@
|------|------|
| 云服务商 | 阿里云 ECS |
| 公网 IP | `39.106.14.107` |
| 域名 | `ityb.me` / `www.ityb.me` |
| 操作系统 | Alibaba Cloud Linux 3 (OpenAnolis Edition) |
| 配置 | 2 核 CPU / 2GB 内存 / 40GB 磁盘 |
| Python 版本 | 3.11.13 |
@ -36,8 +37,9 @@ ssh root@39.106.14.107 # root 直连
| 系统 | 地址 | 账号 | 密码 |
|------|------|------|------|
| CareerBot 管理后台 | `http://39.106.14.107/admin/login` | `ln0422@gmail.com` | `qshs123456` |
| Gitea 代码管理 | `http://39.106.14.107:3000` | `ln0422` | `Qshs123456_` |
| CareerBot 主页 | `http://www.ityb.me/careerbot/` | (访问令牌或匿名) | - |
| CareerBot 管理后台 | `http://www.ityb.me/careerbot/admin/login` | `ln0422@gmail.com` | `qshs123456` |
| Gitea 代码管理 | `http://www.ityb.me:3000` | `ln0422` | `Qshs123456_` |
### 2.3 ECS 用户密码
@ -52,21 +54,24 @@ ssh root@39.106.14.107 # root 直连
## 3. 服务架构
```
外部访问
外部访问 (www.ityb.me)
┌─────────────────────────────────────────┐
│ Nginx (:80) │
│ 配置: /etc/nginx/sites-enabled/ │
│ 日志: /var/log/nginx/ │
├─────────────────────────────────────────┤
│ http://39.106.14.107/ │
│ → proxy_pass http://127.0.0.1:8000 │
│ → CareerBot (uvicorn) │
├─────────────────────────────────────────┤
│ http://39.106.14.107:3000 │
│ → Gitea (直接监听,未经 Nginx 代理) │
└─────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ Nginx (:80) │
│ 配置: /etc/nginx/sites-enabled/ │
│ 日志: /var/log/nginx/ │
├──────────────────────────────────────────────────────┤
│ http://www.ityb.me/ │
│ → 302 重定向到 /careerbot/ │
│ │
│ http://www.ityb.me/careerbot/ │
│ → proxy_pass http://127.0.0.1:8000/careerbot/ │
│ → CareerBot (uvicorn, FastAPI prefix=/careerbot) │
├──────────────────────────────────────────────────────┤
│ http://www.ityb.me:3000 │
│ → Gitea (直接监听,未经 Nginx 代理) │
└──────────────────────────────────────────────────────┘
```
### 端口使用
@ -226,12 +231,12 @@ WantedBy=multi-user.target
```nginx
server {
listen 80;
server_name 39.106.14.107;
server_name www.ityb.me ityb.me 39.106.14.107;
client_max_body_size 10M;
location / {
proxy_pass http://127.0.0.1:8000;
location /careerbot/ {
proxy_pass http://127.0.0.1:8000/careerbot/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -242,16 +247,20 @@ server {
proxy_read_timeout 300s;
}
location /uploads/ {
alias /home/deploy/apps/CareerBot/uploads/;
# 根路径重定向到 CareerBot
location = / {
return 302 /careerbot/;
}
}
```
关键配置说明:
- **子路径部署**CareerBot 部署在 `/careerbot/` 子路径下,后续其他项目可使用其他路径
- `proxy_pass` 尾部带 `/careerbot/`:将完整路径透传给 FastAPIFastAPI 通过 `prefix="/careerbot"` 匹配路由)
- `proxy_buffering off` + `proxy_cache off`**必须关闭**,否则 SSE 流式对话无法实时返回
- `proxy_read_timeout 300s`LLM 长回复可能需要较长时间
- `client_max_body_size 10M`:允许上传最大 10MB 文件
- 静态文件和上传文件通过 FastAPI StaticFiles 挂载在 `/careerbot/static/``/careerbot/uploads/`,无需单独 Nginx location
### 6.3 防火墙规则
@ -330,7 +339,7 @@ uvicorn app.main:app --host 127.0.0.1 --port 8000
### 8.2 AI 对话不工作
- 检查管理后台 LLM Config 是否已配置API URL、API Key、Model Name
- 检查管理后台`http://www.ityb.me/careerbot/admin/llm-config`LLM Config 是否已配置API URL、API Key、Model Name
- 点击 "Test Connection" 测试连通性
- 确认 ECS 能访问外网:`curl https://api.deepseek.com`
@ -364,24 +373,25 @@ ps aux --sort=-rss | head -10
后续在同一台 ECS 上部署新项目的标准流程:
1. **Gitea 上创建仓库**`http://39.106.14.107:3000` → New Repository
1. **Gitea 上创建仓库**`http://www.ityb.me:3000` → New Repository
2. **本地推送代码**
3. **ECS 上克隆并配置**
```bash
cd ~/apps
git clone http://39.106.14.107:3000/ln0422/新项目.git
git clone http://www.ityb.me:3000/ln0422/新项目.git
# 安装依赖、初始化等
```
4. **创建 systemd 服务**(参考 careerbot.service注意更换端口号
5. **添加 Nginx 站点配置**
5. **添加 Nginx 站点配置**(在同一个 `careerbot.conf` 文件或新建独立 conf 文件中,添加新的 `location /新路径/` 块)
```bash
sudo vim /etc/nginx/sites-available/新项目.conf
sudo ln -s /etc/nginx/sites-available/新项目.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
> 建议参考 CareerBot 的子路径部署模式:`location /新路径/ { proxy_pass http://127.0.0.1:新端口/新路径/; }`
6. **如需新端口**:防火墙 + 阿里云安全组同步放行
@ -393,4 +403,4 @@ ps aux --sort=-rss | head -10
2. **Gitea 端口**3000 端口对外开放,建议设置强密码,或后续通过 Nginx 代理并限制访问
3. **数据库文件**`careerbot.db` 不应对外暴露uvicorn 仅监听 127.0.0.1 已确保安全
4. **定期更新**:定期执行 `sudo dnf update -y` 更新系统安全补丁
5. **HTTPS**后续绑定域名后建议配置 Let's Encrypt SSL 证书
5. **HTTPS**域名 `ityb.me` 已绑定,建议配置 Let's Encrypt SSL 证书(`certbot --nginx -d www.ityb.me -d ityb.me`