33 Commits

Author SHA1 Message Date
xfy
2498cd9c0b docs(pitfall): 记录反应式 hook 不追踪普通 prop 的陷阱
将本轮三轮调试(commits 79978aa / 1c56fd8 / f86cb48)踩到的同一 Dioxus 0.7
陷阱写入 Pitfall Log,避免后续重复踩坑:

use_server_future / use_resource / use_memo 只在闭包内读取的 signal 变化时
重跑/重算(经 ReactiveContext 订阅)。普通组件 prop(String/i32 等非 signal)
被 move 进闭包后是冻结快照,读取它不建立订阅——prop 变化时 hook 不刷新,
组件虽重渲染但 hook 永久保留首次值。

该陷阱只在「同路由变体间导航」(/post/a → /post/b)触发:复用组件实例、仅
更新 props;跨变体导航会新挂载组件、hook 首次运行,掩盖问题。

记录两个真实案例(路由取数 use_server_future、正文解析 use_memo)的根因与
修复,给出判断规则(signal 依赖安全 / prop 依赖会静默过期 / prop 派生值
优先内联而非 use_memo),并标注 CommentSection 依赖 article key remount
才安全的潜在隐患。
2026-07-09 16:43:33 +08:00
xfy
2f6f8e549d refactor(code-runner): default CODE_RUNNER_LANGUAGES to all-open
CODE_RUNNER_LANGUAGES 未设置时,白名单不再默认为 python,node,
而是放行 LANGUAGES 注册表里的全部语言。该环境变量变为「可选的收窄开关」:
新增语言到注册表即可默认启用,无需再同步运维白名单(避免两边脱节,
如本次 go/rust 就因 .env 未同步白名单导致 is_supported_lang 拒绝)。

- RunnerConfig.languages: Vec<String> → Option<Vec<String>>,
  None 表示不限制
- is_supported_lang: Option 为 None 时直接放行注册表语言
- 测试 is_supported_lang_default_whitelist → is_supported_lang_default_all_open,
  断言 go/rust 在默认(未设白名单)下可用
2026-07-09 11:02:04 +08:00
xfy
c624997c04 feat(code-runner): add Go and Rust language support
为 Code Runner 新增 Go 和 Rust 两种编译型语言,沿用现有 base 镜像分层结构。

Go:
- run_cmd 直接用 go run(单条命令,内部编译+运行)
- 镜像把 GOCACHE/GOTMPDIR/GOPATH 重定向到 /tmp tmpfs
  (只读根文件系统下 /Users/issuser/.cache 不可写)
- default_limits: 1 核 / 256MB / 10s(编译冷启动比解释型慢)

Rust:
- rustc 编译 + 运行是两步,但 docker.rs 注入脚本用 exec 执行 run_cmd,
  exec 替换 shell 进程后 'A && B' 后半段不执行,
  因此镜像内置 /usr/local/bin/run-rust.sh wrapper 封装两步
- default_limits: 1 核 / 512MB / 15s(rustc 内存大、编译慢)

新增镜像与白名单后,默认 CODE_RUNNER_LANGUAGES=python,node,go,rust。
2026-07-09 09:40:32 +08:00
xfy
20540358c2 docs: remove Playwright from agents 2026-07-08 13:44:17 +08:00
xfy
2a3a48af4e docs(agents): 记录 Tiptap 交互 bug 用 Playwright 调试的方法论
happy-dom 测不出 ProseMirror 真实交互 bug(键盘/selection/NodeView/
Suggestion range)。记录 Playwright 反馈环的标准搭建与诊断模式:
逐字符输入、调试写 DOM、二分定位 NodeView。附 /code 文本残留案例。

这类 bug 不进 git:repro.mjs/package.json/node_modules 用完即删。
2026-07-07 12:01:55 +08:00
xfy
f3eb93f320 docs(agents): document code runner and fix clippy/biome lint
文档:
- AGENTS.md 新增「Code Runner」架构章节(三层架构 + WASM 可见性规则 +
  governor 0.8 无 per_day 的处理 + runner 镜像契约)
- Environment 段补齐 CODE_RUNNER_* 与 RATE_LIMIT_CODE_EXEC_* 环境变量

