const CHANGELOG_MD: &str = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [Unreleased]\n\n_\u{6682}\u{65e0}\u{672a}\u{53d1}\u{5e03}\u{6539}\u{52a8}\u{3002}_\n\n## [0.9.0] - 2026-08-03\n\n### Added\n\n- **\u{684c}\u{9762}\u{7aef}\u{60ac}\u{6d6e}\u{76ee}\u{5f55}\u{ff08}TOC\u{ff09}**\u{ff1a}\u{6587}\u{7ae0}\u{9875}\u{65b0}\u{589e}\u{5c11}\u{6570}\u{6d3e}\u{98ce}\u{683c}\u{60ac}\u{6d6e}\u{76ee}\u{5f55}\u{ff0c}\u{652f}\u{6301}\u{6eda}\u{52a8}\u{76d1}\u{542c}\u{ff08}scroll-spy\u{ff09}\u{3001}\u{60ac}\u{6d6e}\u{5c55}\u{5f00}\u{4e0e}\u{56fa}\u{5b9a}\u{ff08}pin\u{ff09}\u{6a21}\u{5f0f}\u{3002}\n- **\u{79fb}\u{52a8}\u{7aef}\u{5bfc}\u{822a}\u{52a8}\u{753b}**\u{ff1a}\u{4e3a}\u{79fb}\u{52a8}\u{7aef}\u{9876}\u{90e8}\u{5bfc}\u{822a}\u{83dc}\u{5355}\u{6dfb}\u{52a0}\u{53cc}\u{5411}\u{5e73}\u{6ed1}\u{5c55}\u{5f00}/\u{6298}\u{53e0}\u{4e0e}\u{56fe}\u{6807}\u{5fae}\u{52a8}\u{52a8}\u{753b}\u{3002}\n- **\u{53cb}\u{94fe}\u{7ba1}\u{7406}\u{529f}\u{80fd}**\u{ff1a}\u{65b0}\u{589e}\u{540e}\u{53f0}\u{53cb}\u{94fe} CRUD \u{7ba1}\u{7406}\u{3001}\u{524d}\u{53f0} `/friends` \u{5217}\u{8868}\u{5c55}\u{793a}\u{53ca} moka \u{9ad8}\u{6548}\u{7f13}\u{5b58}\u{3002}\n- **\u{8ba2}\u{9605} Feed \u{7aef}\u{70b9}**\u{ff1a}\u{65b0}\u{589e} RSS 2.0 (`/feed.xml` / `/rss.xml`) \u{4e0e} JSON Feed 1.1 (`/feed.json`) \u{8ba2}\u{9605}\u{751f}\u{6210}\u{4e0e}\u{8f93}\u{51fa}\u{7aef}\u{70b9}\u{3002}\n- **Changelog \u{7ed3}\u{6784}\u{5316}\u{65f6}\u{95f4}\u{7ebf}**\u{ff1a}\u{7248}\u{672c}\u{53d8}\u{66f4}\u{65e5}\u{5fd7}\u{5347}\u{7ea7}\u{4e3a}\u{7ed3}\u{6784}\u{5316}\u{89e3}\u{6790} + \u{65f6}\u{95f4}\u{7ebf}\u{5361}\u{7247} UI\u{3002}\n\n### Fixed\n\n- **Changelog \u{5bfc}\u{822a}\u{9ad8}\u{4eae}**\u{ff1a}\u{4fee}\u{590d} CHANGELOG \u{4fa7}\u{680f}\u{7248}\u{672c}\u{5bfc}\u{822a}\u{9ad8}\u{4eae}\u{672a}\u{80fd}\u{7cbe}\u{51c6}\u{8ddf}\u{968f}\u{5f53}\u{524d}\u{9605}\u{8bfb}\u{4f4d}\u{7f6e}\u{7684}\u{95ee}\u{9898}\u{3002}\n- **\u{53cb}\u{94fe}\u{5220}\u{9664}\u{56de}\u{8c03}**\u{ff1a}\u{4fee}\u{590d}\u{540e}\u{53f0}\u{53cb}\u{94fe}\u{5220}\u{9664}\u{786e}\u{8ba4}\u{6846}\u{5f39}\u{7a97}\u{56de}\u{8c03}\u{8bed}\u{6cd5}\u{9519}\u{8bef}\u{3002}\n- **CI \u{591a}\u{67b6}\u{6784}\u{6784}\u{5efa}**\u{ff1a}\u{4fee}\u{590d} GHCR \u{955c}\u{50cf}\u{6784}\u{5efa}\u{811a}\u{672c}\u{4e2d} `docker image inspect` \u{83b7}\u{53d6} Architecture \u{6807}\u{8bc6}\u{7684}\u{95ee}\u{9898}\u{3002}\n\n## [0.8.3] - 2026-08-03\n\n### Added\n\n- **Mermaid \u{6d41}\u{7a0b}\u{56fe}\u{5168}\u{5c4f}\u{653e}\u{5927}\u{6d6e}\u{5c42}**\u{ff1a}\u{590d}\u{6742}/\u{5bbd}\u{6d41}\u{7a0b}\u{56fe}\u{652f}\u{6301}\u{5168}\u{5c4f}\u{70b9}\u{51fb}\u{653e}\u{5927}\u{67e5}\u{770b}\u{ff0c}\u{79bb}\u{6563}\u{7f29}\u{653e}\u{652f}\u{6301} 200ms \u{5e73}\u{6ed1}\u{8fc7}\u{6e21}\u{ff0c}\u{4ea4}\u{4e92}\u{4e0e}\u{56fe}\u{7247}\u{706f}\u{7bb1}\u{7edf}\u{4e00}\u{ff08}\u{652f}\u{6301} FLIP \u{98de}\u{884c}\u{5f00}\u{5173}\u{52a8}\u{753b}\u{3001}\u{6eda}\u{52a8}\u{9a71}\u{52a8}\u{5173}\u{95ed}\u{3001}\u{62d6}\u{62fd}\u{5e73}\u{79fb}\u{3001}\u{6eda}\u{8f6e}/\u{634f}\u{5408}/\u{53cc}\u{51fb}\u{7f29}\u{653e}\u{4e0e} Esc/\u{2715} \u{5173}\u{95ed}\u{ff09}\u{3002}\n- **CI GHCR \u{955c}\u{50cf}\u{5f52}\u{6863}**\u{ff1a}GitHub Actions \u{65b0}\u{589e}\u{4e3b}\u{5e94}\u{7528}\u{591a}\u{67b6}\u{6784}\u{ff08}amd64/arm64\u{ff09}Manifest \u{955c}\u{50cf}\u{53ca} 6 \u{4e2a} Code Runner \u{6c99}\u{7bb1}\u{955c}\u{50cf}\u{5411} GHCR (`ghcr.io`) \u{81ea}\u{52a8}\u{63a8}\u{9001}\u{4e0e}\u{5f52}\u{6863}\u{3002}\n\n### Fixed\n\n- **Mermaid \u{5f02}\u{5e38}\u{5bb9}\u{5668}\u{6e05}\u{7406}**\u{ff1a}\u{4fee}\u{590d} `mermaid.render` \u{89e3}\u{6790}\u{5931}\u{8d25}\u{65f6}\u{5728} `document.body` \u{9057}\u{7559}\u{4e34}\u{65f6} `#d${id}` \u{5bb9}\u{5668}\u{5bfc}\u{81f4}\u{9875}\u{9762}\u{5e95}\u{90e8}\u{51fa}\u{73b0}\u{9519}\u{8bef}\u{5757}\u{7684}\u{89c6}\u{89c9}\u{95ee}\u{9898}\u{3002}\n- **Mermaid \u{5bbd}\u{56fe}\u{653e}\u{5927}\u{5c45}\u{4e2d}\u{504f}\u{4f4d}**\u{ff1a}\u{4fee}\u{590d} `fitToScreen` \u{5c45}\u{4e2d}\u{8ba1}\u{7b97}\u{672a}\u{4e58}\u{4ee5} `fitScale` \u{5bfc}\u{81f4}\u{5bbd}\u{56fe}\u{653e}\u{5927}\u{6d6e}\u{5c42}\u{6574}\u{4f53}\u{5411}\u{5de6}\u{4e0a}\u{504f}\u{4f4d}\u{7684}\u{95ee}\u{9898}\u{3002}\n\n### Changed\n\n- **Mermaid \u{9884}\u{52a0}\u{8f7d}\u{4e0e}\u{6e32}\u{67d3}\u{4f53}\u{9a8c}**\u{ff1a}\u{5728}\u{6d4f}\u{89c8}\u{5668}\u{7a7a}\u{95f2}\u{671f}\u{ff08}`requestIdleCallback`\u{ff09}\u{81ea}\u{52a8}\u{9884}\u{52a0}\u{8f7d} mermaid bundle \u{6a21}\u{5757}\u{ff0c}\u{5e76}\u{5728}\u{56fe}\u{50cf}\u{6e32}\u{67d3}\u{8fc7}\u{7a0b}\u{4e2d}\u{589e}\u{52a0}\u{8f6c}\u{5708}\u{89d2}\u{6807}\u{63d0}\u{793a}\u{3002}\n- **CI \u{6784}\u{5efa}\u{6d41}\u{7a0b}\u{4f18}\u{5316}**\u{ff1a}\u{9650}\u{5b9a} `build-amd64` \u{89e6}\u{53d1}\u{6761}\u{4ef6}\u{ff08}\u{4ec5}\u{4e3b}\u{5e72}\u{5206}\u{652f}\u{3001}tag \u{53ca}\u{624b}\u{52a8}\u{89e6}\u{53d1}\u{ff09}\u{ff0c}\u{589e}\u{52a0}\u{955c}\u{50cf}\u{65e0} DB \u{542f}\u{52a8}\u{5192}\u{70df}\u{6d4b}\u{8bd5}\u{4e0e} Runner \u{76ee}\u{5f55}\u{53d8}\u{66f4}\u{68c0}\u{6d4b}\u{ff0c}\u{63d0}\u{5347} CI \u{6267}\u{884c}\u{6548}\u{7387}\u{3002}\n- **\u{540e}\u{53f0}\u{7ba1}\u{7406} UI \u{7ec6}\u{8282}\u{4f18}\u{5316}**\u{ff1a}\u{4f18}\u{5316}\u{540e}\u{53f0}\u{7ba1}\u{7406}\u{9875}\u{9762} UI \u{5e03}\u{5c40}\u{7ed3}\u{6784}\u{4e0e}\u{98ce}\u{683c}\u{6837}\u{5f0f}\u{3002}\n\n## [0.8.2] - 2026-07-31\n\n### Security\n\n- **session_generation \u{81ea}\u{52a8}\u{5931}\u{6548}\u{65e7}\u{4f1a}\u{8bdd}**\u{ff1a}`users.session_generation` \u{7248}\u{672c}\u{5316}\u{673a}\u{5236}\u{6b64}\u{524d}\u{53ea}\u{6709}\u{8bfb}\u{4fa7}\u{ff08}`get_user_by_token` \u{547d}\u{4e2d}\u{7f13}\u{5b58}\u{540e}\u{56de}\u{67e5}\u{7248}\u{672c}\u{53f7}\u{ff0c}\u{4e0d}\u{5339}\u{914d}\u{5373}\u{9010}\u{51fa}\u{ff09}\u{ff0c}\u{4f46}\u{5199}\u{4fa7}\u{65e0}\u{4efb}\u{4f55}\u{81ea}\u{52a8} bump\u{2014}\u{2014}\u{964d}\u{7ea7}/\u{5c01}\u{7981}\u{7528}\u{6237}\u{540e}\u{5df2}\u{7b7e}\u{53d1}\u{4f1a}\u{8bdd}\u{4ecd}\u{957f}\u{671f}\u{6709}\u{6548}\u{3002}\u{65b0}\u{589e} BEFORE UPDATE \u{89e6}\u{53d1}\u{5668}\u{ff08}migration 018\u{ff09}\u{ff1a}\u{4ec5}\u{5728} `role` \u{771f}\u{6b63}\u{53d8}\u{5316}\u{ff08}`IS DISTINCT FROM`\u{ff09}\u{65f6} bump \u{4e16}\u{4ee3}\u{53f7}\u{ff0c}\u{5176}\u{5b83}\u{5217}\u{66f4}\u{65b0}\u{4e0d}\u{8bef}\u{4f24}\u{ff0c}\u{89e6}\u{53d1}\u{5668}\u{5185}\u{4fee}\u{6539} `NEW` \u{4e0d}\u{9012}\u{5f52}\u{3002}\u{7aef}\u{5230}\u{7aef}\u{8bed}\u{4e49}\u{7531}\u{65e2}\u{6709}\u{8bfb}\u{4fa7}\u{9010}\u{51fa}\u{903b}\u{8f91}\u{627f}\u{63a5}\u{3002}\n\n### Fixed\n\n- **\u{8bc4}\u{8bba}\u{300c}\u{5ba1}\u{6838}\u{4e2d}\u{300d}\u{5fbd}\u{7ae0}\u{6c38}\u{4e45}\u{6b8b}\u{7559}\u{ff08}issue #9 \u{56de}\u{5f52}\u{ff09}**\u{ff1a}\u{8bc4}\u{8bba}\u{5ba1}\u{6838}\u{901a}\u{8fc7}\u{540e}\u{524d}\u{7aef}\u{8f6e}\u{8be2}\u{4ece}\u{4e00}\u{6b21}\u{6027} `use_future` \u{6539}\u{4e3a} `use_resource`\u{ff08}\u{4f9d}\u{8d56} pending \u{5217}\u{8868}\u{81ea}\u{52a8}\u{91cd}\u{542f}\u{ff09}\u{ff0c}\u{5e76}\u{52a0}\u{53bb}\u{91cd} `use_effect` \u{515c}\u{5e95}\u{ff0c}\u{6839}\u{6cbb} pending \u{5360}\u{4f4d}\u{9879}\u{6b8b}\u{7559}\u{3002}\n- **mermaid \u{591a}\u{884c}\u{8282}\u{70b9}\u{6807}\u{7b7e} descender \u{88c1}\u{5207}**\u{ff1a}`foreignObject` \u{9ed8}\u{8ba4} `overflow:hidden` \u{5728}\u{90e8}\u{5206}\u{6d4f}\u{89c8}\u{5668} sub-pixel \u{6e32}\u{67d3}\u{4e0b}\u{88c1}\u{5207}\u{591a}\u{884c}\u{8282}\u{70b9}\u{4e0b}\u{6c89}\u{7b14}\u{753b}\u{ff08}g/p/y\u{ff09}\u{3002}\u{6ce8}\u{5165} SVG `overflow=\"visible\"` presentation attribute \u{4fee}\u{590d}\u{ff08}CSS `overflow` \u{5bf9} foreignObject \u{65e0}\u{6548}\u{ff0c}\u{987b}\u{5199}\u{5c5e}\u{6027}\u{ff09}\u{3002}\n- **\u{5168}\u{6587}\u{641c}\u{7d22} trigram \u{7d22}\u{5f15}**\u{ff1a}\u{6062}\u{590d} `posts.search_text` \u{7684} trigram GIN \u{7d22}\u{5f15}\u{ff08}migration 014 \u{4ee5}\u{9519}\u{8bef}\u{7406}\u{7531}\u{5220}\u{9664}\u{2014}\u{2014}`gin_trgm_ops` \u{672c}\u{5c31}\u{662f}\u{4e3a} `%pat%` \u{5305}\u{542b}\u{5339}\u{914d}\u{8bbe}\u{8ba1}\u{7684}\u{ff1b}migration 019 \u{6309} 004 \u{539f}\u{5b9a}\u{4e49}\u{91cd}\u{5efa}\u{ff09}\u{3002}`search_posts` \u{4e0e} MCP `search_published` \u{7684} ILIKE \u{4e0d}\u{518d}\u{5168}\u{8868}\u{626b}\u{3002}\n- **\u{540e}\u{53f0}\u{8868}\u{683c}\u{5217}\u{6362}\u{884c}**\u{ff1a}\u{65e5}\u{671f}/\u{72b6}\u{6001}/\u{64cd}\u{4f5c}\u{5217}\u{52a0}\u{56fa}\u{5b9a}\u{5bbd}\u{5ea6}\u{4e0e} `whitespace-nowrap`\u{ff0c}\u{907f}\u{514d}\u{7a84}\u{5c4f}\u{6362}\u{884c}\u{3002}\n- **\u{7ebf}\u{4e0a}\u{5bb9}\u{5668}\u{65e0}\u{6cd5}\u{521b}\u{5efa}\u{5907}\u{4efd}**\u{ff1a}scratch \u{955c}\u{50cf}\u{7f3a} `backups/` \u{76ee}\u{5f55}\u{4e14}\u{5c5e}\u{4e3b}\u{4e3a} root\u{3001}\u{8fdb}\u{7a0b}\u{4ee5} nobody \u{8fd0}\u{884c}\u{4e0d}\u{53ef}\u{5199}\u{3002}\u{4fee}\u{590d} `.dockerignore` \u{653e}\u{884c} `backups/.gitkeep`\u{3001}Dockerfile \u{9884}\u{5efa}\u{76ee}\u{5f55}\u{ff1b}\u{5907}\u{4efd}\u{5199}\u{5165}\u{5931}\u{8d25}\u{6539}\u{4e3a}\u{643a}\u{5e26}\u{771f}\u{5b9e} `io::Error`\u{3002}\n- **rustdoc \u{7ebf}\u{4e0a} 404**\u{ff1a}\u{955c}\u{50cf}\u{5185}\u{751f}\u{6210} rustdoc \u{4fee}\u{590d} `/doc` \u{8def}\u{7531} 404\u{ff1b}\u{8ba2}\u{6b63} rustdoc intra-doc \u{65ad}\u{94fe}\u{4e0e}\u{65e0}\u{6548} HTML \u{6807}\u{7b7e}\u{3002}\n- **Docker \u{6784}\u{5efa}**\u{ff1a}cargo-chef tarball \u{89e3}\u{538b}\u{53bb}\u{5b50}\u{76ee}\u{5f55}\u{5c42}\u{ff1b}docker-tests \u{7f3a}\u{5c11} alpine \u{955c}\u{50cf}\u{65f6}\u{8df3}\u{8fc7}\u{800c}\u{975e} panic\u{3002}\n- **release \u{540e} changelog \u{6d4b}\u{8bd5}\u{5931}\u{8d25}**\u{ff1a}\u{4fee}\u{590d}\u{53d1}\u{5e03}\u{540e}\u{9057}\u{7559}\u{7684}\u{6d4b}\u{8bd5}\u{65ad}\u{8a00}\u{5931}\u{8d25}\u{3002}\n\n### Changed\n\n- **CI \u{8fc1}\u{79fb}\u{5230} GitHub Actions**\u{ff1a}\u{4ece} Gitea Actions \u{8fc1}\u{79fb}\u{5230} GitHub Actions\u{ff0c}\u{65b0}\u{589e} SSH \u{90e8}\u{7f72}\u{5230} xun\u{ff1b}`test` + `build-amd64` \u{6539}\u{4e3a}\u{6bcf}\u{6b21}\u{63a8}\u{9001}\u{89e6}\u{53d1}\u{ff0c}`build-arm64`/`release`/`deploy` \u{6539}\u{4e3a}\u{4ec5} tag \u{63a8}\u{9001}\u{ff08}`v*`\u{ff09}\u{6216} `workflow_dispatch` \u{89e6}\u{53d1}\u{3002}\n- **arm64 \u{539f}\u{751f}\u{6784}\u{5efa} + GitHub Release \u{81ea}\u{52a8}\u{53d1}\u{5e03}**\u{ff1a}\u{65b0}\u{589e} arm64 \u{539f}\u{751f}\u{6784}\u{5efa}\u{ff08}`ubuntu-24.04-arm` runner\u{ff09}\u{ff0c}GitHub Release \u{81ea}\u{52a8}\u{53d1}\u{5e03}\u{4e09}\u{4ef6}\u{4ea7}\u{7269}\u{ff08}amd64 \u{955c}\u{50cf} / arm64 \u{955c}\u{50cf} / x86_64 musl \u{9759}\u{6001}\u{4e8c}\u{8fdb}\u{5236} + public \u{8d44}\u{6e90}\u{ff09}\u{3002}\n- **CI \u{7f13}\u{5b58}\u{4f18}\u{5316}**\u{ff1a}cargo-chef \u{4f9d}\u{8d56}\u{5206}\u{5c42} + BuildKit GHA \u{5c42}\u{7f13}\u{5b58}\u{ff1b}\u{5347}\u{7ea7}\u{6240}\u{6709} actions \u{5230} node24 \u{517c}\u{5bb9}\u{7248}\u{672c}\u{3002}\n- **lint \u{589e}\u{5f3a}**\u{ff1a}Makefile `lint` \u{76ee}\u{6807}\u{589e}\u{52a0} `cargo fmt -- --check`\u{ff1b}\u{5168}\u{4ed3}\u{5e93} cargo fmt \u{7edf}\u{4e00}\u{683c}\u{5f0f}\u{3002}\n\n### Internal\n\n- \u{8ba2}\u{6b63} `.cargo/config.toml` \u{8fc7}\u{65f6}\u{7684} cross build \u{53d9}\u{4e8b}\u{ff1b}\u{4fee}\u{6b63} CHANGELOG \u{4ee3}\u{7801}\u{56f4}\u{680f} Markdown \u{8f6c}\u{4e49}\u{3002}\n\n## [0.8.1] - 2026-07-30\n\n### Added\n\n- **MCP `update_post` \u{90e8}\u{5206}\u{66f4}\u{65b0}**\u{ff1a}`update_post` \u{6539}\u{4e3a} PATCH \u{8bed}\u{4e49}\u{ff0c}`UpdatePostParams` \u{6240}\u{6709}\u{53ef}\u{6539}\u{5b57}\u{6bb5}\u{ff08}title / content_md / summary / slug / tags / status / cover_image\u{ff09}\u{6539}\u{4e3a} `Option`\u{ff0c}\u{4ec5} `post_id` \u{5fc5}\u{586b}\u{ff1b}\u{670d}\u{52a1}\u{7aef}\u{6309}\u{63d0}\u{4f9b}\u{7684}\u{5b57}\u{6bb5}\u{52a8}\u{6001}\u{6784}\u{5efa} `UPDATE SET` \u{5b50}\u{53e5}\u{ff0c}\u{672a}\u{63d0}\u{4f9b} `content_md` \u{65f6}\u{8df3}\u{8fc7} Markdown \u{91cd}\u{65b0}\u{6e32}\u{67d3}\u{ff0c}\u{7701}\u{53bb} `spawn_blocking` \u{5f00}\u{9500}\u{3002}\u{8bed}\u{4e49}\u{8981}\u{70b9}\u{ff1a}`summary` \u{968f}\u{6b63}\u{6587}\u{8054}\u{52a8}\u{ff08}\u{6b63}\u{6587}\u{53d8}\u{4e14}\u{672a}\u{7ed9}\u{5219}\u{81ea}\u{52a8}\u{63d0}\u{53d6}\u{ff09}\u{ff1b}`slug` \u{4ec5}\u{663e}\u{5f0f}\u{63d0}\u{4f9b}\u{624d}\u{6539}\u{52a8}\u{ff1b}`tags` \u{4e3a} `None` \u{4e0d}\u{6539}\u{3001}`Some` \u{66ff}\u{6362}\u{ff08}\u{7a7a}\u{5217}\u{8868}\u{6e05}\u{7a7a}\u{ff09}\u{ff1b}`cover_image` \u{4e3a} `None` \u{4e0d}\u{6539}\u{3001}\u{7a7a}\u{4e32}\u{6e05}\u{7a7a}\u{3001}URL \u{8bbe}\u{7f6e}\u{ff1b}`status` \u{53d8}\u{5316}\u{65f6}\u{9996}\u{53d1}\u{81ea}\u{52a8}\u{586b} `published_at`\u{3002}\u{65e7}\u{7684}\u{5168}\u{91cf}\u{8c03}\u{7528}\u{ff08}\u{540c}\u{65f6}\u{4f20} title+content_md\u{ff09}\u{884c}\u{4e3a}\u{4e0d}\u{53d8}\u{ff0c}\u{5411}\u{540e}\u{517c}\u{5bb9}\u{3002}\n\n## [0.8.0] - 2026-07-30\n\n### Added\n\n- **TOML \u{8bed}\u{6cd5}\u{9ad8}\u{4eae}**\u{ff1a}`toml` \u{4ee3}\u{7801}\u{5757}\u{6b64}\u{524d}\u{56de}\u{9000}\u{4e3a}\u{7eaf}\u{6587}\u{672c}\u{ff08}syntect \u{9ed8}\u{8ba4}\u{7cbe}\u{9009}\u{96c6}\u{4e0d}\u{542b} TOML\u{ff09}\u{ff1b}\u{73b0}\u{5df2}\u{5f15}\u{5165}\u{5b98}\u{65b9} sublimehq TOML v2 \u{8bed}\u{6cd5}\u{ff0c}\u{652f}\u{6301}\u{65e5}\u{671f}\u{65f6}\u{95f4}\u{3001}\u{6570}\u{7ec4}\u{8868}\u{3001}\u{5185}\u{8054}\u{8868}\u{4e0e}\u{591a}\u{884c}\u{5b57}\u{7b26}\u{4e32}\u{3002}\n- **Docker \u{5f00}\u{53d1}\u{73af}\u{5883}**\u{ff1a}\u{65b0}\u{589e} `Dockerfile.dev` + `docker-compose.dev.yml`\u{ff0c}\u{5185}\u{7f6e} dx 0.7.9\u{3001}tailwindcss v4\u{3001}Node 22/pnpm \u{4e0e} wasm32 target\u{ff1b}\u{6e90}\u{7801} bind mount \u{5b9e}\u{73b0}\u{70ed}\u{91cd}\u{8f7d}\u{ff0c}cargo/pnpm \u{7f13}\u{5b58}\u{8de8}\u{91cd}\u{542f}\u{6301}\u{4e45}\u{5316}\u{ff0c}\u{76f4}\u{8fde}\u{5bbf}\u{4e3b}\u{539f}\u{751f} PostgreSQL\u{3002}\u{65b0}\u{589e} `make docker-dev` / `docker-dev-down` / `docker-dev-shell` \u{4fbf}\u{5229} target\u{3002}\n- **x86_64 \u{955c}\u{50cf}\u{96f6} QEMU \u{4ea4}\u{53c9}\u{7f16}\u{8bd1}**\u{ff1a}\u{6539}\u{7528} `Dockerfile.cross` \u{4e09}\u{9636}\u{6bb5}\u{6784}\u{5efa}\u{ff08}Trixie \u{7f16}\u{524d}\u{7aef} + Alpine/zig \u{4ea4}\u{53c9}\u{7f16} server + scratch \u{5408}\u{5e76}\u{4ea7}\u{7269}\u{ff09}\u{ff0c}arm64 Mac \u{4e0a}\u{4e0d}\u{518d}\u{7ecf} QEMU/Rosetta \u{7ffb}\u{8bd1}\u{ff0c}\u{544a}\u{522b} cross \u{5de5}\u{5177}\u{94fe}\u{5bb9}\u{5668}\u{5728} Rosetta \u{4e0b}\u{7684} SIGSEGV \u{5d29}\u{6e83}\u{3002}\n\n### Changed\n\n- **MCP \u{5a92}\u{4f53}\u{4e0a}\u{4f20}\u{6539}\u{4e3a}\u{5e26}\u{5916}\u{4f20}\u{8f93}\u{ff0c}\u{5f7b}\u{5e95}\u{79fb}\u{9664} base64**\u{ff1a}`upload_media` \u{5de5}\u{5177}\u{6539}\u{4e3a}\u{63a5}\u{6536} URL\u{ff0c}\u{7531}\u{670d}\u{52a1}\u{7aef}\u{7ecf} SSRF \u{9632}\u{62a4}\u{6293}\u{53d6}\u{ff08}\u{5f3a}\u{5236} https\u{3001}DNS \u{89e3}\u{6790}\u{5373}\u{9501} IP \u{675c}\u{7edd} rebinding\u{3001}\u{7981}\u{91cd}\u{5b9a}\u{5411}\u{3001}\u{6d41}\u{5f0f}\u{4f53}\u{79ef}\u{4e0a}\u{9650}\u{3001}\u{8d85}\u{65f6}\u{ff09}\u{ff1b}\u{65b0}\u{589e} `POST /api/mcp/upload` bearer multipart \u{7aef}\u{70b9}\u{ff0c}\u{4f9b} host/shell \u{76f4}\u{63a5} POST \u{4e8c}\u{8fdb}\u{5236}\u{3002}\u{4e8c}\u{8fdb}\u{5236}\u{4e0d}\u{518d}\u{8fdb} JSON-RPC\u{ff0c}\u{4e0d}\u{518d}\u{53d7} 4MiB \u{8bf7}\u{6c42}\u{4f53}\u{4e0a}\u{9650}\u{ff08}\u{539f} base64 \u{8def}\u{5f84}\u{5b9e}\u{9645}\u{4ec5}\u{7ea6} 2.8MiB \u{539f}\u{59cb}\u{56fe}\u{ff09}\u{7ea6}\u{675f}\u{3002}\u{65b0}\u{589e} server-only \u{4f9d}\u{8d56} `reqwest`\u{ff08}rustls-tls\u{ff0c}musl \u{9759}\u{6001}\u{94fe}\u{63a5}\u{53cb}\u{597d}\u{ff09}\u{ff0c}\u{79fb}\u{9664} `base64` \u{4f9d}\u{8d56}\u{3002}\n\n### Fixed\n\n- **\u{4ea4}\u{53c9}\u{7f16}\u{8bd1}\u{90e8}\u{7f72}\u{540e}\u{767b}\u{5f55} 405**\u{ff1a}Dioxus 0.7.9 \u{7684} server-fn URL \u{672b}\u{5c3e}\u{53bb}\u{51b2}\u{7a81}\u{540e}\u{7f00}\u{4e3a} `xxh64(CARGO_MANIFEST_DIR + module_path!, 0)`\u{ff1b}host \u{4ea4}\u{53c9}\u{7f16}\u{8bd1}\u{4e0e}\u{5bb9}\u{5668}\u{5185}\u{7f16}\u{8bd1}\u{7684} `CARGO_MANIFEST_DIR` \u{4e0d}\u{540c}\u{ff0c}\u{5bfc}\u{81f4}\u{524d}\u{540e}\u{7aef}\u{7b97}\u{51fa}\u{4e0d}\u{540c} URL \u{540e}\u{7f00}\u{ff0c}POST \u{843d}\u{5165} SSR \u{515c}\u{5e95} GET \u{8def}\u{7531}\u{8fd4}\u{56de} 405\u{3002}\u{6539}\u{7531} `.cargo/config.toml` \u{56fa}\u{5b9a} `SERVER_FN_OVERRIDE_KEY`\u{ff0c}\u{4e24}\u{6b21}\u{7f16}\u{8bd1}\u{8bfb}\u{5230}\u{540c}\u{4e00}\u{54c8}\u{5e0c} key\u{3002}\n- **Dockerfile \u{6f0f}\u{62f7} workspace \u{5305}**\u{ff1a}\u{4e24}\u{4e2a} Dockerfile \u{7684} pnpm manifest COPY \u{6b64}\u{524d}\u{53ea}\u{62f7}\u{4e86} 4/7 \u{4e2a}\u{5305}\u{ff0c}\u{8865}\u{9f50} `shared` / `xterm-terminal` / `mermaid-renderer`\u{3002}\n\n## [0.7.0] - 2026-07-29\n\n### Added\n\n- **MCP \u{670d}\u{52a1}\u{5668}**\u{ff1a}\u{535a}\u{5ba2}\u{73b0}\u{5728}\u{662f}\u{4e00}\u{4e2a} Model Context Protocol \u{670d}\u{52a1}\u{5668}\u{ff08}`POST /mcp`\u{ff0c}Streamable HTTP\u{ff0c}\u{65e0}\u{72b6}\u{6001}\u{ff09}\u{ff0c}\u{7ba1}\u{7406}\u{5458}\u{7684} AI \u{5ba2}\u{6237}\u{7aef}\u{ff08}Claude Code / Cursor / Cline\u{ff09}\u{53ef}\u{7ecf} bearer token \u{8fde}\u{63a5}\u{ff0c}\u{628a}\u{5df2}\u{53d1}\u{5e03}\u{6587}\u{7ae0}\u{5f53}\u{77e5}\u{8bc6}\u{5e93}\u{68c0}\u{7d22}\u{ff0c}\u{5e76}\u{6267}\u{884c}\u{51e0}\u{4e4e}\u{6240}\u{6709}\u{540e}\u{53f0}\u{64cd}\u{4f5c}\u{3002}\n - **\u{8ba4}\u{8bc1}**\u{ff1a}\u{7ba1}\u{7406}\u{5458}\u{5728} `/admin/mcp` \u{7b7e}\u{53d1}\u{4ee4}\u{724c}\u{ff0c}\u{4e09}\u{6863}\u{4f5c}\u{7528}\u{57df}\u{ff08}read / write / admin\u{ff09}\u{ff0c}\u{53ef}\u{9009}\u{6709}\u{6548}\u{671f}\u{ff08}1/7/30/90 \u{5929} / \u{6c38}\u{4e0d}\u{8fc7}\u{671f}\u{ff09}\u{3002}\u{4ee4}\u{724c}\u{660e}\u{6587}\u{7ecf} AES-GCM-256 \u{9759}\u{6001}\u{52a0}\u{5bc6}\u{5b58}\u{50a8}\u{ff08}\u{53ef}\u{91cd}\u{67e5}\u{ff09}\u{ff0c}SHA-256 \u{54c8}\u{5e0c}\u{505a}\u{6bcf}\u{8bf7}\u{6c42}\u{67e5}\u{627e}\u{3002}\n - **\u{77e5}\u{8bc6}\u{5e93}\u{ff08}read\u{ff09}**\u{ff1a}`search_posts` / `get_post` / `list_tags` \u{5de5}\u{5177} + \u{5df2}\u{53d1}\u{5e03}\u{6587}\u{7ae0}\u{4f5c}\u{4e3a}\u{53ef}\u{679a}\u{4e3e}\u{7684} MCP Resources\u{ff08}`post://{slug}`\u{ff0c}\u{6e38}\u{6807}\u{5206}\u{9875}\u{ff09}\u{3002}\n - **\u{5199}\u{64cd}\u{4f5c}\u{ff08}write\u{ff09}**\u{ff1a}\u{6587}\u{7ae0} CRUD\u{ff08}\u{542b}\u{8349}\u{7a3f}\u{ff09}\u{3001}\u{8bc4}\u{8bba}\u{5ba1}\u{6838}\u{3001}\u{6807}\u{7b7e}\u{7ba1}\u{7406}\u{3001}\u{5a92}\u{4f53}\u{4e0a}\u{4f20}\u{ff08}base64 \u{2192} WebP \u{8f6c}\u{7801}\u{53bb}\u{91cd}\u{ff09}\u{3002}\n - **\u{7ba1}\u{7406}\u{ff08}admin\u{ff09}**\u{ff1a}\u{7ad9}\u{70b9}\u{8bbe}\u{7f6e}\u{8bfb}\u{5199}\u{3001}\u{4ee3}\u{7801}\u{8fd0}\u{884c}\u{5668}\u{ff08}\u{6c99}\u{7bb1}\u{6267}\u{884c}\u{ff09}\u{3002}\n - **\u{52a0}\u{56fa}**\u{ff1a}token-keyed \u{9650}\u{6d41}\u{ff08}\u{9ed8}\u{8ba4} 10/s burst 30\u{ff0c}\u{8d85}\u{9650} 429\u{ff09}\u{3001}`last_used_at` \u{8282}\u{6d41}\u{5237}\u{65b0}\u{3001}\u{9274}\u{6743}\u{5ba1}\u{8ba1}\u{65e5}\u{5fd7}\u{3001}Origin\u{2192}403\u{ff08}spec \u{5f3a}\u{5236}\u{ff0c}rmcp \u{5185}\u{7f6e}\u{ff09}\u{3001}\u{534f}\u{8bae}\u{7248}\u{672c}\u{5934}\u{6821}\u{9a8c}\u{3001}4MiB \u{8bf7}\u{6c42}\u{4f53}\u{4e0a}\u{9650}\u{3002}\n - **\u{914d}\u{7f6e}\u{751f}\u{6210}**\u{ff1a}\u{540e}\u{53f0}\u{4e00}\u{952e}\u{590d}\u{5236} 4 \u{79cd}\u{5ba2}\u{6237}\u{7aef}\u{914d}\u{7f6e}\u{ff08}Claude Code / Cursor / Cline / \u{901a}\u{7528} JSON + CLI\u{ff09}\u{3002}\n - \u{4f20}\u{8f93}\u{7528}\u{5b98}\u{65b9} `rmcp` crate\u{ff08}`=3.0.0-beta.3`\u{ff0c}3.x \u{624d}\u{6709} Origin \u{6821}\u{9a8c}\u{7b49} spec \u{5f3a}\u{5236}\u{9879}\u{ff09}\u{6302}\u{8f7d}\u{4e8e} axum\u{3002}\u{65b0}\u{589e}\u{4f9d}\u{8d56} `rmcp`\u{3001}`aes-gcm`\u{3001}`base64`\u{ff08}\u{5747} server-only\u{ff09}\u{3002}\n - \u{65b0}\u{589e}\u{73af}\u{5883}\u{53d8}\u{91cf} `MCP_TOKEN_ENC_KEY`\u{ff08}hex \u{7f16}\u{7801} 32 \u{5b57}\u{8282} AES-256 \u{5bc6}\u{94a5}\u{ff0c}`openssl rand -hex 32` \u{751f}\u{6210}\u{ff09}\u{3001}`RATE_LIMIT_MCP_PER_SEC` / `RATE_LIMIT_MCP_BURST`\u{3002}\n- **\u{7d20}\u{6750}\u{7ba1}\u{7406}\u{ff08}\u{5a92}\u{4f53}\u{5e93}\u{ff09}**\u{ff1a}\u{65b0}\u{589e} `media_assets` \u{6ce8}\u{518c}\u{8868}\u{6570}\u{636e}\u{5c42}\u{4e0e} `/admin/assets` \u{7ba1}\u{7406}\u{9875}\u{ff0c}\u{628a}\u{4e0a}\u{4f20}\u{7684}\u{56fe}\u{7247}\u{5f53}\u{4f5c}\u{4e00}\u{7b49}\u{516c}\u{6c11}\u{7ba1}\u{7406}\u{3002}\n - **\u{53ea}\u{8bfb}\u{5217}\u{8868}\u{9875}**\u{ff1a}\u{7d20}\u{6750}\u{7f51}\u{683c} + \u{5f15}\u{7528}/\u{672a}\u{5f15}\u{7528}\u{ff08}\u{5b64}\u{513f}\u{ff09}\u{7b5b}\u{9009}\u{ff1b}\u{5f15}\u{7528}\u{5fbd}\u{6807}\u{5c55}\u{793a}\u{88ab}\u{54ea}\u{4e9b}\u{6587}\u{7ae0}\u{5f15}\u{7528}\u{3002}\n - **\u{5220}\u{9664}\u{4fdd}\u{62a4}\u{3001}\u{5b64}\u{513f}\u{6e05}\u{7406}\u{4e0e} alt \u{7f16}\u{8f91}**\u{ff1a}\u{88ab}\u{5f15}\u{7528}\u{7d20}\u{6750}\u{4e0d}\u{53ef}\u{5220}\u{9664}\u{ff1b}\u{53ef}\u{4e00}\u{952e}\u{6e05}\u{7406}\u{65e0}\u{5f15}\u{7528}\u{7684}\u{5b64}\u{513f}\u{7d20}\u{6750}\u{ff1b}\u{5c31}\u{5730}\u{7f16}\u{8f91} alt \u{6587}\u{672c}\u{3002}\n - **\u{5168}\u{91cf}\u{7d22}\u{5f15}\u{91cd}\u{5efa}**\u{ff1a}\u{626b}\u{63cf} `posts.content_html` \u{91cd}\u{5efa}\u{6bcf}\u{5f20}\u{56fe}\u{7247}\u{7684}\u{5f15}\u{7528}\u{5173}\u{7cfb}\u{ff08}\u{6279}\u{91cf} 500\u{ff09}\u{3002}\n - **\u{5c01}\u{9762}\u{300c}\u{4ece}\u{7d20}\u{6750}\u{5e93}\u{9009}\u{62e9}\u{300d}\u{8054}\u{52a8}**\u{ff1a}\u{5199}\u{6587}\u{7ae0}\u{9875}\u{5c01}\u{9762}\u{56fe}\u{6539}\u{4e3a}\u{4ece}\u{5a92}\u{4f53}\u{5e93}\u{6311}\u{9009}\u{ff0c}\u{5c01}\u{9762}\u{4e0e}\u{7d20}\u{6750}\u{5e93}\u{6253}\u{901a}\u{3002}\n - **\u{706f}\u{7bb1}\u{9884}\u{89c8}**\u{ff1a}\u{7d20}\u{6750}\u{7f51}\u{683c}\u{63a5}\u{5165} Lightbox\u{ff0c}\u{652f}\u{6301}\u{56fe}\u{96c6}\u{5207}\u{6362}\u{6d4f}\u{89c8}\u{3002}\n - **\u{641c}\u{7d22}\u{4e0e}\u{9632}\u{6296}**\u{ff1a}\u{7d20}\u{6750}\u{9875}\u{641c}\u{7d22}\u{6846} 300ms \u{9632}\u{6296}\u{3002}\n - **\u{591a}\u{9009}\u{4e0e}\u{6279}\u{91cf}\u{5220}\u{9664}**\u{3002}\n - **\u{4e0a}\u{4f20}\u{53bb}\u{91cd}**\u{ff1a}\u{4e0a}\u{4f20}\u{56fe}\u{7247}\u{6309}\u{5185}\u{5bb9} SHA-256 \u{8ba1}\u{7b97}\u{6307}\u{7eb9}\u{ff0c}\u{91cd}\u{590d}\u{4e0a}\u{4f20}\u{76f4}\u{63a5}\u{590d}\u{7528}\u{5df2}\u{767b}\u{8bb0}\u{7d20}\u{6750}\u{ff0c}\u{4e0d}\u{518d}\u{4ea7}\u{751f}\u{5197}\u{4f59}\u{6587}\u{4ef6}\u{3002}\n - **Pagination \u{9875}\u{7801}\u{8df3}\u{8f6c}**\u{ff1a}\u{7d20}\u{6750}\u{5217}\u{8868}\u{5206}\u{9875}\u{652f}\u{6301}\u{9875}\u{7801}\u{76f4}\u{8df3}\u{ff08}`Pagination` \u{7ec4}\u{4ef6}\u{65b0}\u{589e}\u{8df3}\u{8f6c}\u{80fd}\u{529b}\u{ff09}\u{3002}\n- **\u{5173}\u{4e8e}\u{9875}\u{91cd}\u{8bbe}\u{8ba1}**\u{ff1a}\u{5173}\u{4e8e}\u{9875}\u{91cd}\u{5236}\u{4e3a}\u{300c}\u{4e16}\u{754c}\u{6811}\u{4e0e}\u{9057}\u{5fd8}\u{300d}\u{4e3b}\u{9898}\u{53d9}\u{4e8b}\u{ff0c}\u{65b0}\u{589e}\u{5e74}\u{8f6e}\u{5f0f}\u{94fe}\u{63a5}\u{533a}\u{3002}\n- **`/changelog` \u{9875}\u{9762}**\u{ff1a}\u{65b0}\u{589e}\u{66f4}\u{65b0}\u{65e5}\u{5fd7}\u{9875}\u{ff0c}\u{5185}\u{5d4c}\u{6e32}\u{67d3} `CHANGELOG.md`\u{ff0c}\u{5e76}\u{5728}\u{5e74}\u{8f6e}\u{533a}\u{63a5}\u{5165}\u{5165}\u{53e3}\u{3002}\n- **\u{540e}\u{53f0}\u{4eea}\u{8868}\u{76d8}\u{52a8}\u{753b}**\u{ff1a}\u{4eea}\u{8868}\u{76d8}\u{5206}\u{5757}\u{8fdb}\u{573a}\u{52a8}\u{753b} + \u{6570}\u{5b57}\u{6eda}\u{52a8}\u{ff0c}\u{8282}\u{594f}\u{53ef}\u{8c03}\u{3002}\n- **`FormSelect` \u{4e3b}\u{9898}\u{5316}\u{4e0b}\u{62c9}\u{7ec4}\u{4ef6}**\u{ff1a}\u{5c01}\u{88c5}\u{81ea}\u{5b9a}\u{4e49}\u{4e3b}\u{9898}\u{5316}\u{4e0b}\u{62c9}\u{5f39}\u{5c42}\u{ff0c}\u{66ff}\u{4ee3}\u{539f}\u{751f} `<select>`\u{ff08}OS \u{5f39}\u{7a97}\u{65e0}\u{6cd5}\u{8ddf}\u{968f}\u{4e3b}\u{9898}\u{ff09}\u{ff1b}\u{5168}\u{9879}\u{76ee}\u{539f}\u{751f} `<select>` \u{7edf}\u{4e00}\u{66ff}\u{6362}\u{4e3a} `FormSelect`\u{3002}\n- **\u{540e}\u{53f0}\u{6587}\u{7ae0}\u{641c}\u{7d22}**\u{ff1a}\u{6587}\u{7ae0}\u{5217}\u{8868}\u{652f}\u{6301}\u{6309}\u{6807}\u{9898}\u{641c}\u{7d22}\u{3002}\n- **MCP \u{914d}\u{7f6e}\u{751f}\u{6210} UI**\u{ff1a}\u{5ba2}\u{6237}\u{7aef}\u{914d}\u{7f6e}\u{4ee3}\u{7801}\u{5757}\u{52a0}\u{8bed}\u{6cd5}\u{9ad8}\u{4eae}\u{3001}\u{590d}\u{5236}\u{6309}\u{94ae}\u{5c31}\u{5730}\u{53cd}\u{9988}\u{ff1b}\u{4ee4}\u{724c}\u{5217}\u{8868}\u{4e0e}\u{914d}\u{7f6e}\u{751f}\u{6210} loading \u{66ff}\u{6362}\u{4e3a}\u{9aa8}\u{67b6}\u{5c4f}\u{ff1b}\u{65b0}\u{589e} OpenCode \u{5ba2}\u{6237}\u{7aef}\u{914d}\u{7f6e}\u{7247}\u{6bb5}\u{3002}\n\n### Changed\n\n- **\u{91cd}\u{6784}\u{7cfb}\u{5217} R2\u{2013}R6**\u{ff1a}\u{62bd}\u{53d6} `tools/common.rs` \u{6d88}\u{9664} MCP helper \u{56db}\u{91cd}\u{62f7}\u{8d1d}\u{ff08}R2\u{ff09}\u{ff1b}\u{653e}\u{5bbd} posts helpers \u{53ef}\u{89c1}\u{6027}\u{5e76}\u{5220}\u{9664} MCP \u{5185}\u{7684}\u{5e73}\u{884c}\u{62f7}\u{8d1d}\u{ff08}R3\u{ff09}\u{ff1b}\u{62bd}\u{53d6} `render_post_fields` \u{6d88}\u{9664}\u{6587}\u{7ae0}\u{6e32}\u{67d3} + \u{5b57}\u{6570}/\u{9605}\u{8bfb}\u{65f6}\u{95f4}\u{5ea6}\u{91cf}\u{7684}\u{91cd}\u{590d}\u{ff08}R4\u{ff09}\u{ff1b}\u{62bd}\u{53d6} `fetch_post_tags` \u{6d88}\u{9664} 9+ \u{5904}\u{6807}\u{7b7e}\u{67e5}\u{8be2}\u{91cd}\u{590d}\u{ff08}R5\u{ff09}\u{ff1b}\u{62bd}\u{53d6} `invalidate_for_post_write` \u{7edf}\u{4e00}\u{5199}\u{540e}\u{7f13}\u{5b58}\u{5931}\u{6548}\u{5e8f}\u{5217}\u{ff08}R6\u{ff09}\u{3002}\n- **utils \u{5e38}\u{91cf}\u{96c6}\u{4e2d}**\u{ff1a}\u{96c6}\u{4e2d} `hash_token` / `EMAIL_REGEX` / `MAX_FILE_SIZE` \u{7684}\u{91cd}\u{590d}\u{5b9a}\u{4e49}\u{ff1b}\u{96c6}\u{4e2d} `MIGRATE_STARTUP_TIMEOUT_SECS` \u{89e3}\u{6790}\u{ff1b}\u{63d0}\u{53d6} `formatted_date` \u{516c}\u{5171}\u{5b9e}\u{73b0}\u{ff1b}\u{7edf}\u{4e00} LIKE \u{6a21}\u{5f0f}\u{8f6c}\u{4e49}\u{ff08}`consts`\u{ff09}\u{3002}\n- **\u{8f93}\u{5165}\u{6846}\u{7edf}\u{4e00} `FormInput`**\u{ff1a}\u{540e}\u{53f0}\u{6587}\u{7ae0}\u{641c}\u{7d22}\u{6846}\u{3001}SQL \u{63a7}\u{5236}\u{53f0}\u{8f93}\u{5165}\u{6846}\u{7b49}\u{7edf}\u{4e00}\u{6539}\u{7528} `FormInput` \u{516c}\u{5171}\u{7ec4}\u{4ef6}\u{3002}\n- **\u{4ee3}\u{7801}\u{8fd0}\u{884c}\u{5668}\u{6267}\u{884c}\u{5c42}**\u{ff1a}\u{62bd}\u{53d6} `spawn_exec_task` \u{6d88}\u{9664} `start_exec` / `stream` \u{91cd}\u{590d}\u{ff08}M10\u{ff09}\u{3002}\n\n### Fixed\n\n- **KaTeX `\\pu` \u{8f6c}\u{8bd1}**\u{ff1a}\u{4fee}\u{590d} `\\pu` \u{9884}\u{8f6c}\u{8bd1}\u{7684} off-by-one \u{4e0e} UTF-8 \u{7834}\u{574f}\u{ff08}C1+C2\u{ff09}\u{3002}\n- **\u{4ee3}\u{7801}\u{8fd0}\u{884c}\u{5668}**\u{ff1a}\u{6d41}\u{5f0f}\u{6267}\u{884c}\u{8d85}\u{9650}\u{65f6}\u{56de}\u{6536}\u{6302}\u{8d77}\u{7684}\u{5bb9}\u{5668}\u{ff0c}\u{907f}\u{514d}\u{6cc4}\u{6f0f}\u{ff08}C3\u{ff09}\u{ff1b}\u{79fb}\u{9664} `source_prop_signal` \u{7684}\u{6e32}\u{67d3}\u{7eaf}\u{51c0}\u{6027}\u{8fdd}\u{89c4}\u{ff08}C4\u{ff09}\u{3002}\n- **\u{56fe}\u{7247}\u{7f13}\u{5b58}\u{6e05}\u{7406}\u{4efb}\u{52a1}**\u{ff1a}\u{9632}\u{6ea2}\u{51fa}/\u{4e0b}\u{6ea2} panic\u{ff08}C5\u{ff09}\u{3002}\n- **MCP \u{5de5}\u{5177}\u{5f52}\u{5c5e}\u{4e0e}\u{7f13}\u{5b58}**\u{ff1a}trash/delete \u{8865}\u{5f52}\u{5c5e}\u{6821}\u{9a8c} + `publish_post` \u{6807}\u{7b7e}\u{7f13}\u{5b58}\u{5931}\u{6548}\u{ff08}M1+M6\u{ff09}\u{ff1b}\u{6807}\u{7b7e}\u{6587}\u{7ae0}\u{6570}\u{8ba1}\u{6570} + \u{6279}\u{91cf}\u{5220}\u{9664} SSR \u{5931}\u{6548}\u{ff08}M2+M5\u{ff09}\u{3002}\n- **\u{5907}\u{4efd}/\u{6062}\u{590d}**\u{ff1a}`pg_dump`/`psql` \u{79fb}\u{5165} `spawn_blocking` \u{5e76}\u{6309}\u{884c}\u{8bfb}\u{53d6}\u{ff0c}\u{907f}\u{514d}\u{963b}\u{585e}\u{5f02}\u{6b65}\u{7ebf}\u{7a0b}\u{ff08}M3\u{ff09}\u{3002}\n- **\u{8bc4}\u{8bba}**\u{ff1a}\u{8bc4}\u{8bba} markdown \u{6e32}\u{67d3}\u{79fb}\u{5165} `spawn_blocking`\u{ff08}M4\u{ff09}\u{3002}\n- **\u{6807}\u{7b7e}\u{9875}\u{7f13}\u{5b58}**\u{ff1a}\u{79fb}\u{9664}\u{672a}\u{4f7f}\u{7528}\u{4e14}\u{6c38}\u{4e0d}\u{5931}\u{6548}\u{7684} `PostsByTagPage` \u{7f13}\u{5b58}\u{952e}\u{ff08}M7\u{ff09}\u{3002}\n- **\u{9650}\u{6d41}**\u{ff1a}\u{952e}\u{63a7}\u{9650}\u{6d41}\u{5668}\u{5b9a}\u{671f} GC + XFF \u{4f2a}\u{9020}\u{98ce}\u{9669}\u{6587}\u{6863}\u{5316}\u{ff08}M8\u{ff09}\u{ff0c}GC \u{4efb}\u{52a1}\u{6d3e}\u{751f}\u{5b88}\u{536b}\u{8fd0}\u{884c}\u{65f6}\u{53ef}\u{7528}\u{6027}\u{3002}\n- **\u{6570}\u{636e}\u{5bfc}\u{51fa}**\u{ff1a}\u{4e0d}\u{518d}\u{5411} HTTP \u{54cd}\u{5e94}\u{6cc4}\u{9732}\u{539f}\u{59cb} DB \u{9519}\u{8bef}\u{ff08}M9\u{ff09}\u{3002}\n- **SQL \u{63a7}\u{5236}\u{53f0}**\u{ff1a}\u{8bfb}\u{8def}\u{5f84}\u{8ffd}\u{52a0} `LIMIT` \u{907f}\u{514d}\u{5168}\u{8868}\u{7269}\u{5316}\u{ff08}M11\u{ff09}\u{ff1b}`SHOW` \u{53ea}\u{8bfb}\u{5206}\u{7c7b}\u{4fee}\u{6b63}\u{3002}\n- **\u{540e}\u{53f0}\u{6587}\u{7ae0}\u{5217}\u{8868}**\u{ff1a}\u{6e32}\u{67d3}\u{62c9}\u{53d6}\u{5931}\u{8d25}\u{7684}\u{9519}\u{8bef}\u{6001}\u{ff08}M12\u{ff09}\u{3002}\n- **\u{7d20}\u{6750}\u{7ba1}\u{7406}**\u{ff1a}uuid \u{53c2}\u{6570}\u{5e8f}\u{5217}\u{5316}\u{5931}\u{8d25}\u{5bfc}\u{81f4}\u{4e0a}\u{4f20} 500\u{ff1b}`SUM(size_bytes)` \u{663e}\u{5f0f}\u{8f6c} bigint \u{4fee}\u{590d}\u{5217}\u{8868} 500\u{ff1b}\u{5f15}\u{7528}\u{5fbd}\u{6807}\u{52a0} `z-10` \u{4fee}\u{590d}\u{88ab} blur-img \u{906e}\u{76d6}\u{ff1b}\u{706f}\u{7bb1}\u{56fe}\u{96c6}\u{5207}\u{6362}\u{4e0d}\u{91cd}\u{7b97}\u{51e0}\u{4f55}\u{5bfc}\u{81f4}\u{56fe}\u{7247}\u{538b}\u{6241}\u{ff1b}\u{5220}\u{9664}\u{8fd4}\u{56de}\u{300c}\u{7d20}\u{6750}\u{4e0d}\u{5b58}\u{5728}\u{300d}\u{65f6}\u{5237}\u{65b0}\u{7f51}\u{683c}\u{81ea}\u{6108}\u{8fc7}\u{671f}\u{6570}\u{636e}\u{ff1b}\u{5de5}\u{5177}\u{680f}\u{53f3}\u{4fa7}\u{6309}\u{94ae}\u{6c89}\u{5165} `FilterTabs` \u{533a}\u{57df}\u{7d27}\u{8d34}\u{6a2a}\u{5e45}\u{ff1b}\u{64cd}\u{4f5c}\u{6a2a}\u{5e45}\u{4e0a}\u{4e0b}\u{95f4}\u{8ddd}\u{4e0d}\u{5bf9}\u{79f0}\u{ff08}40/8 \u{2192} 24/24\u{ff09}\u{3002}\n- **MCP**\u{ff1a}reveal/revoke \u{4ee4}\u{724c}\u{65f6}\u{5c06}\u{5b57}\u{7b26}\u{4e32} id \u{89e3}\u{6790}\u{4e3a} `Uuid`\u{ff1b}`FormSelect` \u{9762}\u{677f}\u{6c34}\u{5e73}\u{5c45}\u{4e2d}\u{4fee}\u{590d}\u{53cc}\u{500d}\u{4f4d}\u{79fb}\u{ff1b}\u{5ba2}\u{6237}\u{7aef}\u{914d}\u{7f6e}\u{683c}\u{5f0f}\u{4fee}\u{6b63}\u{ff08}Claude Code / Cursor / Cline\u{ff0c}\u{8054}\u{7f51}\u{6838}\u{5b9e} 2026\u{ff09}\u{ff1b}\u{914d}\u{7f6e}\u{751f}\u{6210} `use_effect` \u{6b7b}\u{5faa}\u{73af}\u{ff1b}\u{5f00}\u{53d1}\u{671f}\u{653e}\u{884c} `0.0.0.0` Host \u{8ba9} dx \u{4ee3}\u{7406}\u{53ef}\u{7528}\u{3001}Host \u{767d}\u{540d}\u{5355}\u{52a0}\u{5165} `APP_BASE_URL` \u{57df}\u{540d}\u{3002}\n- **\u{6587}\u{6863}**\u{ff1a}\u{4fee}\u{6b63}\u{6587}\u{6863}\u{6f02}\u{79fb}\u{ff08}AGENTS.md / DEPLOYMENT / .env.example \u{7b49}\u{ff09}\u{3002}\n\n### Removed\n\n- **\u{6b7b}\u{4ee3}\u{7801}\u{6e05}\u{7406} D1\u{2013}D12**\u{ff1a}\u{5220}\u{9664}\u{6b7b}\u{6a21}\u{5757} `resources.rs`\u{3001}\u{6b7b} `User` \u{7ed3}\u{6784}\u{4f53}\u{3001}\u{672a}\u{7528}\u{53c2}\u{6570}\u{3001}mhchem \u{5197}\u{4f59}\u{5206}\u{652f}\u{3001}\u{6b7b}\u{5bfc}\u{51fa}\u{4e0e}\u{6587}\u{6863}\u{5316}\u{6b7b}\u{5206}\u{652f}\u{3001}\u{672a}\u{4f7f}\u{7528}\u{4e14}\u{6c38}\u{4e0d}\u{5931}\u{6548}\u{7684}\u{7f13}\u{5b58}\u{952e}\u{7b49}\u{ff1b}\u{6536}\u{7a84}\u{6a21}\u{5757}\u{7ea7} allow\u{3002}\n- \u{8fc1}\u{79fb}\u{540e}\u{8865}\u{56de}/\u{79fb}\u{9664}\u{6d4b}\u{8bd5}\u{4e2d}\u{5931}\u{6548}\u{7684} `sha2::Digest` \u{5bfc}\u{5165}\u{3002}\n\n## [0.6.2] - 2026-07-24\n\n### Fixed\n\n- **web-only \u{6784}\u{5efa}\u{5931}\u{8d25}**\u{ff1a}`sleep_ms` \u{539f}\u{7528} `#[cfg(not(target_arch = \"wasm32\"))]` guard tokio \u{5206}\u{652f}\u{ff0c}\u{4f46} tokio \u{662f} server-only optional \u{4f9d}\u{8d56}\u{3002}\u{8be5} guard \u{5728}\u{300c}\u{975e} wasm32 \u{4e3b}\u{673a} + \u{4ec5} web feature\u{300d}\u{7ec4}\u{5408}\u{4e0b}\u{8bef}\u{6fc0}\u{6d3b}\u{5bfc}\u{81f4}\u{7f16}\u{8bd1}\u{5931}\u{8d25}\u{ff08}\u{957f}\u{671f}\u{88ab} dev-dependencies \u{4e2d}\u{7684} tokio \u{63a9}\u{76d6}\u{ff0c}\u{53ea}\u{6709}\u{6392}\u{9664} dev-deps \u{7684}\u{751f}\u{4ea7}\u{6784}\u{5efa}\u{624d}\u{66b4}\u{9732}\u{ff09}\u{3002}\u{4fee}\u{590d}\u{4e3a} `#[cfg(all(feature = \"server\", not(target_arch = \"wasm32\")))]`\u{ff0c}\u{7b26}\u{5408} dual-target gating \u{89c4}\u{8303}\u{3002}\n- **404 \u{9875}\u{300c}\u{8fd4}\u{56de}\u{9996}\u{9875}\u{300d}\u{5361}\u{6b7b}**\u{ff1a}\u{6587}\u{7ae0}\u{8be6}\u{60c5}\u{9875}\u{5bf9}\u{4e0d}\u{5b58}\u{5728}\u{7684} slug \u{629b}\u{51fa} 404 \u{9519}\u{8bef}\u{540e}\u{ff0c}Dioxus `ErrorBoundary` \u{6355}\u{83b7}\u{9519}\u{8bef}\u{6e32}\u{67d3} fallback\u{ff0c}\u{4f46}\u{70b9}\u{51fb}\u{300c}\u{8fd4}\u{56de}\u{9996}\u{9875}\u{300d}\u{4ec5}\u{66f4}\u{65b0} URL \u{4e0d}\u{5207}\u{6362}\u{9875}\u{9762}\u{ff08}`ErrorBoundary` \u{9700}\u{663e}\u{5f0f} `clear_errors()` \u{624d}\u{80fd}\u{6062}\u{590d}\u{6e32}\u{67d3} children\u{ff09}\u{3002}\u{4fee}\u{590d}\u{ff1a}\u{8fd4}\u{56de}\u{9996}\u{9875}\u{6539}\u{7528} button\u{ff0c}onclick \u{5185}\u{5148} `clear_errors()` \u{518d}\u{5bfc}\u{822a}\u{3002}\n\n## [0.6.1] - 2026-07-23\n\n### Changed\n\n- **\u{6d88}\u{9664}\u{975e}\u{6d4b}\u{8bd5}\u{4ee3}\u{7801}\u{4e2d}\u{7684}\u{88f8} `unwrap()`**\u{ff1a}\u{5728} `panic = \"abort\"` \u{5168}\u{5c40}\u{4e0b}\u{ff0c}\u{4efb}\u{4f55}\u{88f8} `unwrap()` \u{90fd}\u{4f1a}\u{76f4}\u{63a5}\u{5d29}\u{6e83}\u{6574}\u{4e2a}\u{8fdb}\u{7a0b}\u{4e14}\u{65e0}\u{6cd5}\u{6062}\u{590d}\u{3002}\u{5c06}\u{6240}\u{6709}\u{975e}\u{6d4b}\u{8bd5}\u{4ee3}\u{7801}\u{4e2d}\u{7684} `unwrap()` \u{6539}\u{5199}\u{4e3a}\u{5e26}\u{4e0d}\u{53d8}\u{91cf}\u{8bf4}\u{660e}\u{7684} `expect()`\u{ff08}\u{6d88}\u{606f}\u{9700}\u{89e3}\u{91ca}*\u{4e3a}\u{4f55}*\u{4e0d}\u{53ef}\u{80fd}\u{5931}\u{8d25}\u{ff09}\u{ff0c}\u{5e76}\u{5728} AGENTS.md \u{89c4}\u{8303} #16 \u{4e2d}\u{56fa}\u{5316}\u{8be5}\u{7ea6}\u{675f}\u{3002}\n\n### Fixed\n\n- **mhchem \u{8f6c}\u{8bd1}\u{5668}\u{4e09}\u{5904} panic \u{4fee}\u{590d}**\u{ff1a}\u{4fee}\u{590d} `panic = \"abort\"` \u{4e0b}\u{5316}\u{5b66}\u{516c}\u{5f0f}\u{8f6c}\u{8bd1}\u{5668}\u{7684}\u{4e09}\u{5904}\u{5d29}\u{6e83}\u{ff1a}`\". __* \"` \u{6b63}\u{5219}\u{8f6c}\u{5f55}\u{9519}\u{8bef}\u{3001}`find_observe_end` \u{9010}\u{5b57}\u{8282}\u{626b}\u{63cf}\u{591a}\u{5b57}\u{8282}\u{5b57}\u{7b26}\u{8d8a}\u{754c}\u{3001}\u{4ee5}\u{53ca} `re!` \u{5b8f}\u{7f16}\u{8bd1}\u{5931}\u{8d25}\u{65f6}\u{672a}\u{964d}\u{7ea7}\u{4e3a}\u{4e0d}\u{5339}\u{914d}\u{5bfc}\u{81f4}\u{76f4}\u{63a5} panic\u{3002}\u{524d}\u{4e24}\u{5904}\u{4e3a}\u{8f93}\u{5165}\u{89e6}\u{53d1}\u{7684}\u{8fd0}\u{884c}\u{65f6} panic\u{ff0c}\u{7b2c}\u{4e09}\u{5904}\u{8865}\u{4e0a}\u{7f3a}\u{5931}\u{7684}\u{9632}\u{5fa1}\u{6027}\u{8fb9}\u{754c}\u{3002}\n- **Docker \u{6784}\u{5efa}\u{7f3a} `patches/` \u{76ee}\u{5f55}**\u{ff1a}\u{6784}\u{5efa}\u{955c}\u{50cf}\u{65f6}\u{672a}\u{590d}\u{5236} `patches/` \u{76ee}\u{5f55}\u{5bfc}\u{81f4} `pnpm install` \u{62a5} ENOENT\u{ff0c}\u{8865}\u{5145}\u{590d}\u{5236}\u{4fee}\u{590d}\u{3002}\n\n## [0.6.0] - 2026-07-23\n\n### Added\n\n- **\u{7f16}\u{8f91}\u{5668} mermaid \u{5b9e}\u{65f6}\u{9884}\u{89c8}**\u{ff1a}Tiptap \u{4ee3}\u{7801}\u{5757}\u{5728}\u{7f16}\u{8f91}\u{5668}\u{5185}\u{5b9e}\u{65f6}\u{6e32}\u{67d3} mermaid \u{6d41}\u{7a0b}\u{56fe}\u{ff0c}\u{6240}\u{89c1}\u{5373}\u{6240}\u{5f97}\u{3002}\n- **\u{7f16}\u{8f91}\u{5668}\u{811a}\u{6ce8}\u{6240}\u{89c1}\u{5373}\u{6240}\u{5f97}**\u{ff1a}Tiptap \u{5bcc}\u{6587}\u{672c}\u{7f16}\u{8f91}\u{5668}\u{5185}\u{811a}\u{6ce8}\u{76f4}\u{63a5}\u{53ef}\u{89c1}\u{ff0c}\u{4e0d}\u{518d}\u{4f9d}\u{8d56} Markdown \u{6e90}\u{7801}\u{3002}\n- **mhchem \u{5316}\u{5b66}\u{516c}\u{5f0f}**\u{ff1a}\u{79fb}\u{690d} mhchem \u{8f6c}\u{8bd1}\u{5668}\u{ff0c}\u{652f}\u{6301} `\\ce`/`\\pu` \u{5316}\u{5b66}\u{65b9}\u{7a0b}\u{5f0f}\u{8bed}\u{6cd5}\u{8f6c} LaTeX \u{6e32}\u{67d3}\u{3002}\n- **KaTeX \u{7269}\u{7406}\u{5b66}\u{5b8f}\u{8868}**\u{ff1a}\u{6ce8}\u{518c} 16 \u{4e2a}\u{7269}\u{7406}\u{5b66}\u{5b8f}\u{ff08}\u{5982} `\\d`\u{3001}`\\od`\u{3001}`\\textsubscript` \u{7b49}\u{ff09}\u{ff0c}\u{9002}\u{914d}\u{7269}\u{7406}\u{5b66}\u{516c}\u{5f0f}\u{5199}\u{4f5c}\u{4e60}\u{60ef}\u{3002}\n- **\u{65b0}\u{5efa}\u{6587}\u{7ae0}\u{9ed8}\u{8ba4}\u{76f4}\u{63a5}\u{53d1}\u{5e03}**\u{ff1a}`/admin/write` \u{65b0}\u{5efa}\u{6587}\u{7ae0}\u{7684}\u{9ed8}\u{8ba4}\u{53d1}\u{5e03}\u{72b6}\u{6001}\u{6539}\u{4e3a}\u{76f4}\u{63a5}\u{53d1}\u{5e03}\u{3002}\n\n### Changed\n\n- **mermaid \u{4e3b}\u{9898}\u{53d8}\u{91cf}\u{4e0b}\u{6c89}**\u{ff1a}\u{5c06} Catppuccin \u{4e3b}\u{9898}\u{53d8}\u{91cf}\u{4ece} tiptap-editor \u{4e0b}\u{6c89}\u{5230} `@yggdrasil/shared` \u{5171}\u{4eab}\u{5305}\u{ff0c}\u{7edf}\u{4e00}\u{7ba1}\u{7406}\u{3002}\n- **\u{4e2d}\u{95f4}\u{4ef6}\u{62bd}\u{53d6}**\u{ff1a}\u{5c06} `ssr_generation`/`version_headers` \u{4e2d}\u{95f4}\u{4ef6}\u{4ece} `main.rs` \u{62bd}\u{51fa}\u{81f3} `src/middleware.rs`\u{3002}\n\n### Fixed\n\n- **\u{7a84}\u{8868}\u{683c}\u{8fb9}\u{6846}\u{88c1}\u{5207}**\u{ff1a}\u{4fee}\u{590d}\u{7a84}\u{8868}\u{683c}\u{5728} `table-wrap` \u{5bb9}\u{5668}\u{5185}\u{8fb9}\u{6846}\u{88ab}\u{88c1}\u{5207}\u{7684}\u{95ee}\u{9898}\u{3002}\n- **\u{79fb}\u{52a8}\u{7aef}\u{8868}\u{683c}\u{6eda}\u{52a8}**\u{ff1a}\u{4fee}\u{590d}\u{79fb}\u{52a8}\u{7aef}\u{8868}\u{683c}\u{65e0}\u{6cd5}\u{6a2a}\u{5411}\u{6eda}\u{52a8}\u{7684}\u{95ee}\u{9898}\u{3002}\n- **\u{7a7a}\u{5de5}\u{5177}\u{680f}\u{9876}\u{680f}**\u{ff1a}\u{9690}\u{85cf}\u{65e0}\u{8bed}\u{8a00}\u{6807}\u{8bc6}\u{4ee3}\u{7801}\u{5757}\u{7684}\u{7a7a}\u{5de5}\u{5177}\u{680f}\u{9876}\u{680f}\u{3002}\n- **KaTeX sanitizer \u{62e6}\u{622a}**\u{ff1a}\u{5141}\u{8bb8} KaTeX \u{6e32}\u{67d3}\u{6240}\u{9700}\u{7684} `svg`\u{3001}`path` \u{6807}\u{7b7e}\u{53ca}\u{7ed8}\u{56fe}\u{5c5e}\u{6027}\u{901a}\u{8fc7} sanitizer\u{3002}\n- **tiptap-markdown \u{8fc7}\u{5ea6}\u{8f6c}\u{4e49}**\u{ff1a}\u{4fee}\u{590d} tiptap-markdown \u{8fc7}\u{5ea6}\u{8f6c}\u{4e49}\u{5bfc}\u{81f4}\u{5185}\u{5bb9}\u{663e}\u{793a}\u{635f}\u{574f}\u{3002}\n- **\u{811a}\u{6ce8}\u{5e8f}\u{5217}\u{5316}\u{8f6c}\u{4e49}\u{5931}\u{6548}**\u{ff1a}\u{4fee}\u{590d} tiptap \u{5e8f}\u{5217}\u{5316}\u{8f6c}\u{4e49}\u{811a}\u{6ce8}\u{8bed}\u{6cd5} `[^id]` \u{2192} `\\[^id\\]` \u{5bfc}\u{81f4}\u{811a}\u{6ce8}\u{5931}\u{6548}\u{3002}\n- **SQL \u{63a7}\u{5236}\u{53f0}\u{5199}\u{540e}\u{7f13}\u{5b58}\u{5931}\u{6548}**\u{ff1a}SQL \u{63a7}\u{5236}\u{53f0}\u{6267}\u{884c}\u{5199}\u{64cd}\u{4f5c}\u{540e}\u{5168}\u{91cf}\u{5931}\u{6548}\u{76f8}\u{5173}\u{7f13}\u{5b58}\u{3002}\n\n## [0.5.0] - 2026-07-22\n\n### Added\n\n- **\u{6587}\u{7ae0}\u{6570}\u{5b66}\u{516c}\u{5f0f} SSR \u{6e32}\u{67d3}(KaTeX)**\u{ff1a}\u{5f15}\u{5165} `katex-rs` \u{5728}\u{670d}\u{52a1}\u{7aef}\u{628a} `$...$`/`$$...$$` TeX \u{6e32}\u{67d3}\u{6210}\u{89c6}\u{89c9}\u{5c42} HTML span(`OutputFormat::Html`,\u{4e0d}\u{542b} MathML,XSS \u{9762}\u{6700}\u{5c0f};`throw_on_error=false` \u{574f}\u{516c}\u{5f0f}\u{6e32}\u{67d3}\u{6210}\u{7ea2}\u{8272}\u{9519}\u{8bef}\u{800c}\u{975e}\u{4e2d}\u{65ad});\u{81ea}\u{6258}\u{7ba1} KaTeX CSS + woff2 \u{5b57}\u{4f53}\u{5230} `public/katex/`(`make katex-css` \u{4ece} npm `katex` dist \u{62f7}\u{8d1d})\u{3002}\n- **\u{8bc4}\u{8bba}\u{6570}\u{5b66}\u{516c}\u{5f0f}\u{6e32}\u{67d3}**\u{ff1a}\u{8bc4}\u{8bba}\u{8def}\u{5f84}\u{540c}\u{6b65}\u{5f00}\u{542f} `ENABLE_MATH`,span \u{767d}\u{540d}\u{5355}\u{52a0} `style` \u{4fdd}\u{7559} KaTeX \u{5185}\u{8054}\u{5b9a}\u{4f4d}\u{6837}\u{5f0f}\u{3002}\n- **\u{7f16}\u{8f91}\u{5668}\u{6570}\u{5b66}\u{516c}\u{5f0f}\u{8282}\u{70b9}**\u{ff1a}Tiptap \u{6570}\u{5b66}\u{516c}\u{5f0f}\u{8282}\u{70b9}\u{5e26} KaTeX \u{9884}\u{89c8},\u{6839}\u{6cbb}\u{7f16}\u{8f91}\u{5668}\u{5e8f}\u{5217}\u{5316}\u{7834}\u{574f} LaTeX \u{7684}\u{95ee}\u{9898}\u{3002}\n- **mermaid \u{6d41}\u{7a0b}\u{56fe}\u{61d2}\u{52a0}\u{8f7d}\u{6e32}\u{67d3}**\u{ff1a}\u{6587}\u{7ae0}\u{9875} `language-mermaid` \u{4ee3}\u{7801}\u{5757}\u{7ecf} IntersectionObserver \u{89c6}\u{53e3}\u{53ef}\u{89c1}\u{65f6}\u{52a8}\u{6001} `import(\'/mermaid/mermaid.js\')`(\u{72ec}\u{7acb} IIFE bundle,~3.4MB / gzip ~900KB,\u{975e}\u{5168}\u{5c40}\u{6ce8}\u{5165}),`mermaid.render` \u{4ea7} SVG \u{6ce8}\u{5165};\u{4e3b}\u{9898}\u{7ecf} `__initMermaid` \u{4f20}\u{5165},`securityLevel: \'strict\'`,\u{5e42}\u{7b49}\u{5b88}\u{536b}\u{9632}\u{91cd}\u{590d}\u{6e32}\u{67d3};\u{6e32}\u{67d3}\u{5931}\u{8d25}\u{4fdd}\u{7559}\u{6e90}\u{7801}\u{5e76}\u{52a0} `.mermaid-error` class\u{3002}\n- **\u{6d41}\u{7a0b}\u{56fe}\u{914d}\u{8272}\u{5bf9}\u{9f50} Catppuccin**\u{ff1a}mermaid \u{914d}\u{8272}\u{5bf9}\u{9f50} Catppuccin \u{4e3b}\u{9898},\u{5bb9}\u{5668}\u{7f8e}\u{5316}\u{3002}\n- **\u{6d41}\u{7a0b}\u{56fe}\u{4e3b}\u{9898}\u{5207}\u{6362}\u{52a8}\u{753b}**\u{ff1a}\u{6d41}\u{7a0b}\u{56fe}\u{4e3b}\u{9898}\u{5207}\u{6362}\u{8ddf}\u{968f} View Transitions \u{5706}\u{5f62}\u{6269}\u{6563}\u{52a8}\u{753b},\u{4e3b}\u{9898}\u{5207}\u{6362}\u{65f6}\u{91cd}\u{6e32}\u{67d3}\u{5df2}\u{6e32}\u{67d3}\u{7684}\u{6d41}\u{7a0b}\u{56fe}\u{3002}\n- **bun \u{4ee3}\u{7801}\u{8fd0}\u{884c}\u{5668}**\u{ff1a}\u{65b0}\u{589e} `yggdrasil-runner-bun` \u{6c99}\u{7bb1}\u{955c}\u{50cf}(\u{5b98}\u{65b9} `bun.sh/install` \u{811a}\u{672c} + musl \u{53d8}\u{4f53} + `libstdc++`/`libgcc` C++ \u{8fd0}\u{884c}\u{65f6});admin \u{4ee3}\u{7801}\u{8bd5}\u{8fd0}\u{884c}\u{6c99}\u{7bb1}\u{52a0} bun \u{8bed}\u{8a00}\u{6309}\u{94ae};CodeMirror \u{52a0} TypeScript \u{6a21}\u{5f0f};\u{8bed}\u{8a00}\u{522b}\u{540d}\u{5f52}\u{4e00}\u{5316}(`ts`/`typescript`\u{2192}`bun`,\u{5728} `parse_fence_info` \u{7edf}\u{4e00},`LANGUAGES.get` \u{53ea}\u{89c1}\u{89c4}\u{8303}\u{5316} key)\u{3002}\n- **\u{6587}\u{7ae0}\u{9875}\u{811a}\u{6ce8}\u{5b8c}\u{6574}\u{652f}\u{6301}**\u{ff1a}\u{8bed}\u{4e49}\u{5316} + back-link + \u{6837}\u{5f0f}\u{3002}\n- **Vue SFC \u{8bed}\u{6cd5}\u{9ad8}\u{4eae}**\u{ff1a}\u{6587}\u{7ae0}\u{9875}\u{4ee3}\u{7801}\u{5757}\u{652f}\u{6301} Vue SFC \u{8bed}\u{6cd5}\u{9ad8}\u{4eae}\u{3002}\n- **\u{641c}\u{7d22}\u{5165}\u{53e3}\u{6539}\u{4e3a}\u{56fe}\u{6807}\u{6309}\u{94ae}**\u{ff1a}header \u{641c}\u{7d22}\u{5165}\u{53e3}\u{4ece}\u{6587}\u{5b57}\u{6539}\u{4e3a}\u{56fe}\u{6807}\u{6309}\u{94ae}\u{3002}\n- **\u{6b63}\u{6587}\u{6298}\u{53e0}\u{5757}\u{5361}\u{7247}\u{5316}**\u{ff1a}`<details>` \u{6298}\u{53e0}\u{5757}\u{5361}\u{7247}\u{5316},\u{81ea}\u{7ed8} chevron + hover/focus \u{6001}\u{3002}\n- **task-list checkbox \u{81ea}\u{7ed8}**\u{ff1a}\u{6587}\u{7ae0}\u{9875} task-list checkbox \u{6539}\u{7528} `appearance:none` \u{81ea}\u{7ed8}\u{5706}\u{89d2}\u{65b9}\u{6846}\u{3002}\n- **\u{4ee3}\u{7801}\u{5757}\u{5b57}\u{53f7}\u{8c03}\u{6574}**\u{ff1a}\u{6587}\u{7ae0}\u{9875}\u{4ee3}\u{7801}\u{5757}\u{5b57}\u{53f7}\u{4ece} 13.6px \u{8c03}\u{6574}\u{4e3a} 16px\u{3002}\n- **\u{54cd}\u{5e94}\u{5934}\u{66b4}\u{9732}\u{7248}\u{672c}\u{4fe1}\u{606f}**\u{ff1a}server \u{901a}\u{8fc7} `Server`/`X-Yggdrasil-Version`/`X-Yggdrasil-Git` \u{54cd}\u{5e94}\u{5934}\u{4e3b}\u{52a8}\u{66b4}\u{9732}\u{7248}\u{672c}\u{4e0e} git \u{63cf}\u{8ff0}\u{4fe1}\u{606f}(`EXPOSE_VERSION_HEADERS` \u{53ef}\u{5173})\u{3002}\n- **Docker multi-arch \u{6784}\u{5efa}\u{76ee}\u{6807}**\u{ff1a}`make docker-amd64` \u{4e0e} `make docker-apple` \u{6784}\u{5efa} x86_64 \u{955c}\u{50cf}\u{3002}\n- **\u{670d}\u{52a1}\u{5668}\u{7aef}\u{53e3}\u{5360}\u{7528}\u{4f18}\u{96c5}\u{9000}\u{51fa}**\u{ff1a}\u{7aef}\u{53e3}\u{88ab}\u{5360}\u{7528}\u{65f6}\u{4f18}\u{96c5}\u{9000}\u{51fa}\u{800c}\u{975e} panic\u{3002}\n- **\u{538b}\u{7f29}\u{7b97}\u{6cd5}\u{9ed8}\u{8ba4} off**\u{ff1a}`COMPRESSION_ALGORITHMS` \u{4e2d}\u{95f4}\u{4ef6}\u{9ed8}\u{8ba4}\u{503c}\u{6539}\u{4e3a} off\u{3002}\n\n### Changed\n\n- **mimalloc \u{5168}\u{5c40}\u{5206}\u{914d}\u{5668}**\u{ff1a}\u{7528} mimalloc \u{66ff}\u{6362}\u{7cfb}\u{7edf}\u{5168}\u{5c40}\u{5206}\u{914d}\u{5668}(`#[global_allocator]`,\u{53cc} cfg \u{95e8}\u{63a7}:server feature + \u{975e} wasm32;musl \u{9759}\u{6001}\u{94fe}\u{63a5}\u{53cb}\u{597d})\u{3002}\n- **\u{6027}\u{80fd}\u{4f18}\u{5316}\u{7cfb}\u{5217}**\u{ff1a}`escape_html` \u{94fe}\u{5f0f} 5 \u{6b21} replace \u{6539}\u{5355}\u{904d}\u{626b}\u{63cf};`slugify` \u{5355}\u{904d}\u{72b6}\u{6001}\u{673a}\u{91cd}\u{5199}(\u{5206}\u{914d} 4\u{2192}1);Markdown \u{6e32}\u{67d3}\u{6d88}\u{9664}\u{53cc}\u{89e3}\u{6790} + `format!` \u{6539} `write!` \u{76f4}\u{5199};upload \u{6d88}\u{9664} `data.to_vec()` \u{591a}\u{6b21}\u{5168}\u{6587}\u{4ef6}\u{6df1}\u{62f7}\u{8d1d};`cache_key` \u{5355}\u{6b21}\u{62fc}\u{63a5} + `detect_format` \u{96f6}\u{5206}\u{914d}\u{540e}\u{7f00}\u{5339}\u{914d};posts list/search \u{96f6} capacity Vec \u{6539} collect \u{9884}\u{5206}\u{914d} + helpers retain\u{3002}\n- **\u{91cd}\u{6784}\u{7cfb}\u{5217}**\u{ff1a}admin `/admin/posts` \u{4e0e} `/admin/posts/trash` \u{5408}\u{5e76}\u{4e3a}\u{5355}\u{8def}\u{7531} + tab \u{5207}\u{6362};`Pagination` \u{652f}\u{6301}\u{53ef}\u{9009} `on_prev`/`on_next` \u{56de}\u{8c03};\u{62bd}\u{53d6} `@yggdrasil/shared` \u{5185}\u{90e8}\u{6e90}\u{5171}\u{4eab}\u{5305}\u{6d88}\u{9664}\u{8de8} IIFE \u{5e93}\u{7684}\u{7c7b}\u{578b}/\u{5e38}\u{91cf}\u{91cd}\u{590d};\u{62bd} `main.rs` \u{4e2d}\u{95f4}\u{4ef6}\u{5230} `src/middleware.rs`;\u{4e3a} `Response` \u{7c7b}\u{578b}\u{6dfb}\u{52a0}\u{6784}\u{9020}\u{5668}\u{6d88}\u{9664} 51 \u{5904}\u{6837}\u{677f};\u{62bd} `invalidate_post_metadata()`/`upload_error()` \u{7b49}\u{6d88}\u{9664}\u{6837}\u{677f};\u{7edf}\u{4e00} WASM sleep \u{5230} `utils::time::sleep_ms`;\u{5220}\u{9664}\u{6b7b}\u{4ee3}\u{7801}(`delayed_loading.rs`/`ui.rs EmptyState`/`CommentActions`/\u{672a}\u{7528} re-export);\u{62c6}\u{5206} `system.rs` \u{4e3a} `system/` \u{76ee}\u{5f55}(\u{6309} tab \u{5206}\u{6587}\u{4ef6});\u{56fe}\u{7247}\u{5904}\u{7406}\u{5408}\u{5e76}\u{7ef4}\u{5ea6}\u{8bfb}\u{53d6}\u{51fd}\u{6570}\u{5171}\u{4eab} `image_reader_limits`\u{3002}\n- **\u{4f9d}\u{8d56}\u{5347}\u{7ea7}**\u{ff1a}TypeScript \u{5347}\u{7ea7}\u{81f3} 7.0.2(Go \u{539f}\u{751f}\u{7f16}\u{8bd1}\u{5668})\u{3002}\n\n### Fixed\n\n- **SSR \u{7f13}\u{5b58}\u{5931}\u{6548}\u{6839}\u{6cbb}**\u{ff1a}\u{6587}\u{7ae0}\u{5199}\u{5165}\u{540e}\u{7269}\u{7406}\u{5220}\u{9664} SSR \u{78c1}\u{76d8}\u{7f13}\u{5b58}\u{76ee}\u{5f55},\u{6839}\u{6cbb}\u{300c}\u{91cd}\u{5efa}\u{540e}\u{5185}\u{5bb9}\u{4e0d}\u{66f4}\u{65b0}\u{300d}(Dioxus 0.7 \u{589e}\u{91cf}\u{6e32}\u{67d3}\u{5668}\u{53ea}\u{66b4}\u{9732} TTL \u{5931}\u{6548}\u{624b}\u{6bb5},\u{901a}\u{8fc7}\u{5220}\u{6587}\u{4ef6}\u{7ed5}\u{8fc7}\u{9650}\u{5236});build \u{524d}\u{6e05}\u{9664} `static/` SSR \u{7f13}\u{5b58}\u{76ee}\u{5f55}\u{3002}\n- **Docker \u{6784}\u{5efa}/\u{90e8}\u{7f72}**\u{ff1a}Docker \u{6784}\u{5efa}\u{900f}\u{4f20} git \u{4fe1}\u{606f}\u{4fee}\u{590d} `x-yggdrasil-git` \u{6052}\u{4e3a} unknown;\u{9884}\u{88c5} binaryen \u{907f}\u{514d} dx \u{8fd0}\u{884c}\u{65f6}\u{4e0b}\u{8f7d} wasm-opt \u{5931}\u{8d25};\u{8865}\u{9f50} Dockerfile \u{7f3a}\u{5931}\u{7684} katex-css \u{4e0e} restore-webp \u{6b65}\u{9aa4};\u{5347}\u{7ea7} builder \u{81f3} trixie \u{6ee1}\u{8db3} dx \u{5bf9} GLIBC_2.39 \u{7684}\u{9700}\u{6c42};\u{7528} tmpfs `mode=1777` \u{66ff}\u{6362} uid/gid \u{9009}\u{9879}\u{517c}\u{5bb9} Podman;GitHub Releases \u{4e0b}\u{8f7d}\u{6700}\u{7ec8}\u{6539}\u{7528}\u{76f4}\u{8fde}(\u{79fb}\u{9664} gh-proxy)\u{3002}\n- **\u{7ebf}\u{4e0a}\u{4ee3}\u{7801}\u{9ad8}\u{4eae}\u{7f3a}\u{5931}**\u{ff1a}\u{7f16}\u{8bd1}\u{671f}\u{5185}\u{5d4c}\u{81ea}\u{5b9a}\u{4e49}\u{8bed}\u{6cd5},\u{4fee}\u{590d}\u{7ebf}\u{4e0a} Docker \u{955c}\u{50cf}\u{4ee3}\u{7801}\u{9ad8}\u{4eae}\u{7f3a}\u{5931}(\u{539f}\u{5148}\u{8fd0}\u{884c}\u{65f6}\u{52a0}\u{8f7d}\u{8bed}\u{6cd5}\u{6587}\u{4ef6}\u{5728}\u{6253}\u{5305}\u{955c}\u{50cf}\u{4e2d}\u{627e}\u{4e0d}\u{5230})\u{3002}\n- **mermaid \u{6e32}\u{67d3}**\u{ff1a}\u{6539}\u{7528} script \u{6807}\u{7b7e}\u{52a0}\u{8f7d} IIFE bundle \u{4fee}\u{6b63}\u{5168}\u{5c40}\u{53d8}\u{91cf}\u{53d6}\u{503c};\u{4fee}\u{590d} tsc \u{7c7b}\u{578b}\u{9519}\u{8bef};\u{4e3b}\u{9898}\u{5207}\u{6362}\u{65f6}\u{91cd}\u{6e32}\u{67d3}\u{5df2}\u{6e32}\u{67d3}\u{7684}\u{6d41}\u{7a0b}\u{56fe}\u{3002}\n- **\u{6587}\u{7ae0}\u{951a}\u{70b9}\u{5bfc}\u{822a}**\u{ff1a}`scrollToHash` \u{589e}\u{52a0}\u{4e00}\u{6b21}\u{6027}\u{5b88}\u{536b},\u{5207}\u{4e3b}\u{9898}\u{4e0d}\u{518d}\u{8df3}\u{56de} URL hash;\u{589e}\u{52a0} ResizeObserver \u{5e03}\u{5c40}\u{7a33}\u{5b9a}\u{671f},\u{4fee}\u{6b63} mermaid \u{5f02}\u{6b65}\u{6e32}\u{67d3}\u{5bfc}\u{81f4}\u{7684}\u{951a}\u{70b9}\u{843d}\u{70b9}\u{504f}\u{79fb}\u{3002}\n- **WASM \u{53cc}\u{7aef}\u{7f16}\u{8bd1}**\u{ff1a}hooks \u{6a21}\u{5757}\u{79fb}\u{51fa} server gate \u{53cc}\u{7aef}\u{53ef}\u{89c1}(\u{539f}\u{5148} WASM \u{7f16}\u{8bd1}\u{5931}\u{8d25})\u{3002}\n- **\u{8bc4}\u{8bba}\u{4ee3}\u{7801}\u{5757}\u{8f6c}\u{4e49}**\u{ff1a}\u{7edf}\u{4e00} `escape_html`,\u{4fee}\u{590d}\u{4ee3}\u{7801}\u{5757}\u{5355}\u{5f15}\u{53f7}\u{672a}\u{8f6c}\u{4e49}\u{3002}\n- **Docker daemon \u{5bb9}\u{9519}**\u{ff1a}Docker daemon \u{4e0d}\u{53ef}\u{7528}/\u{65ad}\u{8fde}\u{65f6}\u{4e0d}\u{518d} panic(\u{96c6}\u{6210}\u{6d4b}\u{8bd5}\u{5728}\u{65e0} daemon \u{73af}\u{5883}\u{4f18}\u{96c5}\u{8df3}\u{8fc7})\u{3002}\n- **\u{540e}\u{53f0}\u{5e03}\u{5c40}**\u{ff1a}\u{91cd}\u{5efa}\u{7ed3}\u{679c}\u{6d88}\u{606f}\u{6539}\u{7edd}\u{5bf9}\u{5b9a}\u{4f4d},\u{907f}\u{514d}\u{6491}\u{9ad8}\u{5bb9}\u{5668}\u{9876}\u{8d77}\u{6309}\u{94ae}\u{3002}\n- **\u{56fe}\u{7247} cfg \u{95e8}\u{63a7}**\u{ff1a}\u{4e3a} `ImageFmt` \u{522b}\u{540d}\u{8865}\u{4e0a} `#[cfg(feature = \"server\")]` \u{95e8}\u{63a7}\u{3002}\n- **clippy/lint**\u{ff1a}\u{4fee}\u{590d} rust-1.97 clippy `useless_borrows_in_formatting` \u{544a}\u{8b66}\u{3001}Biome \u{544a}\u{8b66}\u{3002}\n- **\u{5b89}\u{5168}\u{6d4b}\u{8bd5}**\u{ff1a}\u{8865}\u{9f50}\u{5b89}\u{5168}\u{5173}\u{952e}\u{8def}\u{5f84}\u{7684}\u{5355}\u{5143}\u{6d4b}\u{8bd5}\u{76f2}\u{533a}\u{3002}\n\n### Internal\n\n- **skills \u{4f53}\u{7cfb}**\u{ff1a}\u{65b0}\u{589e} `optimizing-rust-performance` \u{4e0e} `rust-advanced-performance` \u{6027}\u{80fd}\u{4f18}\u{5316}\u{6280}\u{80fd};\u{6e05}\u{7406}\u{5df2}\u{5378}\u{8f7d}\u{7684}\u{7b2c}\u{4e09}\u{65b9} skills \u{53ca} lock \u{6ce8}\u{518c};`deploy-to-linux` \u{6dfb}\u{52a0}\u{624b}\u{52a8}\u{90e8}\u{7f72}\u{6a21}\u{5f0f}\u{3002}\n- **\u{90e8}\u{7f72}\u{811a}\u{672c}**\u{ff1a}\u{65b0}\u{589e} xun \u{670d}\u{52a1}\u{5668}\u{5168}\u{91cf}\u{90e8}\u{7f72}\u{811a}\u{672c}\u{3002}\n- **\u{6587}\u{6863}**\u{ff1a}AGENTS.md \u{8865}\u{5145}\u{522b}\u{540d}\u{5f52}\u{4e00}\u{5316}\u{4e0e} bun \u{955c}\u{50cf}\u{8bf4}\u{660e}\u{3001}\u{6570}\u{5b66}\u{516c}\u{5f0f}\u{4e0e}\u{6d41}\u{7a0b}\u{56fe}\u{67b6}\u{6784}\u{8bf4}\u{660e}\u{3001}xterm-terminal/shared \u{5e93}\u{8bf4}\u{660e};\u{8865}\u{5168} `.env.example` \u{7f3a}\u{5931}\u{7684} 5 \u{4e2a}\u{73af}\u{5883}\u{53d8}\u{91cf}\u{3002}\n\n## [0.4.0] - 2026-07-13\n\n### Added\n\n- **\u{4ee3}\u{7801}\u{8fd0}\u{884c}\u{5668}\u{ff08}Code Runner\u{ff09}**\u{ff1a}\u{8bfb}\u{8005}\u{53ef}\u{5728}\u{6587}\u{7ae0}\u{9875}\u{76f4}\u{63a5}\u{8fd0}\u{884c} ` `lang runnable ``` \u{4ee3}\u{7801}\u{5757}\u{ff0c}\u{5728}\u{9694}\u{79bb}\u{7684} Docker \u{5bb9}\u{5668}\u{4e2d}\u{6267}\u{884c}\u{ff0c}\u{652f}\u{6301} Python / Node.js / Go / Rust \u{56db}\u{79cd}\u{8bed}\u{8a00}\u{ff1b}admin \u{4fa7} `/admin/runner` \u{8bd5}\u{9a8c}\u{6c99}\u{7bb1}\u{9875}\u{652f}\u{6301}\u{4efb}\u{610f}\u{4ee3}\u{7801}\u{8bd5}\u{8dd1}\u{ff08}\u{8df3}\u{8fc7}\u{901f}\u{7387}\u{9650}\u{5236}\u{ff09}\u{3002}\u{4e09}\u{5c42}\u{67b6}\u{6784}\u{ff1a}`src/infra/docker.rs`\u{ff08}bollard \u{6267}\u{884c}\u{5c42}\u{ff0c}\u{53ea}\u{8bfb} rootfs + tmpfs + \u{8d44}\u{6e90}/\u{80fd}\u{529b}\u{9650}\u{5236} + `ContainerGuard` Drop \u{5f3a}\u{5236}\u{6e05}\u{7406}\u{ff09}\u{3001}`src/api/code_runner/`\u{ff08}\u{4efb}\u{52a1}\u{6ce8}\u{518c}\u{8868}\u{3001}\u{8bed}\u{8a00}\u{6ce8}\u{518c}\u{8868}\u{3001}\u{53cc}\u{901f}\u{7387}\u{9650}\u{5236} + \u{767d}\u{540d}\u{5355} + \u{5927}\u{5c0f}\u{68c0}\u{67e5}\u{ff09}\u{3001}Markdown \u{6e32}\u{67d3}\u{5c42}\u{ff08}`PostContent` \u{62c6}\u{5206} `Html`/`Runnable` \u{7247}\u{6bb5}\u{ff0c}\u{6bcf}\u{5757}\u{6e32}\u{67d3}\u{4e3a}\u{771f}\u{5b9e} `<CodeRunner>` vdom \u{5143}\u{7d20}\u{ff09}\u{3002}\u{6240}\u{6709} `CODE_RUNNER_*` \u{73af}\u{5883}\u{53d8}\u{91cf}\u{53ef}\u{8c03}\u{ff0c}\u{652f}\u{6301} per-IP \u{901f}\u{7387}\u{4e0e}\u{6bcf}\u{65e5}\u{4e0a}\u{9650}\u{3002}\n- **\u{6d41}\u{5f0f}\u{4ee3}\u{7801}\u{6267}\u{884c}\u{ff08}SSE + xterm.js\u{ff09}**\u{ff1a}CodeRunner \u{5207}\u{6362}\u{4e3a} SSE + xterm.js \u{6d41}\u{5f0f}\u{8f93}\u{51fa}\u{65b9}\u{6848}\u{3002}\u{65b0}\u{589e} `xterm-terminal` IIFE \u{5b50}\u{5de5}\u{7a0b}\u{ff08}xterm.js 6.0\u{ff09}\u{3001}`xterm_bridge.rs` wasm-bindgen \u{7ed1}\u{5b9a}\u{3001}`/api/exec/stream` SSE \u{7aef}\u{70b9}\u{3001}Docker \u{6267}\u{884c}\u{5c42}\u{6d41}\u{5f0f}\u{8def}\u{5f84}\u{ff08}wait \u{4e0e} log \u{8bfb}\u{53d6}\u{5e76}\u{53d1}\u{ff09}\u{ff1b}\u{652f}\u{6301}\u{65e0}\u{7f13}\u{51b2} stdout\u{ff08}`python -u`\u{ff09}\u{3001}SSE done \u{4e8b}\u{4ef6}\u{56de}\u{4f20} `duration_ms`\u{3001}\u{8fd0}\u{884c}\u{524d}\u{9690}\u{85cf}\u{8f93}\u{51fa}\u{533a} + skeleton \u{5360}\u{4f4d}\u{3002}\n- **`/admin/system` \u{7ba1}\u{7406}\u{540e}\u{53f0}**\u{ff1a}\u{5168}\u{65b0}\u{7ba1}\u{7406}\u{533a}\u{ff0c}5 \u{4e2a} tab \u{2014}\u{2014} \u{6570}\u{636e}\u{5e93}\u{72b6}\u{6001}\u{ff08}\u{8868}\u{7edf}\u{8ba1}/\u{6d3b}\u{8dc3}\u{8fde}\u{63a5}/\u{8fc1}\u{79fb}\u{7248}\u{672c}\u{ff09}\u{3001}\u{670d}\u{52a1}\u{5668}\u{72b6}\u{6001}\u{ff08}sysinfo \u{4e3b}\u{673a}\u{6307}\u{6807} + moka \u{7f13}\u{5b58}\u{547d}\u{4e2d}\u{7387}\u{8f6e}\u{8be2}\u{ff09}\u{3001}SQL \u{63a7}\u{5236}\u{53f0}\u{ff08}\u{5168}\u{8bfb}\u{5199}\u{ff0c}4 \u{9053}\u{62a4}\u{680f}\u{ff1a}sqlparser AST \u{95e8} + WHERE \u{7f3a}\u{5931}\u{62d2}\u{7edd} + \u{67e5}\u{8be2}\u{8d85}\u{65f6} + \u{524d}\u{7aef}\u{786e}\u{8ba4}\u{ff1b}\u{5355}\u{5143}\u{683c}\u{7c7b}\u{578b}\u{5316}\u{6e32}\u{67d3} NULL/\u{5e03}\u{5c14}/\u{6570}\u{5b57}\u{3001}\u{8868}\u{5934} sticky\u{3001}\u{884c}\u{622a}\u{65ad}\u{5c55}\u{5f00}\u{ff09}\u{3001}\u{6570}\u{636e}\u{5bfc}\u{51fa}\u{ff08}Axum \u{6d41}\u{5f0f} SQL/CSV\u{ff09}\u{3001}\u{5907}\u{4efd}\u{6062}\u{590d}\u{ff08}`pg_dump` \u{4f18}\u{5148} + COPY \u{56de}\u{9000}\u{3001}DashMap \u{4efb}\u{52a1}\u{8fdb}\u{5ea6}\u{8868} + \u{8f6e}\u{8be2}\u{3001}\u{5907}\u{4efd}\u{6587}\u{4ef6}\u{7b7e}\u{540d}\u{6821}\u{9a8c} + \u{8def}\u{5f84}\u{767d}\u{540d}\u{5355}\u{ff09}\u{3002}\n- **UI \u{91cd}\u{65b0}\u{8bbe}\u{8ba1}\u{ff08}\u{5de5}\u{4e1a}\u{6781}\u{7b80} + Catppuccin\u{ff09}**\u{ff1a}\u{5168}\u{7ad9}\u{914d}\u{8272}\u{8fc1}\u{79fb}\u{5230} Catppuccin\u{ff08}Latte/Mocha\u{ff09}\u{ff0c}\u{79fb}\u{9664} Rust \u{4e2d}\u{786c}\u{7f16}\u{7801}\u{989c}\u{8272}\u{ff0c}\u{7edf}\u{4e00}\u{8bed}\u{4e49}\u{8272}\u{9636}\u{ff1b}\u{540e}\u{53f0}\u{91cd}\u{8bbe}\u{8ba1}\u{4e3a}\u{73b0}\u{4ee3}\u{6781}\u{7b80}\u{4fa7}\u{8fb9}\u{680f}\u{5e03}\u{5c40}\u{ff08}\u{5199}\u{6587}\u{7ae0}\u{9875}\u{6539}\u{4e3a}\u{5de6}\u{53f3}\u{4e24}\u{680f}\u{3001}\u{7f16}\u{8f91}\u{5668}\u{81ea}\u{9002}\u{5e94}\u{9ad8}\u{5ea6}\u{ff09}\u{ff1b}\u{5706}\u{89d2} token \u{5316}\u{4e3a}\u{4e09}\u{6863}\u{68af}\u{5ea6}\u{ff08}32/16/8\u{ff09}\u{5e76}\u{7edf}\u{4e00}\u{6240}\u{6709}\u{7ec4}\u{4ef6}\u{ff1b}Markdown \u{8868}\u{683c}\u{91cd}\u{8bbe}\u{8ba1} + \u{8868}\u{683c}\u{5355}\u{5143}\u{683c}\u{5706}\u{89d2}\u{9632}\u{80cc}\u{666f}\u{6ea2}\u{51fa}\u{ff1b}\u{5168}\u{5c40}\u{8def}\u{7531}\u{5207}\u{6362}\u{5e73}\u{6ed1}\u{6302}\u{8f7d}\u{52a8}\u{753b} + View Transitions \u{5706}\u{5f62}\u{5c55}\u{5f00}\u{4e3b}\u{9898}\u{5207}\u{6362}\u{52a8}\u{753b}\u{ff1b}\u{7f16}\u{8f91}\u{5668}\u{80cc}\u{666f}\u{56fe}\u{ff08}\u{7ebf}\u{6761}\u{5c0f}\u{72d7}\u{ff09}\u{6709}\u{5185}\u{5bb9}\u{65f6}\u{81ea}\u{52a8}\u{8c03}\u{6de1}\u{900f}\u{660e}\u{5ea6}\u{3002}\n- **\u{7f16}\u{8f91}\u{5668}\u{53ef}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{5757} NodeView**\u{ff1a}CodeBlock \u{6539}\u{7528} `CodeBlockLowlight` + Catppuccin \u{9ad8}\u{4eae}\u{914d}\u{8272}\u{ff1b}\u{65b0}\u{589e} CodeBlockNodeView\u{ff08}\u{8bed}\u{8a00}\u{6807}\u{7b7e} + \u{8fd0}\u{884c}\u{6309}\u{94ae} + \u{7ed3}\u{679c}\u{533a}\u{ff09}\u{ff0c}\u{70b9}\u{8bed}\u{8a00}\u{6807}\u{7b7e}\u{53ef}\u{7f16}\u{8f91}\u{8bed}\u{8a00}\u{4e0e}\u{914d}\u{7f6e}\u{ff1b}\u{659c}\u{6760}\u{83dc}\u{5355}\u{65b0}\u{589e}\u{300c}\u{53ef}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{5757}\u{300d}\u{6761}\u{76ee} + \u{6a21}\u{6001}\u{6846}\u{914d}\u{7f6e} runnable fence info\u{ff1b}`make_run_code_closure` \u{6865}\u{63a5}\u{7f16}\u{8f91}\u{5668}\u{5185}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{3002}\n- **\u{7f16}\u{8f91}\u{5668}\u{4efb}\u{52a1}\u{5217}\u{8868}\u{624b}\u{52a8}\u{8f93}\u{5165}**\u{ff1a}\u{652f}\u{6301} `- [ ]` \u{9010}\u{5b57}\u{7b26}\u{8f93}\u{5165}\u{521b}\u{5efa}\u{4efb}\u{52a1}\u{5217}\u{8868}\u{ff08}appendTransaction\u{ff0c}\u{975e} InputRule \u{5168}\u{91cf}\u{66ff}\u{6362}\u{ff09}\u{ff1b}\u{524d}\u{53f0}\u{4e0e}\u{7f16}\u{8f91}\u{5668} checkbox \u{5782}\u{76f4}\u{4e2d}\u{7ebf}\u{5bf9}\u{9f50}\u{3002}\n- **SQL \u{63a7}\u{5236}\u{53f0} Ctrl+Enter**\u{ff1a}`/admin/system` SQL \u{63a7}\u{5236}\u{53f0}\u{63a5}\u{901a} Ctrl/Cmd+Enter \u{8fd0}\u{884c}\u{5feb}\u{6377}\u{952e}\u{3002}\n- **CodeMirror Vim \u{6a21}\u{5f0f}**\u{ff1a}admin CodeRunner \u{6c99}\u{7bb1}\u{7f16}\u{8f91}\u{5668}\u{652f}\u{6301} Vim \u{6a21}\u{5f0f}\u{5f00}\u{5173}\u{ff0c}\u{9ed8}\u{8ba4}\u{5f00}\u{542f}\u{ff1b}CodeMirror \u{7f16}\u{8f91}\u{5668}\u{9ad8}\u{5ea6}\u{81ea}\u{9002}\u{5e94}\u{4e0e}\u{6eda}\u{52a8}\u{9650}\u{5236}\u{3002}\n- **\u{6587}\u{7ae0}\u{91cd}\u{5efa}\u{5185}\u{5bb9}\u{6309}\u{94ae}**\u{ff1a}\u{6587}\u{7ae0}\u{5217}\u{8868}\u{64cd}\u{4f5c}\u{5217}\u{65b0}\u{589e}\u{300c}\u{91cd}\u{5efa}\u{5185}\u{5bb9}\u{300d}\u{6309}\u{94ae}\u{ff0c}\u{91cd}\u{5efa}\u{652f}\u{6301}\u{5e76}\u{53d1} loading\u{ff08}spinner \u{8986}\u{76d6}\u{6587}\u{5b57}\u{ff09}\u{3002}\n- **\u{4e2d}\u{6587} slug \u{81ea}\u{52a8}\u{8f6c}\u{62fc}\u{97f3}**\u{ff1a}\u{4e2d}\u{6587}\u{6807}\u{9898}\u{81ea}\u{52a8}\u{8f6c}\u{62fc}\u{97f3}\u{751f}\u{6210} URL slug\u{3002}\n- **FreeBSD x86_64 \u{4ea4}\u{53c9}\u{7f16}\u{8bd1}**\u{ff1a}`make build-freebsd` + `make freebsd-sysroot`\u{ff0c}clang + lld + sysroot\u{3002}\n- **\u{6784}\u{5efa}\u{4fe1}\u{606f}\u{6ce8}\u{5165}**\u{ff1a}\u{542f}\u{52a8}\u{65f6}\u{6253}\u{5370} git/rustc/\u{6784}\u{5efa}\u{65f6}\u{95f4}\u{4fe1}\u{606f}\u{3002}\n- **404 \u{9875}\u{9762}\u{63d0}\u{4ea4} HTTP 404 \u{72b6}\u{6001}\u{7801}**\u{ff08}SSR \u{5c42}\u{ff09}\u{ff1b}`ErrorBoundary` \u{5305}\u{88f9}\u{516c}\u{5f00}\u{8def}\u{7531}\u{ff0c}\u{6587}\u{7ae0}\u{8be6}\u{60c5}\u{9875} 404 \u{7b49}\u{9519}\u{8bef}\u{4e0a}\u{629b}\u{81f3} `ErrorLayout`\u{3002}\n- **SSR \u{5c42} admin \u{8ba4}\u{8bc1}\u{5b88}\u{536b}**\u{ff1a}\u{672a}\u{767b}\u{5f55}\u{8bbf}\u{95ee} admin \u{76f4}\u{63a5}\u{5728} SSR \u{8df3}\u{8f6c}\u{767b}\u{5f55}\u{9875}\u{ff0c}\u{907f}\u{514d}\u{95ea}\u{70c1}\u{3002}\n- **\u{767b}\u{5f55}\u{8868}\u{5355}\u{56de}\u{8f66}\u{63d0}\u{4ea4}**\u{ff1b}\u{7f51}\u{7ad9} favicon\u{ff1b}\u{8bc4}\u{8bba}\u{80cc}\u{666f}\u{56fe}\u{81ea}\u{52a8}\u{8c03}\u{6de1}\u{3002}\n\n### Changed\n\n- **pnpm workspace \u{91cd}\u{6784}**\u{ff1a}JS \u{5b50}\u{9879}\u{76ee}\u{4ece} npm \u{8fc1}\u{79fb}\u{5230} pnpm workspace\u{ff0c}\u{6839}\u{5de5}\u{4f5c}\u{533a}\u{5728} `libs/`\u{ff0c}\u{5355}\u{4e00} `libs/pnpm-lock.yaml` + \u{5171}\u{4eab} `libs/tsconfig.base.json`\u{ff1b}\u{5f15}\u{5165} Biome v2.5 monorepo \u{914d}\u{7f6e}\u{5e76}\u{5168}\u{91cf}\u{683c}\u{5f0f}\u{5316}\u{ff1b}Makefile \u{6574}\u{5408} `lint`/`fix`/`test` \u{76ee}\u{6807}\u{3002}\n- **\u{6d88}\u{9664} `js_sys::eval`**\u{ff1a}DOM \u{4e92}\u{64cd}\u{4f5c}\u{5168}\u{9762}\u{4ece}\u{5b57}\u{7b26}\u{4e32}\u{6c42}\u{503c}\u{8fc1}\u{79fb}\u{5230} wasm-bindgen \u{7ed1}\u{5b9a}\u{5c42}\u{ff08}`tiptap_bridge`\u{3001}`codemirror_bridge`\u{3001}`xterm_bridge`\u{ff09}\u{ff0c}\u{6e05}\u{7406} wasm32 target \u{6b8b}\u{7559} clippy lint\u{3002}\n- **\u{901a}\u{7528} hooks \u{62bd}\u{53d6}**\u{ff1a}\u{65b0}\u{589e} `use_paginated`\u{ff08}\u{5206}\u{9875}\u{52a0}\u{8f7d}\u{ff09}\u{3001}`use_event_listener`\u{ff08}\u{901a}\u{7528}\u{4e8b}\u{4ef6}\u{76d1}\u{542c}\u{ff0c}\u{89e3}\u{51b3} `use_hook` + `use_effect` + `use_drop` \u{8d44}\u{6e90}\u{6240}\u{6709}\u{6743}\u{9677}\u{9631}\u{ff09}\u{3002}\n- **SQL \u{63a7}\u{5236}\u{53f0}\u{7ec4}\u{4ef6}\u{5316}**\u{ff1a}`SqlConsoleTab` \u{6539}\u{7528}\u{72ec}\u{7acb} `SqlResultTable` \u{7ec4}\u{4ef6}\u{3002}\n- **\u{6309}\u{94ae} token \u{5316}**\u{ff1a}\u{65b0}\u{589e} `BTN_PRIMARY`/`BTN_OUTLINE` \u{7b49}\u{6309}\u{94ae}\u{4ee4}\u{724c}\u{4e0e} `LoadingButton` \u{7ec4}\u{4ef6}\u{ff0c}\u{6d88}\u{9664}\u{6837}\u{5f0f}\u{6563}\u{843d}\u{3002}\n- **\u{9aa8}\u{67b6}\u{5c4f}\u{7edf}\u{4e00}\u{5ef6}\u{8fdf}**\u{ff1a}\u{7edf}\u{4e00}\u{9aa8}\u{67b6}\u{5c4f}\u{5ef6}\u{8fdf}\u{673a}\u{5236}\u{ff0c}200ms \u{5185}\u{52a0}\u{8f7d}\u{5b8c}\u{6210}\u{4e0d}\u{663e}\u{793a}\u{9aa8}\u{67b6}\u{ff0c}\u{907f}\u{514d}\u{5feb}\u{7f51}\u{7edc}\u{95ea}\u{70c1}\u{3002}\n- **\u{540e}\u{53f0}\u{83dc}\u{5355}\u{8fb9}\u{8ddd}\u{6536}\u{7d27}**\u{ff1a}\u{540e}\u{53f0}\u{6240}\u{6709}\u{9875}\u{9762}\u{5de6}\u{53f3}\u{8fb9}\u{8ddd}\u{7edf}\u{4e00}\u{ff08}`px-10 \u{2192} px-6`\u{ff09}\u{ff0c}\u{5199}\u{6587}\u{7ae0}\u{9875}\u{79fb}\u{9664}\u{9875}\u{5934}\u{6761}\u{3002}\n- **\u{56de}\u{6536}\u{7ad9}\u{5408}\u{5e76}\u{5165}\u{6587}\u{7ae0}\u{5217}\u{8868}**\u{ff1a}`/admin/trash` \u{5408}\u{5e76}\u{4e3a} `/admin/posts` \u{7684} URL \u{9a71}\u{52a8} tab\u{ff0c}`PostStats` \u{65b0}\u{589e}\u{56de}\u{6536}\u{7ad9}\u{8ba1}\u{6570} badge\u{3002}\n- **\u{4f9d}\u{8d56}\u{5347}\u{7ea7}**\u{ff1a}cargo \u{4e0e} pnpm \u{4f9d}\u{8d56}\u{5168}\u{91cf}\u{5347}\u{7ea7}\u{5230}\u{6700}\u{65b0}\u{7248}\u{672c}\u{ff1b}\u{65b0}\u{589e} `tokio-stream`\u{ff08}SSE\u{ff09}\u{3001}`bollard`\u{ff08}Docker\u{ff09}\u{3002}\n- **Runner \u{914d}\u{7f6e}**\u{ff1a}`CODE_RUNNER_LANGUAGES` \u{9ed8}\u{8ba4}\u{5f00}\u{653e}\u{5168}\u{90e8}\u{8bed}\u{8a00}\u{ff1b}admin runner \u{9875}\u{5c55}\u{793a} Go/Rust\u{3002}\n- **Tooltip \u{7ec4}\u{4ef6}\u{62bd}\u{53d6}**\u{ff1a}\u{6587}\u{7ae0}\u{5217}\u{8868}\u{64cd}\u{4f5c}\u{6309}\u{94ae}\u{7528} `Tooltip` \u{5305}\u{88f9}\u{3002}\n\n### Fixed\n\n- **\u{53cd}\u{5e94}\u{5f0f} hook \u{4e0d}\u{8ffd}\u{8e2a}\u{666e}\u{901a} prop \u{7684}\u{9677}\u{9631}**\u{ff1a}\u{4fee}\u{590d}\u{540c}\u{4e00}\u{8def}\u{7531}\u{53d8}\u{4f53}\u{95f4}\u{5bfc}\u{822a}\u{ff08}\u{5982} `/post/a \u{2192} /post/b`\u{ff09}\u{540e}\u{6587}\u{7ae0}\u{6b63}\u{6587}/\u{5217}\u{8868}/\u{6807}\u{7b7e}\u{4e0d}\u{66f4}\u{65b0}\u{7684}\u{4e25}\u{91cd} bug \u{2014}\u{2014} \u{6839}\u{56e0}\u{662f} `use_server_future`/`use_memo`/`use_resource` \u{4e0d}\u{8ffd}\u{8e2a}\u{975e} signal \u{4f9d}\u{8d56}\u{3002}\u{6539}\u{4e3a}\u{5728}\u{95ed}\u{5305}\u{5185}\u{8bfb} `router.current()` signal \u{6216}\u{76f4}\u{63a5}\u{5185}\u{8054}\u{8ba1}\u{7b97}\u{3002}\u{540c}\u{7406}\u{4fee}\u{590d}\u{8bc4}\u{8bba}\u{533a} `CommentSection` \u{4f9d}\u{8d56}\u{8ffd}\u{8e2a}\u{4e0e} SSR hydration \u{4e0d}\u{5339}\u{914d}\u{3002}\n- **\u{4e3b}\u{9898}\u{5207}\u{6362}\u{52a8}\u{753b}**\u{ff1a}\u{4fee}\u{590d} VT \u{52a8}\u{753b}\u{671f}\u{95f4} CodeMirror/xterm \u{4e3b}\u{9898}\u{540c}\u{6b65}\u{ff08}\u{907f}\u{514d}\u{5706}\u{5f62}\u{5c55}\u{5f00}\u{52a8}\u{753b}\u{671f}\u{95f4}\u{76f4}\u{63a5}\u{8df3}\u{53d8}\u{ff09}\u{3001}\u{6e05}\u{7406} VT \u{671f}\u{95f4}\u{7684} `animate-page-enter` transform\u{ff08}\u{4fee}\u{590d}\u{4ee3}\u{7801}\u{5757}\u{88ab}\u{8986}\u{76d6}\u{ff09}\u{3001}\u{8ddf}\u{968f}\u{7cfb}\u{7edf}\u{6a21}\u{5f0f}\u{7cfb}\u{7edf}\u{504f}\u{597d}\u{53d8}\u{5316}\u{65f6}\u{540c}\u{6b65} dark class\u{ff08}\u{6539}\u{56de}\u{77ac}\u{5207}\u{907f}\u{514d}\u{52a8}\u{753b}\u{51b2}\u{7a81}\u{ff09}\u{3001}`prefers-reduced-motion` \u{964d}\u{7ea7}\u{3002}\n- **\u{5907}\u{4efd}\u{6062}\u{590d}\u{5047}\u{6210}\u{529f}**\u{ff1a}\u{4fee}\u{590d}\u{5907}\u{4efd}\u{6062}\u{590d}\u{5b9e}\u{9645}\u{4e0d}\u{5199}\u{5165}\u{6570}\u{636e}\u{5374}\u{8fd4}\u{56de}\u{6210}\u{529f}\u{ff08}`psql` \u{672a}\u{52a0} `ON_ERROR_STOP=1` \u{5bfc}\u{81f4}\u{8bed}\u{53e5}\u{5168}\u{9519}\u{4ecd} exit 0\u{ff09}\u{ff1b}\u{4fee}\u{590d}\u{5907}\u{4efd}/\u{6062}\u{590d}\u{4efb}\u{52a1}\u{8f6e}\u{8be2}\u{6c38}\u{4e0d}\u{542f}\u{52a8}\u{5bfc}\u{81f4}\u{6309}\u{94ae}\u{5361}\u{5728} loading\u{3002}\n- **\u{53ef}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{5757}\u{5bb9}\u{5668}\u{6e05}\u{7406}**\u{ff1a}\u{4fee}\u{590d}\u{5bb9}\u{5668}\u{6e05}\u{7406}\u{5931}\u{8d25}\u{9759}\u{9ed8}\u{6cc4}\u{6f0f}\u{ff08}\u{91cd}\u{8bd5} + \u{65e5}\u{5fd7}\u{544a}\u{8b66}\u{ff09}\u{3001}\u{7f16}\u{8bd1}\u{578b}\u{8bed}\u{8a00}\u{9700} `/tmp` tmpfs \u{6267}\u{884c}\u{6743}\u{3001}\u{53bb}\u{6389} `nproc` ulimit \u{4fee}\u{590d}\u{5bb9}\u{5668}\u{542f}\u{52a8} EAGAIN\u{3002}\n- **\u{6587}\u{7ae0}\u{951a}\u{70b9}\u{5bfc}\u{822a}**\u{ff1a}\u{4fee}\u{590d}\u{76f4}\u{63a5}\u{8bbf}\u{95ee} `#hash` \u{65f6}\u{6807}\u{9898}\u{88ab} sticky header \u{906e}\u{4f4f}\u{3001}hydration \u{540e}\u{70b9}\u{51fb}\u{6807}\u{9898}\u{951a}\u{70b9}\u{89e6}\u{53d1}\u{6574}\u{9875}\u{5237}\u{65b0}\u{3001}hash \u{951a}\u{70b9}\u{8df3}\u{8f6c}\u{5931}\u{6548}\u{3002}\n- **Tiptap \u{7f16}\u{8f91}\u{5668}**\u{ff1a}\u{4fee}\u{590d}\u{659c}\u{6760}\u{547d}\u{4ee4}\u{521b}\u{5efa}\u{53ef}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{5757}\u{65f6}\u{6a21}\u{6001}\u{6846}\u{88ab}\u{7acb}\u{5373}\u{5173}\u{95ed}\u{3001}\u{659c}\u{6760}\u{547d}\u{4ee4}\u{6587}\u{672c}\u{6b8b}\u{7559}\u{8fdb}\u{65b0}\u{8282}\u{70b9}\u{ff08}`/code` \u{5e26}\u{5165} codeBlock\u{ff09}\u{3001}\u{4ee3}\u{7801}\u{5757}\u{5185} Backspace \u{5220}\u{6574}\u{5757}\u{ff08}`ignoreMutation` \u{8bef}\u{5ffd}\u{7565} contentDOM \u{7f16}\u{8f91}\u{ff09}\u{3001}Backspace \u{5728} lowlight decoration \u{91cd}\u{5efa}\u{540e}\u{5931}\u{6548}\u{3001}runnable \u{5757} `classList.add` \u{629b} `InvalidCharacterError`\u{3001}\u{8bed}\u{8a00}\u{4e0b}\u{62c9}\u{5c55}\u{5f00}\u{65f6} Enter \u{8bef}\u{89e6}\u{53d1}\u{63d2}\u{5165}\u{3001}\u{7a7a}\u{9879} Enter \u{4e0d}\u{9000}\u{51fa}\u{5217}\u{8868}\u{ff08}\u{7578}\u{5f62}\u{6587}\u{6863}\u{6839}\u{56e0}\u{ff09}\u{3001}TaskInputRule \u{5347}\u{7ea7}\u{540e}\u{5149}\u{6807}\u{88ab}\u{7529}\u{5230}\u{4e0b}\u{4e00}\u{884c}\u{3001}\u{5347}\u{7ea7}\u{540e}\u{6298}\u{53e0}\u{884c}\u{88ab}\u{6491}\u{9ad8} + \u{6298}\u{53e0}\u{56fe}\u{6807}\u{5782}\u{76f4}\u{4e0d}\u{5c45}\u{4e2d}\u{3001}CodeMirror \u{6298}\u{53e0}\u{56fe}\u{6807}\u{5782}\u{76f4}\u{4e0d}\u{5c45}\u{4e2d}\u{3002}\n- **CodeMirror \u{7f16}\u{8f91}\u{5668}**\u{ff1a}\u{4fee}\u{590d}\u{7f16}\u{8f91}\u{56de}\u{9000}\u{53cd}\u{9988}\u{5faa}\u{73af}\u{ff08}editing reversion loop\u{ff09}\u{3001}\u{7f16}\u{8f91}\u{5668}\u{584c}\u{7f29}\u{5bfc}\u{81f4}\u{4e0a}\u{4e0b}\u{80cc}\u{666f}\u{5272}\u{88c2}\u{ff08}`height:100%` \u{5931}\u{6548}\u{ff09}\u{3001}\u{884c}\u{53f7}\u{533a}\u{80cc}\u{666f}\u{4e0e}\u{4ee3}\u{7801}\u{533a}\u{5272}\u{88c2}\u{3001}\u{672a}\u{6491}\u{6ee1}\u{5bb9}\u{5668}\u{3001}SQL \u{7f16}\u{8f91}\u{5668} gutter \u{4e0e} content \u{80cc}\u{666f}\u{5272}\u{88c2}\u{3002}\n- **\u{540e}\u{53f0}\u{9aa8}\u{67b6}\u{5c4f}**\u{ff1a}\u{4fee}\u{590d}\u{540e}\u{53f0}\u{9aa8}\u{67b6}\u{5c4f}\u{4e0d}\u{53ef}\u{89c1}\u{3001}\u{9aa8}\u{67b6}\u{5c4f}\u{2192}\u{8ba4}\u{8bc1}\u{2192}\u{6b63}\u{5e38}\u{9875}\u{9762}\u{5e03}\u{5c40}\u{95ea}\u{70c1}\u{3001}\u{5199}\u{6587}\u{7ae0}\u{9875}\u{9aa8}\u{67b6}\u{5c4f}\u{9ad8}\u{5ea6}\u{4e0d}\u{6491}\u{6ee1}\u{ff08}\u{591a}\u{6b21}\u{8fed}\u{4ee3}\u{ff09}\u{3002}\n- **\u{8def}\u{7531}\u{4e0e}\u{5206}\u{9875}**\u{ff1a}\u{4fee}\u{590d} SQL \u{63a7}\u{5236}\u{53f0} Ctrl+Enter \u{89e6}\u{53d1} panic\u{ff08}\u{65e0} dioxus scope\u{ff09}\u{3001}\u{4e0a}\u{4e0b}\u{7bc7}\u{5207}\u{6362}\u{540e}\u{53ef}\u{8fd0}\u{884c}\u{4ee3}\u{7801}\u{5757}\u{6d88}\u{5931}\u{3002}\n- **UI \u{7ec6}\u{8282}**\u{ff1a}\u{4fee}\u{590d} markdown \u{8868}\u{683c}\u{6c34}\u{5e73}\u{586b}\u{5145}\u{6e32}\u{67d3}\u{3001}admin \u{5e03}\u{5c40}\u{6eda}\u{52a8}\u{6761}\u{4f4d}\u{7f6e}\u{3001}\u{5199}\u{6587}\u{7ae0}\u{9875}\u{6eda}\u{52a8}\u{6027}\u{3001}`--font-sans` \u{8865}\u{9f50} CJK sans \u{5b57}\u{4f53}\u{6808}\u{3001}\u{6697}\u{8272} type \u{8272}\u{503c}\u{3002}\n- **\u{6570}\u{636e}\u{5e93}\u{9519}\u{8bef}\u{65e5}\u{5fd7}**\u{ff1a}\u{5c55}\u{5f00}\u{8fc1}\u{79fb}\u{9519}\u{8bef}\u{7684} source chain \u{5168}\u{94fe}\u{8def}\u{3002}\n- \u{5176}\u{4ed6}\u{6784}\u{5efa}\u{3001}CI\u{3001}Docker \u{955c}\u{50cf}\u{ff08}multi-arch buildx\u{3001}HTTPS Debian \u{955c}\u{50cf}\u{7ed5}\u{8fc7} HTTP \u{900f}\u{660e}\u{62e6}\u{622a}\u{3001}apk \u{6e05}\u{534e}\u{955c}\u{50cf}\u{ff09}\u{3001}\u{683c}\u{5f0f}\u{5316}\u{4e0e}\u{6d4b}\u{8bd5}\u{4fee}\u{590d}\u{3002}\n\n### Security\n\n- **SQL \u{63a7}\u{5236}\u{53f0}\u{62a4}\u{680f}\u{52a0}\u{56fa}**\u{ff1a}`DROP DATABASE`/`DROP SCHEMA`/`CREATE DATABASE` \u{7edd}\u{5bf9}\u{7981}\u{6b62}\u{ff08}\u{5b57}\u{7b26}\u{4e32}\u{9884}\u{68c0} + AST \u{95e8}\u{ff09}\u{ff1b}`DROP`/`TRUNCATE`/`ALTER` \u{9700}\u{786e}\u{8ba4}\u{ff1b}`UPDATE`/`DELETE` \u{65e0} `WHERE` \u{62d2}\u{7edd}\u{ff1b}\u{591a}\u{8bed}\u{53e5}\u{9ed8}\u{8ba4}\u{7981}\u{7528}\u{ff1b}\u{7ed3}\u{679c}\u{4e0a}\u{9650} 500 \u{884c}\u{3002}\n- **\u{5907}\u{4efd}\u{6587}\u{4ef6}\u{6821}\u{9a8c}**\u{ff1a}\u{5907}\u{4efd}\u{6587}\u{4ef6}\u{643a}\u{5e26}\u{7b7e}\u{540d}\u{5934}\u{ff0c}restore \u{62d2}\u{7edd}\u{975e}\u{7cfb}\u{7edf}\u{6587}\u{4ef6}\u{ff1b}`backup_path` \u{8def}\u{5f84}\u{7a7f}\u{8d8a}\u{6f0f}\u{6d1e}\u{4fee}\u{590d}\u{ff08}\u{8865}\u{5355}\u{6d4b}\u{ff09}\u{ff1b}`pg_dump --clean --if-exists` \u{4f7f} restore \u{5e42}\u{7b49}\u{ff08}drop+recreate \u{800c}\u{975e} relation \u{5df2}\u{5b58}\u{5728}\u{62a5}\u{9519}\u{ff09}\u{3002}\n- **\u{5907}\u{4efd}\u{6062}\u{590d}\u{8865}\u{5355}\u{6d4b}**\u{ff1a}`backup_path` \u{8def}\u{5f84}\u{7a7f}\u{8d8a}\u{6f0f}\u{6d1e}\u{8865}\u{8868}\u{9a71}\u{52a8}\u{5355}\u{6d4b}\u{3002}\n\n### Internal\n\n- **\u{65b0}\u{5b50}\u{5de5}\u{7a0b} `xterm-terminal`**\u{ff1a}xterm.js 6.0 IIFE \u{5e93} + smoke \u{6d4b}\u{8bd5}\u{3002}\n- **\u{65b0}\u{5b50}\u{5de5}\u{7a0b} `codemirror-editor`**\u{ff1a}CodeMirror \u{7f16}\u{8f91}\u{5668} + Rust bridge\u{ff0c}Ctrl/Cmd+Enter \u{8fd0}\u{884c}\u{5feb}\u{6377}\u{952e}\u{3002}\n- **Docker runner \u{955c}\u{50cf}**\u{ff1a}`docker/build-runners.sh` \u{6784}\u{5efa} base \u{2192} python \u{2192} node \u{2192} go \u{2192} rust \u{94fe}\u{ff1b}Go \u{955c}\u{50cf}\u{91cd}\u{5b9a}\u{5411} `GOCACHE`/`GOPATH` \u{5230} `/tmp`\u{ff0c}Rust \u{955c}\u{50cf}\u{5c01}\u{88c5} `run-rust.sh` \u{4e24}\u{6b65}\u{7f16}\u{8bd1}+\u{8fd0}\u{884c} wrapper\u{3002}\n- **\u{65b0}\u{589e} Rust \u{5355}\u{6d4b}**\u{ff1a}SQL \u{63a7}\u{5236}\u{53f0}\u{62a4}\u{680f}\u{8868}\u{9a71}\u{52a8}\u{5355}\u{6d4b}\u{3001}\u{5907}\u{4efd}\u{6062}\u{590d}\u{5355}\u{6d4b}\u{3001}markdown `wrap_images_with_blur` \u{89e3}\u{8026}\u{6587}\u{4ef6}\u{7cfb}\u{7edf}\u{4f9d}\u{8d56}\u{3002}\n- **codemirror-editor smoke \u{6d4b}\u{8bd5}**\u{3001}`xterm-terminal` smoke \u{6d4b}\u{8bd5}\u{3002}\n- **AGENTS.md \u{6587}\u{6863}\u{6269}\u{5145}**\u{ff1a}Code Runner \u{67b6}\u{6784}\u{8bf4}\u{660e}\u{3001}\u{53cc} target \u{9a8c}\u{8bc1}\u{9677}\u{9631}\u{3001}custom hook \u{8d44}\u{6e90}\u{6240}\u{6709}\u{6743}\u{9677}\u{9631}\u{3001}\u{53cd}\u{5e94}\u{5f0f} hook \u{4e0d}\u{8ffd}\u{8e2a}\u{666e}\u{901a} prop \u{7684}\u{8e29}\u{5751}\u{8bb0}\u{5f55}\u{3001}Tiptap \u{4ea4}\u{4e92} bug Playwright \u{8c03}\u{8bd5}\u{65b9}\u{6cd5}\u{8bba}\u{3002}\n- **matt-pocock engineering skills** \u{5f15}\u{5165}\u{3002}\n\n## [0.3.0] - 2026-06-29\n\n### Added\n\n- **\u{8bc4}\u{8bba}\u{7cfb}\u{7edf}**\u{ff1a}\u{5b8c}\u{6574}\u{7684}\u{8bbf}\u{5ba2}\u{8bc4}\u{8bba}\u{529f}\u{80fd}\u{ff0c}\u{5305}\u{542b}\u{6635}\u{79f0}/\u{90ae}\u{7bb1}/URL\u{3001}\u{5d4c}\u{5957}\u{56de}\u{590d}\u{3001}\u{7ba1}\u{7406}\u{540e}\u{53f0}\u{5ba1}\u{6838}\u{ff08}\u{901a}\u{8fc7}/\u{6807}\u{5783}\u{573e}/\u{5220}\u{9664}\u{ff09}\u{3001}\u{5f85}\u{5ba1}\u{8bc4}\u{8bba} localStorage \u{6301}\u{4e45}\u{5316}\u{4e0e} pending \u{72b6}\u{6001}\u{8f6e}\u{8be2}\u{3001}\u{76f8}\u{5bf9}\u{65f6}\u{95f4}\u{663e}\u{793a}\u{3002}\n- **\u{6587}\u{7ae0}\u{56de}\u{6536}\u{7ad9}**\u{ff1a}\u{5220}\u{9664}\u{6587}\u{7ae0}\u{8fdb}\u{5165}\u{56de}\u{6536}\u{7ad9}\u{ff0c}\u{652f}\u{6301}\u{6062}\u{590d}\u{3001}\u{5f7b}\u{5e95}\u{5220}\u{9664}\u{3001}\u{6279}\u{91cf}\u{64cd}\u{4f5c}\u{4e0e}\u{6e05}\u{7a7a}\u{ff1b}\u{65b0}\u{589e} `/admin/trash` \u{7ba1}\u{7406}\u{9875}\u{9762}\u{3001}`settings` \u{952e}\u{503c}\u{8868}\u{4e0e}\u{53ef}\u{914d}\u{7f6e}\u{7684}\u{81ea}\u{52a8}\u{6e05}\u{7406}\u{540e}\u{53f0}\u{4efb}\u{52a1}\u{ff08}\u{4fdd}\u{7559}\u{5929}\u{6570}\u{3001}\u{4e0a}\u{9650}\u{6570}\u{91cf}\u{ff09}\u{3002}\n- **\u{4e3b}\u{9898}\u{5207}\u{6362}\u{52a8}\u{753b}**\u{ff1a}\u{57fa}\u{4e8e} View Transitions API \u{7684}\u{5706}\u{5f62}\u{5c55}\u{5f00}\u{52a8}\u{753b}\u{ff08}\u{7eaf} CSS \u{5b9e}\u{73b0}\u{ff0c}\u{4ece}\u{70b9}\u{51fb}\u{70b9}\u{6269}\u{6563}\u{ff09}\u{ff0c}\u{652f}\u{6301} `prefers-reduced-motion` \u{964d}\u{7ea7}\u{3002}\n- **\u{7f16}\u{8f91}\u{5668}\u{56fe}\u{7247}\u{4e0a}\u{4f20}\u{534f}\u{8c03}\u{5668}**\u{ff1a}Tiptap \u{81ea}\u{5b9a}\u{4e49} Image \u{6269}\u{5c55}\u{ff0c}\u{5e26}\u{4e0a}\u{4f20}\u{4e2d}\u{5360}\u{4f4d}\u{56fe}\u{ff08}\u{6a21}\u{7cca} + spinner + \u{9519}\u{8bef}\u{6001}\u{ff09}\u{3001}\u{5931}\u{8d25}\u{91cd}\u{8bd5}\u{3001}\u{4fdd}\u{5b58}\u{62e6}\u{622a}\u{3001}\u{4e0a}\u{4f20}\u{8ba1}\u{6570}\u{ff1b}\u{652f}\u{6301} slash \u{547d}\u{4ee4}\u{3001}\u{7c98}\u{8d34}\u{3001}\u{62d6}\u{62fd}\u{3002}\n- **\u{5c01}\u{9762}\u{56fe}\u{4e0a}\u{4f20}**\u{ff1a}\u{6587}\u{7ae0}\u{7f16}\u{8f91}\u{5668}\u{652f}\u{6301}\u{5c01}\u{9762}\u{56fe}\u{4e0a}\u{4f20}\u{ff08}\u{62d6}\u{62fd}/\u{70b9}\u{51fb}/\u{7c98}\u{8d34}\u{ff09}\u{ff0c}\u{5c01}\u{9762}\u{533a}\u{7a7a}\u{6001}\u{77ee}\u{6a2a}\u{6761} + \u{53ef}\u{6eda}\u{52a8}\u{4e3b}\u{4f53}\u{5e03}\u{5c40}\u{3002}\n- **Blur-up \u{6e10}\u{8fdb}\u{5f0f}\u{56fe}\u{7247}\u{52a0}\u{8f7d}**\u{ff1a}Markdown \u{56fe}\u{7247}\u{5305}\u{88f9}\u{53cc}\u{5c42}\u{7ed3}\u{6784}\u{ff08}\u{4f4e}\u{6e05}\u{6a21}\u{7cca} + \u{9ad8}\u{6e05}\u{6de1}\u{5165}\u{ff09}\u{ff0c}\u{57fa}\u{4e8e}\u{56fe}\u{7247}\u{5c3a}\u{5bf8}\u{7f13}\u{5b58}\u{7684}\u{5bbd}\u{9ad8}\u{6bd4}\u{5360}\u{4f4d}\u{3002}\n- **Lightbox \u{5b50}\u{5de5}\u{7a0b}**\u{ff1a}`libs/lightbox/` TypeScript \u{9879}\u{76ee}\u{ff0c}\u{56fe}\u{5e93}\u{5bfc}\u{822a}\u{ff08}\u{6de1}\u{5165}\u{3001}\u{7bad}\u{5934}\u{3001}\u{952e}\u{76d8}\u{ff09}\u{3001}\u{539f}\u{70b9}\u{611f}\u{77e5}\u{7f29}\u{653e}\u{3001}\u{6eda}\u{52a8}\u{5173}\u{95ed}\u{3001}\u{9632}\u{6b62}\u{80cc}\u{666f}\u{6eda}\u{52a8}\u{4e0e}\u{95ea}\u{70c1}\u{3002}\n- **yggdrasil-core \u{5b50}\u{5de5}\u{7a0b}**\u{ff1a}\u{6838}\u{5fc3} JS bundle \u{5b50}\u{5de5}\u{7a0b}\u{ff0c}\u{8fc1}\u{79fb} `post-content` \u{590d}\u{5236}\u{6309}\u{94ae}\u{4e0e}\u{4e3b}\u{9898}\u{5207}\u{6362}\u{903b}\u{8f91}\u{ff0c}\u{5220}\u{9664} `public/js/`\u{3002}\n- **\u{65b0}\u{589e}\u{8bed}\u{6cd5}\u{9ad8}\u{4eae}**\u{ff1a}TypeScript\u{3001}JSX\u{3001}TSX\u{3001}Zig\u{ff1b}\u{8865}\u{5168} Swift \u{9ad8}\u{4eae}\u{ff1b}\u{5927}\u{5c0f}\u{5199}\u{4e0d}\u{654f}\u{611f}\u{7684}\u{8bed}\u{6cd5}\u{540d}\u{5339}\u{914d}\u{3002}\n- **Markdown \u{6e90}\u{7801}\u{89c6}\u{56fe}\u{5207}\u{6362}**\u{ff1a}\u{7f16}\u{8f91}\u{5668}\u{53ef}\u{5728}\u{5bcc}\u{6587}\u{672c}\u{4e0e}\u{6e90}\u{7801}\u{89c6}\u{56fe}\u{95f4}\u{5207}\u{6362}\u{ff0c}\u{6309}\u{6eda}\u{52a8}\u{6bd4}\u{4f8b}\u{540c}\u{6b65}\u{4f4d}\u{7f6e}\u{3002}\n- **\u{5065}\u{5eb7}\u{68c0}\u{67e5}\u{7aef}\u{70b9}**\u{ff1a}\u{65b0}\u{589e} `healthz` \u{4e0e} `readyz`\u{3002}\n- **\u{5185}\u{5d4c}\u{6570}\u{636e}\u{5e93}\u{8fc1}\u{79fb}**\u{ff1a}\u{542f}\u{52a8}\u{65f6}\u{81ea}\u{52a8}\u{8fd0}\u{884c}\u{8fc1}\u{79fb}\u{ff08}advisory lock + \u{9010}\u{8fc1}\u{79fb}\u{4e8b}\u{52a1}\u{ff09}\u{ff0c}\u{8fc1}\u{79fb}\u{5931}\u{8d25}\u{4ee5}\u{53cb}\u{597d}\u{9000}\u{51fa} + \u{53ef}\u{914d}\u{7f6e}\u{91cd}\u{8bd5}\u{7a97}\u{53e3}\u{ff08}`MIGRATE_STARTUP_TIMEOUT_SECS`\u{ff09}\u{66ff}\u{4ee3} panic\u{ff1b}\u{542f}\u{52a8}\u{671f}\u{81ea}\u{52a8}\u{521b}\u{5efa}\u{76ee}\u{6807}\u{6570}\u{636e}\u{5e93}\u{3002}\n- **\u{4f1a}\u{8bdd}\u{5b89}\u{5168}**\u{ff1a}Session token \u{4ee5} SHA-256 \u{54c8}\u{5e0c}\u{5b58}\u{50a8}\u{ff08}\u{4e0d}\u{518d}\u{5b58}\u{660e}\u{6587}\u{ff09}\u{ff1b}\u{53ef}\u{914d}\u{7f6e}\u{7684}\u{5355}\u{7528}\u{6237} session \u{6570}\u{91cf}\u{4e0a}\u{9650}\u{ff08}\u{884c}\u{9501}\u{4e32}\u{884c}\u{5316}\u{ff09}\u{ff1b}\u{89d2}\u{8272}/\u{72b6}\u{6001}\u{53d8}\u{66f4}\u{901a}\u{8fc7} generation \u{5931}\u{6548}\u{6240}\u{6709}\u{4f1a}\u{8bdd}\u{3002}\n- **CSRF \u{9632}\u{62a4}**\u{ff1a}\u{57fa}\u{4e8e} Origin \u{7684}\u{5199}\u{63a5}\u{53e3} CSRF \u{68c0}\u{67e5}\u{ff0c}`APP_BASE_URL` \u{672a}\u{8bbe}\u{7f6e}\u{65f6}\u{542f}\u{52a8}\u{544a}\u{8b66}\u{3002}\n- **Cookie \u{5b89}\u{5168}**\u{ff1a}`COOKIE_SECURE` \u{73af}\u{5883}\u{53d8}\u{91cf}\u{63a7}\u{5236} session cookie \u{7684} Secure \u{6807}\u{5fd7}\u{3002}\n- **\u{771f}\u{5b9e}\u{5ba2}\u{6237}\u{7aef} IP**\u{ff1a}\u{4ece} `X-Forwarded-For` \u{6309} `TRUSTED_PROXY_COUNT` \u{63d0}\u{53d6}\u{771f}\u{5b9e} IP\u{ff1b}\u{672a}\u{77e5} IP \u{65f6}\u{4f7f}\u{7528}\u{5bbd}\u{677e}\u{9650}\u{6d41}\u{6876}\u{3002}\n- **\u{56fe}\u{7247}\u{54cd}\u{5e94}\u{7f13}\u{5b58}**\u{ff1a}`Cache-Control` \u{4e0e} `ETag` \u{5934}\u{ff0c}\u{652f}\u{6301} `If-None-Match` 304\u{ff08}RFC 7232 \u{5408}\u{89c4}\u{ff09}\u{ff1b}\u{56fe}\u{7247}\u{5185}\u{5b58}\u{7f13}\u{5b58}\u{6539}\u{7528} `bytes::Bytes`\u{ff0c}\u{65b0}\u{589e}\u{6309}\u{6587}\u{4ef6}\u{5e74}\u{9f84}\u{4e0e}\u{603b}\u{5927}\u{5c0f}\u{6dd8}\u{6c70}\u{7684}\u{78c1}\u{76d8}\u{7f13}\u{5b58}\u{5b9a}\u{65f6}\u{6e05}\u{7406}\u{4efb}\u{52a1}\u{3002}\n- **\u{56fe}\u{7247}\u{4e0a}\u{9650}\u{53ef}\u{914d}\u{7f6e}**\u{ff1a}`MAX_IMAGE_DIMENSION`\u{3001}`MAX_IMAGE_PIXELS`\u{3001}`WEBP_QUALITY`\u{3001}`WEBP_METHOD` \u{7b49}\u{73af}\u{5883}\u{53d8}\u{91cf}\u{ff0c}\u{9ed8}\u{8ba4}\u{503c}\u{7ffb}\u{500d}\u{ff1b}\u{7edf}\u{4e00}\u{5404}\u{683c}\u{5f0f}\u{5927}\u{5c0f}\u{4e0a}\u{9650}\u{3002}\n- **`posts` \u{8868}\u{5b57}\u{6570}\u{4e0e}\u{9605}\u{8bfb}\u{65f6}\u{95f4}**\u{ff1a}\u{65b0}\u{589e} `word_count`/`reading_time` \u{5217}\u{5e76}\u{5728}\u{5199}\u{5165}\u{65f6}\u{7ef4}\u{62a4}\u{ff1b}\u{5217}\u{8868}/\u{641c}\u{7d22}\u{63a5}\u{53e3}\u{4e0d}\u{518d}\u{8fd4}\u{56de}\u{6b63}\u{6587}\u{ff0c}\u{8bfb}\u{53d6}\u{9884}\u{5b58}\u{7684}\u{5b57}\u{6570}\u{4e0e}\u{9605}\u{8bfb}\u{65f6}\u{95f4}\u{3002}\n- **`PostListItem` \u{8f7b}\u{91cf} DTO**\u{ff1a}\u{5217}\u{8868}/\u{6807}\u{7b7e}/\u{641c}\u{7d22}\u{63a5}\u{53e3}\u{4e0d}\u{518d}\u{8fd4}\u{56de}\u{5b8c}\u{6574}\u{6b63}\u{6587}\u{ff0c}\u{663e}\u{8457}\u{964d}\u{4f4e}\u{7f13}\u{5b58}\u{4e0e}\u{5e8f}\u{5217}\u{5316}\u{4f53}\u{79ef}\u{3002}\n- **\u{4f1a}\u{8bdd}\u{4e0e}\u{641c}\u{7d22}\u{7f13}\u{5b58}**\u{ff1a}\u{57fa}\u{4e8e} moka \u{7684}\u{4f1a}\u{8bdd}\u{5185}\u{5b58}\u{7f13}\u{5b58}\u{ff08}\u{7f13}\u{5b58}\u{5bf9}\u{8c61}\u{4e0d}\u{542b}\u{5bc6}\u{7801}\u{54c8}\u{5e0c}\u{ff09}\u{ff1b}\u{641c}\u{7d22}\u{7ed3}\u{679c}\u{77ed} TTL \u{7f13}\u{5b58}\u{ff08}10 \u{79d2}\u{ff0c}key \u{89c4}\u{8303}\u{5316}\u{ff09}\u{3002}\n- **\u{7a7a}\u{72b6}\u{6001}\u{4e0e}\u{914d}\u{56fe}**\u{ff1a}\u{9996}\u{9875}\u{3001}\u{5f52}\u{6863}\u{3001}\u{6807}\u{7b7e}\u{3001}\u{641c}\u{7d22}\u{3001}\u{540e}\u{53f0}\u{6587}\u{7ae0}/\u{8bc4}\u{8bba}/\u{56de}\u{6536}\u{7ad9}\u{5747}\u{63a5}\u{5165} `EmptyState` \u{7ec4}\u{4ef6}\u{4e0e}\u{88c5}\u{9970}\u{6027}\u{914d}\u{56fe}\u{ff08}\u{7ebf}\u{6761}\u{5c0f}\u{72d7}\u{7b49}\u{ff09}\u{ff0c}\u{914d}\u{56fe}\u{5706}\u{89d2} + \u{6697}\u{8272}\u{6a21}\u{5f0f}\u{964d}\u{4eae}\u{3002}\n- **UI \u{91cd}\u{65b0}\u{8bbe}\u{8ba1}**\u{ff1a}\u{6e29}\u{6696}\u{8272}\u{8c03} + \u{9f20}\u{5c3e}\u{8349}\u{7eff}\u{4e3b}\u{8272}\u{ff0c}\u{7edf}\u{4e00} `paper-*` \u{4e3b}\u{9898}\u{53d8}\u{91cf}\u{ff1b}\u{540e}\u{53f0}\u{5bf9}\u{9f50}\u{524d}\u{53f0}\u{4e3b}\u{9898}\u{53d8}\u{91cf}\u{ff0c}\u{65b0}\u{589e}\u{6b21}\u{8981}\u{6309}\u{94ae}\u{51b7}\u{8c03}\u{73ab}\u{7470}\u{8272}\u{3002}\n- **\u{540e}\u{53f0}\u{4ea4}\u{4e92}\u{6539}\u{8fdb}**\u{ff1a}\u{6587}\u{7ae0}\u{7ba1}\u{7406}\u{5206}\u{9875}\u{3001}\u{91cd}\u{5efa}\u{5185}\u{5bb9}\u{6309}\u{94ae}\u{ff08}\u{5e26} tooltip\u{ff09}\u{3001}\u{91cd}\u{5efa}\u{7f13}\u{5b58}\u{680f}\u{ff1b}\u{8bc4}\u{8bba}\u{72b6}\u{6001}\u{7b5b}\u{9009} `FilterTabs` \u{7ec4}\u{4ef6}\u{5e26}\u{6ed1}\u{52a8}\u{6307}\u{793a}\u{52a8}\u{753b}\u{ff1b}\u{56de}\u{6536}\u{7ad9}\u{81ea}\u{52a8}\u{6e05}\u{7406}\u{9762}\u{677f}\u{5e26}\u{6ed1}\u{5165}\u{52a8}\u{753b}\u{3002}\n- **HTTP \u{538b}\u{7f29}**\u{ff1a}\u{9ed8}\u{8ba4}\u{542f}\u{7528}\u{6240}\u{6709}\u{538b}\u{7f29}\u{7b97}\u{6cd5}\u{ff0c}\u{53ef}\u{901a}\u{8fc7} `COMPRESSION_ALGORITHMS` \u{914d}\u{7f6e}\u{ff1b}\u{516c}\u{5171}\u{9875}\u{9762}\u{4e0e}\u{9759}\u{6001}\u{8d44}\u{6e90} `Cache-Control`\u{3002}\n- **Dockerfile**\u{ff1a}\u{9759}\u{6001} musl \u{955c}\u{50cf}\u{6784}\u{5efa}\u{ff08}release \u{4e8c}\u{8fdb}\u{5236} strip \u{7b26}\u{53f7}\u{ff09}\u{3002}\n- **Gitea Actions CI**\u{ff1a}CI \u{5de5}\u{4f5c}\u{6d41}\u{3002}\n\n### Changed\n\n- \u{5199}\u{8def}\u{5f84}\u{7f13}\u{5b58}\u{5931}\u{6548}\u{4ece}\u{300c}\u{5168}\u{91cf}\u{6e05}\u{7a7a}\u{300d}\u{6539}\u{4e3a}\u{300c}\u{7cbe}\u{786e}\u{5230} slug / tag / \u{5217}\u{8868}\u{9875}\u{300d}\u{ff0c}\u{5e76}\u{5728}\u{8bfb}\u{53d6} slug/tag \u{5143}\u{6570}\u{636e}\u{65f6}\u{4f7f}\u{7528}\u{4e8b}\u{52a1} + `FOR UPDATE` \u{907f}\u{514d}\u{5e76}\u{53d1}\u{7ade}\u{6001}\u{ff1b}\u{6279}\u{91cf}\u{6062}\u{590d}\u{3001}\u{6e05}\u{7a7a}\u{3001}\u{91cd}\u{5efa}\u{7b49}\u{8def}\u{5f84}\u{5747}\u{91c7}\u{7528}\u{7cbe}\u{786e}\u{5931}\u{6548}\u{3002}\n- `get_post_stats` \u{5c06} 3 \u{6b21}\u{72ec}\u{7acb} `COUNT(*)` \u{5408}\u{5e76}\u{4e3a}\u{5355}\u{6b21}\u{6761}\u{4ef6}\u{805a}\u{5408}\u{67e5}\u{8be2}\u{3002}\n- \u{56fe}\u{7247}\u{89e3}\u{7801}\u{3001}\u{7f29}\u{653e}\u{3001}\u{7f16}\u{7801}\u{903b}\u{8f91}\u{901a}\u{8fc7} `tokio::task::spawn_blocking` \u{79fb}\u{81f3}\u{963b}\u{585e}\u{7ebf}\u{7a0b}\u{6c60}\u{ff1b}Argon2 hash/verify\u{3001}Markdown \u{6e32}\u{67d3}\u{3001}GIF/WebP \u{539f}\u{59cb}\u{6821}\u{9a8c}\u{540c}\u{6837} offload \u{5230}\u{963b}\u{585e}\u{7ebf}\u{7a0b}\u{6c60}\u{3002}\n- \u{4e3a}\u{975e}\u{56fe}\u{7247}\u{8def}\u{7531}\u{542f}\u{7528} `CompressionLayer` \u{4e0e} `TimeoutLayer`\u{ff0c}`/uploads/*` \u{56fe}\u{7247}\u{8def}\u{7531}\u{8df3}\u{8fc7}\u{538b}\u{7f29}\u{4e0e}\u{5168}\u{5c40}\u{8d85}\u{65f6}\u{3002}\n- \u{8fde}\u{63a5}\u{6c60}\u{56de}\u{6536}\u{65b9}\u{6cd5}\u{4ece} `Verified` \u{6539}\u{4e3a} `Fast`\u{ff1b}\u{91cd}\u{8bd5}\u{4ece}\u{56fa}\u{5b9a} 2s \u{6539}\u{4e3a}\u{6307}\u{6570}\u{9000}\u{907f} + \u{6296}\u{52a8}\u{ff1b}\u{65b0}\u{589e} `statement_timeout`\u{ff08}`STATEMENT_TIMEOUT_SECS`\u{ff09}\u{3002}\n- \u{4e3a} `deadpool-postgres` \u{663e}\u{5f0f}\u{6307}\u{5b9a} Tokio1 runtime\u{ff1b}\u{5220}\u{9664}\u{65e0}\u{6548}\u{7684} trgm GIN \u{7d22}\u{5f15}\u{3002}\n- Tiptap \u{7f16}\u{8f91}\u{5668}\u{5347}\u{7ea7}\u{5230} Vite 8 / Vitest 4 / TypeScript 6 / Tiptap 3.27\u{ff08}Rolldown\u{ff09}\u{ff0c}\u{5e76}\u{4ece} `js_sys::eval` \u{8fc1}\u{79fb}\u{5230} wasm-bindgen \u{7ed1}\u{5b9a}\u{5c42}\u{ff08}`tiptap_bridge`\u{ff09}\u{ff0c}EditorOptions/onReady/onUploadEvent \u{56de}\u{8c03}\u{66ff}\u{4ee3}\u{8f6e}\u{8be2}\u{3002}\n- Lightbox \u{4e0e} post-content \u{4ece} `include_str!` \u{5185}\u{8054}\u{6539}\u{4e3a}\u{914d}\u{7f6e}\u{9a71}\u{52a8}\u{521d}\u{59cb}\u{5316}\u{ff1b}\u{79fb}\u{9664}\u{65e7} `ImageViewer` \u{7ec4}\u{4ef6}\u{3002}\n- JS \u{5b50}\u{9879}\u{76ee}\u{4ece} npm \u{8fc1}\u{79fb}\u{5230} pnpm\u{3002}\n- \u{5c01}\u{9762}\u{56fe}\u{6bd4}\u{4f8b}\u{7edf}\u{4e00}\u{4e3a} 21:9\u{ff1b}\u{5361}\u{7247}\u{91cd}\u{6784}\u{4f7f}\u{7528}\u{539f}\u{751f} `blur-img` \u{7ed3}\u{6784}\u{3002}\n- \u{90ae}\u{7bb1}\u{6b63}\u{5219}\u{3001}sanitizer allowlist \u{7528} `LazyLock` \u{9759}\u{6001}\u{5316}\u{4ee5}\u{907f}\u{514d}\u{6bcf}\u{6b21}\u{8c03}\u{7528}\u{5206}\u{914d}\u{3002}\n- Markdown \u{6e32}\u{67d3}\u{8bfb}\u{53d6} DB \u{4e2d}\u{9884}\u{6e32}\u{67d3}\u{7684} `content_html`/`toc_html`\u{ff0c}\u{5199}\u{5165}\u{65f6}\u{5b58}\u{50a8} `toc_html`\u{3002}\n- \u{5927}\u{91cf}\u{300c}\u{4e0a}\u{5e1d}\u{7ec4}\u{4ef6}\u{300d}\u{62c6}\u{5206}\u{4e3a}\u{5b50}\u{7ec4}\u{4ef6}\u{ff1a}`CoverUploader`\u{3001}`FilterTabs`\u{3001}`AutoPurgeSettings`\u{3001}`RebuildCacheBar`\u{ff0c}\u{5171}\u{4eab} `EmptyState` \u{7ec4}\u{4ef6}\u{3002}\n\n### Fixed\n\n- \u{4fee}\u{590d} `/uploads/{*path}` \u{8def}\u{5f84}\u{56e0}\u{7f3a}\u{5c11} `ConnectInfo` \u{6269}\u{5c55}\u{800c}\u{8fd4}\u{56de} HTTP 500 \u{7684}\u{95ee}\u{9898}\u{3002}\n- \u{4fee}\u{590d}\u{5e76}\u{53d1}\u{91cd}\u{590d}\u{8bc4}\u{8bba}\u{63d0}\u{4ea4}\u{ff08}advisory lock\u{ff09}\u{ff1b}\u{91cd}\u{590d}\u{68c0}\u{67e5}\u{6539}\u{4e3a}\u{4e8b}\u{52a1}\u{5185}\u{539f}\u{5b50}\u{64cd}\u{4f5c}\u{5e76}\u{5bf9} `content_hash` \u{5efa}\u{7d22}\u{5f15}\u{3002}\n- \u{4fee}\u{590d}\u{8bc4}\u{8bba}\u{8868}\u{5355}\u{ff1a}\u{670d}\u{52a1}\u{7aef} honeypot\u{3001}a11y label\u{3001}\u{56de}\u{590d}\u{5e03}\u{5c40}\u{ff1b}\u{5f85}\u{5ba1}\u{8bc4}\u{8bba}\u{5d4c}\u{5957}\u{663e}\u{793a}\u{4e8e}\u{7236}\u{8bc4}\u{8bba}\u{4e0b}\u{ff1b}\u{8bc4}\u{8bba}\u{9879}\u{6dfb}\u{52a0} `md-content` \u{7c7b}\u{4fee}\u{590d}\u{9ad8}\u{4eae}\u{4e0e}\u{7a7a}\u{884c}\u{3002}\n- \u{4fee}\u{590d}\u{65f6}\u{5e8f}\u{679a}\u{4e3e}\u{653b}\u{51fb}\u{ff1a}\u{4e0d}\u{5b58}\u{5728}\u{7528}\u{6237}\u{6267}\u{884c} dummy Argon2 verify\u{ff1b}\u{5bf9} `check_pending_status` \u{9650}\u{6d41}\u{9632}\u{6b62}\u{72b6}\u{6001}\u{679a}\u{4e3e}\u{3002}\n- \u{4fee}\u{590d}\u{56fe}\u{7247}\u{78c1}\u{76d8}\u{7f13}\u{5b58}\u{6e05}\u{7406}\u{8df3}\u{8fc7}\u{7b26}\u{53f7}\u{94fe}\u{63a5}\u{ff0c}\u{9632}\u{6b62}\u{904d}\u{5386}\u{5230}\u{7f13}\u{5b58}\u{76ee}\u{5f55}\u{5916}\u{90e8}\u{ff1b}\u{8fc7}\u{671f} session \u{6e05}\u{7406}\u{540c}\u{65f6}\u{5931}\u{6548}\u{4f1a}\u{8bdd}\u{5185}\u{5b58}\u{7f13}\u{5b58}\u{3002}\n- \u{4fee}\u{590d} SSR hydration \u{4e0d}\u{5339}\u{914d}\u{3001}\u{6697}\u{8272}\u{6a21}\u{5f0f} FOUC\u{3001}ThemeToggle \u{72b6}\u{6001}\u{540c}\u{6b65}\u{3002}\n- \u{4fee}\u{590d} Tiptap \u{4e8c}\u{6b21}\u{5bfc}\u{822a}\u{7a7a}\u{767d}\u{3001}\u{94fe}\u{63a5}\u{547d}\u{4ee4}\u{987a}\u{5e8f}\u{4e0e} URL scheme \u{6821}\u{9a8c}\u{3001}blob \u{6cc4}\u{6f0f}\u{ff08}\u{8282}\u{70b9}\u{9500}\u{6bc1}\u{65f6} revoke\u{ff09}\u{3002}\n- \u{4fee}\u{590d} 404 \u{9875}\u{9762}\u{3001}\u{9996}\u{9875}\u{5361}\u{7247}\u{5d4c}\u{5957}\u{951a}\u{70b9}\u{3001}\u{5c01}\u{9762}\u{56fe}\u{9ad8}\u{5ea6}\u{584c}\u{9677}\u{3001}\u{6697}\u{8272}\u{6a21}\u{5f0f}\u{5c01}\u{9762}\u{7070}\u{80cc}\u{666f}\u{3002}\n- \u{4fee}\u{590d} WASM \u{6784}\u{5efa}\u{5047}\u{9633}\u{6027} warning\u{ff08}27 \u{5904} `cfg` gate\u{ff09}\u{3001}Tailwind v4 \u{4e0e} Tiptap \u{6784}\u{5efa}\u{95ee}\u{9898}\u{3002}\n- \u{4fee}\u{590d} dev \u{6a21}\u{5f0f} SSR \u{7f13}\u{5b58}\u{5bfc}\u{81f4}\u{6e32}\u{67d3}\u{9648}\u{65e7} HTML\u{ff1b}`/doc` \u{8def}\u{7531}\u{4e0e}\u{9759}\u{6001}\u{6258}\u{7ba1}\u{51b2}\u{7a81}\u{7684} panic\u{3002}\n- \u{4fee}\u{590d} `b7afd12` \u{8d77}\u{7684} highlight \u{5927}\u{5c0f}\u{5199}\u{5339}\u{914d}\u{5bfc}\u{81f4} Haskell \u{7b49}\u{9ad8}\u{4eae}\u{5931}\u{6548}\u{3002}\n- \u{5176}\u{4ed6}\u{6784}\u{5efa}\u{3001}CI\u{3001}\u{683c}\u{5f0f}\u{5316}\u{4e0e}\u{6d4b}\u{8bd5}\u{4fee}\u{590d}\u{3002}\n\n### Security\n\n- Session token \u{4ee5} SHA-256 \u{54c8}\u{5e0c}\u{5b58}\u{50a8}\u{ff1b}\u{53ef}\u{914d}\u{7f6e}\u{5355}\u{7528}\u{6237} session \u{4e0a}\u{9650}\u{5e76}\u{4ee5}\u{884c}\u{9501}\u{4e32}\u{884c}\u{5316}\u{3002}\n- \u{57fa}\u{4e8e} Origin \u{7684}\u{5199}\u{63a5}\u{53e3} CSRF \u{9632}\u{62a4}\u{ff1b}`COOKIE_SECURE` \u{63a7}\u{5236} Secure \u{6807}\u{5fd7}\u{3002}\n- \u{4e0d}\u{5b58}\u{5728}\u{7528}\u{6237}\u{6267}\u{884c} dummy Argon2 verify \u{9632}\u{65f6}\u{5e8f}\u{679a}\u{4e3e}\u{ff1b}`check_pending_status` \u{9650}\u{6d41}\u{3002}\n- \u{56fe}\u{7247}\u{8def}\u{5f84} `canonicalize` \u{524d}\u{7f00}\u{68c0}\u{67e5}\u{ff08}\u{7eb5}\u{6df1}\u{9632}\u{5fa1}\u{ff09}\u{ff1b}\u{62d2}\u{7edd}\u{4e0d}\u{53ef}\u{89e3}\u{7801}\u{56fe}\u{7247}\u{8fd4}\u{56de} 422\u{ff0c}\u{539f}\u{59cb}\u{6587}\u{4ef6}\u{4e0a}\u{9650} 20MB\u{ff1b}\u{6240}\u{6709}\u{56fe}\u{7247}\u{54cd}\u{5e94}\u{52a0} `X-Content-Type-Options: nosniff`\u{3002}\n- \u{5206}\u{9875}\u{53c2}\u{6570} `per_page` \u{4e0e} `page` \u{4e0a}\u{9650}\u{94b3}\u{5236}\u{ff0c}\u{6d88}\u{9664}\u{516c}\u{5f00}\u{63a5}\u{53e3} DoS \u{4e0e}\u{65e0}\u{754c} OFFSET / \u{7f13}\u{5b58}\u{952e}\u{6247}\u{51fa}\u{3002}\n- \u{78c1}\u{76d8}\u{7f13}\u{5b58}\u{5199}\u{5165}\u{6539}\u{4e3a} temp-file + rename \u{539f}\u{5b50}\u{64cd}\u{4f5c}\u{3002}\n\n### Internal\n\n- \u{65b0}\u{589e} vitest \u{6d4b}\u{8bd5}\u{5957}\u{4ef6}\u{ff1a}`tiptap-editor`\u{ff08}UploadCoordinator\u{3001}UploadImageNodeView\u{3001}isValidUrl\u{ff09}\u{3001}`lightbox`\u{ff08}geometry\u{3001}lightbox \u{751f}\u{547d}\u{5468}\u{671f}\u{ff09}\u{3001}`yggdrasil-core`\u{ff08}post-content\u{3001}theme-transition \u{964d}\u{7ea7}\u{ff09}\u{3002}\n- \u{6269}\u{5145} Rust \u{5355}\u{5143}\u{6d4b}\u{8bd5}\u{8986}\u{76d6}\u{ff1a}AppError\u{3001}sanitizer\u{3001}WebP\u{3001}theme\u{3001}cache\u{3001}db\u{ff08}\u{8fc1}\u{79fb}\u{6ce8}\u{518c}\u{6821}\u{9a8c}\u{ff09}\u{3001}PostListItem \u{7b49}\u{3002}\n- \u{8865}\u{9f50}\u{5927}\u{91cf}\u{4e2d}\u{6587}\u{6587}\u{6863}\u{6ce8}\u{91ca}\u{ff1b}\u{66f4}\u{65b0} AGENTS.md\u{3001}\u{65b0}\u{589e} DEVELOPMENT.md \u{4e0e}\u{751f}\u{4ea7}\u{90e8}\u{7f72}\u{6307}\u{5357}\u{3002}\n- Makefile \u{5b8c}\u{5584} `test`\u{ff08}cargo test + vitest\u{ff09}\u{3001}`clippy`\u{3001}`fix`\u{3001}`doc`\u{ff08}ayu \u{4e3b}\u{9898}\u{ff09}\u{3001}`build-lightbox` \u{7b49}\u{76ee}\u{6807}\u{3002}\n- \u{4ed3}\u{5e93}\u{5b89}\u{5168}\u{5ba1}\u{67e5}\u{ff08}`449a545`\u{ff09}\u{4fee}\u{590d}\u{591a}\u{9879}\u{5173}\u{952e}\u{95ee}\u{9898}\u{3002}\n\n## [0.2.0] - 2026-06-10\n\n### Added\n\n- 404 Not Found \u{9875}\u{9762}\n- \u{57fa}\u{4e8e} moka \u{7684}\u{5185}\u{5b58}\u{7f13}\u{5b58}\u{6a21}\u{5757}\u{ff08}\u{6587}\u{7ae0}\u{3001}\u{6807}\u{7b7e}\u{3001}\u{7edf}\u{8ba1}\u{67e5}\u{8be2}\u{7f13}\u{5b58}\u{ff09}\n- \u{8bfb}\u{5199}\u{64cd}\u{4f5c}\u{7f13}\u{5b58}\u{652f}\u{6301}\u{ff1a}\u{8bfb}\u{64cd}\u{4f5c}\u{547d}\u{4e2d}\u{7f13}\u{5b58}\u{ff0c}\u{5199}\u{64cd}\u{4f5c}\u{81ea}\u{52a8}\u{5931}\u{6548}\u{76f8}\u{5173}\u{7f13}\u{5b58}\n- \u{6587}\u{7ae0}\u{5217}\u{8868}\u{8fd4}\u{56de}\u{51c6}\u{786e}\u{7684}\u{603b}\u{6761}\u{76ee}\u{6570}\u{ff0c}\u{524d}\u{53f0}\u{9996}\u{9875}/\u{5f52}\u{6863}/\u{6807}\u{7b7e}\u{9875}\u{5206}\u{9875}\u{4f7f}\u{7528}\u{51c6}\u{786e}\u{603b}\u{6570}\n- WebP \u{56fe}\u{7247}\u{7f16}\u{7801}\u{652f}\u{6301}\u{ff08}zenwebp\u{ff09}\u{ff0c}\u{4e0a}\u{4f20}\u{56fe}\u{7247}\u{81ea}\u{52a8}\u{8f6c}\u{6362}\u{4e3a} WebP \u{4ee5}\u{8282}\u{7701}\u{5b58}\u{50a8}\u{7a7a}\u{95f4}\n- \u{56fe}\u{7247}\u{53d8}\u{4f53}\u{78c1}\u{76d8}\u{7ea7}\u{7f13}\u{5b58}\n\n### Changed\n\n- `posts.rs` API \u{62c6}\u{5206}\u{4e3a}\u{6a21}\u{5757}\u{76ee}\u{5f55}\u{7ed3}\u{6784}\n- \u{7edf}\u{4e00}\u{9519}\u{8bef}\u{5904}\u{7406}\u{4e3a} `AppError` \u{679a}\u{4e3e}\n- \u{7f13}\u{5b58}\u{5c42}\u{4f18}\u{5316}\u{ff1a}\u{76f4}\u{63a5}\u{8fd4}\u{56de}\u{547d}\u{4e2d}\u{7ed3}\u{679c}\u{ff0c}COUNT(*) \u{7ed3}\u{679c}\u{5355}\u{72ec}\u{7f13}\u{5b58}\n- \u{63d0}\u{53d6} WebP \u{7f16}\u{7801}\u{8f85}\u{52a9}\u{51fd}\u{6570}\u{51cf}\u{5c11}\u{91cd}\u{590d}\u{4ee3}\u{7801}\n- \u{7b80}\u{5316} TraceLayer \u{914d}\u{7f6e}\u{5e76}\u{91cd}\u{65b0}\u{683c}\u{5f0f}\u{5316}\u{8def}\u{7531}\u{5b9a}\u{4e49}\n\n### Fixed\n\n- \u{4fee}\u{590d}\u{591a}\u{5904} `#[cfg(feature = \"server\")]` \u{95e8}\u{63a7}\u{7f3a}\u{5931}\u{5bfc}\u{81f4}\u{7684}\u{7f16}\u{8bd1}\u{95ee}\u{9898}\n- \u{7f13}\u{5b58}\u{6b63}\u{786e}\u{5931}\u{6548}\u{65e7} slug \u{548c}\u{65b0} slug\n- WebP \u{89e3}\u{7801}\u{7f13}\u{51b2}\u{533a}\u{5927}\u{5c0f}\u{9650}\u{5236}\u{ff0c}\u{9632}\u{6b62}\u{6076}\u{610f}\u{5927}\u{5206}\u{914d}\n- \u{4ee3}\u{7801}\u{5757}\u{590d}\u{5236}\u{6309}\u{94ae}\u{70b9}\u{51fb}\u{5904}\u{7406}\n- \u{5176}\u{4ed6}\u{7ec6}\u{8282}\u{4fee}\u{590d}\n\n### Internal\n\n- \u{65b0}\u{589e}\u{7f13}\u{5b58}\u{3001}WebP \u{914d}\u{7f6e}\u{6d4b}\u{8bd5}\u{7528}\u{4f8b}\n- \u{6dfb}\u{52a0} release \u{81ea}\u{52a8}\u{5316}\u{6280}\u{80fd}\n\n## [0.1.0] - 2026-06-09\n\n### Added\n\n- Dioxus 0.7 \u{5168}\u{6808}\u{9879}\u{76ee}\u{811a}\u{624b}\u{67b6}\n- PostgreSQL \u{6570}\u{636e}\u{5e93}\u{5efa}\u{8868}\u{ff08}\u{7528}\u{6237}\u{3001}\u{6587}\u{7ae0}\u{3001}\u{6807}\u{7b7e}\u{3001}\u{4f1a}\u{8bdd}\u{ff09}\n- \u{7528}\u{6237}\u{8ba4}\u{8bc1}\u{7cfb}\u{7edf}\u{ff1a}\u{6ce8}\u{518c}\u{3001}\u{767b}\u{5f55}\u{3001}Session \u{7ba1}\u{7406}\n- \u{9996}\u{4e2a}\u{6ce8}\u{518c}\u{7528}\u{6237}\u{81ea}\u{52a8}\u{6210}\u{4e3a} admin\u{ff0c}\u{540e}\u{7eed}\u{6ce8}\u{518c}\u{5173}\u{95ed}\n- HttpOnly cookie \u{4f1a}\u{8bdd}\u{673a}\u{5236}\n- \u{540e}\u{53f0}\u{7ba1}\u{7406}\u{9875}\u{9762}\u{4e0e}\u{8def}\u{7531}\n- Tiptap \u{5bcc}\u{6587}\u{672c}\u{7f16}\u{8f91}\u{5668}\u{96c6}\u{6210}\u{ff08}Markdown \u{6a21}\u{5f0f}\u{ff09}\n - Slash \u{547d}\u{4ee4}\u{3001}\u{8868}\u{683c}\u{3001}\u{4efb}\u{52a1}\u{5217}\u{8868}\u{3001}\u{56fe}\u{7247}\u{548c}\u{94fe}\u{63a5}\u{6269}\u{5c55}\n - \u{56fe}\u{7247}\u{7c98}\u{8d34}/\u{62d6}\u{62fd}\u{4e0a}\u{4f20}\n- \u{6587}\u{7ae0} CRUD\u{ff1a}\u{521b}\u{5efa}\u{3001}\u{7f16}\u{8f91}\u{ff08}\u{542b}\u{6570}\u{636e}\u{56de}\u{586b}\u{ff09}\u{3001}\u{5217}\u{8868}\u{3001}\u{5220}\u{9664}\n- \u{6587}\u{7ae0}\u{5c01}\u{9762}\u{56fe}\u{652f}\u{6301}\n- Markdown \u{6e32}\u{67d3}\u{ff1a}TOC \u{76ee}\u{5f55}\u{3001}\u{951a}\u{70b9}\u{94fe}\u{63a5}\u{3001}\u{5b57}\u{6570}\u{7edf}\u{8ba1}\u{3001}\u{9884}\u{8ba1}\u{9605}\u{8bfb}\u{65f6}\u{95f4}\n- \u{4ee3}\u{7801}\u{9ad8}\u{4eae}\u{ff08}syntect + catppuccin \u{4e3b}\u{9898}\u{ff09}\u{ff0c}\u{652f}\u{6301} Swift/Kotlin \u{81ea}\u{5b9a}\u{4e49}\u{8bed}\u{6cd5}\n- XSS \u{9632}\u{62a4}\u{ff08}ammonia \u{6e05}\u{6d17} HTML\u{ff09}\n- \u{524d}\u{53f0}\u{535a}\u{5ba2}\u{9875}\u{9762}\u{ff08}PaperMod \u{98ce}\u{683c}\u{ff09}\n - \u{9996}\u{9875}\u{ff08}\u{4e2a}\u{4eba}\u{7b80}\u{4ecb} + \u{6587}\u{7ae0}\u{5217}\u{8868} + \u{5206}\u{9875}\u{ff09}\n - \u{5f52}\u{6863}\u{9875}\u{ff08}\u{6309}\u{5e74}\u{6708}\u{5206}\u{7ec4}\u{ff09}\n - \u{6807}\u{7b7e}\u{9875}\u{ff08}\u{6807}\u{7b7e}\u{4e91} + \u{6807}\u{7b7e}\u{8be6}\u{60c5}\u{ff09}\n - \u{6587}\u{7ae0}\u{8be6}\u{60c5}\u{9875}\u{ff08}\u{76ee}\u{5f55}\u{3001}\u{4e0a}\u{4e0b}\u{7bc7}\u{5bfc}\u{822a}\u{ff09}\n - \u{641c}\u{7d22}\u{9875}\n - \u{5173}\u{4e8e}\u{9875}\n- \u{6697}\u{8272}\u{6a21}\u{5f0f}\u{ff08}\u{7cfb}\u{7edf}\u{504f}\u{597d}\u{68c0}\u{6d4b} + \u{624b}\u{52a8}\u{5207}\u{6362}\u{ff0c}SSR \u{5b89}\u{5168}\u{ff09}\n- SSR \u{9884}\u{6e32}\u{67d3}\u{ff08}\u{9996}\u{9875}\u{3001}\u{6587}\u{7ae0}\u{3001}\u{5f52}\u{6863}\u{3001}\u{6807}\u{7b7e}\u{ff09}+ \u{589e}\u{91cf}\u{7f13}\u{5b58}\n- \u{9aa8}\u{67b6}\u{5c4f}\u{52a0}\u{8f7d}\u{52a8}\u{753b}\u{ff08}\u{5404}\u{9875}\u{9762}\u{72ec}\u{7acb}\u{9aa8}\u{67b6}\u{ff0c}\u{9632}\u{95ea}\u{70c1}\u{ff09}\n- \u{56fe}\u{7247}\u{5904}\u{7406}\u{ff1a}\u{7f29}\u{653e}\u{3001}\u{7f29}\u{7565}\u{56fe}\u{3001}\u{65cb}\u{8f6c}\u{3001}\u{683c}\u{5f0f}\u{8f6c}\u{6362}\u{ff08}moka \u{7f13}\u{5b58}\u{ff09}\n- \u{56fe}\u{7247}\u{706f}\u{7bb1}\u{67e5}\u{770b}\u{5668}\n- pg_trgm \u{5168}\u{6587}\u{641c}\u{7d22}\n- Rate limiting\u{ff08}\u{6ce8}\u{518c}\u{3001}\u{767b}\u{5f55}\u{3001}\u{4e0a}\u{4f20}\u{63a5}\u{53e3}\u{ff09}\n- \u{6570}\u{636e}\u{5e93}\u{8fde}\u{63a5}\u{6c60}\u{91cd}\u{8bd5}\u{903b}\u{8f91}\n- Session \u{8fc7}\u{671f}\u{81ea}\u{52a8}\u{6e05}\u{7406}\u{ff08}\u{6bcf}\u{5c0f}\u{65f6}\u{ff09}\n- \u{6570}\u{636e}\u{5e93}\u{6027}\u{80fd}\u{7d22}\u{5f15}\u{ff08}posts/tags/sessions\u{ff09}\n- \u{6570}\u{636e}\u{5e93}\u{8fc1}\u{79fb}\u{811a}\u{672c}\u{ff08}migrate.sh\u{ff09}\n- 122 \u{4e2a}\u{5355}\u{5143}\u{6d4b}\u{8bd5}\u{8986}\u{76d6} 12 \u{4e2a}\u{6a21}\u{5757}\n- \u{9879}\u{76ee}\u{5f00}\u{53d1}\u{6307}\u{5357}\u{ff08}AGENTS.md\u{ff09}\n\n### Changed\n\n- Tailwind CSS v4 + \u{72ec}\u{7acb} CLI \u{6784}\u{5efa}\n- admin \u{6a21}\u{5757}\u{91cd}\u{6784}\u{4e3a}\u{5171}\u{4eab}\u{7ec4}\u{4ef6} + card \u{5e03}\u{5c40}\n- \u{5168}\u{5c40}\u{4f7f}\u{7528} Dioxus \u{5ba2}\u{6237}\u{7aef}\u{8def}\u{7531}\u{66ff}\u{4ee3}\u{539f}\u{751f}\u{5bfc}\u{822a}\n- \u{63d0}\u{53d6}\u{516c}\u{5171}\u{7ec4}\u{4ef6}\u{ff1a}FormInput/FormLabel/AlertBox\u{3001}SkeletonLine/SkeletonBox/SkeletonCard\n- \u{63d0}\u{53d6}\u{5de5}\u{5177}\u{6a21}\u{5757}\u{ff1a}slug\u{3001}markdown\u{3001}tags\u{3001}text\u{3001}time\u{3001}session\n- API \u{5c42} DRY \u{91cd}\u{6784}\u{ff08}\u{9519}\u{8bef}\u{5904}\u{7406}\u{3001}N+1 \u{67e5}\u{8be2}\u{4fee}\u{590d} via JOIN+array_agg\u{ff09}\n- \u{6587}\u{7ae0} slug ASCII \u{5316} + \u{65f6}\u{95f4}\u{6233}\u{56de}\u{9000}\n- Tiptap \u{7f16}\u{8f91}\u{5668} Vite \u{6784}\u{5efa}\u{8f93}\u{51fa}\u{56fa}\u{5b9a}\u{6587}\u{4ef6}\u{540d}\n- \u{9996}\u{9875} HomeInfo \u{4e2a}\u{4eba}\u{7b80}\u{4ecb}\u{66ff}\u{4ee3}\u{539f}\u{59cb}\u{9996}\u{533a}\n\n### Fixed\n\n- \u{4fee}\u{590d} admin \u{8def}\u{7531}\u{5207}\u{6362}\u{95ea}\u{70c1}\n- \u{4fee}\u{590d}\u{7f16}\u{8f91}\u{5668}\u{6697}\u{8272}\u{4e3b}\u{9898}\u{548c}\u{5217}\u{8868}\u{6837}\u{5f0f}\n- \u{4fee}\u{590d} Footer \u{6eda}\u{52a8}\u{76d1}\u{542c}\u{5668}\u{672a}\u{6e05}\u{7406}\n- \u{4fee}\u{590d} CJK \u{5b57}\u{6570}\u{7edf}\u{8ba1}\n- \u{4fee}\u{590d}\u{4ee3}\u{7801}\u{5757} Tailwind `.block` \u{7c7b}\u{51b2}\u{7a81}\n- \u{4fee}\u{590d} SSR \u{6c34}\u{5408}\u{4e0d}\u{5339}\u{914d}\u{ff08}ThemeToggle\u{ff09}\n- \u{4fee}\u{590d} WASM \u{751f}\u{4ea7}\u{73af}\u{5883} 404\u{ff08}symlink \u{4fee}\u{590d}\u{ff09}\n- \u{4fee}\u{590d}\u{56fe}\u{7247}\u{4e0a}\u{4f20} 500 \u{9519}\u{8bef}\n- \u{4fee}\u{590d} Markdown \u{6e32}\u{67d3}\u{4e2d} data URI \u{4e22}\u{5931}\n- \u{4fee}\u{590d}\u{6697}\u{8272}\u{6a21}\u{5f0f} FOUC \u{548c}\u{72b6}\u{6001}\u{540c}\u{6b65}\n- \u{4fee}\u{590d}\u{767b}\u{5f55}\u{540e} UserContext \u{672a}\u{91cd}\u{7f6e}\n- \u{4fee}\u{590d}\u{6587}\u{7ae0} slug \u{552f}\u{4e00}\u{6027}\u{68c0}\u{67e5}\u{ff08}\u{542b}\u{5df2}\u{5220}\u{9664}\u{6587}\u{7ae0}\u{ff09}\n- \u{4fee}\u{590d} Tiptap \u{7f16}\u{8f91}\u{5668}\u{4e8c}\u{6b21}\u{5bfc}\u{822a}\u{7a7a}\u{767d}\u{95ee}\u{9898}\n- \u{4fee}\u{590d}\u{6a21}\u{677f} hydration \u{4e0d}\u{5339}\u{914d}\u{8b66}\u{544a}\n- \u{4fee}\u{590d} Clippy \u{548c}\u{7f16}\u{8bd1}\u{5668}\u{8b66}\u{544a}\n";Expand description
CHANGELOG.md 原文,编译期内嵌。