feat(spam-ring): add detection storage and OSS freeze mutations#4863
Merged
Conversation
新增 spam ring(帳號層垃圾集團)的伺服器骨幹,供 OSS 控制台列群集與一鍵處置。
凍結=對群內每個帳號 banUser 但省略 banDays(永久、不寫 punish_record、無到期、
仍發 user_banned 申訴通知),可由 unbanUser 還原 → 符合 roadmap 軸一 D「可逆+可申訴」。
資料模型(3 migration):
- spam_ring(fingerprint unique、status pending|frozen|dismissed|restored、signals jsonb、
計數、score/severity、frozen_at/by)
- spam_ring_member(banned_by_this_ring 旗標=可逆關鍵:解凍只還原本 ring 造成的封禁、
不動其他原因已封者;pre_freeze_state、skip_reason)
- spam_ring_event(稽核,mirror community_watch_review_event;actor_id nullable 供機器 detected)
GraphQL(admin-gated,新增不刪):
- OSS.spamRings 查詢(status 過濾、score/detectedAt/nAuthors 排序、members 子連線、memberSample)
- freezeSpamRing / unfreezeSpamRing(partial-success {frozen|unbanned, skipped})
/ dismissSpamRing / upsertSpamRingCandidates(給 VPC 偵測 job,fingerprint idempotent、
不覆寫已凍結/已駁回決策)
spamRingService 重用 userService.banUser/unbanUser/findScore。硬性護欄:成員帳齡 >30d
或 authorScore >5 → 跳過不自動封、列入人工複查(member_skipped 事件)。每成員處理即寫入
(crash-safe idempotent,batch 可超 50)。被封帳號 state=banned 已被 L1 SQL 自動收為正樣本→閉環。
驗證:gen(schema.graphql + schema.d.ts 重生)、tsc 0 錯、eslint 0 錯(僅 jsonb 的 any 警告,
與既有風格一致)。jest+PG 測試靠 CI(本機無 PG)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…erService 改注入 - spamRingService.freezeRing/unfreezeRing 改成由 resolver 注入 userService(取代內部 new UserService),DI 讓核心邏輯可用 mock 測試、也是較佳設計 - spamRingService.test.ts:freeze 老帳號豁免/已封略過/eligible 封禁、拒絕 dismissed、 unfreeze 只解本 ring 封禁/不動他因已封/state 變則略過、拒絕非 frozen、dismiss - spamRingMigration.test.ts:3 表欄位/索引/entity_type/rollback - spamRingResolvers.test.ts:fromGlobalId 解碼、viewer guard、upsert 的 JSON.parse 與 null 映射 全部 mock-based,本機 14/14 通過(免 PG);tsc/eslint 綠。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4021fcb to
2887825
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #4863 +/- ##
===========================================
+ Coverage 72.77% 73.12% +0.35%
===========================================
Files 1071 1081 +10
Lines 21307 21644 +337
Branches 4657 4735 +78
===========================================
+ Hits 15506 15828 +322
- Misses 5324 5339 +15
Partials 477 477 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Summary
Why
This is the server-side dependency for the old matters-oss SpamRing console. The server remains the source of truth for candidates and decisions; OSS only reads and invokes admin mutations.
Validation
npx tsc -p .MATTERS_ENV=test node --experimental-vm-modules --no-experimental-fetch node_modules/.bin/jest build/connectors/__test__/spamRingService.test.js build/common/utils/__test__/spamRingMigration.test.js build/common/utils/__test__/spamRingResolvers.test.js --coverage=falseRollout Notes