Lint 修复(clippy --all-targets --all-features -D warnings 全绿):
- runner.rs/runner.rs: use_signal 冗余闭包 → 直接传 fn
- runner_config.rs: &*RUNNER_CONFIG 去 deref;assert_eq!(...false/true) → assert!
- markdown.rs: 局部变量 /// 改 //;Option.map().flatten() → and_then
- languages.rs: 删除从未读取的 LanguageDef.name 字段(语言名即 map key)
- docker.rs: start_container if let Err → ?;timeout match → is_err();
  嵌套 if 合并(修 task 2 遗留 + clippy 1.96 新 lint)
- pages/admin/posts.rs: use_signal 冗余闭包(预存 lint,顺带修绿)
- codemirror editor.ts: biome format 重排 setSchema 单行
2026-07-03 18:57:25 +08:00
xfy
2a7f7be738 chore(docker,ci): Dockerfile 与 CI 切换 pnpm workspace,docs 同步
Dockerfile:
- Node 22 安装段追加 corepack enable + pnpm 11.8.0
- 缓存层从'只 tiptap 的 package.json'扩展为整个 workspace
  (libs/package.json + pnpm-workspace.yaml + pnpm-lock.yaml + 4 lib manifest),
  npm ci 改为 pnpm install --frozen-lockfile,覆盖全部 4 个 lib 的 Docker 层缓存
- 构建步骤 make build-editor 改为 make build-libs

Gitea CI:
- check job 的 Install Node 步骤加装 pnpm,新增 Biome lint 步骤
  (cd libs && pnpm install --frozen-lockfile && pnpm exec biome check .)
- build job 同步装 pnpm,make build 不变(Makefile 已改用 workspace)

.dockerignore: 补齐其余 3 个 lib 的 public 产物 + workspace node_modules 模式

AGENTS.md: Development Commands 删 make clippy、新增 make lint/make fix 说明;
Prerequisites 补 Biome;libs 段改为 pnpm workspace 模型;修正文档漂移
(tt-reveal→tt-expand,eval→Reflect::get)
2026-07-02 18:10:11 +08:00
xfy
d11385e3ee docs(agents): 沉淀双 target 验证与 custom hook 踩坑记录
Testing 章节补充:fullstack 项目必须同时验证 server 与 wasm32 两个
target,给出 wasm 编译命令;说明 dx check 不等于完整 cargo wasm
build,会漏掉 borrow/move 错误;列出三类常见 target-mismatch 陷阱
(cfg 不可见、unused_mut 误删、函数内 use 作用域)。

新增 Pitfall Log 章节,记录本次重构踩过的四个坑:
- 持有资源的 custom hook(use_hook+use_effect+use_drop)里 FnMut 闭包
  move FnOnce 参数的 E0507/E0310,用 Option::take 模式解决;
- 单 target 验证的危害(只跑 cargo build --all-features 会漏 wasm 错误);
- 仅 wasm 需要的 mut 绑定用 cfg_attr 压制非 wasm 的 unused_mut;
- 往 utils 模块搬函数前先查目标模块的 feature gate(text.rs 是
  server-only 且依赖 regex,前端可达函数不能进)。
2026-07-02 16:49:48 +08:00
xfy
5a00ef31f3 docs(agents): update agents for JavaScript 2026-07-02 15:45:42 +08:00
xfy
9a4e6c3e6e docs(agents): 校正构建/测试/迁移说明,对齐当前代码库
- 移除不存在的 ./migrate.sh:迁移实际由 src/db/migrate.rs 在启动期自动运行,
  目标库由 db/pool.rs::ensure_database_exists 自举创建;补充新增迁移需在
  MIGRATIONS 数组登记(编译期校验磁盘与数组一致)
