docs/ 是唯一事实来源。 所有代码按 docs/ 生成,不做反向推导。docs/ 下任何文件只读。 不得创建、修改、删除、格式化 docs/;需求变更由人类先改文档。见 docs/conventions.md 第二、五节。遇到题面没覆盖的行为:不自己发明,写进回复里让人类决定补文档还是补禁令。
TODO.md 执行TODO.md 是唯一的任务清单。按章节顺序(0 → 8)从上往下做,不要跳章节挑"有意思的"先做。[x](部分完成用 [~] 并在后面注明缺什么),再开始下一条。不要把多个章节的改动混在一次提交里。TODO.md 可以用 [x]/[~] 反映进度,但不得删除条目或改动其含义——需求变更走文档流程,由人类改。docs/overview.md、docs/architecture.md、docs/conventions.md(第四节是硬性禁令清单)docs/api.md、docs/backend/{data-model,auth,audit}.mddocs/api.md、docs/frontend/frontend.mdAGENTS.md 已落初版,措辞可复核;根 opencode.json 只把 docs/conventions.md 与 docs/overview.md 作为常驻 instructions,其余文档按任务读。docs/conventions.md 第四节,只摘最容易违反的)user_id 字段是预留,不实现注册)。database/sql + pgx)。*gin.Context 只出现在 handler 层,业务函数只收 context.Context。visibility;公开只走 publish。internal/llm 只有接口,不加 SDK 依赖)。仓库处于脚手架阶段(TODO.md 第 0 章):
backend/cmd/haven/ 已有可启动入口:main.go / logger.go,读 HAVEN_* 环境变量、缺失即拒绝启动,启动时连库并 ping,只注册了 GET /api/health。backend/internal/config 与 backend/internal/db 已可用;backend/internal/{auth,notes,tags,search,portfolio,audit,httpx,llm} 仍是空目录。backend/migrations/0001_init.up.sql 已建全部表与索引;cmd/haven-init-user 用于创建唯一账号。deploy/ 尚不存在(migration 执行方式待第 7 章补)。frontend/ 是清理过的 Vite 模板:main.ts 已接 vue-router(History,路由表暂空)与 pinia,App.vue 只渲染 RouterView;src/{api,views,stores} 是空目录。frontend/src/style.css 只剩全局基础样式,页面样式未开始。frontend/dist/ 是构建产物,已被 gitignore,不要手改、不要提交。后端(在 backend/ 下执行):
go build ./...
go vet ./...
go test ./... # 单包:go test ./internal/auth/...
go test ./internal/auth -run TestLoginTotp -v
go test ./internal/db -v # 需要 HAVEN_TEST_DB_DSN,见下
集成测试(目前只有 internal/db)在未设置 HAVEN_TEST_DB_DSN 时自动 skip。手动初始化本地库:
psql "$HAVEN_DB_DSN" -f migrations/0001_init.up.sql # 建表(启动时不会自动跑)
HAVEN_DB_DSN=... HAVEN_INIT_PASSWORD='至少12位' go run ./cmd/haven-init-user -username kairo
前端(在 frontend/ 下执行):包管理器是 pnpm(有 pnpm-lock.yaml,不要用 npm/yarn 生成新 lockfile)。
pnpm install
pnpm dev # Vite dev server,需自行代理 /api 到后端
pnpm build # = vue-tsc -b && vite build → frontend/dist/
没有 lint / format / CI 配置,不要自造工具链。
认证相关的本地运行需要 PostgreSQL 并 CREATE EXTENSION IF NOT EXISTS pg_trgm;;其它 HAVEN_* 环境变量见 docs/architecture.md 第四节(缺必填项应拒绝启动)。
github.com/kairo/haven;go.mod 用 go 1.27.3,pgx 是 v5。golang-migrate 命名 0001_init.up.sql / .down.sql,放 backend/migrations/;顺序为 users → sessions/pending_logins/trusted_devices/tokens/audit_events → notes/tags/portfolio_items → note_tags/portfolio_repos。后端启动时不跑 migration。表结构以 docs/backend/data-model.md + auth.md 第九节 + audit.md 为准;users 表只在 auth.md 里定义。postgres 超级用户跑 migration,之后必须 GRANT ALL ON ALL TABLES IN SCHEMA public TO haven;,否则应用连接会报 permission denied for table users。notes、tags、search、portfolio、audit),禁止建 handlers/、services/、repositories/;跨领域公共代码只放 httpx / auth / config。notes.search_text,应用层不写该字段;ILIKE '%q%',无中文分词。visibility = 'public' AND published_at IS NOT NULL;撤回 public→private 时保留 published_at。snake_case,不转 camelCase;列表响应固定 {items, total}(空列表不能是 null);笔记列表 item 必须带后端截断好的 content_preview(按 rune 截 200)。docs/architecture.md 第四节)。origin(GitHub github.com:Flint-lab-art/Haven.git,主仓库)和 gogs(自建 git.vorin.icu:kairo/Haven.git,仅作备份镜像)。只推 origin 视为未完成。git push:
git push origin dev && git push gogs dev(不要写成 git push --all,那会连 main 一起推)。dev,main 受保护。绝对不要 push、提交或合并到 main(两个 remote 都一样)、不要 force-push 任何分支。 合并到 main 只由人类操作。dev(或人类指定的其他分支)上提交;当前分支不是 dev 时,先停下确认,不要自行切换。feat(backend): ... / fix(frontend): ... / doc(docs): ...,中文描述,不加 AI 署名或 Co-Authored-By。git add -A / git commit -a,以免带上别人未完成的改动。docs/ 只读,因此任何 AI 发起的提交都不应包含 docs/ 变更;若 git status 里 docs/ 有改动,视为人类未提交的编辑,必须原样保留。go build ./... + go test ./...,或 pnpm build);node_modules/、frontend/dist/ 已在 .gitignore 中,不要强制添加。