AITEK_LJH d94aa6cff9
Build and Push Echo / build (push) Failing after 107h39m36s
Build and Push Echo / notify (push) Failing after 107h39m30s
chore(1panel): 删除旧版本应用包 + 同步文档引用
- 删除 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
引用属于历史事实描述,保留不变
2026-09-06 12:49:46 +08:00

Echo · 忆刻 · 个人知识语义搜索引擎

当前版本:v1.5.3(2026-09-05)—— 版本号同步 + Node 24 落地 + CI 全面迁移至 Gitea Actions

当前默认开发分支:develop

CI 说明: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)
Supabase 全栈 PostgREST + GoTrue + supabase-proxy(v1.5.0 已停用)
向量服务 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.json devDeps 按 24 校准)。
  • Node 24 升级执行记录与回退预案见 Requirements/Node24升级执行规划.md。
node -v   # 确认版本 >= 24

PostgreSQL + pgvector

v1.5.0 起不再依赖 Supabase 自托管栈,可直接使用 1Panel 的 pgvector/pgvector:pg15 本地应用:

  1. 1Panel → 应用商店 → 本地应用,安装 pgvector 应用。
  2. 网络可达:确保 echo 容器能通过容器网络名解析并连接到 pgvector 容器。
  3. 启用扩展(容器首次启动后执行):
    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;"
    
  4. 应用迁移(Drizzle Kit):容器启动时 entrypoint.sh 自动执行 npx drizzle-kit migrate。

获取 DashScope API Key

  1. 访问千问 AI 平台(或阿里云百炼),登录阿里云账号。
  2. 创建 API Key,复制即 DASHSCOPE_API_KEY(Bearer Token 鉴权)。
  3. 默认模型 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):

  1. 在 develop 分支提交代码并 git push(origin=GitHub、gitea=Gitea 双远端同步推送);
  2. Gitea 端 .gitea/workflows/build-and-push-echo.yml 触发构建:
    • 拉取代码 → docker build → docker push 到本地 Registry;
    • tag 规则:develop 分支 → localhost:5000/arutera-docker/echo:develop;显式 tag v* → echo:<v*> + echo:latest。
  3. 1Panel 从应用市场识别 1panel-app/echo/ 应用包,并拉取对应镜像运行。
  4. 容器启动时自动执行 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)

新增数据源

  1. src/lib/types.ts:SourceType 增加新值;
  2. src/lib/sync/<name>-syncer.ts:实现 Syncer.sync();
  3. src/app/api/sync/route.ts:动态 import 分支;
  4. src/lib/source-config.ts + src/lib/db/repositories/config-repository.ts:env 默认 + 配置 schema;
  5. 数据源页卡片适配(icon/描述)。

未来迭代方向

  1. 测试基建:vitest 单测(searchHybrid / auth / recycle-repository P0 用例)+ Playwright E2E;
  2. API 鉴权加固:共享密钥 middleware 或 IP allowlist;
  3. 可观测性:trace_id(AsyncLocalStorage)+ /api/metrics(Prometheus);
  4. 并发下载:Nextcloud 下载改 Promise.all + p-limit(5);
  5. Rerank:DashScope qwen-rerank 后处理;
  6. 长文档分块:按语义单元分块索引。

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.ts APP_VERSION 与 package.json version 同步到 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 lint 0 errors / npm run build 20 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. 相关文档

需求与设计

部署与运维

变更历史


Echo · 忆刻 —— 让每一份碎片知识都可被找回。

S
Description
Echo · 忆刻 · 个人知识语义搜索引擎
https://echo.arutera.top/
Readme
937 KiB
2026-09-06 12:50:08 +08:00
Languages
TypeScript 95%
Shell 1.5%
Dockerfile 1.2%
CSS 1.1%
PowerShell 1.1%
Other 0.1%