- 删除 1panel-app/echo/{1.5.0,1.5.1,1.5.2}/ 三个旧版本目录
- README.md:1.5.3 目录注释不再提及"另含 1.5.0-1.5.2 历史版本"
- 产品说明书.md §14.1:目录注释同步
- echo-1panel-deploy.md §一:版本目录注释同步
- Node24升级执行规划.md §2.1/§4.4:1panel 路径引用从 1.5.0 改为 1.5.3
历史 RELEASE_NOTES / CodeReview §14.7 / 版本历史表中的 v1.5.0-1.5.2
引用属于历史事实描述,保留不变
Echo · 忆刻 · 个人知识语义搜索引擎
当前版本:v1.5.3(2026-09-05)—— 版本号同步 + Node 24 落地 + CI 全面迁移至 Gitea Actions
当前默认开发分支:
developCI 说明:GitHub Actions 已弃用(2026-09-05 起),CI 仅在自托管 Gitea(git.arutera.top)的 Actions 中运行,构建产物推送到本地 Docker Registry(localhost:5000)。GitHub 与 Gitea 双远端同步推送,GitHub 仅作代码托管/备份。
1. 项目简介
Echo · 忆刻 是一个面向个人的知识聚合与语义检索引擎。它将分散在多个外部系统(Nextcloud 笔记、Gitea 代码提交等)中的内容统一汇聚到一个可搜索的知识库,提供基于向量语义的智能搜索、按时间倒序的时间轴视图,以及对已删除文件的回收站机制。
核心价值
- 语义搜索:基于通义千问(DashScope)
qwen3.7-text-embedding生成 2560 维向量,通过 pgvector(halfvec)做余弦相似度检索,能命中「意思相近但字面不同」的内容(如搜「部署」可找到含「上线 / 发布」的笔记)。 - 混合检索:关键词 ILIKE 路 + 语义向量路并行,RRF 融合排序——精确字面命中(文件名、版本号、专有名词)与语义相近结果同时保留。
- 高可用降级:向量服务不可用时自动降级为关键词匹配,保证搜索功能始终可用。
- 多源聚合:通过统一的 Syncer 接口接入 Nextcloud、Gitea 等数据源,新增数据源只需实现接口即可被路由统一调度。
- 回收站(v1.4.1 起):WebDAV 已删除文件做软删除 + 可恢复快照,超期自动清理。
- 静态密码 + httpOnly Cookie(v1.5.0 起):去除 Supabase 会话刷新、双客户端模型,认证链路极致简化。
技术栈(v1.5.0)
| 类别 | 技术 |
|---|---|
| 前端框架 | Next.js 16(App Router,Turbopack)+ React 19 |
| 语言 | TypeScript(严格模式) |
| 样式 | Tailwind CSS v4 |
| UI 组件 | shadcn/ui(New York 风格)+ lucide-react 图标 |
| ORM | Drizzle ORM 0.45 + node-postgres (pg) 8.23 |
| 迁移 | drizzle-kit 0.31(登记式应用) |
| 数据库 | PostgreSQL 18 + pgvector(halfvec 索引 + HNSW) |
| 向量服务 | qwen3.7-text-embedding(DashScope,2560 维 halfvec) |
| 认证 | bcryptjs + ECHO_STATIC_PASSWORD_HASH + ECHO_API_TOKEN Cookie |
| 主题 | next-themes |
| 通知 | sonner |
| 部署 | Docker 多阶段构建(standalone)+ 1Panel + OpenResty 反代 |
| 构建/CI | Gitea Actions(git.arutera.top)→ 本地 Docker Registry(localhost:5000/arutera-docker/echo) |
2. 目录结构(v1.5.0)
Echo/
├── .gitea/
│ └── workflows/
│ └── build-and-push-echo.yml # Gitea CI:push → 本地 Registry 镜像
├── 1panel-app/ # ★ 1Panel 应用包(应用市场识别)
│ └── echo/ # 替代旧 apps/echo 位置
│ ├── data.yml
│ ├── README.md / README_en.md
│ ├── logo.png
│ └── 1.5.3/ # data.yml + docker-compose.yml(当前版本)
├── src/
│ ├── app/ # Next.js App Router 路由
│ │ ├── (auth)/ # 登录 / 注册(路由组)
│ │ │ ├── login/ # 登录页(仅密码输入)
│ │ │ └── register/ # 重定向到 /login
│ │ ├── api/ # API 路由
│ │ │ ├── auth/login|logout/ # 登录 / 登出
│ │ │ ├── health/ # 健康检查
│ │ │ ├── search/ # 混合检索
│ │ │ ├── timeline/ # 时间轴分页
│ │ │ ├── stats/ # 仪表盘统计
│ │ │ ├── sources/ # 数据源配置
│ │ │ ├── sync/ # 触发数据源同步
│ │ │ ├── seed/ # 种子数据(仅开发环境)
│ │ │ ├── recycle-bin/ # 列表 / 恢复 / 永久删除 / 清空
│ │ │ └── settings/recycle-bin/ # 保留天数设置
│ │ ├── dashboard/ # 仪表盘(受保护路由)
│ │ ├── layout.tsx
│ │ └── globals.css
│ ├── components/ # React 组件
│ ├── hooks/
│ ├── lib/
│ │ ├── auth.ts # 静态密码 + Token 校验
│ │ ├── api-client.ts
│ │ ├── db/ # Drizzle 数据访问层
│ │ │ ├── schema.ts
│ │ │ ├── index.ts
│ │ │ └── repositories/ # item / config / recycle / sync
│ │ ├── source-config.ts
│ │ ├── sync/ # Syncer 接口 + Nextcloud / Gitea
│ │ ├── embedding.ts
│ │ ├── types.ts
│ │ ├── version.ts
│ │ └── utils.ts
│ └── proxy.ts # 路由保护
├── drizzle/ # Drizzle 迁移目录
│ ├── migrations/
│ │ ├── 0000_baseline.sql # 基线迁移(登记式应用)
│ │ └── meta/_journal.json
├── drizzle.config.ts
├── public/
├── docs/ # 运维 / 部署手册(不进入生产镜像)
│ └── echo-1panel-deploy.md
├── Requirements/ # ★ 需求 / 产品 / 重构文档归档
│ ├── 产品说明书.md
│ ├── 产品说明书-CodeReview报告.md
│ ├── 产品设计文档.md / 产品设计文档V1.0.md / 产品设计文档V1.0变更摘要.md
│ ├── 功能需求说明书.md / 功能需求说明书v1.4.1.md
│ ├── 重构说明.md / 重构详细要求.md
│ ├── Node24升级执行规划.md # ★ Node 22 → 24 升级规划
│ └── RELEASE_NOTES_v1.5.0.md / RELEASE_NOTES_v1.5.1.md
├── .env.example
├── next.config.ts / tsconfig.json / eslint.config.mjs
├── Dockerfile # 多阶段构建(node:24-alpine)
├── entrypoint.sh # 容器启动:drizzle-kit migrate → next start
├── .dockerignore / .gitignore
└── README.md # 本文档
已移除目录(v1.5.0 工作区整合)
apps/echo/→ 已迁移到1panel-app/echo/1panel-app/supabase/→ 已删除(不再提供 Supabase 应用包)supabase-migrations-archive/→ 已删除(迁移已切到 Drizzle)scripts/→ 已删除(构建上移到 Gitea Actions)drizzle/register-baseline.sql→ 已删除(一次性基线登记脚本,git 历史可回溯)
3. 环境准备
Node.js 版本
- 当前要求 Node.js 24+(
Dockerfile三阶段均使用node:24-alpine,package.jsondevDeps 按 24 校准)。 - Node 24 升级执行记录与回退预案见
Requirements/Node24升级执行规划.md。
node -v # 确认版本 >= 24
PostgreSQL + pgvector
v1.5.0 起不再依赖 Supabase 自托管栈,可直接使用 1Panel 的 pgvector/pgvector:pg15 本地应用:
- 1Panel → 应用商店 → 本地应用,安装 pgvector 应用。
- 网络可达:确保 echo 容器能通过容器网络名解析并连接到 pgvector 容器。
- 启用扩展(容器首次启动后执行):
docker exec <pgvector 容器> psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS vector;" docker exec <pgvector 容器> psql -U postgres -c "CREATE EXTENSION IF NOT EXISTS halfvec;" - 应用迁移(Drizzle Kit):容器启动时
entrypoint.sh自动执行npx drizzle-kit migrate。
获取 DashScope API Key
- 访问千问 AI 平台(或阿里云百炼),登录阿里云账号。
- 创建 API Key,复制即
DASHSCOPE_API_KEY(Bearer Token 鉴权)。 - 默认模型
qwen3.7-text-embedding(输出 2560 维向量,支持 256~2560 自定义维度)。
说明:DashScope 为可选配置。未配置时搜索会自动降级为关键词 ILIKE 匹配,功能仍可正常使用,仅缺少语义检索能力。
生成静态密码 hash(v1.5.0)
node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 10))" "your-password"
# 输出示例:$2b$10$...
# 将输出写入环境变量 ECHO_STATIC_PASSWORD_HASH
4. 安装与运行
安装依赖
npm install
配置环境变量
cp .env.example .env.local
编辑 .env.local,填入真实凭据(参考第 6 节)。
启动开发服务器
npm run dev
开发服务器默认运行在 http://localhost:3000。
数据库迁移
npm run db:generate # 重新生成迁移(可选,仅当修改 src/lib/db/schema.ts 后)
npm run db:migrate # 应用迁移到目标数据库
npm run db:push # 推 schema 到数据库(仅开发期便利)
5. 数据库迁移治理(v1.5.0 重写)
当前唯一迁移源为 Drizzle Kit:
- 生成:
npm run db:generate读取src/lib/db/schema.ts,输出drizzle/migrations/<n>_<name>.sql。 - 登记式应用:
npm run db:migrate检测drizzle.__drizzle_migrations中已登记的 hash,一致即跳过;不一致才执行。 - 基线迁移:
0000_baseline.sql是 v1.5.0 与历史 supabase 库形态对齐的"零差异"登记版本——首次应用即可让现有库与 schema.ts 完全一致,后续 diff 仅产生预期 DDL。 - 数据零丢失:迁移不执行
DROP或重命名现有列;只新增 / 修改元数据。
⚠️
drizzle-kit generate输出后请人工 review,确认无非预期ALTER TABLE/DROP再db:migrate。
6. 环境变量说明(v1.5.0 重写)
数据库 / 认证(v1.5.0 新增)
| 变量名 | 必填 | 说明 |
|---|---|---|
DATABASE_URL |
是 | PostgreSQL 直连 URL,如 postgresql://postgre:ASDljh@postgresql:5432/echo |
ECHO_API_TOKEN |
是 | API Token(登录态 Cookie 值;建议 32+ 字节随机十六进制) |
ECHO_STATIC_PASSWORD_HASH |
是 | bcrypt hash 后的登录密码(见第 3 节生成方法) |
向量服务
| 变量名 | 必填 | 说明 |
|---|---|---|
DASHSCOPE_API_KEY |
否 | DashScope API Key;未配置时搜索降级为关键词匹配 |
DASHSCOPE_EMBEDDING_MODEL |
否 | 默认 qwen3.7-text-embedding |
DASHSCOPE_EMBEDDING_API_URL |
否 | DashScope Embedding API URL |
EMBEDDING_DIMENSION |
否 | 向量维度,默认 2560,须与迁移一致 |
SEARCH_MATCH_THRESHOLD |
否 | 检索阈值,默认 0.35 |
数据源凭据(数据库 source_configs 无记录时的兜底)
| 变量名 | 必填 | 说明 |
|---|---|---|
NEXTCLOUD_WEBDAV_URL |
否 | Nextcloud WebDAV URL |
NEXTCLOUD_USERNAME |
否 | Nextcloud 用户名 |
NEXTCLOUD_APP_PASSWORD |
否 | Nextcloud 应用密码 |
NEXTCLOUD_ROOT_DIR |
否 | 同步根目录,默认 / |
GITEA_API_URL |
否 | Gitea API 地址 |
GITEA_TOKEN |
否 | Gitea 访问 token |
GITEA_OWNER |
否 | Gitea 用户名(活动流接口用) |
RECYCLE_BIN_RETENTION_DAYS |
否 | 回收站默认保留天数,默认 30(0=永不清除) |
运行时
| 变量名 | 必填 | 说明 |
|---|---|---|
NODE_ENV |
是 | production / development(影响 /api/seed 等) |
PORT |
否 | 容器内监听端口,默认 3002 |
NEXT_TELEMETRY_DISABLED |
否 | 关闭 Next.js 遥测,建议 1 |
v1.4.x 已移除
NEXT_PUBLIC_SUPABASE_URL |
v1.5.0 移除 |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
v1.5.0 移除 |
SUPABASE_SERVICE_ROLE_KEY |
v1.5.0 移除 |
SUPABASE_INTERNAL_URL |
v1.5.0 移除 |
MOCK_DATA_ENABLED |
v1.5.0 移除 |
安全提醒:
ECHO_API_TOKEN、ECHO_STATIC_PASSWORD_HASH、DASHSCOPE_API_KEY为敏感密钥,仅在服务端使用(无NEXT_PUBLIC_前缀),绝不进 Client Component bundle。
7. 功能说明
仪表盘(/dashboard)
- 登录后默认首页,含顶栏(搜索框 + 主题切换 + 登出)与可折叠侧边栏。
- 搜索框 300ms 防抖,输入后自动跳转时间轴页
?q=。
时间轴(/dashboard/timeline)
- 按
created_at DESC分页,无限滚动。 - 首次加载骨架屏,失败显示中文错误与重试按钮。
- 详情弹窗展示 title / source badge / 文件类型 / 大小 / 时间 / 内容预览 + 下载按钮。
数据源同步(/dashboard/sources)
- 展示 Nextcloud / Gitea 卡片,每张卡片可触发手动同步。
- 同步结果通过 toast 即时反馈。
- 凭据编辑表单对 password/token 字段做"空值保留原值"处理。
搜索
- 顶栏搜索框随时搜索;结果在时间轴页展示。
- 搜索结果顶部显示当前模式(hybrid / keyword_ilike)。
搜索模式(v1.5.0 重写)
| 模式 | 触发条件 | 检索方式 |
|---|---|---|
| 混合检索(hybrid) | DASHSCOPE_API_KEY 已配置且调用成功 |
关键词 ILIKE 路(Drizzle)+ 语义向量路(pg 原生 SQL,::halfvec 强转)并行,RRF 融合排序;向量路余弦距离阈值过滤 |
| 关键词检索(keyword_ilike) | 未配置 DASHSCOPE_API_KEY 或向量调用失败 |
Drizzle ILIKE 模糊匹配 title / content,status='active' 过滤 |
回收站(/dashboard/recycle-bin)
- 按
deleted_at DESC倒序展示已删除条目,支持来源过滤; - 单条恢复(status: deleted → active)、单条永久删除(物理清理);
- 设置页保留天数(0~365,0=永不清除)+ 立即清空按钮。
8. 构建与部署
构建工作流(v1.5.3 重写:GitHub Actions → Gitea Actions)
本项目 CI 已从 GitHub Actions 全面迁移到 自托管 Gitea(git.arutera.top)的 Actions,镜像推送到 本地 Docker Registry(localhost:5000):
- 在
develop分支提交代码并git push(origin=GitHub、gitea=Gitea 双远端同步推送); - Gitea 端
.gitea/workflows/build-and-push-echo.yml触发构建:- 拉取代码 →
docker build→docker push到本地 Registry; - tag 规则:
develop分支 →localhost:5000/arutera-docker/echo:develop;显式 tagv*→echo:<v*>+echo:latest。
- 拉取代码 →
- 1Panel 从应用市场识别
1panel-app/echo/应用包,并拉取对应镜像运行。 - 容器启动时自动执行
entrypoint.sh:先npx drizzle-kit migrate,再next start。
GitHub 端不再保留任何 workflow 文件(
.github/已删除),推送 GitHub 不会触发 CI;GitHub 仅作代码托管/备份。 本地不再需要构建 / 推送镜像 / 同步源码脚本,所有动作都在 Gitea Actions 完成。
Docker 镜像构建(仅 CI 使用)
docker build -t echo:local .
镜像:node:24-alpine 多阶段构建(deps → builder → runner),standalone 输出,HEALTHCHECK 探 /api/health。
启动生产服务器(直接运行)
PORT=3002 npm start
1Panel 部署
详见 docs/echo-1panel-deploy.md:
- 1Panel 已安装 pgvector 应用;
- 本地应用 → 同步应用列表 → 看到「Echo·忆刻」 → 安装;
- 表单字段:
DATABASE_URL/ECHO_API_TOKEN/ECHO_STATIC_PASSWORD_HASH/DASHSCOPE_API_KEY/PANEL_APP_PORT_HTTP。
OpenResty 反向代理示例
server {
listen 443 ssl http2;
server_name echo.arutera.top;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location = /api/health {
proxy_pass http://127.0.0.1:3002/api/health;
access_log off;
}
}
9. API 文档
所有 API 返回 JSON,错误统一为 { "error": "中文错误信息" }。除 /api/auth/* 与 /api/health 外,大部分为受保护路由(cookie 鉴权由 proxy.ts 强制),管理端点(/api/sync、/api/recycle-bin DELETE 等)当前依赖内网部署假设,公网部署前应加共享密钥或 IP allowlist。
GET /api/health
健康检查(不依赖数据库)。
{ "status": "ok", "timestamp": "2026-09-01T..." }
POST /api/auth/login
登录。body:{ "password": "..." }
- 200 + Set-Cookie(HttpOnly/SameSite=Lax/Max-Age=604800)+
{ "ok": true, "redirect": "/dashboard" } - 400 缺参数 / 401 密码错 / 500 服务端配置缺失
POST /api/auth/logout
登出。清空 cookie。
GET /api/search
混合检索。
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
q |
string | 是 | — | 搜索关键词 |
limit |
number | 否 | 10 | 返回条数上限,1~50 |
{
"items": [SearchResultItem],
"mode": "hybrid | keyword_ilike",
"query": "原始查询词"
}
GET /api/timeline
按 created_at DESC 分页。
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
offset |
number | 否 | 0 | 偏移量 |
limit |
number | 否 | 20 | 每页条数,1~100 |
source_type |
string | 否 | — | nextcloud / gitea |
{ "items": [Item], "total": 120, "offset": 0, "limit": 20 }
GET /api/stats
{
"sources": [{ "source_type", "total", "recent7", "recent30", "latest_at" }],
"latest_items": [Item]
}
POST /api/sync
触发数据源同步。body:{ "source_type": "nextcloud | gitea" }
{
"source_type": "nextcloud",
"inserted_count": 69,
"status": "success | failed",
"message": "成功同步 69 条 nextcloud items;GC:0 条移入回收站;自动清理:0 条超期记录已物理删除"
}
syncer 内部出错仍返回 200 +
status: "failed",前端需检查 body.status。
GET /api/recycle-bin
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
page |
number | 否 | 1 | 页码 |
limit |
number | 否 | 20 | 每页条数,1~100 |
source_type |
string | 否 | — | 过滤 |
{ "items": [RecycleBinItem], "total": 3, "page": 1, "limit": 20 }
POST /api/recycle-bin/restore/:id / DELETE /api/recycle-bin/:id / DELETE /api/recycle-bin
恢复单条 / 永久删除单条 / 清空全部。
PUT /api/settings/recycle-bin
设置保留天数。body:{ "retention_days": 0|30|... }(0~365)。
GET /api/seed
种子数据(仅 development 环境)。12 条 mock 数据写入;生产环境返回 403。
10. 开发说明
代码规范
- 中文注释:所有代码注释使用详细中文,说明「为什么这么做」而非「做了什么」。
- 绝对路径导入:
@/前缀(如@/components/ui/button、@/lib/db/repositories/item-repository)。 - 显式类型:函数参数与返回值必须有显式 TypeScript 类型,禁止滥用
any。 - 异步错误处理:所有异步操作必须 try-catch,错误信息中文。
- 数据访问:所有 SQL 必须通过
src/lib/db/repositories/*,不在 API 路由层直接拼 SQL。
常用命令
npm run dev # 开发服务器
npm run build # 类型检查 + 生产构建
npm run start # 生产启动(须先 build)
npm run lint # ESLint
npm run db:generate # 生成 Drizzle 迁移
npm run db:migrate # 应用迁移
npm run db:push # 推 schema 到数据库(dev only)
新增数据源
src/lib/types.ts:SourceType增加新值;src/lib/sync/<name>-syncer.ts:实现Syncer.sync();src/app/api/sync/route.ts:动态 import 分支;src/lib/source-config.ts+src/lib/db/repositories/config-repository.ts:env 默认 + 配置 schema;- 数据源页卡片适配(icon/描述)。
未来迭代方向
- 测试基建:vitest 单测(searchHybrid / auth / recycle-repository P0 用例)+ Playwright E2E;
- API 鉴权加固:共享密钥 middleware 或 IP allowlist;
- 可观测性:trace_id(AsyncLocalStorage)+ /api/metrics(Prometheus);
- 并发下载:Nextcloud 下载改 Promise.all + p-limit(5);
- Rerank:DashScope qwen-rerank 后处理;
- 长文档分块:按语义单元分块索引。
11. 更新日志
v1.5.3(2026-09-05)— 版本号同步 + Node 24 落地 + CI 全面迁移至 Gitea
CI / 远端迁移
- GitHub Actions 彻底弃用(2026-09-05 起):删除
.github/workflows/build-and-deploy.yml与test.txt;GitHub 端不保留任何 workflow 文件,后续推送不会触发 GitHub CI。 - CI 迁移至 Gitea Actions:
.gitea/workflows/build-and-push-echo.yml承接全部构建——develop分支 push →:develop镜像;v*tag push →:<tag>+:latest镜像。 - 镜像仓库变更:腾讯云 TCR → 本地 Docker Registry(
localhost:5000/arutera-docker/echo)。 - 双远端同步:GitHub(origin)+ Gitea(gitea)双远端同步推送;GitHub 仅作代码托管/备份,不再承担 CI。
版本号同步
src/lib/version.tsAPP_VERSION与package.jsonversion同步到 1.5.3;sidebar / settings 页面自动联动。
Node 24 落地
Dockerfile三处FROM node:22-alpine→FROM node:24-alpine(deps / builder / runner);1Panel 手动升级后全量 API + 浏览器回归测试通过。
v1.5.2(2026-09-04)— 1Panel 应用包发布
- 发布 1Panel 本地应用包
1panel-app/echo/1.5.2/(data.yml + docker-compose.yml)。 - 拉取 v1.5.2 镜像并上传 NAS 1Panel 部署;同步 develop / main / v1.5.2 tag。
v1.5.1(2026-09-03)— 1Panel 应用重构 + 构建优化
1Panel 应用重构
- 数据库配置取消连接串:1Panel 应用表单不再要求用户填写
DATABASE_URL,改为 1Panel 标准数据库服务字段PANEL_DB_HOST / PANEL_DB_PORT / PANEL_DB_NAME / PANEL_DB_USER / PANEL_DB_USER_PASSWORD,由 1Panel 自动查询并注入本地 PostgreSQL 应用容器名;数据库名默认echo、用户默认postgres,密码无默认值(必填)。 - 应用代码支持新字段:
src/lib/db/index.ts的assembleDatabaseUrl()优先读取DATABASE_URL(兼容旧部署 / 本地 dev),缺省时回退到 5 个PANEL_DB_*字段拼装 postgresql 连接串,URL 编码用户名/密码。 - 登录密码接受明文:表单字段直接展示"登录密码",entrypoint.sh 启动时检测到明文
ECHO_STATIC_PASSWORD即 bcrypt 哈希并写入ECHO_STATIC_PASSWORD_HASH、unset 明文;src/lib/auth.ts同时新增"模块加载期明文→hash 自检",兜底绕过 entrypoint 的本地开发场景。 - API Token 自动生成:表单字段默认值为
{{ random(32) }},1Panel 首次安装时自动生成 32 位随机串。 - HTTP 端口字段名称调整:表单字段从"HTTP 端口"改为"访问端口",对齐 1Panel 应用市场常规命名。
构建优化(镜像体积与推送时间)
- Dockerfile runner 瘦身:移除"COPY 整个 node_modules(≈296MB)"的粗暴拷贝,改为仅 COPY
drizzle-kit/drizzle-orm/esbuild三个运行时必需的 npm 包目录及其依赖;预期 runner 阶段增量层从 ~296MB 降到 ~30MB。 - 缓存策略调整:GitHub Actions 中
cache-to: type=gha,mode=max→cache-to: type=gha(mode=max会把所有中间层全部入 GHA 缓存,远端推送时仍要全量上传一遍,对体积优化无收益)。 - 验证通过:
npm run lint0 errors /npm run build20 routes 编译通过(Next.js 16.3 + Turbopack)。
v1.5.0(2026-09-01)— 重大重构
架构升级
- 移除 Supabase 全栈:PostgREST、GoTrue、supabase-proxy 三个容器全部停用;少 4 类密钥、少 1 类外部服务依赖,运维面收窄 50%。
- Drizzle ORM + pg 直连:引入 Drizzle ORM 0.45 + node-postgres (pg) 8.23;数据访问收敛到
src/lib/db/repositories/(item/config/recycle/sync 四模块);API 路由层零 SQL;类型安全全链路打通。 - 静态密码 + httpOnly Cookie:
src/lib/auth.ts一个文件覆盖密码校验(bcryptjs)+ 令牌校验(Edge 兼容的恒定时间比较)+ Cookie 常量;proxy.ts取代middleware.ts(Next.js 16 新约定)。 - Drizzle Kit 登记式迁移:基线迁移
drizzle/migrations/0000_baseline.sql与历史 supabase 库形态完全一致;hash 一致即 SKIP,数据零丢失。 - 环境变量重写:删除所有
SUPABASE_*与NEXT_PUBLIC_SUPABASE_*,新增DATABASE_URL/ECHO_API_TOKEN/ECHO_STATIC_PASSWORD_HASH三件套。 - PostgreSQL 升级到 pg18:容器从
pgvector/pgvector:pg15切到pgvector/pgvector:0.8.6-pg18-bookworm。
CI / 部署升级
- GitHub Actions 云端构建 → 腾讯云 TCR:
git push触发 CI,自动构建并推送镜像到 TCR;1Panel 应用市场从仓库1panel-app/echo/识别应用包;本地不再构建或同步源码。 - 1Panel 应用包位置变更:从
apps/echo/→1panel-app/echo/,便于 1Panel 应用市场直接同步。
工作区整合
- 迁移
apps/echo/→1panel-app/echo/; - 删除
1panel-app/supabase/(不再提供 Supabase 应用包); - 删除
supabase-migrations-archive/、scripts/、drizzle/register-baseline.sql; - 需求 / 产品 / 重构 / 设计类文档统一迁移到
Requirements/,仓库根目录仅保留代码与构建配置。
关键修复
- hybrid 搜索 500 → 200:v1.5.0 部署期定位并修复
item-repository.ts的 SQL 运算符优先级 bug——distanceExpr加内层括号(content_embedding <=> $1::halfvec),否则 PG 把(1 - content_embedding <=> $1)解析为(1 - content_embedding) <=> $1→operator does not exist: integer - halfvec。 - 导入体验:Drizzle + pg 直连消除"构建期数据库依赖"陷阱——
db()/pool()惰性初始化,DATABASE_URL 缺失在 import 期不报错。
验证(v1.5.0 部署后回归实测)
- 登录(正确/错误密码)✓ / hybrid 搜索 mode=hybrid、similarity 0.38~0.43 ✓
- 临时容器移除 DASHSCOPE_API_KEY → keyword_ilike 降级 ✓
- 时间轴 total=228 ✓ / 统计 nextcloud 69 + gitea 159 ✓
- 同步 Nextcloud 69 条 / Gitea 0 条 ✓
- 回收站 total=3,分页 + 来源过滤 ✓
- seed GET 生产环境 403 ✓
注意事项
- 管理 API(
/api/sync、/api/recycle-bin DELETE/PUT)当前依赖"服务暴露 = 内网"假设;公网部署前必须加共享密钥或 IP allowlist(已在 P0 列表)。 service_role_key/GoTrue JWT/RLS 双客户端全部移除——所有授权由应用层负责;code review 需严格检查"哪些 Repository 暴露给哪些 API 路由"。
v1.4.2(2026-08-13)— Bug 修复
- Nextcloud .docx 解析失败:mammoth 1.8.0 的
openZip不接受arrayBuffer,原代码每次同步丢 21 条 .docx;改为{ buffer: buf }成功数从 46→66。详见Requirements/产品说明书-CodeReview报告.md §10。
v1.4.1(2026-08-12)— 回收站机制
问题修复
- Nextcloud Desktop APP 同步检测:移除同步器基于
lastmod的增量过滤(Desktop 上传时间戳不晚于上次同步导致跳过),改为全量列举 WebDAV + upsert 幂等。 - 文件创建时间:WebDAV PROPFIND 增
creationdate,有效值入metadata.creation_time,详情弹窗展示;无效值置 null 不报错。 - 移除冗余字段:
page_count_or_sheets从file-parser.ts/nextcloud-syncer.ts/item-detail-dialog.tsx移除。
回收站机制
- 垃圾回收(GC):Nextcloud 同步末尾检测已删除文件,复制快照到
recycle_bin(content 截断 500 字)并标items.status='deleted';GC 安全阀:列举数 < 上次 50% 时跳过 GC,防 WebDAV 临时故障误删。 - 自动清理:超期快照物理删除;保留天数配置(默认 30,0=永不清除)。
- 回收站页面:
/dashboard/recycle-bin,列表 + 恢复/永久删除;设置页保留天数 + 立即清空。 - API:
GET/DELETE /api/recycle-bin、DELETE /api/recycle-bin/:id、POST /api/recycle-bin/restore/:id、PUT /api/settings/recycle-bin。
技术改进
items.status字段 + RLS 收紧 authenticated 仅可见 active。sync_logs.file_count(GC 安全阀依据)。recycle_bin.item_id外键 ON DELETE CASCADE。- timeline/search/stats 查询加
.eq('status', 'active')。
v1.4.0(2026-08-11)
- Nextcloud 文件类型扩展:
.docx(mammoth)+.xlsx/.xls(SheetJS)+.csv原生;解析失败单文件跳过;20MB 硬限 + 20,000 字向量化截断。 - 时间轴详情弹窗:点击从"直接下载"升级为"详情预览 + 下载按钮";存量数据缺字段显示
--。
v1.3.1(2026-08-07)
- Gitea 活动事件时间:feeds 接口
created而非created_at,v1.3.1 修复。 - Gitea 非默认分支提交:放开
commit_repo事件,与 commits 接口按 sha 去重;ref_name 入 metadata。
v1.3.0(2026-08-07)
- 混合检索(Hybrid Search):关键词 ILIKE 路 + 语义向量路并行,RRF 融合排序。
- 入库向量数据增强:向量化前补来源上下文(
Nextcloud 个人网盘文件:xxx.pdf等)。 - 构建可靠性:移除
next/font/google,改系统字体栈。
v1.2.0(2026-08-07)
- 向量模型升级:MiniMAX
embo-01→ 通义千问qwen3.7-text-embedding(2560 维 halfvec)。 - 数据库维度迁移(0004):halfvec(2560) + HNSW 重建 + match_items 阈值改 0.35。
v1.1.0(2026-08-07)
- Gitea 活动流事件同步:feeds 全量操作动态(创建仓库/推送删除标签/合并 PR 等)。
- 统一版本号管理:
src/lib/version.ts单一来源;三段式MAJOR.MINOR.PATCH。 - 主页文案:忆刻 → Echo · 忆刻;搜索展示位置迁移到时间轴页。
v1.0.0(2026-08-06)
首个正式版本(自 v1 ~ v3 迭代成果汇总):
- 真实数据源(Nextcloud WebDAV + Gitea REST API)。
- 定时同步(cron 触发
/api/sync)。 - 登录认证(Supabase Auth,注册关闭)。
- 数据源配置数据库化(
source_configs表)。 - 仪表盘数据源统计视图、时间轴侧边栏吸顶 + 数据源筛选。
- 设置页动态化(数据库 / Embedding 状态实时展示)。
12. 相关文档
需求与设计
- Requirements/产品说明书.md —— 工程实现详细说明(v1.5.3)
- Requirements/产品说明书-CodeReview报告.md —— 当前版本代码审查(v2.3)
- Requirements/产品设计文档.md —— 产品视角文档
- Requirements/产品设计文档V1.0.md —— 产品视角文档 V1.0
- Requirements/产品设计文档V1.0变更摘要.md
- Requirements/功能需求说明书.md / 功能需求说明书v1.4.1.md
- Requirements/重构说明.md / 重构详细要求.md
- Requirements/Node24升级执行规划.md —— Node 22 → 24 升级评估与执行记录
- Requirements/RELEASE_NOTES_v1.5.0.md
- Requirements/RELEASE_NOTES_v1.5.1.md
部署与运维
- docs/echo-1panel-deploy.md —— 1Panel 部署指南
- .gitea/workflows/build-and-push-echo.yml —— Gitea Actions 构建工作流(push → 本地 Registry)
变更历史
- .trae/specs/cleanup-and-node24-upgrade/ —— 工作区整合 + Node 24 升级规划
- .trae/specs/refactor-remove-supabase-drizzle-auth/ —— v1.5.0 重构 tasks / checklist
- .trae/specs/v1-4-1-recycle-bin-and-fixes/ —— v1.4.1 回收站 tasks / checklist
- .trae/specs/echo-mvp-foundation/ —— 项目基线
Echo · 忆刻 —— 让每一份碎片知识都可被找回。