- npm → pnpm:4 个 libs 均使用 pnpm-lock.yaml,Makefile 全程 pnpm
- make test / make build 覆盖 4 个 libs(补充 codemirror-editor)
- 补充 restore-webp 兜底步骤的成因(dx 0.7.9 重编码 .webp)
- 补全 make clippy(-D warnings)、make fix、make clean 真实行为
- 模块树补齐 context/router/ssr_cache/sysinfo_sampler 及 *_bridge
- 4 个前端子项目合并为对比表,保留 wasm-bindgen 接线等关键细节
- 保留 Workflow 提交规范
2026-07-02 11:40:47 +08:00
xfy
a4331bd813 feat(build): add FreeBSD x86_64 cross-compile support
方案 A(clang + lld + 本地 sysroot)。rustc 为 freebsd target 链接的系统库
(libc/libexecinfo/libgcc_s/libthr)及 sysinfo 依赖的 freebsd 专有库
(libkvm/libmemstat/libprocstat/libdevstat)需 FreeBSD 运行时,无法纯靠
clang+lld 无 sysroot 完成;故从 FreeBSD 15.1 base.txz 解出 crt 对象 + 系统库
到 .freebsd-sysroot/(gitignored,machine-local)。

- .cargo/config.toml: freebsd target 配置作为注释模板(sysroot 路径机器相关,
  不硬编码进仓库);linker 经 rustflags 的 -C linker=clang 设置,使 Makefile
  能用 CARGO_TARGET_*_RUSTFLAGS 环境变量整体注入。
- Makefile: 新增 freebsd-sysroot(幂等下载+解压 base.txz)与 build-freebsd
  (release server 二进制交叉编译)target。server 用 cargo 直出而非 dx CLI,
  因 dx 对该 target 的支持未经验证。
- .gitignore: 忽略 .freebsd-sysroot/。
- AGENTS.md: 补充构建命令说明。

实测 release 二进制 16MB,stripped ELF for FreeBSD 15.1,动态依赖均为
FreeBSD base 自带库(libc.so.7 libthr.so.3 libkvm.so.7 等)。
2026-07-01 13:40:00 +08:00
xfy
6e94db0c2b feat(admin): add backup/restore tab (dual-mode + task progress polling)
新增 dashmap 依赖。create_backup 探测 pg_dump 优先(含 schema,签名头前置)、
不可用回退纯 SQL(COPY TO STDOUT 逐表,按表精确进度)。restore_backup 校验
签名头(仅本系统备份)+ 路径穿越防护 + 二次确认,探测 psql 执行。
list_backups/delete_backup 管理备份,GET /api/database/backups/{name} 下载
(admin 鉴权 + 白名单)。tasks.rs DashMap 进度表(1h 惰性 GC),前端每 1.5s
轮询 get_task_progress 显示进度条/stage,完成后刷新列表。
backups/ gitignored 不直接暴露。AGENTS.md 同步新增 CodeMirror 子项目与
数据库管理章节。
2026-06-29 19:16:11 +08:00
xfy
30a861f910 docs(agents): 新增 yggdrasil-core 子工程章节
与 lightbox/tiptap-editor 并列,记录用途、构建、注入方式与
主题展开动画的 View Transitions 实现。同步更新 make test 注释
与 Build Artifacts 列表。
2026-06-26 14:09:46 +08:00
xfy
731547e6df docs(agents): 新增 Workflow 章节,约定每完成功能点即提交
Some checks failed
CI / check (push) Failing after 5m8s
CI / build (push) Has been skipped
- Agent 自主判断提交时机,验证通过后直接提交,无需等待指令
- 顺带更新 make build 注释,补充 doc 步骤与 make doc/doc-open 命令
2026-06-26 11:08:55 +08:00
xfy
97b413dd50 docs: 同步 AGENTS.md 与当前代码
修正与代码不符的过时描述:
- server functions 分布补全 comments/ 与 settings.rs(原仅列 auth + posts)
- rate_limit tiers 从 3 个更正为 5 个(strict/upload/image/comment/unknown)
- Rust 测试数 392 → 402

补全 lightbox 子项目文档(新增独立章节,说明其经 Dioxus.toml
全局注入而非 wasm-bindgen 桥接的差异),并在 Build Artifacts
与 make test 描述中补上 lightbox 产物与测试(23 tests)。
2026-06-25 13:39:28 +08:00
xfy
ff2694c5a3 feat(image): make size/pixel limits configurable, double defaults
Some checks failed
CI / check (push) Failing after 6m23s
CI / build (push) Has been skipped
将 MAX_IMAGE_DIMENSION / MAX_IMAGE_PIXELS 从编译期 const 改为运行时
LazyLock(启动读环境变量),默认值 x2。

