chore(deploy): 移除 Docker 配置与文档中的部署方案,待从代码重议

This commit is contained in:
2026-10-12 19:02:38 +08:00
parent 9966f03347
commit 86782c63ad
13 changed files with 13 additions and 254 deletions
-17
View File
@@ -1,17 +0,0 @@
.git
.env
.env.*
!.env.example
node_modules
**/node_modules
**/dist
**/.tmp
**/.vite
*.log
api*.json
session-archive
coverage
*.tsbuildinfo
.claude
.agents
agent
+2 -4
View File
@@ -1,14 +1,12 @@
# ── new-api-key-usage · 环境变量示例 ──────────────────────────
# 复制为 .env 后填写(.env 已被 .gitignore,勿提交)
# 开发:任意可用的 PostgreSQL,DATABASE_URL 指向即可
# 部署:docker compose up -d --build(见 README)
# 本服务端口(避开 3000/3001 等常见占用;容器内固定 18456 即可)
# 本服务端口(避开 3000/3001 等常见占用)
PORT=18456
# PostgreSQL 连接串——数据库配置的唯一来源
# 开发:指向你本机/已有的库(主机 127.0.0.1 或 localhost)
# 部署:同一份即可;compose 会把主机改写为容器服务名 postgres
# 指向你本机/已有的库(主机 127.0.0.1 或 localhost)
# 密码含 @ : / 等字符时请 URL 编码
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/new_api_key_usage
-2
View File
@@ -8,7 +8,6 @@
- **命名**:需求 / 设计 / 交互 / 技术 / 计划等**文档名**用中文(`README` / `AGENTS` / `LICENSE` 等约定俗成除外)、**目录**用英文;新文档按性质放入 `docs/design/`(我们定的方案与决策)或 `docs/references/`(平台可用接口参考——实证事实,不做设计决策),并同步更新 README 的「文档地图」;`docs/deprecated/` 只归档已废弃文档——**勿引用、勿作依据**(需要时再建)
- **代码文件命名**:所有**目录名与文件名**一律 kebab-case(如 `time-range-picker.vue` · `admin-session.ts`);**组件在模板中引用时用大驼峰**(`<TimeRangePicker />`)——文件名 kebab、模板标签 PascalCase
- **文档状态**:头部表格标「状态」(草案 → 讨论中 → 待审阅 → 定稿(日期) → 已实现);设计文档定稿后不搬家、只改状态;被取代时删除(git 历史即考古)
- **部署**:交付物必须保证「一条命令链」可部署;**双形态并行已裁决**——完整前后端(运营方服务器)先行,Cloudflare Workers 抽取版(作者自部署)后续(见 `docs/design/需求清单.md` R13)
- **不引入版本叙事**:不使用 v1/v2/v3 之类版本编号,不以「MVP」等标签或指称显式描述任何历史阶段;文档内容必须**自立**——不得引用、描述任何当前仓库之外、可能被删除的分支或目录内容
- **本地不入库也不 ignore 的物料**(AI 提交时务必避开):`api*.json`(上游实测快照)、`session-archive/`(作者主动备份的会话记录)——不加入 git、不写 `.gitignore`,靠提交时人工/执行者目视把关
@@ -34,7 +33,6 @@ Bun 工具链(选型见 `docs/design/技术选型.md`)。**Windows 上 `bun`
| `bun run dev:engine` | 开发跑同步引擎(独立进程,读 `SYNC_*` env) |
| `bun run dev:web` | 开发跑前端 Vite |
| `bun run build:web` | 前端类型检查 + 产物构建 |
| `docker compose up -d --build` | 部署一键起(server / engine / caddy / pg) |
环境变量见 `.env.example`(复制为 `.env` 后填写)。
-37
View File
@@ -1,37 +0,0 @@
# 语法:docker/dockerfile:1
# 构建产物:/app/naku-server · /app/naku-engine · /app/drizzle · /srv(前端)
# ---------- 构建:依赖 + 前端 + 两个单文件 ----------
FROM oven/bun:1.4-alpine AS build
WORKDIR /src
COPY package.json bun.lock ./
COPY apps ./apps
COPY packages ./packages
RUN bun install --frozen-lockfile
# 前端静态资源
RUN bun run --cwd apps/web build-only
# 单文件(linux-x64;构建发生在 Linux 容器内,无需交叉编译)
RUN mkdir -p /out \
&& bun build --compile --outfile /out/naku-server apps/server/src/index.ts \
&& bun build --compile --outfile /out/naku-engine apps/engine/src/index.ts
# ---------- 应用运行时:两个二进制 + 迁移 SQL ----------
FROM alpine:3.20 AS app
WORKDIR /app
# Bun 单文件仍需 C++ 运行时与 CA;从构建镜像拷贝,避免 apk 联网
COPY --from=build /usr/lib/libstdc++.so.6 /usr/lib/libgcc_s.so.1 /usr/lib/
COPY --from=build /etc/ssl/certs /etc/ssl/certs
COPY --from=build /out/naku-server /out/naku-engine /app/
COPY --from=build /src/packages/db/drizzle /app/drizzle
ENV MIGRATIONS_FOLDER=/app/drizzle
# 默认跑 server;compose 里 engine 覆盖 command
CMD ["/app/naku-server"]
# ---------- 网关:Caddy + 前端静态资源 ----------
FROM caddy:2-alpine AS proxy
COPY deploy/Caddyfile /etc/caddy/Caddyfile
COPY --from=build /src/apps/web/dist /srv
+1 -54
View File
@@ -6,7 +6,7 @@
| 项目 | 内容 |
|------|------|
| 当前状态 | **实现推进中**——设计文档主体定稿;后端 + 同步引擎 + 前端(管理面与成员视图)已落地;部署链与衍生形态待收尾 |
| 当前状态 | **实现推进中**——设计文档主体定稿;后端 + 同步引擎 + 前端(管理面与成员视图)已落地;部署方案与衍生形态待定 |
| 技术栈 | 全栈 TypeScript(选型见 [`docs/design/技术选型.md`](docs/design/技术选型.md)):Bun + Hono + Drizzle + PostgreSQL · 前端 Vue 3 + antdv-next |
## 这是什么
@@ -79,59 +79,6 @@ bun run dev:web # 前端 Vite(5175)
更多命令与协作约定见 [`AGENTS.md`](AGENTS.md)。
## 部署
生产形态:**Caddy**(前端静态 + `/api` 反代)+ **server / engine 单文件**(Bun `--compile`)+ PostgreSQL。**迁移不随服务启动**——改表后先用 `db:push` / 手动应用 SQL,再起服务。开发不依赖本 Compose——把 `DATABASE_URL` 指到任意可用 PostgreSQL 即可。
### 起服务
```bash
cp .env.example .env
# 必改:DATABASE_URL、SK_KEY_ENCRYPTION_SECRET、NEWAPI_BASE、COOKIE_SECURE
docker compose up -d --build
```
- 页面:`http://<服务器>/`;接口文档:`http://<服务器>/api/docs`
- 升级:`git pull` → 有表变更时先应用 schema → 再 `docker compose up -d --build`
### 环境变量要点
| 变量 | 说明 |
|------|------|
| `DATABASE_URL` | 数据库配置的**唯一来源**(用户 / 密码 / 库名都在串里)。开发指向本机库;部署同一份即可,compose 会把主机改写为容器服务名 `postgres` |
| `SK_KEY_ENCRYPTION_SECRET` | ≥32 字节随机数(base64url)。**生成一次、入库后不可更换**——丢失则已登记 key 无法解密,与库同等备份 |
| `NEWAPI_BASE` | 上游 NewAPI 实例根地址 |
| `COOKIE_SECURE` | HTTPS / 域名用 `true`;纯 IP + HTTP 用 `false`(否则登录后立刻 401) |
| `ADMIN_INIT_USERNAME` / `ADMIN_INIT_PASSWORD` | 可选;同时存在时空库首次静默建管理员 |
### 服务分工
| 服务 | 职责 | 对外 |
|------|------|------|
| `caddy` | 前端静态 + `/api` 反代 | 仅 80 / 443 |
| `server` | 管理面 / 成员视图 API | 内网 |
| `engine` | 轮询上游、去重入库 | 内网 |
| `postgres` | 数据(卷 `pgdata`) | 内网 |
### HTTPS
把 `deploy/Caddyfile` 站点行从 `:80` 改成域名(如 `your.domain.example`),重建后 Caddy 自动签证书;同时设 `COOKIE_SECURE=true`。
### 常用命令
```bash
docker compose ps # 运行状态
docker compose logs -f engine # 看同步
docker compose restart server # 只重启后端
docker compose down # 全停(数据在卷里,不丢)
```
### 注意
1. `COOKIE_SECURE` 必须与访问方式匹配:HTTP + `true` 会「登录后立刻 401」
2. `SK_KEY_ENCRYPTION_SECRET` 更换等于已登记 key 全部作废
3. `DATABASE_URL` 密码含 `@` `:` `/` 等字符时做 URL 编码
## 文档地图
| 文档 | 什么时候读 | 状态 |
-17
View File
@@ -1,17 +0,0 @@
# 站点地址按部署环境改:
# 本地/内网 HTTP → :80
# 公网 HTTPS → your.domain.example(Caddy 自动签证书)
:80 {
root * /srv
# 接口反代到 server 容器
handle /api/* {
reverse_proxy server:18456
}
# SPA:非 /api 的路径回退 index.html
handle {
try_files {path} /index.html
file_server
}
}
-12
View File
@@ -1,12 +0,0 @@
#!/bin/sh
# 把 DATABASE_URL 的主机改写为 compose 服务名 postgres,再启动应用
set -e
if [ -z "$DATABASE_URL" ]; then
echo "DATABASE_URL is required" >&2
exit 1
fi
export DATABASE_URL="$(echo "$DATABASE_URL" | sed -E 's#(@)[^:/]+(:[0-9]+)?(/)#\1postgres\2\3#')"
exec "$@"
-19
View File
@@ -1,19 +0,0 @@
#!/bin/sh
# 从 DATABASE_URL 拆出官方镜像建库所需的 POSTGRES_*,再交回原入口
set -e
if [ -z "$DATABASE_URL" ]; then
echo "DATABASE_URL is required" >&2
exit 1
fi
u="${DATABASE_URL#*://}"
auth="${u%%@*}"
rest="${u#*@}"
export POSTGRES_USER="${auth%%:*}"
export POSTGRES_PASSWORD="${auth#*:}"
export POSTGRES_DB="${rest#*/}"
export POSTGRES_DB="${POSTGRES_DB%%\?*}"
exec docker-entrypoint.sh postgres
-76
View File
@@ -1,76 +0,0 @@
# 部署一键起:docker compose up -d --build
# 配置只认 DATABASE_URL(见 .env.example);开发不依赖本文件
# 注意:PASSWORD 含 @ : / 等字符时需 URL 编码
services:
postgres:
image: postgres:17-alpine
entrypoint: ["/bin/sh", "/entrypoint-pg.sh"]
environment:
DATABASE_URL: ${DATABASE_URL:?set DATABASE_URL in .env}
volumes:
- ./deploy/entrypoint-pg.sh:/entrypoint-pg.sh:ro
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$(echo $$DATABASE_URL | sed -E 's#^[^:]+://([^:]+):.*#\\1#')"]
interval: 5s
timeout: 3s
retries: 12
restart: unless-stopped
server:
build:
context: .
target: app
entrypoint: ["/bin/sh", "/entrypoint-app.sh"]
command: ["/app/naku-server"]
environment:
PORT: "18456"
DATABASE_URL: ${DATABASE_URL}
SK_KEY_ENCRYPTION_SECRET: ${SK_KEY_ENCRYPTION_SECRET:?set SK_KEY_ENCRYPTION_SECRET in .env}
NEWAPI_BASE: ${NEWAPI_BASE:?set NEWAPI_BASE in .env}
COOKIE_SECURE: ${COOKIE_SECURE:-true}
LOG_LEVEL: ${LOG_LEVEL:-info}
ADMIN_INIT_USERNAME: ${ADMIN_INIT_USERNAME:-}
ADMIN_INIT_PASSWORD: ${ADMIN_INIT_PASSWORD:-}
MIGRATIONS_FOLDER: /app/drizzle
volumes:
- ./deploy/entrypoint-app.sh:/entrypoint-app.sh:ro
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
engine:
build:
context: .
target: app
entrypoint: ["/bin/sh", "/entrypoint-app.sh"]
command: ["/app/naku-engine"]
environment:
DATABASE_URL: ${DATABASE_URL}
SK_KEY_ENCRYPTION_SECRET: ${SK_KEY_ENCRYPTION_SECRET}
NEWAPI_BASE: ${NEWAPI_BASE}
SYNC_INTERVAL_MS: ${SYNC_INTERVAL_MS:-300000}
LOG_LEVEL: ${LOG_LEVEL:-info}
MIGRATIONS_FOLDER: /app/drizzle
volumes:
- ./deploy/entrypoint-app.sh:/entrypoint-app.sh:ro
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
caddy:
build:
context: .
target: proxy
ports:
- "80:80"
- "443:443"
depends_on:
- server
restart: unless-stopped
volumes:
pgdata:
+1 -1
View File
@@ -27,7 +27,7 @@
- **会话 cookie**:`HttpOnly + Secure + SameSite=Lax`,`Path=/api/admin`(「路径限管理面」裁决的落地);随请求自动携带、登出即删行
- **成员令牌**:`Authorization: Bearer <token>`;明文令牌只存在于登录壳输入与 sessionStorage(关标签即失效——《交互设计-登录与会话》§4)
- 401 分流为前端职责:管理面任意 401 → 登录页「会话已过期」;成员视图任意 401 → 登录壳「令牌无效或已停用」——后端 401 响应不带面特化信息,前端按所在面分流(共性 §1)
- **命名空间约定:`/api/*` 专属接口**——前端页面路由永不进入 `/api` 前缀;未知 `/api/*` 路径 = 接口 `404` 错误信封,非 `/api` 请求归前端托管(SPA history 回退「非 `/api` → index.html」,细则归骨架与部署设计)
- **命名空间约定:`/api/*` 专属接口**——前端页面路由永不进入 `/api` 前缀;未知 `/api/*` 路径 = 接口 `404` 错误信封,非 `/api` 请求归前端托管(SPA history 回退「非 `/api` → index.html」,细则归骨架设计)
## 3. 错误信封
+1 -1
View File
@@ -55,7 +55,7 @@
- `key_hash`(HMAC-SHA256,不可逆):只服务「命中判定」——没有它,每次查询都要把全部 key 送去上游验证
- `key_ciphertext`(AES-256-GCM,可解密):唯一用途是调上游
- 密钥 `SK_KEY_ENCRYPTION_SECRET` 经 env 注入(HKDF 派生 hmac / aes 子密钥);**密钥丢失 = 全部 key 需重新登记**(记入部署文档)
- 密钥 `SK_KEY_ENCRYPTION_SECRET` 经 env 注入(HKDF 派生 hmac / aes 子密钥);**密钥丢失 = 全部 key 需重新登记**
> **注解:为什么是两个字段(给非密码学背景的读者)**
>
+2 -2
View File
@@ -26,7 +26,7 @@ apps/engine ──► 定时 syncRound() ──► packages/db
| 共享 | `packages/core`(上游客户端、dedupe、折算)· `packages/db`(仓储)——**业务能力仍一份** |
| 不共享 | 进程内存、事件循环、调度器;HTTP 与引擎**互不调用** |
| 不调自家 API | 引擎只打上游 NewAPI + 写库;不走 `/api/admin/*` |
| 部署 | 开发:两个命令(`dev:server` / `dev:engine`);生产 compose 两个 service(均连同一 PostgreSQL) |
| 运行形态 | 开发:两个命令(`dev:server` / `dev:engine`);生产两个进程(均连同一 PostgreSQL) |
**为何分进程(2026-10-05 复审)**:一轮可能解析上千条日志并做指纹/加密/批量写,若与 API 同进程会争事件循环,查询延迟与「引擎是否在跑」绑死;定时器漂移本身对本业务无害,**互扰才是拆分动因**。
@@ -174,7 +174,7 @@ apps/
## 9. 验收清单(实现后)
- [ ] 只启 `dev:engine`(或 compose 仅 engine+db):日志入库、`log_synced_at` 前进
- [ ] 只启 `dev:engine`(或只跑 engine + db):日志入库、`log_synced_at` 前进
- [ ] 只启 `dev:server`:HTTP 正常,无轮询日志
- [ ] 同一数据重复轮次不产生重复行
- [ ] 某 key 401:其余 key 正常;`engine_status.last_round.failed_api_key_ids` 含之
+6 -12
View File
@@ -22,7 +22,6 @@
| 调度 | **独立进程 `apps/engine`**:手写 `setTimeout` 循环(细则见《同步引擎设计》) |
| 加密 | WebCrypto(Bun 原生) |
| 前端 | **Vue 3 + antdv-next + Vite** |
| 部署 | **Docker**(倾向,§6) |
## 2. 语言:TypeScript 全栈
@@ -39,7 +38,7 @@
| 数据访问 | **Drizzle ORM** | TS 优先、查询保持 SQL 形态(不藏 SQL,利于学与审计);schema 即代码,drizzle-kit 迁移配套齐全 | Kysely / 裸驱动 + 手写仓储 |
| pg 驱动 | **postgres.js** | Drizzle 文档主推;查询构建器式 API;内置连接池;Bun 兼容好 | node-postgres |
| 前端框架 | **Vue 3** | 作者近年常用栈;实现期自由度(共性 §3.5「作者即前端」) | — |
| 组件库 | **antdv-next**(作者指定尝试项) | Vue 3 企业组件库、对齐 ant-design(React 上游)设计体系;**已核验通过**(§7.1):活跃周更、§3.7 清单逐项有对应组件、Agent 文档齐备 | Element Plus / ant-design-vue(§3.7 全覆盖) |
| 组件库 | **antdv-next**(作者指定尝试项) | Vue 3 企业组件库、对齐 ant-design(React 上游)设计体系;**已核验通过**(§6.1):活跃周更、§3.7 清单逐项有对应组件、Agent 文档齐备 | Element Plus / ant-design-vue(§3.7 全覆盖) |
| 加密 | **WebCrypto** | HKDF / AES-256-GCM / HMAC-SHA256 / PBKDF2 与裁决一致(密钥体系见各表设计);Bun 原生 | HKDF 若 Bun 覆盖滞后:基于 HMAC 的纯 TS 垫片(同原语) |
| 构建 / 测试 | **Vite**(web);质量门 = `typecheck` + `build` + 人工验收 | 前端构建走 Vite 生态默认;自动化测试不在当前范围 | 需要时再引入测试框架 |
| API 文档与校验 | **zod** + **@hono/zod-openapi** + **Scalar**(作者确认) | 一源三用:TS 类型 / 请求校验(`422` 与 `fields` 的机器来源)/ OpenAPI 生成;Scalar 为 Hono 官方搭档,规范与渲染器解耦 | Swagger UI(规范不动、换皮即可) |
@@ -69,19 +68,15 @@ R13 的 CFW 抽取版仍是长期裁决,功能全集实现后启动,届时
Hono(双运行时可跑)与 WebCrypto 本身恰好与 CFW 兼容,属顺手之得,不构成现阶段约束。
## 6. 部署通道(倾向,细则归后续部署设计)
母体以 **Docker 镜像**交付(server 容器 + PostgreSQL,compose 编排):满足仓库「一条命令链可部署」约定;运营方服务器零环境依赖(Bun 运行时随镜像内置),升级 = 换镜像重启;作者不接触服务器,镜像化把运行时选择与运营方环境解耦。
## 7. 风险与回退
## 6. 风险与回退
| 风险 | 评估 | 对策 |
|------|------|------|
| antdv-next 项目年轻、维护者 3 人 | 桌面核验通过(§7.1);未核验项:社区采用规模 | 实现期第一步做 **§3.7 能力 spike**(实测);锁版本;实测不满足即触发回退(Element Plus / ant-design-vue) |
| antdv-next 项目年轻、维护者 3 人 | 桌面核验通过(§6.1);未核验项:社区采用规模 | 实现期第一步做 **§3.7 能力 spike**(实测);锁版本;实测不满足即触发回退(Element Plus / ant-design-vue) |
| Bun 生态资料少于 Node、边角兼容性 | 本项目规模小、依赖面窄(Hono / Drizzle / postgres.js 均成熟) | **Bun → Node 回退不伤业务代码**:换 `@hono/node-server` 装配即可,packages/* 原样 |
| Bun 的 WebCrypto 原语覆盖(HKDF 等) | 未逐项实测 | 实现期首轮加密任务实测;缺失则 HMAC 纯 TS 垫片 |
### 7.1 antdv-next 核验记录(2026-10-02,一手源直查)
### 6.1 antdv-next 核验记录(2026-10-02,一手源直查)
口径:npm registry / GitHub API / 官网 llms.txt 直查(当轮无浏览器检索通道——社区口碑与采用规模未核验)。
@@ -96,7 +91,6 @@ Hono(双运行时可跑)与 WebCrypto 本身恰好与 CFW 兼容,属顺手
结论:**通过核验,维持选定**;§3.7 spike 与回退预案照旧——桌面核验不替代实测。
## 8. 待裁决项
## 7. 待裁决项
1. Docker 细则:基础镜像、compose 形态、密钥注入方式——部署设计时定;
2. 前端测试设施是否引入 vitest。
1. 前端测试设施是否引入 vitest。