fix(message): stop repeating private member fields in reaction badges - #63
Merged
Conversation
The port was generic in name only. Its methods returned DiscordGuildMembership, DiscordMessage and DiscordReactionUser, and every identifier was validated against the Discord snowflake format, so the identifier regex reached callers that have no reason to know what a snowflake is. Replacing the provider would have meant editing the interface and both api_v0 services rather than swapping an adapter. The port now speaks CommunityRole, CommunityMembership, CommunityMessage, CommunityReactionUser and CommunityAccountProfile, treats identifiers as opaque strings, and drops the Discord message length limit. Discord's snowflake format, its 2000-character limit, and the global_name field it returns are refinements applied in discord/schema.ts, which is the only layer that issues those values. The provider-specific field name is mapped to displayName at the adapter boundary, matching the provider_display_name column it is stored in. Behaviour is unchanged: the adapter still rejects a malformed provider response and a guild member response for another user, both of which depend on the snowflake assertion that moved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
yufoxda
force-pushed
the
refactor/community-neutral-types
branch
from
July 27, 2026 07:45
636e09e to
c18ece5
Compare
The reaction summary returned the complete member record — student ID, student email, emergency contact, insurance and allergy details — inside every reaction's user list as well as in `members`. A member who reacted with three emoji had those fields serialised four times, so the private data on the wire grew with the number of reactions rather than the number of members. The badges only ever rendered names: the client maps that list through getDisplayName and reads nothing else from it. They now carry a ReactionParticipant with the identity and name fields, while `members` keeps the full record the admin table and its CSV export need, including the emergency contact and allergy details an organiser relies on. Adds a regression test asserting no private field appears in the badge payload. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
yufoxda
force-pushed
the
refactor/reaction-payload-pii
branch
from
July 27, 2026 07:46
4299e4d to
f2650c9
Compare
yufoxda
changed the base branch from
refactor/community-neutral-types
to
develop
July 27, 2026 12:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
経緯 — 当初のレビュー指摘を訂正します
レビューで「リアクション取得が6テーブルを手書きjoinして21列引いている。許可リストビューを入れるべき」と指摘しましたが、コードを詳しく読んだ結果その案は誤りでした。
CSV出力(
buildReactionMembersCsv)を見ると、学籍番号・緊急連絡先・アレルギー詳細は意図的にエクスポートされている運用機能です。イベント主催者が参加者の緊急連絡先やアレルギーを把握するのは正当な要件で、許可リストでこれらを落とせば実在する機能を壊します。実際の問題
代わりに、より確かな問題が見つかりました。
membersreactions[].usersbuildEventDetailViewModelは badges をreaction.users.map(getDisplayName)としか使っていません。つまり緊急連絡先・学籍番号・アレルギー情報が、表示名を出すためだけに、リアクション数ぶん重複してネットワークに流れていました。1人が3種類の絵文字で反応すると、その人の私的情報が 4回(badges 3回 + members 1回)直列化されます。送信量が「部員数」ではなく「リアクション数」に比例して増える構造です。
変更内容
ReactionParticipant型を追加(discordUserId/discordUsername/discordGlobalName/memberName/displayName)reactions[].usersをこの型に変更。OpenAPI スキーマも分離membersは従来どおり完全なまま(CSV出力の要件を維持)検証
tsc --noEmitクリーン回帰テストを追加しました:
private member fields are never repeated inside the reaction badges— badges を直列化し、緊急連絡先・学籍番号・学生メール・アカウントメールが含まれないことを検証します。あわせて
members側に緊急連絡先と学籍番号が残っていることも検証し、CSV機能を壊していないことを担保しています。残る改善余地(別PR)
このエンドポイントは管理者限定(403)ですが、名簿ビューのようなDB層の多層防御(
security_barrier+ 閲覧者の資格チェック)はありません。ハンドラの管理者チェックが唯一の防壁です。DBビュー化は移行を伴うため、別途検討が妥当です。🤖 Generated with Claude Code