恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
civitai 审核查询移植全景清单:主应用到 `@civitai/db-queries` 的收敛(Convergence)与 Net-new 实战指南
首页
资讯中心
/
civitai 审核查询移植全景清单:主应用到 `@civitai/db-queries` 的收敛(Convergence)与 Net-new 实战指南
civitai 审核查询移植全景清单:主应用到 `@civitai/db-queries` 的收敛(Convergence)与 Net-new 实战指南
发布时间:2026/9/18 16:32:01
civitai 审核查询移植全景清单主应用到civitai/db-queries的收敛Convergence与 Net-new 实战指南【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai导读本文以仓库中的 docs/db-queries-moderation-port-checklist.md 为骨架系统梳理 civitai 主应用main app尚未迁入共享包civitai/db-queries的全部审核moderation数据库查询一部分是已移植域在主应用中的孪生实现Convergence收敛项另一部分是审核应用完全没有覆盖、需要全新写入共享包的能力Net-new全新项。读完本文你将掌握主应用与共享查询包之间的边界划分规则、19 个已移植域与剩余待办域的一一对应关系、14 个 Net-new 域的取舍理由与优先级以及 Prisma → Kysely 移植过程中被EXPLAIN测试网捕获的真实坑位含strike.service.ts的FOR UPDATE聚合陷阱等源码级证据。一、背景为什么需要一份审核查询移植清单1.1 共享数据访问层civitai/db-queriescivitai/db-queries是 monorepo 的共享数据访问层以类型化的 Kysely 查询函数形式承载跨应用的数据库读写主应用与各 SvelteKit 分支spoke共用同一套查询。Prisma 并不消失而是降级为schema 来源、迁移工具与类型生成器通过 prisma-kysely 生成civitai/db-schema/kysely的DB类型查询 API 全部由 Kysely 承担。该包的完整设计与迁移计划见 docs/db-queries-kysely-plan.md作者约定与测试规范见 packages/civitai-db-queries/README.md。1.2 现状moderator 应用已先行主应用只消费了一个函数审核应用moderator app自身的查询已经完成移植共 19 个域reports、users、model3d、cosmetics、mod-activity、comics、ingestion、blocklist、image-rating-review、image-review、image-moderation、image-moderation-effects、image-tags、articles、article-rating-review、scanner、tags-on-image、sidebar-counts、rewards约 60 个查询函数每个都配有编译 SQL DB 支撑的EXPLAIN测试以子路径civitai/db-queries/domain导出。而主应用侧目前只有report.service.ts一个消费点——bulkSetReportStatus委托共享包的setReportStatusMany。清单中bulkSetReportStatus一项已打勾[x]其余全部是主应用本地实现等待收敛或新写入。1.3 黄金规则纯查询进包副作用留应用这是整个移植工作的第一原则清单开头原文即强调许多convergence项是签名分叉signature-divergent的主应用函数在包暴露的窄原语之上叠加了多步编排索引/缓存/申诉/通知等副作用——收敛意味着在主应用侧基于包原语重组编排而不是 1:1 互换。纯查询留在包内副作用留在应用与 moderator 移植采用的规则一致。从源码看这条规则的落地bulkSetReportStatussrc/server/services/report.service.ts先以findMany读取目标报告、再用$transaction批量更新状态随后仍在应用侧完成trackModReports审核行为审计与reportAcceptedReward举报奖励发放等副作用——包内的setReportStatusMany只负责那一条原子UPDATE … WHERE id IN (…) RETURNING。二、Part A — 收敛项18 个已移植域的孪生实现收敛项的含义该域在包中已有共享查询主应用里存在同一能力的本地版本目标是用共享实现替换本地实现必要时重组编排。以下按主文档顺序逐域展开标注来源服务文件与包内对应原语。2.1 reportsservices/report.service.ts主应用函数包内对应备注getReports包getReports审核队列读取getReportById/getReportByIds—批量 id 读取updateReportByIdnotes/status包updateReportNotes/setReportStatus状态转移窄原语updateImageReportStatusByReason在image.service.ts—按原因批量更新图片报告createReport尚未入包含 Report 各类型 join ImageRatingRequest / tag-vote / article 分支是净新增工作bulkSetReportStatussetReportStatusMany✅已委托唯一已收敛项2.2 image-reviewservices/image.service.tsgetImageModerationReviewQueue主应用的巨石队列查询内含 needsReview / tagReview / reportReview 三个 CTE。注意翻译注记中的警告其tagReview分支TagsOnImageNew.attributes位掩码 CTE在包内所有 image-review 函数中均无对应实现收敛时必须补移植。getImageModerationCounts按桶 reported 的计数与包内getImageReviewCounts语义不同见下文调和注记。getImagesModRules/bustImageModRulesCache→ 包getModerationRuleDefinitions。getModeratorPOITagsPOI 标签汇总包内无精确孪生接近 Net-new。2.3 image-moderationservices/image.service.ts基于包原语重组主应用函数包原语handleBlockImagessetImageBlockedphash/通知/mod-activity 副作用留应用handleUnblockImagessetImageAccepted申诉/索引/标签副作用留应用moderateImages调度器dispatcher自身不迁移重组调用updateNsfwLevelrecomputeImageNsfwLevelupdateImageNsfwLevel6779setImageNsfwLevelupdateImageAcceptableMinor、toggleImageFlag/updateImagesFlag—reportCsamImagesimage 分支报告分支归 reports 域resolveEntityAppealimage 分支setImageAppealStatus/-Restored/-Rejected、getPendingImageAppealAppellants2.4 image-moderation-effectsservices/image.service.tsphash 的 ClickHouse 写入addBlockedImage/bulkAddBlockedImages/bulkRemoveBlockedImages——大概率留在应用侧ClickHouse 不在包章程范围内。搜索索引/缓存扇出辅助函数queueImageSearchIndexUpdate只是副作用辅助不迁移。2.5 image-tagsservices/tag.service.ts、services/image-review.service.tsgetTagsForReview→ 包getImageTagReviewQueue/getImageTagReviewTags。moderateTags、disableTags标签禁用核心。注意disableTags的 model 分支引用了一个TagsOnModels上不存在的disabled列源实现自身就带TODO.fix是死分支移植时如实照搬并在注释中标注。2.6 tags-on-imageservices/tagsOnImageNew.service.tsinsertTagsOnImageNew/upsertTagsOnImageNew/deleteTagsOnImageNew存储过程写入 →upsert_tag_on_image。applyTagRules/getTagRules。2.7 blocklistservices/blocklist.service.tsupsertBlocklist、getBlocklistDTO/getBlocklistData、removeBlocklistItems。执法读取throwOnBlockedLinkDomain、throwOnBlockedMessagePattern、getBlockedEmailDomains、stripBenignPhrases。边界澄清moderation-utils.ts中的 blocklist 是Redis 支撑而非 DB 表不属于移植目标——清单特意标注防止把 Redis 逻辑误当 PG 查询迁入。2.8 ingestionservices/image.service.ts、jobs/image-ingestion.tsgetImagesPendingIngestion、getIngestionErrorImages、resolveIngestionError、getIngestionResults。ingestImages作业的读写JobQueue 驱动。2.9 scannerservices/scanner-audit.service.tsrecordImageScan→scanner_label_results表 → 包upsertScannerLabelVerdict/insertScannerContentSnapshot。2.10 image-rating-reviewservices/image.service.tsgetImageRatingRequests包getImageRatingRequests的主应用孪生。2.11 articlesservices/article.service.ts、nsfwLevels.service.tsunpublishArticleById、restoreArticleById、getModeratorArticles、rescanArticle。recomputeArticleIngestion/recomputeArticleIngestionInTx这两处源实现特意用原生$executeRaw绕过updatedAt自增——Kysely 移植版天然规避类型化 builder 的set中不含updatedAt。updateArticleNsfwLevels。articleModerationAdapterEntityModeration 管线钩子与 Net-new #5 联动。2.12 article-rating-reviewservices/article.service.ts、services/article-rating-review.helpers.tsgetArticleRatingReviews、getArticleRatingReviewCounts、resolveArticleRatingReview、createArticleRatingReview、getArticleRatingReviewForOwner。辅助函数computeArticleDerivedNsfwLevel、evaluateAutoApproveGate、autoResolveArticleRatingReview、maybeAutoResolveDisputeAfterScan。2.13 model3dservices/model3d.service.ts、nsfwLevels.service.tsunpublishModel3D、deleteModel3D、restoreModel3D、setModel3DNsfwLevel、toggleModel3DFlag。updateModel3DNsfwLevels/updateModel3DNsfwLevelForThumbnailImage后者在翻译注记中有一个 CTE 优化直接以thumbnailImageId过滤替代先读 id 再IN(...)的两趟往返。范围确认待办model3d-review.service.ts用户评价与model3d-report.service.ts用户举报是否属于已移植的 model3d 域需要与包维护者确认。2.14 comicsrouters/comics.router.ts内联实现setTosViolation、setProjectNsfwLevel、setChapterNsfwLevel、getModReviewQueue、moderatorUnpublishChapter。updateComicChapterNsfwLevels/updateComicProjectNsfwLevels/updateComicNsfwLevels(ForImage)。关键前置comic 审核逻辑内联在comics.router.ts里没有comic.service.ts必须先抽取为 service 函数再移植见提取后再移植原则。2.15 cosmeticsservices/cosmetic.service.tsgrantCosmeticsToUsersgrantCosmetics→ 包grantCosmeticsToUsers/insertUserCosmeticGrant。getPaginatedCosmetics已移植只需替换调用方。2.16 mod-activityservices/moderator.service.tstrackModActivity→ 包recordModActivity。调用方分布在 report / image 服务与 entity-moderation 作业中。2.17 rewards部分services/rewards-bonus-event.service.tsgetGlobalRewardsBonus✅ 已移植。扩展项getActiveRewardsBonusEventRewardsBonusEventCRUD见 Net-new #12。2.18 sidebar-counts部分包内已有 report / appeal / tag-review 计数但主应用仪表盘计数不同。需调和getImageModerationCounts、CSAM 的getCsamReportStats、申诉的getAppealCount与包内计数对齐。三、Part B — 14 个 Net-new 域moderator 应用没有对应物这些是共享包完全未覆盖、需全新写入的能力。按主文档编号逐一说明。#1 model / modelVersion 审核services/model.service.ts、model-version.service.tsunpublishModelById、unpublishModelVersionById、deleteModelById、restoreModelById、permaDeleteModelById事务组合器、toggleLockModel、toggleLockComments、setModelsCategorypoi/nsfw/minor/sfwOnly lockedProperties经upsertModel/updateModelByIdgetTrainingModelsForModeratorsupdateModelNsfwLevels/updateModelVersionNsfwLevelsnsfwLevels.service.ts。#2 model-flag 自动扫描队列services/model-flag.service.ts、model-file-scan.service.tsupsertModelFlag、getFlaggedModels、resolveFlaggedModel、unpublishBlockedModel。注意源实现upsertModelFlag的原生 upsert SQL缺少逗号无法执行移植时已修正保证每个扫描列都能回写且ModelFlag.sfwOnly列在schema.prisma和生成的 Kysely 类型中存在但线上表尚无该列未应用的迁移EXPLAIN因此失败移植版已移除该列写入isFlagged决策仍使用该字段待迁移落地后恢复。#3 collection 审核services/collection.service.ts、nsfwLevels.service.tsupdateCollectionItemsStatus、setCollectionItemNsfwLevel、updateCollectionsNsfwLevels。#4 post 审核services/post.service.ts、nsfwLevels.service.tsdeletePostmod 路径事务组合器、updatePostNsfwLevel/updatePostNsfwLevels。#5 entity / 文本审核XGuard / Clavataservices/entity-moderation.service.ts、jobs/entity-moderation.tsupsertEntityModerationPending、recordEntityModerationSuccess、recordEntityModerationFailure、getEntityModerationWithImageNsfwLevel。作业编排runModQueue、runModChat、clearAutomatedReports、autoMuteIfScamAccountReportAutomated、JobQueue。决策点主应用已有ModerationAdapter注册表src/server/services/moderation-adapters.ts目前注册 Article / Challenge / Model / WildcardSetCategory 四个适配器getModerationAdapter(entityType)按实体类型取用需决定包是否将其标准化。适配器接口定义在 src/server/services/entity-moderation.service.ts核心是resolveContent(ids)批量取文本内容与submit({entityId, content})提交审核失败时写 EM 行为 Failed 供重试作业拾取。#6 申诉生命周期超出图片状态services/report.service.tscreateEntityAppeal、getRecentAppealsByUserId、getAppealCount、getAppealDetails、resolveEntityAppeal非 image 分支。#7 用户审核 / 执法services/user.service.ts、jobs/confirm-mutes.tstoggleBan、toggleContestBan、setUserMuted、setUserModerator、updateUserById。softDeleteUserCSAM、deleteUser、removeAllContent约 15 张表的清空。bulkUnpublishModelsForBannedUser、setLeaderboardEligibility。getUsersmod 查找含 banned/muted/deleted 状态、原生前缀搜索——与包内searchUsers需要先核实 Meili 还是 SQL再决定取舍。confirmMutes作业。#8 strike / 惩罚系统services/strike.service.ts——纯 Net-newraw-SQL 重读shouldRateLimitStrike、getActiveStrikePoints、getStrikeSummary、getStrikesForUser、getStrikeHistoryForMod、getStrikesForMod、getUserStandings动态 SQL。写evaluateStrikeEscalationFOR UPDATE事务、createStrike、voidStrike、expireStrikes、processTimedUnmutes。源码证据表明该域为何是 raw-SQL 重灾区evaluateStrikeEscalationsrc/server/services/strike.service.ts在源实现中直接用SELECT SUM(points) … FOR UPDATE而 Postgres 明确拒绝聚合查询带FOR UPDATE错误码 0A000移植版把行锁下推进WITH locked AS MATERIALIZED (SELECT points … FOR UPDATE) SELECT SUM(points) FROM locked子查询——MATERIALIZED是关键内联 CTE 会把两个层级塌缩回一个。该函数还演示了正确的边界划分点数和禁言状态写入是原子单元锁必须与写入在同一事务内而通知、会话失效等 I/O 全部留在事务外。#9 用户限制生成执法routers/user-restriction.router.ts、orchestrator/promptAuditing.tsgetAllmod 队列、resolveuphold/overturn、submitContextPromptAllowlist upsert、backfillTriggers。auditPromptServer拦截提示词 → 自动禁言 UserRestriction、getCachedPromptAllowlist/bustPromptAllowlistCache。#10 CSAM / NCMECservices/csam.service.tscsam.service-new.tscreateCsamReport、createExternalCsamReport、uploadExternalCsamEvidence。getCsamReportsPaged、getCsamReportStats、getCsamsToReport/getCsamsToArchive/getCsamsToRemoveContent。processCsamReport、archiveCsamDataForReport、getUserIpInfoClickHouse PG 混合、getImageResources。先调和再移植两个 CSAM 实现需先合并csam.service-new.ts是超集旧csam.service.ts是其严格子集翻译注记明确 CSAM 以-new.ts为移植源。#11 装扮撤销 / 定向发放services/cosmetic.service.tsassignCosmeticByTargetcollection/userIds支持 dry-run、unassignCosmetic、equipCosmeticToEntity/unequipCosmetic。#12 RewardsBonusEvent CRUDservices/rewards-bonus-event.service.tsgetActiveRewardsBonusEvent、upsertRewardsBonusEvent、deleteRewardsBonusEvent、getRewardsBonusEventById、getRewardsBonusEventsPaged。#13 knights 降级 复核services/image.service.tsgetDownleveledImagesClickHouseknights_new_order_downleveled PG joinaddToNewOrderQueue。#14 扫描结果摄取管线内部services/image-scan-result.service.tsresolveScanOutcome、auditScanResults、markImageScanError、blockImageFromRating、getAssociatedEntities、evaluateImageModRules、isExemptFromAiVerification、processTags。四、排序原则与执行策略Sequencing notes主文档给出的四条推进纪律是执行这份清单时避免返工的关键ClickHouse 一律排除在包外按当前包章程phashblocked_images、降级复核down-leveled review、getUserIpInfo的 CH 读取、prohibited-request 计数等均只移植 PG 部分CH 部分按 moderator 移植先例标注留在应用。这也与 docs/db-queries-kysely-plan.md 的Out of scope — ClickHouse (deliberately not ported)一致civitai/db-queries是 Postgres/Kysely-only。先调和再移植Reconcile-before-port两个 CSAM 实现csam.service.tsvs-new.ts与 Meili-vs-SQL 用户搜索必须在移植前拍板以哪个为准。先提取再移植Extract-before-portcomic 审核内联在comics.router.ts先抽出 service 函数再动查询。最高 Net-new 价值排序strike 系统、用户 ban/mute/delete 执法、CSAM/NCMEC、entity/文本审核——这四类体积大、raw-SQL 密集且今天没有共享等价物值得优先投入。五、移植工程底座Prisma → Kysely 的翻译纪律与验证体系清单落地所依托的翻译纪律与测试体系完整记录见 docs/db-queries-moderation-translation-notes.md 与 packages/civitai-db-queries/README.md是理解清单各条目为什么这么列的底层背景。5.1EXPLAIN测试网捕获的源实现缺陷每个移植查询都配有 DB 支撑的EXPLAIN测试对实时 schema 解析规划、不执行借此发现了多处源实现本身就是坏的问题——这些问题与迁移无关主应用也值得修复位置源问题移植处理strike.service.tsevaluateStrikeEscalationSUM(points) … FOR UPDATE被 Postgres 拒绝行锁下推子查询外层求和锁意图一致user.service.tsgetUsersORDER BY LENGTH(username)夹在两个WHERE AND之间query 设置时 SQL 非法头像读取用了未加引号的i.nsfwLevel折叠成不存在的nsfwlevel且以文本None默认值对 int 列ORDER BY移到WHERE之后加引号nsfwLevel且默认值改0user.service.tsremoveAllContentPrisma{ OR: [...] }实际编译为单个 AND 谓词只清自己忠实照搬并注释标注model-flag.service.tsupsertModelFlag原生 upsert SQL 缺逗号无法执行修正保证列完整回写ModelFlag.sfwOnlyschema 与类型有、线上表无此列移除写入isFlagged仍用注释待迁移恢复tag.service.tsdisableTagsmodel 分支引用不存在的disabled列死分支忠实移植并注释标注排除出 EXPLAIN5.2 语义翻译选择行为等价非字节一致典型如cannotPublish过滤器从 Prisma 的{ not: { path: [cannotPublish], equals: true } }译为meta - cannotPublish IS DISTINCT FROM true::jsonbnull/false 均视为可发布与 Prisma 对 null 键的NOT(x true)略有差异toggleImageFlag把源实现的读后取反写两条语句折叠为一条无竞态的SET flag NOT flagupdateModel3DNsfwLevelForThumbnailImage以thumbnailImageId直接过滤 CTE省一次往返。updatedAt是系统性问题Prisma 客户端自动 bumpKysely 不 bump 且无 DB 触发器——Prisma-builder 类 UPDATE 显式写updatedAtraw-SQL 类 UPDATE 刻意不写源 raw SQL 也不写。5.3 收敛调和注记Convergence reconcile主应用函数与已移植的 moderator 版本语义分叉的 5 处采用不重复、先调和策略getImageReviewCounts包vsgetImageModerationCounts主应用后者计appeal无摄取门禁且追加 reported-image 的 UNION语义不同。getImageReviewQueue包vsgetImageModerationReviewQueue巨石monolith 的tagReview分支无对应物需补移植。getArticlesForModeration包vsgetModeratorArticles主应用后者更丰富id游标分页 更宽嵌套 select未移植。unpublishModel3d包vsunpublishModel3D主应用写入核心相同保留已有实现。getComicReviewQueue包vsgetModReviewQueue主应用谓词相同仅结果形状不同router 返回 Prisma 嵌套对象移植版返回扁平行。5.4 三层测试体系编译 SQL 测试必需、免 DB断言函数编译出的精确 SQL 与参数用离线 harnesssrc/test/harness.ts的compileHarness()基于 KyselyDummyDriver——能捕获IN ()空数组守卫缺失、where丢失、set乱序等回归。执行pnpm --filter civitai/db-queries test。行为 执行计划测试热路径必需、需活库explainHarness()对编译 SQL 做EXPLAIN不 ANALYZE列/join/类型/存储过程签名解析失败会在此暴露环境门控TEST_DATABASE_URL或本地根.env的DATABASE_URL无库时describe.skipIf(!h.hasDb)跳过。Prisma-vs-Kysely 行为等价移植自 Prisma 的热路径双实现跑同一批行、深比较结果防谓词丢失位于消费应用内civitai/src/server/db/__tests__/kysely-prisma-parity.test.ts通过KYSELY_PARITY_DATABASE_URL开启且刻意不回退DATABASE_URL它要写 fixture需要一次性数据库。正确性硬规则还包括in ([])前的空数组守卫Kysely 编译出IN ()是语法错误Prisma 静默 no-opjsonb 写入必须toJson()node-postgres 会把 JS 数组误序列化成 Postgres 数组字面量Postgres 枚举数组列需注册registerEnumArrayTypeParsers动态 oid 无默认解析器否则读出{a,b}字面量。事务组合器如unpublishModelById、permaDeleteModelById、deletePost、unpublishBlockedModel、setModelsCategory、autoResolveArticleRatingReview无法在离线 harness 上EXPLAIN只对其组成语句函数做编译与 EXPLAIN组合器本身保持薄封装。六、相关文档导航docs/db-queries-moderation-port-checklist.md —— 本文主体主应用剩余审核查询的全量清单Convergence Net-new。docs/db-queries-moderation-translation-notes.md —— Prisma→Kysely 翻译偏差逐条记录按风险分组。docs/db-queries-kysely-plan.md —— 包的整体迁移计划执行器注入、事务组合、lag 感知、分阶段推进。packages/civitai-db-queries/README.md —— 包结构与作者约定命名、签名、jsonb/updatedAt/枚举数组处理、三层测试。docs/moderator-app-package-boundary.md —— moderator 应用包边界分析纯查询入包、副作用留应用规则的由来读队列自持、跨图写入按动作选 Redis 缓存失效或代理回主应用。源码参照src/server/services/report.service.ts已收敛的bulkSetReportStatus、src/server/services/strike.service.tsFOR UPDATE聚合陷阱、src/server/services/moderation-adapters.ts实体审核适配器注册表、packages/civitai-db-queries/src/model.db.ts包内查询函数的作者风格范例含空数组守卫与枚举类型说明。这份清单的执行边界清晰包负责类型化、可共享、可EXPLAIN验证的纯查询主应用保留编排、缓存、通知、ClickHouse、计费等一切副作用。按ClickHouse 排除 → 先调和 → 先提取 → 高价值优先四条纪律推进即可逐步把主应用审核查询全部收敛到civitai/db-queries与已移植的 19 个 moderator 域最终合流。【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考