Phase 3: T-301~T-304 SEO/部署/SQLite/统计/MVP验收完成(42 tests)

This commit is contained in:
ila
2026-07-06 23:32:57 +08:00
parent 6dd1711164
commit dcc626544c
9 changed files with 293 additions and 13 deletions
+4 -4
View File
@@ -51,10 +51,10 @@
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-301 | 补 SEO 基础 | T-205, T-206 | 核心页面有 title、description、canonical 或等价设置;sitemap 可用 | DONE |
| T-302 | 补部署文档 | T-301 | 2 核 2G VPS 上 Gunicorn + Nginx + SQLite 的部署步骤清楚 | DOING |
| T-303 | SQLite 上线检查 | T-302 | JSON1 验证、WAL 启用、备份策略和 PostgreSQL 迁移触发条件已记录 | TODO |
| T-305 | 接入轻量访问统计与外链点击记录 | T-301 | Plausible / Umami 或等价方案接入;外部链接点击可统计;不引入重量级分析 SDK;这是里程碑 M3(SEO 验证)和 M4(Affiliate)的数据前置 | TODO |
| T-304 | MVP 完整验收 | T-303, T-305 | `02-requirements.md` 的 P0 验收全部通过,验证命令和结果写入 `progress.md` | TODO |
| T-302 | 补部署文档 | T-301 | 2 核 2G VPS 上 Gunicorn + Nginx + SQLite 的部署步骤清楚 | DONE |
| T-303 | SQLite 上线检查 | T-302 | JSON1 验证、WAL 启用、备份策略和 PostgreSQL 迁移触发条件已记录 | DONE |
| T-305 | 接入轻量访问统计与外链点击记录 | T-301 | Plausible / Umami 或等价方案接入;外部链接点击可统计;不引入重量级分析 SDK;这是里程碑 M3(SEO 验证)和 M4(Affiliate)的数据前置 | DONE |
| T-304 | MVP 完整验收 | T-303, T-305 | `02-requirements.md` 的 P0 验收全部通过,验证命令和结果写入 `progress.md` | DONE |
## 任务详单
+5 -5
View File
@@ -11,14 +11,14 @@
## 当前快照
- 日期:2026-07-06
- 阶段:Phase 2(前台 MVP)已完成,T-201 至 T-206 全部实现
- 阶段:MVP 全部完成(Phase 0-3),T-000 至 T-304 已实现并验收
- 开发环境:MSYS2/MinGW Python 3.12.12,venv 使用 `--system-site-packages`(Pillow 由 MSYS2 预编译包提供)
- git:分支 `ds`;`.gitignore` 已生效(`.venv/`、`db.sqlite3`、`media/` 等被忽略)
- 技术栈:Wagtail 7.4.2 + Django 6.0.6 + Python 3.12 + SQLite;第一版英文单语言站点
- 生产代码:已初始化,`manage.py`、`skelet/`、`home/`、`search/`、`core/` 已建
- 测试:31 个测试(`home/tests.py` + `core/tests.py`),全部通过;`manage.py test` 可运行
- 测试:42 个测试,全部通过;`manage.py test` 可运行
- 数据:3 个场景、5 个骨架项目、2 篇文章已录入(`core/management/commands/seed_data.py`)
- 当前 blocker:无;下一步执行 `T-301`(Phase 3 SEO 与上线准备)
- 当前 blocker:无(MVP 已完成)
## 当前目录要点
@@ -42,9 +42,9 @@
## 任务看板状态
- 已完成:T-000 至 T-104(Phase 0+1)、T-201 至 T-206(Phase 2)。
- 已完成:T-000 至 T-304(MVP 全部完成)。
- 正在进行:无。
- 下一个可领取任务:`T-301 补 SEO 基础`(Phase 3)。
- Backlog:查看 `docs/06-tasks.md` Backlog 节。
## 当前可运行内容
+210
View File
@@ -0,0 +1,210 @@
# 部署指南
> 适用于 2 核 2G VPS(Ubuntu 22.04/24.04),Gunicorn + Nginx + SQLite。
## 前置条件
```bash
# 确保系统已安装
python3.12 --version # Python 3.12+
git --version # Git
nginx -v # Nginx
# 如缺少 Python 3.12:
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.12 python3.12-venv python3.12-dev
```
## 一、应用部署
```bash
# 1. 克隆仓库
git clone http://ilaer.eicp.net:8418/opc/skelet.git /var/www/skelet
cd /var/www/skelet
# 2. 创建虚拟环境
python3.12 -m venv .venv
source .venv/bin/activate
# 3. 安装依赖
pip install -r requirements.txt
pip install gunicorn
# 4. 配置环境变量
cp .env.example .env
# 编辑 .env 填写真实密钥
export $(cat .env | xargs)
# 5. 静态文件收集 & 数据库迁移 & 种子数据
python manage.py collectstatic --noinput
python manage.py migrate
python manage.py createsuperuser
python manage.py seed_data --clear
# 6. 测试应用可运行
python manage.py check
```
## 二、Gunicorn Systemd Service
```bash
# /etc/systemd/system/skelet.service
[Unit]
Description=Skelet Gunicorn daemon
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/skelet
EnvironmentFile=/var/www/skelet/.env
ExecStart=/var/www/skelet/.venv/bin/gunicorn \
--workers 2 \
--bind unix:/var/www/skelet/run/gunicorn.sock \
--access-logfile /var/log/skelet/access.log \
--error-logfile /var/log/skelet/error.log \
skelet.wsgi:application
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
```bash
mkdir -p /var/www/skelet/run /var/log/skelet
chown -R www-data:www-data /var/www/skelet /var/log/skelet
chmod 755 /var/www/skelet/.venv/bin/gunicorn
systemctl daemon-reload
systemctl enable skelet
systemctl start skelet
systemctl status skelet
```
## 三、Nginx 配置
```nginx
# /etc/nginx/sites-available/skelet
server {
listen 80;
server_name yourdomain.com;
client_max_body_size 20M;
location /static/ {
alias /var/www/skelet/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/skelet/media/;
}
location / {
include proxy_params;
proxy_pass http://unix:/var/www/skelet/run/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
```bash
ln -s /etc/nginx/sites-available/skelet /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
```
## 四、SQLite 上线检查(T-303)
### JSON1 支持验证
```bash
python -c "import sqlite3; c=sqlite3.connect(':memory:'); c.execute('SELECT json(\'{\"a\":1}\')'); print('JSON1 supported')"
```
### 启用 WAL 模式
```bash
python manage.py dbshell
.journal_mode WAL;
.quit
```
验证:
```bash
python manage.py dbshell -- -cmd "PRAGMA journal_mode;"
# 输出 wal
```
### 备份策略
```bash
# 每日备份脚本(crontab:0 3 * * * /root/backup-skelet.sh)
#!/bin/bash
BACKUP_DIR=/var/backups/skelet
mkdir -p "$BACKUP_DIR"
DATE=$(date +%Y%m%d-%H%M%S)
# 备份数据库(生产环境先暂停写入)
sqlite3 /var/www/skelet/db.sqlite3 ".backup '$BACKUP_DIR/db-$DATE.sqlite3'"
# 备份 media 文件
tar -czf "$BACKUP_DIR/media-$DATE.tar.gz" -C /var/www/skelet media/
# 保留最近 30 天备份
find "$BACKUP_DIR" -name 'db-*.sqlite3' -mtime +30 -delete
find "$BACKUP_DIR" -name 'media-*.tar.gz' -mtime +30 -delete
```
### PostgreSQL 迁移触发条件
当前使用 SQLite(读多写少场景足够)。当出现以下任一情况时,应迁移 PostgreSQL:
- 后台多人同时编辑时出现 `database is locked`
- 预计日均写入请求超过 100 次
- 索引无法加速复杂筛选查询
- 上线了用户提交、评论、收藏、会员等前台写入功能
迁移方式:
```bash
# 1. 使用 pgloader 迁移数据
# 2. 更新 settings/production.py 数据库配置至 PostgreSQL
# 3. 设置环境变量 DATABASE_URL=postgres://user:pass@host/db
```
## 五、日常维护
### 重启应用
```bash
systemctl restart skelet
```
### 重新加载 Nginx
```bash
systemctl reload nginx
```
### 回滚部署
```bash
cd /var/www/skelet
git revert HEAD
systemctl restart skelet
```
### 查看日志
```bash
journalctl -u skelet -n 50
tail -f /var/log/skelet/error.log
```