Skip to content

feat(comment): add campaignDiscussion comment type for campaign discussion board#4841

Merged
mashbean merged 6 commits into
thematters:developfrom
yingshinlee:feat/campaign-discussion
Jun 13, 2026
Merged

feat(comment): add campaignDiscussion comment type for campaign discussion board#4841
mashbean merged 6 commits into
thematters:developfrom
yingshinlee:feat/campaign-discussion

Conversation

@yingshinlee

Copy link
Copy Markdown
Collaborator

這是什麼

在寫作活動頁(WritingChallenge)新增「留言區」討論板的後端支援:新增評論類型 campaignDiscussion,沿用 Comment 體系的 targetId / targetTypeId 綁到 campaign(與 moment 類型先例同手法)。

權限模型:公開可讀;只有報名成功者(campaign_user.state = 'succeeded')與 creator / organizerIds / managerIds 可發言。

前端對應 PR:thematters/matters-web 的同名分支 feat/campaign-discussion
產品脈絡:七日書活動頁要開一個輕量討論區,重用圍爐眾聊的既有架構。

改動

檔案 內容
src/common/enums/index.ts COMMENT_TYPE.campaignDiscussionMAX_CAMPAIGN_COMMENT_LENGTH = 240(比照 moment)
src/types/comment.ts enum CommentTypecampaignDiscussionCommentInput 加 optional campaignId
src/types/campaign.ts WritingChallenge.discussion / discussionCount
src/mutations/comment/putComment.ts campaign 分支(target 解析、參加者權限檢查、240 字上限、無單一 target author 時跳過 block 檢查、invalidateFQC 用 NODE_TYPES.Campaign
src/queries/comment/campaign/discussion.ts(新) 公開讀、無成員檢查,比照 circle/discussion.ts(cursor 分頁、filter)
src/queries/comment/campaign/discussionCount.ts(新) 比照 circle/discussionCount.ts
src/queries/campaign/index.ts 註冊 resolver
src/queries/comment/node.ts campaignDiscussion → 回傳 WritingChallenge(前端回覆/編輯靠 comment.node 取 campaignId)
src/connectors/campaignService.ts isParticipant(campaignId, userId) helper

不需要 migration

entity_type 已有 campaign20240703145306_create_campaign_tables.js),comment 表 targetId/targetTypeId 為通用欄位。

刻意不做(MVP)

  • 通知:campaign 留言不觸發任何 notice(circle mention 分支已 guard)。
  • 即時推送:無 WebSocket,定位是討論區非聊天室。

權限驗收矩陣

角色
未登入 / 未報名 / pending / rejected
succeeded 參加者、creator/organizers/managers

備註

  • enum 追加與 optional 欄位皆向後相容,不影響 article/circle/moment 既有行為。
  • Draft 原因:由社群貢獻者提交,尚未在完整 dev 環境跑過測試,請團隊協助 review 與驗證。

🤖 Generated with Claude Code

yingshinlee and others added 3 commits June 11, 2026 22:14
…ssion board

- new COMMENT_TYPE campaignDiscussion bound to campaign via targetId/targetTypeId
- putComment: accept campaignId; only succeeded participants (campaign_user.state)
  or campaign organizers/managers may comment; cap content at 240 chars
- WritingChallenge.discussion / discussionCount: public read resolvers
- Comment.node resolves campaign comments to WritingChallenge
- campaignService.isParticipant helper

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- run codegen so schema.graphql / schema.d.ts include the new
  campaignDiscussion comment type, campaign discussion field and
  CommentInput.campaignId (CI relies on committed generated types)
- putComment: guard article/moment notification blocks with targetAuthor
  (now string|undefined since campaign discussions have no single author)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.35714% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.46%. Comparing base (85bdbe1) to head (409a9d5).
⚠️ Report is 19 commits behind head on develop.

Files with missing lines Patch % Lines
src/queries/comment/campaign/discussion.ts 48.14% 12 Missing and 2 partials ⚠️
src/mutations/comment/putComment.ts 83.33% 5 Missing and 1 partial ⚠️
...0000_alter_comment_type_add_campaign_discussion.js 80.00% 1 Missing ⚠️
src/mutations/comment/unvoteComment.ts 90.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4841      +/-   ##
===========================================
- Coverage    72.82%   72.46%   -0.36%     
===========================================
  Files         1054     1057       +3     
  Lines        21263    21013     -250     
  Branches      4671     4586      -85     
===========================================
- Hits         15485    15228     -257     
+ Misses        5706     5309     -397     
- Partials        72      476     +404     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

mashbean and others added 3 commits June 13, 2026 10:10
…archived campaign

- commentService.upvote & unvoteComment: add explicit campaignDiscussion
  branch with participant/organizer permission, skip blocked check (no
  single target author) instead of falling through to circle
- deleteComment: invalidate the Campaign node (not Circle) and allow
  campaign creator/organizers/managers to delete discussion comments
- togglePinComment: throw ForbiddenError for campaignDiscussion instead of
  loading it as a circle
- putComment: reject commenting on archived campaigns
- discussionCount: count via commentService.count (active + collapsed) to
  match the public discussion list

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add integration tests for the campaign discussion comment feature
covering putComment (participant/organizer/manager permission matrix,
archived-campaign guard), vote/unvote (including the circle fallthrough
fix), deleteComment author/organizer permissions, togglePinComment
forbidden case, and discussion list/discussionCount consistency.

Also add the missing DB migration that extends the comment_type_check
constraint to allow 'campaign_discussion'. Without it, every attempt to
create a campaignDiscussion comment fails at the database layer with a
check-constraint violation, breaking the feature end-to-end. The feat
branch added the code, GraphQL schema, and resolvers for the new type
but never added this migration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add error-path coverage for putComment campaignDiscussion: missing
campaignId, non-existing campaign, and over-length content; plus
organizer upvote and non-participant unvote-forbidden cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants