2026-04-08-message-board-design
# Message Board Design
# Goal
Add a reusable message board for collecting visitor feedback. It must work on the resume landing page and tools pages, while each page remains in control of whether the board is shown.
The first version should reuse the existing Flask message-board API in pywork/statistics_index.py. It should not introduce a new backend, new database, or third-party comment system.
# Existing Context
The site is a VuePress 1 + vdoing static blog. Tools live under docs/07.工具/, and the resume page uses docs/index.md with pageComponent.name: ResumeLanding.
There is already message-board functionality embedded in docs/.vuepress/components/PinyinDictationTool.vue:
- It posts messages to
https://wangmouren.online:9000/api/message-board/messages. - It lists messages by
pageKey. - It displays author replies.
- It derives the message-board base URL from the existing tracking endpoint.
The backend in pywork/statistics_index.py already provides:
POST /api/message-board/messagesGET /api/message-board/messages?pageKey=...&limit=...POST /api/message-board/reply- SQLite storage in
message_board_entries - Feishu notification on submit and reply
# Recommended Approach
Create a reusable MessageBoard.vue component and make page owners opt in explicitly.
This keeps the implementation small and avoids touching the global vdoing layout. It also lets the custom resume page and normal tool pages use the same behavior without duplicating form, fetch, state, and styles.
# Component API
Create docs/.vuepress/components/MessageBoard.vue.
Props:
enabled: Boolean, defaulttruepageKey: String, required for API callssource: String, defaultmessage-boardtitle: String, default留言板description: String, default欢迎反馈使用体验。endpointBase: String, default derived fromhttps://wangmouren.online:9000limit: Number, default50
Behavior:
- If
enabledis false, render nothing. - If
pageKeyis empty, show a local error instead of calling the API. - On mount, load recent messages for the given
pageKey. - On submit, send
pageKey,nickname,message, andsource. - After a successful submit, clear the form and reload messages.
- Show loading, success, and error states.
- Display nickname, creation time, message body, and optional author reply.
# Page Control
Each page controls display through either component props or frontmatter.
For the resume page, add frontmatter to docs/index.md:
messageBoard:
enabled: true
pageKey: resume-home
source: resume-landing
title: 给我留言
description: 如果你对我的经历、项目或合作方向有问题,可以在这里留言。
2
3
4
5
6
ResumeLanding.vue reads this.$page.frontmatter.messageBoard and passes those values into MessageBoard.vue. If the frontmatter object is missing or enabled is not true, the resume page does not show the board.
For tool components, use explicit props where the board is needed:
<MessageBoard
page-key="pinyin-helper"
source="pinyin-helper-tool"
title="留言板"
description="欢迎反馈使用体验,我会在飞书收到留言并可通过接口回复。"
/>
2
3
4
5
6
This avoids adding the board globally to every tool by accident.
# Pinyin Tool Migration
Refactor PinyinDictationTool.vue to remove its embedded message-board form, state, API helpers, and styles. Replace that section with the reusable MessageBoard component using the same pageKey and source.
The migration should preserve current behavior for the pinyin page:
- Existing pinyin-helper messages remain visible because the
pageKeystayspinyin-helper. - Submissions still trigger the existing backend and Feishu notification.
- Author replies still render under the original message.
# Resume Placement
Place the resume message board after the contact section, still inside the resume landing page. This keeps it near the direct contact options without interrupting the hero, case studies, or technical summary.
Use resume-local spacing styles only for the outer section. Keep form and message-list styles inside MessageBoard.vue so tools and resume pages share the same interaction behavior.
# Backend
Do not change backend routes in V1.
The current backend already validates pageKey and message, truncates long values, stores IP and user agent, returns serialized messages, and supports replies protected by MESSAGE_BOARD_REPLY_TOKEN when configured.
One known limitation remains: public submissions do not have captcha or rate limiting. That is acceptable for this iteration because the goal is to reuse the existing lightweight feedback flow. If spam appears later, add backend throttling or a honeypot field as a separate change.
# Error Handling
Frontend handling:
- Empty message: show
请输入留言内容. - Missing
pageKey: show留言板配置缺少 pageKey. - Failed list call: show
留言加载失败. - Failed submit call: show the backend
infomessage when available, otherwise提交失败.
Network failures should not block the rest of the page. The message board should fail locally and leave the resume or tool content usable.
# Testing
Add or update focused wiring tests to verify:
MessageBoard.vueexists and calls/api/message-board/messages.PinyinDictationTool.vueimports and rendersMessageBoard.PinyinDictationTool.vueno longer contains duplicate message-board API methods.ResumeLanding.vueimports and rendersMessageBoard.docs/index.mdincludesmessageBoard.enabled: trueandpageKey: resume-home.
Manual verification:
- Start the VuePress dev server.
- Open
/tools/pinyin-helper/, verify existing messages load and submit works. - Open
/, verify the resume board appears when enabled. - Set
messageBoard.enabled: falseindocs/index.md, verify the resume board disappears. - Confirm the rest of the resume and tool pages still render if the message-board API is unavailable.
- 01
- 2026-04-07-paper-game-generator04-07
- 03
- 2026-04-07-english-word-daily04-07