chore: 新增 .ai-memory 记忆备份,换机器可恢复

CodeBuddy 的记忆原本只存在本机用户目录(不进版本控制),换机器即丢失。
把 5 个记忆文件备份进仓库,clone 后让助手「从 .ai-memory/ 导入记忆」即可恢复。

- README 说明用途、导入方法与维护约定
- CODEBUDDY.md 补充同步约定(改完记忆须同步本目录)
- 内容仅含基础设施信息(IP/域名/用户名),无任何密码或密钥
This commit is contained in:
gjm committed 2026-09-27 20:27:45 +08:00
1 parent f167550957
commit 6c5770b754
7 files changed
+316

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
- [项目当前进度与待办](project_progress.md) — 三阶段状态、ICP 备案阻塞、出包前必须去掉 IP 覆盖等;**新对话先读这个**
- [生产服务器部署环境](project_server_deploy.md) — ethereal-realm.top 的路径/服务/MySQL/nginx 实况,自建 Git 代码服务器拓扑,及 ICP 拦截、pypi 不可达、MySQL 非 Docker、nginx 双 server 块等坑
- [CAD 插件微信授权集成](project_cad_wxauth_integration.md) — d:/Ethereal-Realm 的 CadOcr+cadAgent 接入进度、两端分工、先编 CadOcr 的顺序约束、本机只能编 R230+
- [用户的命令行习惯与协作方式](user_shell_workflow.md) — 用 PuTTY,长命令会被折行截断,sudo 操作要写成脚本交给用户执行
+47
View File
@@ -0,0 +1,47 @@
# .ai-memory —— AI 助手记忆备份
本目录是 CodeBuddy Code 在本项目的**持久记忆备份**。
## 它是什么
CodeBuddy 的记忆原本存放在**本机用户目录**,不进版本控制:
```
C:\Users\<用户名>\.codebuddy\projects\d-wx-scan-authorize\memory\
```
那里存的是「代码和 git 历史里看不出来」的东西:生产服务器实况、踩过的坑、
协作习惯、当前进度与待办。换一台机器这些就没了,所以在仓库里留一份副本。
## 怎么用
**换机器 / 新环境恢复:**
1. `git clone` 本仓库
2. 对 CodeBuddy 说:「从 `.ai-memory/` 导入记忆」
3. 助手会把本目录的文件写回本机记忆目录
> 注意:记忆目录名由**工作目录路径**派生(`d:\wx-scan-authorize` →
> `d-wx-scan-authorize`)。把仓库克隆到 `d:\wx-scan-authorize` 可保持目录名
> 一致;放在别的路径也能用,导入时告诉助手实际路径即可。
**日常维护:**
改完记忆后,把本机记忆目录的文件同步回本目录并提交。
CodeBuddy 每次修改记忆时都会顺手同步,不需要你提醒。
## 里面有什么
| 文件 | 内容 |
|---|---|
| `MEMORY.md` | 索引,助手每次对话自动加载 |
| `project_progress.md` | 三阶段进度、阻塞项、待办(新对话先读这个) |
| `project_server_deploy.md` | 生产服务器实况与反直觉的坑 |
| `project_cad_wxauth_integration.md` | CAD 插件集成进度与构建约束 |
| `user_shell_workflow.md` | 协作习惯(PuTTY 长命令折行、sudo 走脚本等) |
## 重要:不要在这里放密钥
本目录**会进 Git**。所有密码、token、私钥一律留在服务器的 `.env` 里,
不要写进这些记忆文件。当前文件里只有基础设施信息(IP、域名、用户名),
没有任何凭据。
@@ -0,0 +1,43 @@
---
name: CAD 插件微信授权集成
description: d:/Ethereal-Realm 里 CadOcr+cadAgent 接入微信扫码授权的进度、两端分工与构建顺序约束,以及本机只能编 R230/R243+ 工具集的事实
type: project
---
把 `d:/Ethereal-Realm`(SVN 工作区)里的 CAD 插件从「本地时间毒药」授权换成
服务端(本项目 d:/wx-scan-authorize)微信扫码授权。2026-09-27 完成编码 +
客户端侧端到端验证。
- 公众号后台「服务器配置」URL 已改到 Cloudflare 快速隧道,微信真实
`subscribe`/`SCAN` 推送已打通(见 [生产服务器部署环境](project_server_deploy.md))。
- **仍需用户本人做**:在 AutoCAD 里加载 `cadAgent.arx`,人工验证二维码对话框
(我这边没有 AutoCAD)。用户 2026-09-27 表示暂不做。
- `test_wxauth.exe` 已从控制台程序改造成 **Win32 对话框**:二维码显示区 +
本地授权状态区 + 「清空令牌」「模拟新机器」两个按钮。为此 DLL 新增导出
序号 **44/45**(`ocr_wxAuthGetLocalState` / `ocr_wxAuthClearLocalState`)。
**分工**(用户拍板)
- `CadOcr`(DLL,无 MFC):全部网络 + 注册表 + 授权状态机(`src/wxAuth.cpp`)。
- `cadAgent`(ARX,MFC):只做 UI(`WxAuthDlg.cpp`)。
- 新增导出序号 **40~43**(`ocr_wxAuthBegin/Poll/Reset/FreeBuffer`),原有 2/5/13/25
一律不动。宿主侧 `ocr_check` 仍导出在序号 20,握手保留、时间毒药删除。
**关键约束**
- **必须先编 CadOcr 再编 cadAgent**:`CadOcr/include/*.h` 靠 PostBuildCopy 同步到
`CADProject/dep_inc/cadOcr/`,顺序反了会用到旧头文件。
- 服务端基址是编译期常量 `CADOCR_WX_BASE_URL`(默认域名),联调时用
`cmake --preset msvc-ocr -DCADOCR_WX_BASE_URL=http://39.107.55.179` 覆盖。
刻意不做运行时覆盖,避免被指向假服务端绕过授权。
- 本机 VS18 只装了 MSVC 14.16/14.29/14.42/14.44/14.51,**没有 v100(VS2010)、
v140(VS2015)**,所以 `R190`/`R220` 这两个 preset 编不出来(`CADProject/out/R190`
里连 vcxproj 都没生成)。实际能编的是 **R230/R243/R250/R260**;`build.bat`
里写的 R220 会失败。
- CadOcr 的 `test/test_wxauth.exe` 是独立验证程序,不装 AutoCAD 就能跑通整条链路。
它靠 `#pragma comment(linker, "/EXPORT:ocr_check,@20,NONAME")` 导出握手函数
—— CMake 只对库目标识别 `.def`,对可执行目标会当普通文件忽略。
**Why:** 这些跨了两个工作区的耦合约束(构建顺序、共享头同步、导出序号、
工具集可用性)从任一端的代码里都看不出来,踩了会很难查。
**How to apply:** 改 CadOcr 的公共头后务必先编 CadOcr;给用户的构建命令别用
R190/R220;讨论授权链路时记得 UI 在 cadAgent、网络在 CadOcr。
+44
View File
@@ -0,0 +1,44 @@
---
name: 项目当前进度与待办
description: wx-scan-authorize 三阶段状态快照、当前阻塞项与下一步,用于跨对话续接——新对话应先读本文件
type: project
---
`d:/wx-scan-authorize`(微信公众号扫码授权服务)截至 **2026-09-27 晚** 的状态。
**三阶段进度**
| 阶段 | 内容 | 状态 |
|---|---|---|
| 1 | 扫码授权(`/wechat` 事件 + `/auth/*` + 首次关注送 7 天) | 已上线,微信真实推送已打通 |
| 2 | 使用扣减(`/usage/consume` + session_token + 节流记账) | 已上线 |
| 3 | 充值(微信公众号支付) | **未开始** |
| 附加 | 只读管理后台 `/admin`(计划外新增) | 2026-09-27 已上线 |
代码状态:本地与服务器均在 `f167550`,工作区干净,远端是自建 Git 服务器
(见 [生产服务器部署环境](project_server_deploy.md))。
客户端在 `d:/Ethereal-Realm`:CadOcr + cadAgent 已完成编码与客户端侧端到端验证,
`test_wxauth.exe` 已从控制台程序改造成 Win32 对话框。详见
[CAD 插件微信授权集成](project_cad_wxauth_integration.md)。
**阻塞项与待办**
1. **ICP 备案进行中**(用户 2026-09-27 已提交,等待通过)——当前最大的外部变量:
- 通过前:公众号后台「服务器配置」URL 指向 Cloudflare 快速隧道
(URL 每次重启会变,捞取命令见 server_deploy 记忆)
- 通过后:切回 `http://ethereal-realm.top/wechat`,并撤掉隧道
2. **阶段 3 充值暂缓**。用户原话:「阶段3现放着吧,因为微信公众号想要收费的话,
需要营业执照,现在域名的备案也没有做好。」→ 等营业执照 + 备案。
3. **正式出包前必须去掉编译覆盖** `-DCADOCR_WX_BASE_URL=http://39.107.55.179`
——当前本地 DLL 是 IP 联调版,把服务端地址写死成了 IP。
4. **AutoCAD 里人工验证 `cadAgent.arx`** ——我这边没有 AutoCAD,只能用户做。
用户 2026-09-27 明确表示暂不做。
5. **IP 直连暴露 `/docs` 与 `/openapi.json`** ——用户选择暂不处理(详见
server_deploy 记忆的 nginx 双 server 块章节)。
**Why:** 会话内的任务列表不跨对话持久化,关闭对话后这些状态不会自动带过去;
只有写进记忆才能在新对话里续上。用户 2026-09-27 明确问过「关掉对话后怎么重新开始」。
**How to apply:** 新对话开始时先读本文件确认进度。**动手前先问用户 ICP 备案是否
已通过**——它决定公众号 URL 该配隧道还是配域名,是当前唯一会改变操作方式的变量。
+143
View File
@@ -0,0 +1,143 @@
---
name: 生产服务器部署环境
description: ethereal-realm.top 的部署拓扑、自建 Git 代码服务器(47.93.46.28:1216,已弃用 GitHub)、MySQL/nginx 实际配置与几个反直觉的坑(pypi 不可达、MySQL 非 Docker、skip_name_resolve、nginx 只代理部分路径)
type: project
---
生产服务器 `deploy@ethereal-realm.top`(Alibaba Cloud Linux 3,公网 `39.107.55.179`,内网 `172.17.151.49`)的实际环境,与 REQUIREMENTS.md 的描述有出入。
**部署拓扑**
- 应用代码:`/home/deploy/app`(git 仓库,remote 指向自建 Git 服务器,见下)
- 虚拟环境:`/home/deploy/venv`(Python 3.11),**不是** 项目目录下的 venv
- 服务:systemd `wechat-api.service`(`/etc/systemd/system/`),`ExecStart=/home/deploy/venv/bin/python /home/deploy/app/run_server.py`,`Restart=always`,监听 `127.0.0.1:8000`
- 入口:systemd `cloudflared-quick.service`(`cloudflared tunnel --url http://127.0.0.1:80`,
快速隧道,无配置文件、无路径限制,`Restart=always`,`User=deploy`)→ nginx:80 → 应用。
**注意服务名是 `cloudflared-quick` 不是 `cloudflared`**——查 journal 时用错名字会显示空,误判成裸进程。
- nginx 配置:`/etc/nginx/conf.d/wechat-api.conf`,`server_name ethereal-realm.top`
- `deploy` 在 `wheel` 组,`sudo` 需要密码 → 涉及 sudo 的操作必须让用户手动执行
**代码仓库拓扑(2026-09-27 起)**
用户自建了一台 Linux 代码服务器 `gjm@47.93.46.28:1216`(CentOS 7.2,git 1.8.3.1),
裸仓库在 `/srv/git/wx-scan-authorize.git`(owner `gjm`)。
```
本地 d:/wx-scan-authorize ──push──> 代码服务器 47.93.46.28 (唯一远端) ──pull──> 应用服务器 ~/app
```
- 本地:只有一个远端 `origin` = 代码服务器。`git push` / `git pull` 不带参数即可。
- 应用服务器:`origin`=`ssh://gjm@47.93.46.28:1216/srv/git/wx-scan-authorize.git`,
直接 `git pull`。两端读写都已验证。
- **GitHub 已弃用**(2026-09-27 用户决定):国内访问不稳定,不再作备份。本地 remote
已删除,`origin` 这个名字改指代码服务器。GitHub 上那个仓库(`LittleGuo/wx-scan-authorize`)
是否删除由用户决定。
- 代码服务器上 `gjm` **没有免密 sudo**,涉及 root 的操作(装软件等)要让用户做。
- 该裸仓库 `HEAD` 曾误指 `refs/heads/master`(`git init --bare` 默认值),已改为
`refs/heads/main`。以后新建裸仓库记得顺手改,否则 clone 会拿到空工作区。
**域名被阿里云 ICP 拦截(2026-09-27 确认)**
> 用户已于 2026-09-27 提交 ICP 备案,预计不久下来。因此**决定不搞 Cloudflare 命名隧道**
> (那需要账号 + 把 ethereal-realm.top 的 NS 改到 Cloudflare,代价不值)。隧道只是过渡,
> 备案通过后应把公众号后台 URL 改回 `http://ethereal-realm.top/wechat` 并撤掉隧道。
`http://ethereal-realm.top` 在公网访问会返回阿里云的拦截页
(403 `Non-compliance ICP Filing`),因为备案还没做。**直连公网 IP
`http://39.107.55.179` 一切正常**(nginx 的 `/auth/`、`/usage/` 都能打到应用)。
影响面:
- 微信服务器的回调推送也进不来 —— 公众号后台「服务器配置」URL 若指向该域名,
`subscribe`/`SCAN` 事件永远到不了应用(journal 里完全没有 `/wechat` POST)。
- 可用的公网入口是 Cloudflare **快速隧道**(`cloudflared-quick.service`,已 enabled +
`Restart=always`,所以 SSH 断开/进程崩溃/服务器重启都能自动拉起)。隧道 URL 形如
`https://<随机词>-<随机词>-<随机词>-<随机词>.trycloudflare.com`,**每次重启都会变**
(这是快速隧道的固有行为,不是配置问题),捞当前值:
`journalctl -u cloudflared-quick | grep -oE "https://[a-z0-9-]+\.trycloudflare\.com" | tail -1`。
公众号后台的服务器配置要填 `<隧道URL>/wechat`。若推送突然不来了,先查这个 URL 是否变过。
**微信真实推送已打通(2026-09-27 19:12 验证)**
绕开 ICP 的办法:把测试号后台的服务器配置 URL 指向 Cloudflare 快速隧道,
`https://catering-thumbnails-pirates-workstation.trycloudflare.com/wechat`(Token 不变)。
微信随即发来 GET 校验(来源 `162.62.81.123`,腾讯云网段),签名复算一致、返回 200,
后台配置成功。之后真实扫码产生了第一条**非模拟**推送:
```
162.62.80.57 - "POST /wechat?signature=...&timestamp=...&nonce=...&openid=ohve625WiuQVosBDGLVwxGT68S4c" 200 OK
```
整条链路结果(库内):新建 `users.id=2`(真实 openid `ohve625WiuQVosBDGLVwxGT68S4c`),
发 7 天免费时间授权(`authorizations.id=2`,`2026-09-27 19:12:43 → 2026-10-04 19:12:43`),
`auth_scenes.id=9` 置 authorized,`usage_logs.id=2` 记账一条。
- **微信推送 URL 里会带一个 `openid=` 查询参数**(官方文档没写)。我们忽略它——
`verify_signature()` 只用 token/timestamp/nonce,业务用 XML 正文的 `FromUserName`。
已确认代码里没有任何地方往 query 拼 openid,是微信自己加的。
- 隧道**已经是 systemd 服务** `cloudflared-quick.service`(enabled + `Restart=always`),
服务器重启/进程崩溃都会自动拉起,公众号后台配置不会因进程死掉而失效。
但快速隧道 URL **每次重启仍会变**——所以重启后仍要重新捞 URL 并回填公众号后台。
- 库里的早期手工测试数据(`users.id=1 / openid='oTEST_CLIENT_01'`,其
`authorizations.id=1` 的 `end_at` 早于 `start_at`)**已于 2026-09-27 20:19 清理干净**,
连同 9 条无归属的过期测试场景。清理前整库备份在
`/home/deploy/backup-cleanup-20260927-201903.sql`(11 KB)。
现在库里只剩真实数据:`users.id=2`(openid `ohve625WiuQVosBDGLVwxGT68S4c`)。
- **`end_at` 倒挂不是 bug**(这条结论仍然成立):生产代码路径
(`_grant_free_authorization`)在同一条 INSERT 里取 `NOW()` 算 start/end,不可能倒挂。
- **清理用户数据时注意 `auth_scenes` 的删除规则是 `SET NULL` 不是 `CASCADE`**
(`authorizations`/`usage_logs`/`sessions` 才是 CASCADE)。直接删 `users` 会在
`auth_scenes` 留下一条 `user_id=NULL` 的孤儿记录,状态可能还是 `authorized`——
客户端轮询时可能读到。**正确顺序是先删该用户的 `auth_scenes`,再删 `users`**。
**几个反直觉的坑**
1. **服务器连不上 pypi.org**(超时),但阿里云镜像正常(0.06s)。装包必须加
`-i https://mirrors.aliyun.com/pypi/simple/`,否则 pip 会长时间挂住。
2. **MySQL 是原生安装的 8.0.46,不是 REQUIREMENTS 里写的 Docker**。且
`skip_name_resolve=ON` + `bind_address=127.0.0.1`,导致 `root@localhost`
匹配不了 TCP 连接(报 `ERROR 1130 Host '127.0.0.1' is not allowed`)。
应用用专用账号 `wechat@127.0.0.1`(只授权 `wechat_api.*`),凭据在服务器 `.env` 里。
注意:本机 Windows 的 `.env` 仍是 `MYSQL_USER=root`,连的是本机 MySQL,两份不一样。
3. **nginx 有两个 server 块,访问行为取决于 Host 头**(2026-09-27 发现,很反直觉):
| 入口 | 匹配的 server 块 | 行为 |
|---|---|---|
| `Host: ethereal-realm.top` | `wechat-api.conf` | **精确白名单**:只放行 `/wechat`、`/auth/`、`/usage/`、`/admin`,其余落到 `location /` 的占位响应 `return 200 'wechat api ok'` |
| `Host: 39.107.55.179`(IP 直连)| `app.conf` | **全量代理**:`listen 80 default_server` + `location / { proxy_pass http://fastapi; }`,所有路径都转发到 8000 |
`app.conf` 是 Sep 25 就存在的早期配置(不是本次部署引入)。后果:
- **IP 直连会暴露 FastAPI 的 `/docs` 与 `/openapi.json`**(实测 200 + 真实 schema);
域名路径下这两个路径返回占位文本,不暴露。
- MFC 插件当前 `-DCADOCR_WX_BASE_URL=http://39.107.55.179` 正是依赖 IP 直连,
所以**不能简单删掉 `app.conf`**(删了 IP 访问会落到 nginx.conf 内置的静态
server,`/auth/`、`/usage/` 全部 404)。要收紧的话,应把 `wechat-api.conf`
改成 `listen 80 default_server` 并删 `app.conf`,而不是单独删。
- 新增对外接口必须**同时**在 `wechat-api.conf` 加 `location` 块(给域名路径),
否则备案后走域名会落到占位响应。
- 改 nginx 的流程见 `user_shell_workflow.md`:**写成脚本 + `sudo bash ~/xxx.sh`**,
不要给内联长命令。
- **`/docs` 暴露问题用户 2026-09-27 决定暂不处理**(原话选了"暂不处理"):判断是
风险低(只泄露接口结构、不含数据,`/admin` 另有强密码),等 ICP 备案通过、插件
切回域名后再一并处理。**不要再自作主张去关 docs 或删 `app.conf`**——要动先问。
**`/admin` 已于 2026-09-27 20:13 上线**:`wechat-api.conf` 新增 `location /admin`
块(显式透传 `Authorization` 头),应用侧 `ADMIN_USER=admin`、密码为 24 位随机串
存于服务器 `.env`(用户已自行保存)。`/admin` 需重启应用才生效——`ADMIN_PASSWORD`
是进程启动时读入的模块级常量。
4. **GitHub 已弃用,不要再往那儿推**(2026-09-27 用户决定)。服务器到 github.com 的连接
本就间歇性失败(`git pull` 报 `Empty reply from server` 或超时;`curl -sI` 探到 200
也**不代表** git 协议可用,实测出现过 curl 200 而 pull 仍失败)。国内访问不稳定,
用户明确不要 GitHub 备份了。所有代码走自建 Git 服务器。
若哪天需要从 GitHub 临时取东西(例如查旧仓库),仍可用 bundle 绕:
本地 `git bundle create /tmp/x.bundle main`,
`ssh deploy@... 'cat > /tmp/x.bundle' < /tmp/x.bundle`,服务器上
`git fetch /tmp/x.bundle main && git merge --ff-only FETCH_HEAD`。
**Why:** 这些都是服务器实际状态,仓库代码和 git 历史里看不出来;REQUIREMENTS.md 的
技术栈描述(Docker MySQL)与实际不符,照着文档操作会踩坑。
**How to apply:** 涉及服务器操作时,直接用上面的真实路径/账号/镜像;给用户的命令要
考虑他需要手动 sudo;新增对外路由时提醒同步改 nginx。
+26
View File
@@ -0,0 +1,26 @@
---
name: 用户的命令行习惯与协作方式
description: 用户用 PuTTY 操作服务器,对多行粘贴/heredoc 不熟;偏好自己执行 sudo 操作,重要改动要先确认
type: user
---
用户通过 **PuTTY** 连接服务器,对 Linux shell 的细节不算熟练。
**表现**
- 我给的 `sudo tee ... <<'EOF'` 多行 heredoc 命令,粘贴到 PuTTY 后卡在 `>` 二级提示符
没能执行(用户当时不确定自己是否改好了)。
- **长单行命令也会被截断**(2026-09-27 实测):一条约 200 字符的
`sudo cp A B && sudo cp C D && sudo nginx -t && ...` 粘贴后被 PuTTY 折成三行,
前两行报 `cp: missing destination file operand`,第三行把配置文件路径当命令执行
报 `Permission denied`。**"单行"不等于安全**——长度也是风险。
- 涉及 `.env` 这类含密钥的文件,用户会拒绝我直接编辑。
**How to apply:**
- 需要用户 sudo 时,**不要给内联命令**(无论单行还是多行)。正确做法:
1. 我把脚本写到服务器 `~/xxx.sh`(用 `ssh ... 'cat > ~/xxx.sh' < 本地文件`,我有写权限);
2. 让用户只执行 `sudo bash ~/xxx.sh` —— 短到不可能折行;
3. 脚本里自带备份与失败回滚,并 `echo` 每一步进度,方便用户贴回显。
- 若确实要给单行命令,控制在 **60 字符以内**,或拆成多条分别给。
- 涉及 `sudo` 的操作(重启服务、改 nginx 配置等)用户需要自己执行——我没有密码,
非交互 `sudo -n` 会失败。把命令准备好交给用户,并附上回滚方案。
- 改动 `.env`、nginx 配置、重启服务这类动作,先说明清楚再让用户确认。