- 默认值:单边 4096→8192,总像素 25M→50M
- clamp 策略:只设下限防危险小值(DIMENSION≥512,PIXELS≥1M),
  超下限 clamp + warn;无上限,完全信任运维
- 内存影响:默认 50M 像素对应 ~200MB/图解码缓冲(max_alloc)
- 模式复用 WEBP_CONFIG:env→parse→(val,clamped)→clamp→warn→info
- 所有引用点解引用(*MAX_...),含 upload.rs/webp.rs 跨文件
- check_upload_dimensions 超限文案改为动态读取上限,不再硬编码数值
- 测试改用 *MAX_IMAGE_DIMENSION+1,数值无关

.env.example 与 AGENTS.md 同步更新环境变量说明。
2026-06-24 13:54:36 +08:00
xfy
368a651fa6 build: make test runs both cargo test and vitest 2026-06-24 10:14:20 +08:00
xfy
c0af99736d docs: update AGENTS.md for vite 8 build, vitest tests, and tiptap toolchain 2026-06-24 10:12:16 +08:00
xfy
a6d30ed5d9 refactor(write): address code review feedback
- remove duplicate `use dioxus::prelude::*` (keep #[allow] inline with comment)
- update write_editor doc comment: callback-driven init, EditorHandle::drop cleanup
  (no more polling/globals)
- restore empty-url check in make_upload_closure (match original JS `success && url`):
  empty url on success now rejects with clear message instead of inserting broken image
- update AGENTS.md tiptap section: write.rs uses tiptap_bridge, no eval/polling
2026-06-23 13:32:34 +08:00
xfy
a3ed0a2b4e docs(env): document RATE_LIMIT_COMMENT_* and RATE_LIMIT_UNKNOWN_* vars
rate_limit.rs registers four limiters (strict/upload/image/comment) plus
an "unknown" fallback bucket for when the real client IP can't be
determined, but only the strict/upload/image tiers were listed in
.env.example and AGENTS.md. Add the missing comment and unknown tier
tunables so the documented surface matches the code.
2026-06-22 13:16:34 +08:00
xfy
b24cfdcabc fix(startup): replace migration panic with friendly exit + configurable retry window
DB migration failure at startup panicked via .expect() (main.rs:223),
dumping a raw backtrace for what is usually just "PostgreSQL isn't running
yet". Worse, the 1.6s runtime retry budget was reused at startup, so it
almost always failed against a cold/slow DB (docker-compose without
healthchecks, local Postgres not started, etc.).

Changes:
- pool: extract build_pg_config() (returns Result, no panic); add
  validate_database_url() so URL-format / DB_POOL_SIZE errors surface as
  friendly exit(1) instead of hitting the LazyLock's unreachable .expect()
- pool: add get_conn_for_startup() — a startup-only retry loop with a
  configurable total-duration window (MIGRATE_STARTUP_TIMEOUT_SECS,
  default 30s, 500ms interval), separate from the runtime get_conn()
  anti-avalanche fast retry (untouched)
- migrate: split run() into run_on_conn(&mut conn) so callers control the
  connection-acquisition strategy; main.rs pairs this with the startup
  retry. Advisory-lock release comment updated: exit(1) terminates the
  process just like panic, so the session-level lock is still freed
- main: startup fatal errors (bad URL, DB unreachable, migration failed)
  now each emit tracing::error! + eprintln! ERROR + targeted HINT, then
  exit(1) — no panic, no backtrace nudge
- .env.example / AGENTS.md: document MIGRATE_STARTUP_TIMEOUT_SECS

No runtime behavior change: get_conn() and its ~40 call sites are
unchanged. Advisory-lock safety preserved (documented in migrate.rs).
2026-06-22 11:24:13 +08:00
xfy
1e2e3c9332 perf(db): add statement_timeout; skip retry on pool Timeout errors
- 连接配置 statement_timeout(默认 30s,STATEMENT_TIMEOUT_SECS 可调),
  防慢查询长时间占用连接拖垮池(L6)
- get_conn 对 Timeout(池满)错误立即返回不再 sleep 重试,避免雪崩;
  仅 Backend/Postgres 错误才退避重试
2026-06-18 13:35:33 +08:00
xfy
82a3c12940 feat(security): add Origin-based CSRF protection for write endpoints
对所有 POST/PUT/PATCH/DELETE 请求校验 Origin(回退 Referer)等于本站,
堵住 login CSRF 与未来 GET 化写接口的盲区(SameSite=Lax 覆盖不到)。

- 新增 src/api/csrf.rs:纯函数 origin 解析(不引入 url crate)+ axum 中间件
- 挂载到 upload 路由与 Dioxus app 路由(最外层,先于超时/压缩)
- APP_BASE_URL 配置可信域名;未设置时回退 Host + X-Forwarded-Proto
- GET/OPTIONS 放行;拿不到本站 origin 时放行避免误杀
- 9 个单测覆盖写方法识别、origin 标准化、默认端口省略、头解析回退
2026-06-18 13:22:59 +08:00
xfy
7d713cabc2 docs: document server-only optional dependencies in AGENTS.md
Some checks failed
CI / check (push) Failing after 5m15s
CI / build (push) Has been skipped
2026-06-16 17:32:04 +08:00
xfy
d246adbb32 build: make rand optional and remove explicit getrandom dependency 2026-06-16 17:10:27 +08:00
xfy
cafbddb861 refactor: replace server-only dead_code allows with cfg(feature = "server")
Replace #[allow(dead_code)] on server-only helpers with #[cfg(feature = "server")]
to make the server/WASM split explicit and avoid compiling unused server logic
into the WASM frontend.

- Gate password/session/auth/comment helpers and model parsers with server feature
- Gate related imports and tests accordingly
- Remove genuinely unused CreatePostRequest and CreateCommentRequest
- Keep #[allow(dead_code)] for true dead code (stub methods, unused public APIs)
- Use #[cfg(any(target_arch = "wasm32", test))] for THEME_KEY
- Update AGENTS.md note
2026-06-16 16:45:08 +08:00
xfy
76ad4ec8fb ci: 修正 Tailwind CLI 包名并收敛重复的环境准备步骤
Some checks failed
CI / check (push) Failing after 2s
CI / build (push) Has been skipped
Tailwind v4 将 CLI 拆为独立包 @tailwindcss/cli,核心包 tailwindcss
不再注册 bin,导致 npx tailwindcss 报 "could not determine executable
to run"。CI 改为安装 @tailwindcss/cli。

同时将 check 与 build 两个 job 重复的 checkout、镜像、Rust/Node/dx/
tailwind 安装步骤抽到 .gitea/actions/setup 复合 action,顶层 env
统一管理 Rust 镜像配置。AGENTS.md 同步说明 v4 拆包这一坑。
2026-06-15 11:47:54 +08:00
xfy
fa6fa9a77c docs: document COOKIE_SECURE and TRUSTED_PROXY_COUNT 2026-06-12 17:31:20 +08:00
xfy
bd9e87128d perf(ssr): optimize request throughput by 32%
- Cache ammonia::Builder with LazyLock (was rebuilt per request)
- Enable tracing release_max_level_info to strip tracing overhead at compile time
- Remove TraceLayer and tower-http trace feature from production
- Increase DB pool size 10→20 (configurable via DB_POOL_SIZE)
- Increase SSR cache TTL 300s→3600s (configurable via SSR_CACHE_SECS)

Benchmark: 7,444 → 9,840 req/s, P99 latency 27.6ms → 11.1ms
2026-06-12 09:36:53 +08:00
xfy
efa41b42c2 feat(auth): add loading state to login/register forms and update AGENTS.md 2026-06-11 10:44:27 +08:00
xfy
9452c196fa docs: document why image crate excludes WebP decoder 2026-06-09 16:14:28 +08:00
xfy
9c5b09a278 chore: code cleanup - formatting, EOF newlines, model helper, and UI tweaks 2026-06-02 17:33:28 +08:00
xfy
e48253c6f7 添加 AGENTS.md 项目开发指南文档 2026-06-02 17:33:28 +08:00