53bfb1b7c0
feat(session): invalidate all sessions on role/status change via generation
...
users 表加 session_generation 列。get_user_by_token 缓存命中后回查 DB
generation,不匹配则逐出缓存并视为未登录,消除降级/封禁用户的权限残留
窗口(H2)。新增 invalidate_user_sessions 用于 bump generation,当前仓库
无运行时角色变更入口,作为未来用户管理功能的基础设施预留。
- 迁移 012:ADD COLUMN IF NOT EXISTS session_generation INT DEFAULT 0
- User/SessionUser 同步加字段,From<User> 如实传递
- 缓存校验走主键查询,亚毫秒级
2026-06-18 13:26:09 +08:00
79cb809010
perf(posts): add optional pagination to get_posts_by_tag, fix total count
...
- get_posts_by_tag 现接受 page/per_page 可选参数;两者均 None 时返回全部
(上限 200,用于无翻页 UI 的标签详情页),均提供时走标准分页。
- 修正 total:不再用 posts.len(),改为真实 COUNT(*),即使被 LIMIT 截断
也返回完整计数。
- 新增 CacheKey::PostsByTagPage 分页缓存键,与不分页键 PostsByTag 共存。
- 前端 tags.rs 传 (None, None) 保持原全部展示行为。
2026-06-18 11:14:56 +08:00
411e565465
docs(cache,search): update module and function comments
2026-06-18 09:55:45 +08:00
518b4e5d64
refactor(auth): store SessionUser instead of full User in session cache
2026-06-18 09:55:00 +08:00
c40a771989
feat(search): cache search results with short TTL
2026-06-17 17:20:54 +08:00
1d216faa2f
feat(auth): add in-memory session cache
2026-06-17 17:20:47 +08:00
7bd02d0ea9
perf(cache): run tag post invalidations concurrently
2026-06-17 16:59:29 +08:00
c528936abb
feat(cache): add invalidate_tag_posts_for helper
2026-06-17 16:37:20 +08:00
170c021b37
feat(cache): add PostListItem DTO and use it in list/tag/search caches
2026-06-17 15:51:19 +08:00
d1c9cea683
refactor(cache): remove unused per-post comment count cache
2026-06-17 11:52:57 +08:00
2caca3a48d
fix(dead_code): 清理假阳性与真死代码
...
CI / build (push) Has been cancelled
CI / check (push) Has been cancelled
- settings.rs: retention 常量与 clamp_retention 仅服务端使用,加 #[cfg(feature = "server")]
- comment.rs: 删除未使用的 Comment 结构体
- cache.rs: 删除未使用的 invalidate_all_comment_caches 及其测试
验证: cargo check (server/wasm), cargo test (311 passed), dx check, cargo clippy
2026-06-16 17:48:47 +08:00
054d7450f7
feat(model): Post 新增 deleted_at 字段并用 try_get 兼容现有查询
2026-06-16 12:29:37 +08:00
2db652137d
docs(models, db, cache): 补充中文注释
2026-06-12 18:56:56 +08:00
041cdf4102
test(cache): mark cache tests serial to fix parallel flakiness
2026-06-12 17:40:15 +08:00
294d60afab
style: format rust code
CI / build (push) Has been cancelled
CI / check (push) Has been cancelled
2026-06-12 17:14:31 +08:00
04737300e6
feat(comments): add complete comment system with guest commenting, moderation, and admin UI
...
Implements a fully self-built comment system for the blog:
Data layer:
- comments table with BIGSERIAL PK, parent_id self-reference (ON DELETE SET NULL),
depth tracking (max 20), status workflow (pending/approved/spam/trash),
content hashing for dedup, GDPR consent tracking, IP/UA storage with auto-purge
- 5 partial indexes optimized for read patterns
- updated_at auto-trigger
API (9 Dioxus server functions):
- Public: get_comments, get_comment_count, create_comment
- Admin: get_pending_comments, get_pending_count, get_all_comments,
approve_comment (with ancestor auto-approval), spam_comment, trash_comment,
batch_update_comment_status
Security:
- Function-level rate limiting (1/sec, burst 5) via FullstackContext IP extraction
- Input validation (name, email, URL scheme, content length, consent)
- Parent chain validation (must be approved, same post)
- Strict comment Markdown renderer (headings→strong, no img/id/data URIs, nofollow links)
- Honeypot anti-spam field
- 5-minute dedup window via SHA-256 content hash
Frontend:
- CommentSection with SuspenseBoundary isolation
- Flat-list rendering with depth-based CSS indentation (responsive)
- Gravatar via cravatar.cn (server-computed, email never exposed)
- Inline reply forms (one-at-a-time via Signal)
- Admin action buttons (approve/spam/delete) visible per-comment
- CommentForm with privacy consent, Markdown hint, loading states
Admin:
- /admin/comments page with status tabs, batch operations, pagination
- Pending count badge on admin dashboard
Infrastructure:
- Shared get_current_admin_user moved from posts/helpers to auth module
- COMMENT_LIMITER rate limiter tier
- Moka caches (60s TTL for comments, 10s for pending count)
- IP/UA purge background task (daily, 90-day retention)
2026-06-11 12:34:26 +08:00
311ddbe204
perf(cache): cache COUNT(*) result separately to avoid redundant queries
...
- Add TotalPublishedPosts cache key for reusing total count across pages
- list_published_posts now checks total cache before running COUNT(*)
- Add note to get_posts_by_tag about total = posts.len() assumption
- Remove unused invalidate_total_published_posts helper
2026-06-10 14:44:53 +08:00
116f3281a4
feat: update post list cache to store total count
2026-06-10 13:59:41 +08:00
b7220c28ef
Fix WebpError trait impls missing #[cfg(feature = "server")]
2026-06-09 18:30:10 +08:00
263771e403
test(cache): fix invalidation test isolation
2026-06-09 17:24:14 +08:00
73b4d28135
test(cache): use unique key in roundtrip test to avoid parallelism conflict
2026-06-09 17:20:03 +08:00
3041535cf7
test(cache): add cache key and roundtrip tests
2026-06-09 17:18:39 +08:00
0b594ff719
refactor(cache): use CacheKey directly, remove unnecessary async
2026-06-09 16:56:41 +08:00
62e2045b35
feat: add cache module with moka-backed post/tag/stats caching
...
- Create src/cache.rs with CacheKey enum, moka cache instances,
getter/setter functions, and invalidation helpers.
- TTLs: post list 60s, tags 300s, single post 600s, stats 60s,
tag posts 120s.
- Register mod cache in src/main.rs.
- All cache internals gated behind #[cfg(feature = "server")]
2026-06-09 16:47:17 +08:00