feat(content): add guestbook and configurable post cards - #119
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📜 Recent review details⏰ Context from checks skipped due to timeout. (1)
📝 WalkthroughSummary by CodeRabbit
Walkthrough新增留言板的公开提交、审核管理、分页与速率限制能力,并为文章增加可持久化的卡片尺寸、封面布局模式、编辑器预览和响应式展示。 Changes留言板与文章卡片布局
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant Visitor
participant GuestbookPage
participant GuestbookAPI
participant Database
Visitor->>GuestbookPage: Open guestbook
GuestbookPage->>GuestbookAPI: Fetch approved messages
GuestbookAPI->>Database: Query paginated messages
Database-->>GuestbookAPI: Messages and cursor
GuestbookAPI-->>GuestbookPage: Render messages
Visitor->>GuestbookPage: Submit message
GuestbookPage->>GuestbookAPI: POST message
GuestbookAPI->>Database: Store pending message
Database-->>GuestbookAPI: Created message
GuestbookAPI-->>GuestbookPage: Submission result
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
client/src/pages/home.tsx (1)
410-416: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win加载骨架屏未同步更新为响应式网格。
正式渲染已改为
grid-cols-1 sm:grid-cols-6 xl:grid-cols-12,但骨架屏(loading分支)仍是纵向flex-col排列的 3 个占位块,加载完成后布局会发生明显跳变。建议骨架屏也采用同样的网格结构,减少内容加载时的布局抖动。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/pages/home.tsx` around lines 410 - 416, Update the loading branch in the home page’s skeleton rendering to use the same responsive grid structure as the loaded content: grid-cols-1 sm:grid-cols-6 xl:grid-cols-12. Adjust the three placeholder blocks to occupy the corresponding grid spans so the loading and completed layouts align without a noticeable shift.client/src/lib/card-layout.ts (1)
22-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win建议为核心布局阈值函数补充单元测试。
getCardGridSize与getArticleCardImageMode的阈值组合被编辑器预览与文章卡片渲染两处依赖,任何阈值调整都会同时影响两个渲染路径。建议补充边界值单测(如 width=68/82、height=190/250/260 的临界点),防止后续修改导致两处渲染不一致。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/lib/card-layout.ts` around lines 22 - 41, 为 getCardGridSize 和 getArticleCardImageMode 补充单元测试,覆盖各阈值的临界值及临界值前后行为,包括 width=58/84、width=68/82,以及 height=190/250/260 的组合;同时验证 hasCover=false 始终返回 text,确保编辑器预览与文章卡片依赖的布局规则保持一致。server/src/index.ts (1)
984-1008: 🧹 Nitpick | 🔵 Trivial内存限流仅对单个 Worker 实例有效,跨边缘节点不具备全局限流保证。
guestbookAttempts是进程内Map,Cloudflare Workers 会在多个隔离实例/边缘节点运行,攻击者分散请求即可绕过该限流。如需更强保证,建议评估 Cloudflare 内置 Rate Limiting 规则或基于 KV/Durable Objects 的跨实例计数方案。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/index.ts` around lines 984 - 1008, Replace the process-local guestbookAttempts Map enforcement used by pruneGuestbookAttempts and isGuestbookRateLimited with a cross-instance rate-limiting mechanism, such as Cloudflare Rate Limiting, KV, or a Durable Object. Ensure requests are counted consistently across Worker instances and edge nodes, and update the surrounding request flow to handle the selected mechanism’s asynchronous API.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/src/components/article-card.tsx`:
- Around line 24-28: Update the gridClass responsive classes in the article-card
grid-size mapping so the "third" density becomes a three-column layout at an
intermediate md or lg breakpoint instead of matching "half" from sm through xl.
Keep the full and half behaviors intact while ensuring the third option aligns
with CARD_GRID_SIZE_LABEL.third and the editor preview across mobile, tablet,
and desktop widths.
In `@client/src/pages/admin/editor.tsx`:
- Around line 856-860: 预览信息条中重复渲染了 cardDensity。更新该信息条内第三个 span,改为显示
cardImageModeLabel,并保留第一个 cardDensity 和中间 form.cardHeight 的展示不变。
In `@client/src/pages/admin/guestbook.tsx`:
- Around line 212-235: Update the action-button container in the message row
around the approve and delete buttons to include a desktop focus-within
visibility state alongside the existing hover state, so keyboard focus reveals
the controls and their focus remains visibly identifiable without changing the
button behavior.
In `@client/src/pages/home.tsx`:
- Around line 417-423: Remove the "contents" class from the AnimateIn wrapper in
the posts.map rendering within the home page so its ref and IntersectionObserver
can track a real layout box. Preserve the grid layout by applying the necessary
card/grid classes to an element that participates in layout, or use a real
wrapper element for the animation.
In `@server/src/storage/db/d1.ts`:
- Around line 17-18: 提取 normalizeCardWidth 和 normalizeCardHeight
到共享模块,保留现有裁剪范围与默认值;在
server/src/storage/db/d1.ts(17-18)、server/src/storage/db/turso.ts(19-20)及
server/src/storage/db/postgres.ts(19-20)移除重复定义并改为导入共享函数。
---
Nitpick comments:
In `@client/src/lib/card-layout.ts`:
- Around line 22-41: 为 getCardGridSize 和 getArticleCardImageMode
补充单元测试,覆盖各阈值的临界值及临界值前后行为,包括 width=58/84、width=68/82,以及 height=190/250/260
的组合;同时验证 hasCover=false 始终返回 text,确保编辑器预览与文章卡片依赖的布局规则保持一致。
In `@client/src/pages/home.tsx`:
- Around line 410-416: Update the loading branch in the home page’s skeleton
rendering to use the same responsive grid structure as the loaded content:
grid-cols-1 sm:grid-cols-6 xl:grid-cols-12. Adjust the three placeholder blocks
to occupy the corresponding grid spans so the loading and completed layouts
align without a noticeable shift.
In `@server/src/index.ts`:
- Around line 984-1008: Replace the process-local guestbookAttempts Map
enforcement used by pruneGuestbookAttempts and isGuestbookRateLimited with a
cross-instance rate-limiting mechanism, such as Cloudflare Rate Limiting, KV, or
a Durable Object. Ensure requests are counted consistently across Worker
instances and edge nodes, and update the surrounding request flow to handle the
selected mechanism’s asynchronous API.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: db50f6a1-75ab-42e5-a396-3f868c27bfc2
📒 Files selected for processing (20)
client/src/app.tsxclient/src/components/admin-layout.tsxclient/src/components/article-card.tsxclient/src/components/navbar.tsxclient/src/lib/api.tsclient/src/lib/card-layout.tsclient/src/pages/admin/editor.tsxclient/src/pages/admin/guestbook.tsxclient/src/pages/guestbook.tsxclient/src/pages/home.tsxscripts/reconcile-d1-schema.mjsserver/src/db/schema-pg.tsserver/src/db/schema.tsserver/src/index.tsserver/src/migrations/0011_guestbook_messages.sqlserver/src/migrations/0012_post_card_layout.sqlserver/src/storage/db/d1.tsserver/src/storage/db/postgres.tsserver/src/storage/db/turso.tsserver/src/storage/interfaces.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
client/src/components/**
⚙️ CodeRabbit configuration file
client/src/components/**: 这是 React 前端组件目录。审查时请关注: 1. 是否同时兼容暗色和亮色主题(检查 CSS 变量和 data-theme) 2. 响应式布局是否完整(移动端/平板/桌面端) 3. 无障碍访问(aria 标签、键盘导航) 4. 组件是否保持单一职责
Files:
client/src/components/admin-layout.tsxclient/src/components/navbar.tsxclient/src/components/article-card.tsx
client/src/pages/**
⚙️ CodeRabbit configuration file
client/src/pages/**: 页面级组件。审查时请关注: 1. 数据加载和错误处理是否完善 2. SEO 相关(页面标题、meta 标签) 3. 导航和路由是否正确
Files:
client/src/pages/home.tsxclient/src/pages/guestbook.tsxclient/src/pages/admin/guestbook.tsxclient/src/pages/admin/editor.tsx
server/src/index.ts
⚙️ CodeRabbit configuration file
server/src/index.ts: Hono Workers API 路由总入口。审查时请关注: 1. JWT 认证中间件是否正确保护管理接口 2. CORS 配置是否安全 3. 请求参数验证
Files:
server/src/index.ts
server/src/storage/**
⚙️ CodeRabbit configuration file
server/src/storage/**: 存储适配器层(数据库 + 对象存储)。审查时请关注: 1. 接口实现是否完整(IDatabase / IObjectStorage) 2. SQL 注入防护(参数化查询) 3. 多后端(D1/Turso/PostgreSQL)行为一致性 4. 错误处理和边界情况
Files:
server/src/storage/interfaces.tsserver/src/storage/db/d1.tsserver/src/storage/db/postgres.tsserver/src/storage/db/turso.ts
🔇 Additional comments (23)
client/src/lib/card-layout.ts (1)
1-42: LGTM!client/src/pages/admin/editor.tsx (3)
4-6: LGTM!Also applies to: 105-111, 126-127, 153-158, 181-182, 251-252, 383-383
687-864: LGTM! 展示块面板的数值输入与滑块均正确关联了label/aria-label,无障碍支持到位。
882-887: LGTM!client/src/components/article-card.tsx (2)
13-33: LGTM! 派生状态(宽高、封面裁剪、compact 判定)逻辑清晰,正确复用了card-layout.ts的工具函数。
34-112: LGTM! 四种封面布局分支在移动端均正确隐藏/裁剪图片区域(hidden md:block/hidden sm:block),暗/亮主题 token 使用一致,loading="lazy" decoding="async"也覆盖到位。server/src/storage/interfaces.ts (1)
17-18: LGTM!Also applies to: 38-39, 79-80, 98-99, 160-174, 283-289
server/src/db/schema-pg.ts (1)
18-19: LGTM!Also applies to: 92-107
server/src/db/schema.ts (1)
13-14: LGTM!Also applies to: 91-108
server/src/migrations/0012_post_card_layout.sql (1)
1-2: LGTM!scripts/reconcile-d1-schema.mjs (1)
106-107: LGTM!server/src/index.ts (3)
215-229: LGTM!
publicGuestbookMessage正确剔除了authorEmail,避免公开接口泄露访客邮箱;游标分页与限流+校验的执行顺序合理。Also applies to: 612-664
937-940: 🎯 Functional Correctness无需修改:
guestbookAttempts仅声明一次。
1194-1229: 🔒 Security & Privacy无需修改。
/api/admin/*的 JWT 鉴权中间件已覆盖留言管理的列表、审核和删除接口,满足管理路由鉴权要求。server/src/migrations/0011_guestbook_messages.sql (1)
1-11: LGTM!client/src/lib/api.ts (2)
44-59: LGTM!Also applies to: 241-262
559-628: LGTM!Also applies to: 706-721
client/src/pages/guestbook.tsx (2)
1-62: LGTM!Also applies to: 69-105, 111-251
64-67: 🎯 Functional Correctness不必删除这里的页面标题设置。
SeoHead只使用默认站点名 "Monolith",并不从/api/settings/public获取site_title,因此这里硬编码的document.title = "留言板 | Monolith"不会与动态站点名冲突。> Likely an incorrect or invalid review comment.client/src/pages/admin/guestbook.tsx (1)
1-211: LGTM!Also applies to: 236-253
client/src/app.tsx (1)
18-18: LGTM!Also applies to: 27-27, 174-174, 225-225
client/src/components/admin-layout.tsx (1)
34-34: LGTM!client/src/components/navbar.tsx (1)
16-16: LGTM!
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
server/src/storage/db/postgres.ts (2)
77-82: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win不要静默吞掉卡片字段迁移失败。
这里即使
card_width或card_height添加失败,ensureCoreTables()仍会成功返回;随后getPublishedPosts()等查询会直接选择这些列,最终在运行时失败。应传播错误并阻止适配器就绪,或至少执行明确的 schema 校验并记录失败原因。As per path instructions: “错误处理和边界情况”。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/storage/db/postgres.ts` around lines 77 - 82, Update ensureCoreTables() so the card_width and card_height ALTER TABLE migrations no longer silently swallow errors: remove the empty catch handlers and propagate migration failures, preventing the adapter from becoming ready when either schema change fails.Source: Path instructions
1043-1064: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win公开留言不要复用包含邮箱的完整映射。
getApprovedGuestbookMessages()调用toGuestbookMessage(),而该映射会返回authorEmail。如果公开 API 直接序列化结果,留言者邮箱将暴露给所有访客。请为公开查询使用不包含邮箱的PublicGuestbookMessage映射,管理端再使用完整结构。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/src/storage/db/postgres.ts` around lines 1043 - 1064, Update getApprovedGuestbookMessages to map rows through a PublicGuestbookMessage representation that excludes authorEmail, while retaining toGuestbookMessage for administrative or internal consumers requiring the complete GuestbookMessage structure.client/src/components/article-card.tsx (1)
85-92: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win避免封面图片重复朗读文章标题。
这些图片位于同一个包含可见标题的链接内,
alt={post.title}可能让屏幕阅读器重复朗读标题。若封面仅用于装饰,应改为alt="";若封面具有独立语义,则提供不重复的图片描述。As per path instructions: “无障碍访问(aria 标签、键盘导航)”。
Also applies to: 100-101
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@client/src/components/article-card.tsx` around lines 85 - 92, Update the cover images in the article card, including both the shown image and the corresponding images around the alternate locations, to avoid repeating the visible article title for screen readers. Since they are decorative within the containing link, use an empty alt attribute while preserving the existing image rendering and behavior.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@client/src/pages/home.tsx`:
- Around line 418-425: Update the empty-state container in the posts grid around
the posts.length conditional to include the col-span-full class, while leaving
the article card mapping and responsive grid behavior unchanged.
In `@server/src/storage/db/card-layout.ts`:
- Around line 8-13: Update normalizeCardWidth and normalizeCardHeight to use the
default value whenever the input is not finite, including NaN and infinities,
before rounding and clamping. Preserve the existing min/max bounds and defaults,
matching the client normalization behavior.
---
Outside diff comments:
In `@client/src/components/article-card.tsx`:
- Around line 85-92: Update the cover images in the article card, including both
the shown image and the corresponding images around the alternate locations, to
avoid repeating the visible article title for screen readers. Since they are
decorative within the containing link, use an empty alt attribute while
preserving the existing image rendering and behavior.
In `@server/src/storage/db/postgres.ts`:
- Around line 77-82: Update ensureCoreTables() so the card_width and card_height
ALTER TABLE migrations no longer silently swallow errors: remove the empty catch
handlers and propagate migration failures, preventing the adapter from becoming
ready when either schema change fails.
- Around line 1043-1064: Update getApprovedGuestbookMessages to map rows through
a PublicGuestbookMessage representation that excludes authorEmail, while
retaining toGuestbookMessage for administrative or internal consumers requiring
the complete GuestbookMessage structure.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: cb1b09b4-d978-4c2c-a480-cbc49581d955
📒 Files selected for processing (9)
client/src/components/article-card.tsxclient/src/lib/card-layout.tsclient/src/pages/admin/editor.tsxclient/src/pages/admin/guestbook.tsxclient/src/pages/home.tsxserver/src/storage/db/card-layout.tsserver/src/storage/db/d1.tsserver/src/storage/db/postgres.tsserver/src/storage/db/turso.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- client/src/pages/admin/guestbook.tsx
- client/src/lib/card-layout.ts
- client/src/pages/admin/editor.tsx
- server/src/storage/db/turso.ts
- server/src/storage/db/d1.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
server/src/storage/**
⚙️ CodeRabbit configuration file
server/src/storage/**: 存储适配器层(数据库 + 对象存储)。审查时请关注: 1. 接口实现是否完整(IDatabase / IObjectStorage) 2. SQL 注入防护(参数化查询) 3. 多后端(D1/Turso/PostgreSQL)行为一致性 4. 错误处理和边界情况
Files:
server/src/storage/db/card-layout.tsserver/src/storage/db/postgres.ts
client/src/pages/**
⚙️ CodeRabbit configuration file
client/src/pages/**: 页面级组件。审查时请关注: 1. 数据加载和错误处理是否完善 2. SEO 相关(页面标题、meta 标签) 3. 导航和路由是否正确
Files:
client/src/pages/home.tsx
client/src/components/**
⚙️ CodeRabbit configuration file
client/src/components/**: 这是 React 前端组件目录。审查时请关注: 1. 是否同时兼容暗色和亮色主题(检查 CSS 变量和 data-theme) 2. 响应式布局是否完整(移动端/平板/桌面端) 3. 无障碍访问(aria 标签、键盘导航) 4. 组件是否保持单一职责
Files:
client/src/components/article-card.tsx
🔇 Additional comments (4)
server/src/storage/db/postgres.ts (2)
1054-1063: 🚀 Performance & Scalability确认分页参数在进入适配器前已限制范围。
limit直接传给.limit(limit),此处没有正数校验或最大值限制;如果上游 API 将查询参数原样传入,可能造成超大结果集、内存压力或数据库参数错误。请确认server/src/index.ts已限制limit,并验证beforeId只接受正整数。As per path instructions: “错误处理和边界情况”。
Also applies to: 1080-1086
Source: Path instructions
16-16: LGTM!Also applies to: 36-54, 84-137, 249-289, 357-403
client/src/components/article-card.tsx (1)
4-23: LGTM!Also applies to: 25-79, 81-84, 93-99, 102-107
client/src/pages/home.tsx (1)
11-11: LGTM!
摘要
关联 Issue
Closes #87
验证
npm run checknpm run lintnpm run buildnpm run db:migrate:localnpm run db:reconcile:d1:local/api/health、/api/guestbook、留言提交 smoke test