75 Commits

Author SHA1 Message Date
xfy
970ff8dc5b chore: release v0.6.0 2026-07-23 16:33:07 +08:00
xfy
b25abcb9d8 chore(deps): 更新 tokio 与 regex 依赖包版本
Some checks failed
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
2026-07-23 13:38:10 +08:00
xfy
bcd13958ac feat(katex): 移植 mhchem 化学公式转译器(\ce/\pu → LaTeX)
Some checks failed
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
katex-rs 默认无 mhchem 解析器,\ce/\pu 化学公式渲染为红字(实测正确页面 648
的 137 个公式中 32 处化学公式坏掉,含 \ce×24 + \pu×8)。

从 mhchemParser 4.2.2(Apache-2.0)机械移植状态机转译器为纯 Rust:
- src/api/mhchem.rs:数据模型 + 模式匹配 + go() 主循环 + texify 输出 + 公开 API
- src/api/mhchem_tables.rs:14 个状态机转移表 + 机器局部动作(ce/pu/...)
- 模式含 lookahead (?=)/(?!),Rust regex crate 不支持,故用 fancy-regex
  (已被 syntect 间接引入,此处显式声明为直接 server 依赖)
- ce/pu 包裹 catch_unwind,任何内部异常回退原样输出,绝不 panic
- katex.rs 新增 expand_chem:渲染前嵌套花括号配对扫描 \ce/\pu 预转译
- 行尾 ^ 气体符号转译为 \uparrow,消解原 mhchem 解析错误
- 8 个 mhchem 单测 + 5 个 katex 集成测试(水/反应箭头/气体箭头/单位/络离子)
2026-07-23 12:23:53 +08:00
xfy
f7e4d2f5ea chore: release v0.5.0
Some checks failed
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
数学公式(KaTeX)、mermaid 流程图、bun 代码运行器、文章脚注、Vue SFC 高亮等新功能;SSR 缓存失效根治、Docker 构建/部署修复、性能优化系列(mimalloc + 热点路径零拷贝/单遍扫描)。
2026-07-22 17:41:29 +08:00
xfy
891a576dc0 feat(deps): 引入 katex-rs 服务端数学公式渲染
纯 Rust 的 katex-rs 0.2.4 重实现 KaTeX,把 TeX 公式渲染成 HTML span,
供后续 pulldown-cmark 的 InlineMath/DisplayMath 事件调用。

- Cargo.toml: katex-rs 作为 optional dep 经 server feature 启用
- src/api/katex.rs: thread_local 缓存 KatexContext/Settings(因含 RefCell
  宏表非 Sync,不能放全局 static);OutputFormat::Html 避开 MathML 标签
  使 sanitizer 无需开白名单;throw_on_error=false 防坏公式中断全文
- src/api/mod.rs: #[cfg(feature="server")] 注册 katex 模块

双 target 编译通过(server + wasm32),4 个单测通过。
2026-07-16 14:09:14 +08:00
xfy
5b183007a7 perf(server): 用 mimalloc 替换系统全局分配器
多线程高频小对象分配场景下,mimalloc 吞吐显著优于系统 malloc,且对全静态
musl 链接友好(生产 Docker 镜像即 musl 目标)。选 mimalloc 而非 jemalloc:
本项目生产 server 是全静态 musl 二进制,jemalloc 在 musl 上有 pthread_getname_np
(musl<1.2.3)/unprefixed-malloc 符号冲突的已知坑。

