feat: 交付官方 Docker 运行时,外观改背景图并下线自定义 CSS/JS

站点/后台分轨背景与用户列表排序一并落地;生产 CORS 改走 SITE_URL,健康检查带版本号。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-18 05:27:33 +08:00
parent 5f7193042f
commit d784b0ea7a
68 changed files with 2588 additions and 768 deletions

90
deploy/CONTRACT.md Normal file
View File

@@ -0,0 +1,90 @@
# 官方运行时契约
变更本文件中的服务名、端口、volume、环境变量,视为**运行时大版本**,须在 changelog 写明,并给出最低可升级的应用版本。不要为了省事改本地开发的 `start.bat` / 仓库根 `docker-compose.yml`。
当前应用版本见仓库根 `VERSION`(现 `0.1.0`)。最低可升级版本:无(首个官方运行时)。
## 与本地开发的边界
| | 本地开发 | 官方运行时 |
|--|----------|------------|
| Compose | 仓库根 `docker-compose.yml`,只起 Postgres,映射 `5432` | `deploy/docker-compose.yml`,项目名 `jiang13` |
| 后端 | `cd backend && go run ./cmd/jiang13`,数据 `backend/data/` | 容器 `api`,`JIANG13_WORK_PATH=/var/lib/jiang13` |
| 前端 | `cd frontend && npm run dev`,`:3000` | 容器 `web`,Next standalone `:3000` |
| 入口 | 浏览器 `http://localhost:3000` | 宿主机反代(Nginx 等)同源反代 `127.0.0.1:3000` + `127.0.0.1:3001` |
两套 Postgres volume 名字空间不同,可以并存,互不覆盖。官方 Compose **不包含**反代容器。
## 服务名(Compose)
- `postgres` — PostgreSQL 17(不映射宿主机 5432)
- `api` — Go,容器内 `3001`,默认发布 `127.0.0.1:3001`
- `web` — Next.js standalone,容器内 `3000`,默认发布 `127.0.0.1:3000`
禁止把 API 单独做到另一个子域。`/api` 与 `/api/ws` 必须由反代直达 `api`,不能进 Next(Upgrade 无法经 Next rewrite)。
## Volume
| 名 | 容器路径 | 内容 |
|----|----------|------|
| `pgdata` | `/var/lib/postgresql/data` | 数据库 |
| `appdata` | `/var/lib/jiang13/data` | 上传、`private/` 附件、`.jwt_secret` |
镜像内不放真实 `app.ini`、不放用户数据。
## 环境变量
### api
| 变量 | 必需 | 说明 |
|------|------|------|
| `HTTP_PORT` | 否 | 默认 `3001` |
| `DEV_MODE` | 是(Compose 写死 `false`) | 生产 cookie 走 `__Host-`,须反代 HTTPS |
| `JIANG13_WORK_PATH` | 是 | 固定 `/var/lib/jiang13` |
| `DATA_DIR` | 是 | 固定 `/var/lib/jiang13/data` |
| `DB_DSN` | 是 | 指向服务名 `postgres` |
| `JWT_SECRET` | 是 | 强随机;勿依赖自动生成做多副本 |
| `SITE_URL` | 建议 | 对外 origin,无尾斜杠,如 `https://bbs.example.com` |
| `CORS_ORIGINS` | 否 | 额外 origin,逗号分隔 |
### web
| 变量 | 必需 | 说明 |
|------|------|------|
| `BACKEND_URL` | 是 | 固定 `http://api:3001`(SSR / middleware,勿写成公网 URL) |
| `PORT` / `HOSTNAME` | 否 | `3000` / `0.0.0.0` |
| `NEXT_PUBLIC_APP_VERSION` | 构建期 | 与 `VERSION` 相同;**不要**设置 `NEXT_PUBLIC_API_URL=http://api:3001`(会泄漏到浏览器) |
浏览器 API 走同源 `/api/*`(由宿主机反代直达 Go)。WebSocket 走同源 `/api/ws`,不要设 `NEXT_PUBLIC_WS_URL`。
### 宿主机发布
| 变量 | 默认 | 说明 |
|------|------|------|
| `JIANG13_BIND` | `127.0.0.1` | 只给本机反代;需要对外直连再改 |
| `JIANG13_WEB_PORT` | `3000` | web 宿主机端口 |
| `JIANG13_API_PORT` | `3001` | api 宿主机端口 |
### 镜像 tag
`JIANG13_VERSION` 同时作为 `api`/`web` 镜像 tag。`JIANG13_IMAGE_API` / `JIANG13_IMAGE_WEB` 默认为本地名;推仓库后改成 registry 路径即可 `docker compose pull`。
`POSTGRES_PASSWORD` 会拼进 `DB_DSN`,不要包含 `@ : / # ?` 等 URL 保留字符。
## 健康检查
- `api`:`GET http://127.0.0.1:3001/health`(含 DB ping、`version`)
- `web`:`GET http://127.0.0.1:3000/healthz`(不访问后端)
## 更新
应用升级:换同一契约下的新镜像 tag,然后:
```
docker compose pull
docker compose up -d
```
新 `api` 启动时执行既有 `AutoMigrate`。接受短暂停机。上线前不为双版本并存写兼容垫片。
改 Compose / 环境变量 / volume 路径属于运行时升级,不能只 pull。