cfg 双门控(与项目双目标编译约定一致):
- feature=server:分配器只服务端二进制需要
- not(wasm32):mimalloc_rust 在 wasm32 上无法编译(Issue #76),前端走默认分配器

mimalloc 声明为 optional + 经 server feature 启用,与 argon2/uuid 等 server-only
依赖同栏位。验证:server native + WASM 双目标编译通过 + clippy 零告警。
musl 目标受本机无 musl-gcc 限制,需 Docker 内构建验证(同 zenwebp 等任何 C 依赖)。
2026-07-16 10:53:51 +08:00
xfy
eccaa9f2a9 chore: release v0.4.0
Code Runner + /admin/system + UI 重新设计
2026-07-13 19:59:22 +08:00
xfy
56f599574f feat(slug): 中文标题自动转拼音生成 URL slug
文章 URL slug 与 markdown 标题锚点此前会吃掉中文字符:纯中文标题
退化成时间戳,混入 ascii 时只剩 ascii 片段。

引入 pinyin crate(纯 Rust、零依赖,安全交叉编译到 musl/FreeBSD),
slugify 与 slugify_heading 在字符过滤前先尝试 to_pinyin():
- 汉字 → 无声调拼音,每字成词用 - 分隔(你好 → ni-hao)
- ASCII 字母数字与 -/_ 保留
- 多音字取默认读音,博客场景足够

示例:你好世界 → ni-hao-shi-jie;Rust 入门指南 → rust-ru-men-zhi-nan

is_valid_slug 不变(原本就允许 Unicode),手动输入中文 slug 仍可用。
pinyin 为 server-only optional 依赖,不进 WASM bundle。
2026-07-13 18:04:35 +08:00
xfy
26f7465943 feat(deps): add tokio-stream for SSE streaming
- tokio-stream 0.1 (sync feature) wraps mpsc::Receiver into a Stream
  for the upcoming axum SSE handler; axum::response::sse ships with
  axum 0.8 already so no extra dep needed there
- web-sys features: add EventSource + MessageEvent so the WASM frontend
  can consume SSE via the native EventSource API
2026-07-10 11:33:07 +08:00
xfy
1584e01425 chore(deps): update all cargo and pnpm dependencies to latest versions 2026-07-09 18:12:54 +08:00
xfy
2fba43dc3f chore(infra): add bollard dependency and modular structure 2026-07-03 17:49:08 +08:00
xfy
ecf3c73715 fix(database): make src/api/database compile under WASM (web-only) build
The /admin/system feature was never verified against the WASM frontend
target (dx serve builds src/main.rs with --features web and no server).
The entire src/api/database/ tree unconditionally pulled in server-only
crates (axum, sqlparser, dashmap, tokio, tokio_postgres, futures, regex)
and server-gated helpers (get_current_admin_user, parse_session_token,
get_user_by_token), so the frontend build failed with 43 errors.

Root cause + fixes (mirror the established settings.rs pattern):

- Gate server-only  imports behind #[cfg(feature = server)] in
  status/system_status/sql_console/schema/tasks/backup. The #[server] macro
  strips call sites but NOT use statements, so unresolved imports remained.
- Ungate  in main.rs: SystemSnapshot is a shared serde
  type referenced by ServerStatus.host on both targets; only the sampler
  task/SNAPSHOT static are internally server-gated.
- Gate  (pure Axum handler, zero WASM consumers) and the
  download_backup Axum handler in backup.rs.
- Move restore_backup's validation preamble (regex/backup_path/fs) inside
  the #[cfg(feature = server)] block; gate std::path/chrono::Utc imports.
- Add [[bin]] required-features=[server] for generate_highlight_css so the
  syntect-dependent build tool is skipped in web-only builds.

Genuine WASM bugs surfaced once the server bodies stopped masking them:

- system.rs: Closure import path (dioxus::prelude::wasm_bindgen ->
  wasm_bindgen, matching write.rs); setTimeout expects i32 not u32;
  editor_handle() -> editor_handle.read() (Signal is not Fn in 0.7).
- codemirror_bridge.rs: set_schema extern took &SqlSchema but SqlSchema is
  a serde type with no IntoWasmAbi. Changed both set_schema signatures to
  &JsValue; call site now serializes via serde-wasm-bindgen::to_value.
- system.rs: signals .set() inside spawn/use_future/onclick closures need
   bindings (incl. the *_f rebinding copies); added cfg_attr
  allow(unused_mut) on the 4 tab components, matching write.rs convention.

Verified: cargo check (default/server) clean; cargo check --features web
--target wasm32-unknown-unknown clean (0 errors); dx check clean; 411
cargo tests pass.
2026-06-30 13:41:23 +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
a49f47c8a6 feat(admin): add SQL console tab (read-write + 4 guards + sqlparser)
新增 sqlparser 依赖(optional+server),AppError 加 BadRequest 变体(护栏
返回动态用户可见消息)。execute_sql server function 全读写执行,4 道护栏:
(1) sqlparser AST 高危语句闸门——DROP DATABASE/SCHEMA 字符串预检绝禁、
DROP/TRUNCATE/ALTER 需勾选「我了解后果」;(2) 无 WHERE 的 UPDATE/DELETE 拒绝;
(3) 复用 STATEMENT_TIMEOUT_SECS 超时上限;(4) 前端写操作二次确认。
默认禁多语句,结果 500 行截断。get_db_schema 拉表/列供 CodeMirror 补全。

前端 SqlConsoleTab:CodeMirror 编辑器(Vim + Catppuccin 主题跟随站点 +
实时 schema 补全)+ 选项 toggles + 结果表格 + EXPLAIN 输出。
2026-06-29 18:56:15 +08:00
xfy
c4c490b881 feat(admin): add server status tab (sysinfo host metrics + cache hit rate)
新增 sysinfo 依赖(optional+server),sysinfo_sampler 后台采样任务
(SYSINFO_SAMPLE_SECS 可配,默认 0.5s)周期刷新 CPU/内存/磁盘/load 到 RwLock
快照,get_server_status 只读快照零成本。cache.rs 给 9 个缓存加 AtomicU64
hit/miss 计数 + cache_stats() 聚合命中率。

前端 ServerStatusTab:应用内指标(运行时间/连接池/会话/CPU/内存/磁盘/load)+
缓存命中率表 + 刷新按钮 + 自动刷新开关(500ms/1s/2s/5s/手动,默认手动)。
2026-06-29 18:45:02 +08:00
xfy
b309f2dbc1 chore: release v0.3.0
Some checks failed
CI / check (push) Failing after 4m42s
CI / build (push) Has been skipped
Comment system, post trash, View Transitions theme animation, Tiptap image
upload coordinator, blur-up progressive images, lightbox & yggdrasil-core
subprojects, session/CSRF hardening, image Cache-Control/ETag, Dockerfile,
Gitea Actions CI, plus numerous performance and security improvements.
2026-06-29 16:12:18 +08:00
xfy
0398cc6c66 perf(render): 列表加显式 key + release 启用 panic=abort
依据 Dioxus 0.7 optimizing 指南做两项改进:

- 为数据驱动列表渲染补全显式 key(13 处,9 个文件):
  home/archives/tags/search 文章与标签列表、post_card/post_footer
  标签、header 桌面/移动导航、admin dashboard/posts/write 列表。
  使用各类型稳定唯一字段(post.id / tag / tag.name / item.label /
  err.id / year_group.year / month_group.month_en)作为 key,
  让 Dioxus diff 正确识别元素身份。骨架屏 for _ in 0..N 静态占位
  循环与已带 key 的评论树/admin 行不动。

- [profile.release] 加 panic = "abort":WASM 去掉 unwind 元数据减小
  体积;server 端错误处理走 Result+?(见 error.rs),不依赖 panic
  unwind,无副作用。

其余文件为本机格式化(单行折叠/多行展开),一并提交。

验证:dx check 通过、cargo test 405 passed。
2026-06-25 18:07:22 +08:00
xfy
8971fbe1a2 feat(write): 支持封面图上传(拖拽/点击/粘贴)
将编辑页封面图从纯 URL 输入框升级为完整的上传控件:
- 16:9 拖拽区,支持拖拽文件、点击选择、剪贴板粘贴三种上传入口
- 完整交互状态:空态/上传中(骨架占位)/预览/错误提示
- 保留外链 URL 输入(内联折叠),覆盖图床/CDN 场景
- 上传复用现有 POST /api/upload,服务端零改动

tiptap_bridge 提取 upload_image_file 通用上传函数,
make_upload_upload 改为薄包装,消除 fetch 逻辑重复。

Cargo.toml 补 web-sys feature(ClipboardEvent/DataTransfer/FileList/
HtmlInputElement),供粘贴/拖拽读取文件。
2026-06-24 15:09:47 +08:00
xfy
9ef3fbfed9 build: add web-sys features for tiptap bridge upload closure 2026-06-23 10:52:59 +08:00
xfy
45d14e2ad9 feat(image): add image dimensions cache with header-only reading 2026-06-22 17:55:16 +08:00
xfy
c0b14ed498 refactor(image): make bytes dependency optional and server-gated 2026-06-18 10:10:40 +08:00
xfy
36554af5f5 perf(image): store cached image data as Bytes to avoid Vec cloning 2026-06-18 10:03:35 +08:00
xfy
7bd02d0ea9 perf(cache): run tag post invalidations concurrently 2026-06-17 16:59:29 +08:00
xfy
31d5a99d2a Merge cleanup/redundancies: remove dead comment code and duplicate DB indexes
Some checks failed
CI / check (push) Failing after 7m33s
CI / build (push) Has been skipped
2026-06-17 15:24:47 +08:00
xfy
36055f99fa chore(deps): remove unused http-body-util and tower-http dependencies 2026-06-17 13:11:52 +08:00
xfy
260b26c693 deps: add tower-http for compression, timeout, trace middleware 2026-06-17 13:03:59 +08:00
xfy
b045a1b978 fix build errors 2026-06-17 10:52:01 +08:00
xfy
449a545886 security: fix critical issues from repository review
Some checks failed
CI / build (push) Has been cancelled
CI / check (push) Has been cancelled
P0 blockers:
- Fix migration numbering conflict and duplicate indexes
- Change comments.post_id FK to ON DELETE CASCADE
- Restrict public post detail endpoint to published posts only
- Fix rate-limiting IP extraction and fallback to ConnectInfo
- Harden HTML sanitizer: deny unknown URL schemes, restrict data URIs
- Remove session token from login response body
- Enforce image pixel/dimension limits on upload and serving

P1 high-risk:
- Validate uploads by magic bytes and decode GIF/WebP
- Add pagination/rate-limiting to search, tag posts, and comments
- Make first-admin registration and slug uniqueness check atomic
- HTML-escape comment author fields
- Improve HTML minify cache key and skip admin/error responses
- Add mobile navigation menu

P2 accessibility/quality:
- Associate form labels with inputs
- Key PostDetail article by slug to re-init scripts on navigation
- Improve image viewer keyboard accessibility
- Make theme toggle SSR-friendly and add aria-label
- Invalidate slug 404 cache on create and pending count on new comment
- Deduplicate tags case-insensitively

P3 cleanup:
- Remove unused tower-http dependency, expand make clean
- Configure DB pool timeouts and verified recycling
- Run background cleanup tasks immediately on startup
- Use SHA-256 for stable disk cache keys
- Log DB errors with Display instead of Debug
- Update README migration instructions

All tests pass (321), clippy clean, dx check clean.
2026-06-17 10:34:14 +08:00
xfy
bd659c5b4f perf: add HTML/CSS minification for SSR responses and highlight CSS
Some checks failed
CI / check (push) Failing after 5m54s
CI / build (push) Has been skipped
- Add lol_html-based HTML whitespace minifier (utils/html_minify.rs)
  that collapses whitespace and strips comments while preserving
  <pre>, <code>, <textarea>, <script>, <style> content
- Add Axum middleware (middleware/minify_html.rs) that minifies
  text/html responses with per-URL moka cache (256 entries, 300s TTL)
- Wire middleware into the server router in main.rs
- Add CSS minifier to generate_highlight_css build step
- Apply minify_html to rendered markdown output and TOC
- Add http-body-util dependency for body collection in middleware
2026-06-17 09:49:44 +08:00
xfy
56adbcf227 build: strip symbols from release binaries
Some checks failed
CI / check (push) Failing after 6m6s
CI / build (push) Has been skipped
2026-06-16 17:53:05 +08:00
xfy
a06e4a5b9d build: remove uuid js feature and commit Cargo.lock updates 2026-06-16 17:21:22 +08:00
xfy
1444ccef86 build: make sha2 and hex optional and gated by server feature 2026-06-16 17:11:15 +08:00
xfy
fa5216c6c5 build: make http optional and gated by server feature 2026-06-16 17:10:52 +08:00
xfy
d246adbb32 build: make rand optional and remove explicit getrandom dependency 2026-06-16 17:10:27 +08:00
xfy
726c6ec4e5 build: make pulldown-cmark optional and gated by server feature 2026-06-16 17:09:39 +08:00
xfy
6489ac604e build: make regex optional and gated by server feature 2026-06-16 17:09:16 +08:00
xfy
837f120621 build: make uuid optional and gated by server feature 2026-06-16 17:08:48 +08:00
xfy
6a98e8767d build: make argon2 optional and gated by server feature 2026-06-16 17:08:19 +08:00
xfy
041cdf4102 test(cache): mark cache tests serial to fix parallel flakiness 2026-06-12 17:40:15 +08:00
xfy
a10bf8737c refactor(sanitizer): extract shared sanitizer module and migrate from ammonia to lol_html 2026-06-12 11:15:42 +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
04737300e6 feat(comments): add complete comment system with guest commenting, moderation, and admin UI
Implements a fully self-built comment system for the blog:

Data layer:
- comments table with BIGSERIAL PK, parent_id self-reference (ON DELETE SET NULL),
  depth tracking (max 20), status workflow (pending/approved/spam/trash),
  content hashing for dedup, GDPR consent tracking, IP/UA storage with auto-purge
- 5 partial indexes optimized for read patterns
- updated_at auto-trigger

API (9 Dioxus server functions):
- Public: get_comments, get_comment_count, create_comment
- Admin: get_pending_comments, get_pending_count, get_all_comments,
  approve_comment (with ancestor auto-approval), spam_comment, trash_comment,
  batch_update_comment_status

Security:
- Function-level rate limiting (1/sec, burst 5) via FullstackContext IP extraction
- Input validation (name, email, URL scheme, content length, consent)
- Parent chain validation (must be approved, same post)
- Strict comment Markdown renderer (headings→strong, no img/id/data URIs, nofollow links)
- Honeypot anti-spam field
- 5-minute dedup window via SHA-256 content hash

Frontend:
- CommentSection with SuspenseBoundary isolation
- Flat-list rendering with depth-based CSS indentation (responsive)
- Gravatar via cravatar.cn (server-computed, email never exposed)
- Inline reply forms (one-at-a-time via Signal)
- Admin action buttons (approve/spam/delete) visible per-comment
- CommentForm with privacy consent, Markdown hint, loading states

Admin:
- /admin/comments page with status tabs, batch operations, pagination
- Pending count badge on admin dashboard

Infrastructure:
- Shared get_current_admin_user moved from posts/helpers to auth module
- COMMENT_LIMITER rate limiter tier
- Moka caches (60s TTL for comments, 10s for pending count)
- IP/UA purge background task (daily, 90-day retention)
2026-06-11 12:34:26 +08:00
xfy
1fa379fe4a chore: add sha2 and hex dependencies for session token hashing 2026-06-11 09:42:08 +08:00
xfy
b1a5fdcb6e chore: release v0.2.0 2026-06-10 15:46:11 +08:00
xfy
9452c196fa docs: document why image crate excludes WebP decoder 2026-06-09 16:14:28 +08:00
xfy
2e2be7b16d feat: add WebP encoding support with zenwebp
- Replace image crate's WebP with zenwebp for better quality/speed
- Add webp.rs module with configurable quality and method
- Update .env.example with WEBP_QUALITY and WEBP_METHOD
- Add WebP decode support in image serving pipeline
- Add detailed timing logs for WebP conversion
2026-06-09 15:30:06 +08:00
xfy
0345fa70f2 fix: add click handler for code block copy button 2026-06-09 11:33:26 +08:00
xfy
28d3ed998a chore: optimize release profile for fullstack and add linux static build target
- Change opt-level from 'z' to 3 for better runtime performance
- Use thin LTO for faster compilation with similar results
- Remove panic=abort and strip=true to preserve server debuggability
- Add --debug-symbols=false to dx build for smaller WASM
- Add build-linux target for static musl binary
2026-06-09 10:30:36 +08:00
xfy
4595d1c8e7 chore: remove unused dependencies and slim down features
- Remove tower_governor (unused, governor used directly instead)
- Remove tower-http fs feature (only trace is used)
- Remove 4 unused web-sys features: HtmlDocument, HtmlScriptElement, HtmlButtonElement, HtmlElement
- Slim tokio features from full to rt-multi-thread,macros,fs,time,sync
2026-06-09 10:21:27 +08:00
xfy
4f368e6fb8 test: add 122 unit tests across 12 modules
Cover utils/text, api/slug, auth/password, auth/session,
models/post, models/user, api/auth validation, api/markdown,
api/image, highlight, api/rate_limit. Add make test target.
2026-06-09 09:25:44 +08:00