收尾工程清单全解析:门禁语义、产品规则与 Creator Studio 界面打磨)
Civitai 付费访问Paid Access收尾工程清单全解析门禁语义、产品规则与 Creator Studio 界面打磨【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai导读本文以 docs/creator-studio/monetization/paid-access-followups.md 这份跟进清单为主体系统梳理 Civitai 付费访问Permanent Paid Access Timed Early Access功能在评审会议之后落地的全部收尾动作从 Creator Studio 抽屉/批量输入/模型列表的界面打磨到不可删除已付费版本EA 天数上限读取模型所有者分数等产品规则的确认再到两个已修复的工程缺陷scheduled EA 永不 materializeendsAt、mini/[id].ts免费试用额度 SQL 谓词错误的源码级验证。读完本文你将完整理解 Civitai 付费门禁的单表数据模型与endsAt语义并掌握如何沿着源码定位每一个清单项的真实状态。本文对应的代码实现参考 paid-access-current-state.md数据表结构与termsJSON 语义见 paid-access-schema.md四条货币化规则的权威定义见 monetization-rules.md。一、背景单表门禁模型与endsAt单一信号在展开清单之前需要先建立付费门禁的底层心智模型否则清单中隐藏 0 费用不可删除已购买版本scheduled EA 变永久门禁等条目都无法被正确理解。1.1PaidAccess表行存在即被门禁付费门禁统一存放在PaidAccess表schema.full.prisma以(entityType, entityId)为复合主键其中entityType目前支持ModelVersion与ComicChapter行存在 ⇒ 被门禁无行 ⇒ 免费。门禁只读一列endsAtendsAt IS NULL表示永久Permanent Paid Access值为未来时间表示计时门禁Timed Early Access正在生效值为过去时间表示已过期tombstone。ownerId在写入时冗余落库使按 owner 的查询无需多态 join。terms是 JSON描述可购买的东西标准价格与何时结束endsAt完全解耦。之所以不再引入kind枚举区分永久/计时是因为endsAt IS NULL本身就是完美的永久判别式——任何第二个事实副本当年earlyAccessPermanent列与earlyAccessConfig.permanentjsonb 两源并存都会漂移这正是本次重构要消灭的故障模式。1.2terms语义bundle 与免费试用terms的类型定义paid-access-schema.md如下export type ModelVersionTerms { download?: Grant; // 全量访问 tier购买它同时授予 generation generation?: GenerationGrant; // 可选更便宜的 generation-only tier freeGeneration?: boolean; // 罕见download 被门禁但 generation 免费 }; export type Grant { price: number }; // 标准价格单位 Buzz export type GenerationGrant Grant { trialLimit?: number }; // 免费预览次数上限关键语义Bundle 语义购买download同时授予 download generation权限位掩码3仅购买generation只授予 generation权限位1。download.price ≥ generation.price是校验不变量download 是超集 tier这正是升级按差价补费可良好定义的前提。缺失generation不意味着免费——generation 仍被 download bundle 门禁与旧行为完全一致。generation.trialLimit是真实功能模式购买 generation tier 前可免费预览 N 次。价格下限download.price ≥ 100、generation.price ≥ 50、trialLimit ≤ 1000由 zod 在写入边界校验。示例行// 全量 8000cheaper generation-only 5000含 10 次预览 { download: { price: 8000 }, generation: { price: 5000, trialLimit: 10 } } // 仅 download历史上 173 个版本generation 仍被 bundle 门禁 { download: { price: 8000 } }1.3 两条写路径与三处强制的规则分布规则是否被强制取决于写路径是否覆盖通向门禁有两条写路径——REST 端点/api/v1/model-versions/early-accessCreator Studio 调用与 tRPCmodelVersion.upsert主应用表单调用而 licensing fee 与 usage control 在 Creator Studio 中直接通过 Kysely 写 Postgres根本不经过主应用。只在其中一条路径强制 未强制。这个认知是理解后续两个实现副本需保持同步如pricing-slot.service.ts与 spoke 侧pricing-slot.ts的前提。二、跟进清单全景以下是评审会Justin/Ellie 录音回放 Briant 笔记与工程开放项的全景。清单按界面打磨 → 产品规则 → 工程遗留项三个层次组织[x]表示已完成、[ ]表示待办区域条目状态Creator Studio 抽屉小窗口滚动条✅Creator Studio 抽屉Save 按钮标签跟随模式✅Creator Studio 抽屉隐藏 0/过期费用✅批量付费价格输入加 Buzz 图标前缀✅批量付费Access fee/Gen-only fee 标签✅模型列表桌面端渲染为表格⏳模型列表移动端徽章折叠价格 行堆叠✅/join合格成员从 studio 加入 Creator Program✅主应用用户导航加入 Creator Studio 链接✅主应用licensing fee 整数化✅产品验证永久付费购买端到端测试⏳产品验证捐赠目标启动后不可关闭确认意图⏳产品验证有付费则不可删模型 确认buyer protection✅产品验证EA 天数上限读取 owner 分数✅产品验证Justin 文章更新为月度定价额度⏳工程scheduled EA 永无endsAt✅ 已修复验证工程mini/[id].tstrial-limit SQL 谓词✅ 已修复验证工程免费预览 clear 语义跨应用对齐✅工程CSV 导出/导入增加付费列⏳工程抽取的 Svelte 组件运行时冒烟测试⏳工程layout.server.tsdev-gate 移除并提交✅下面逐层展开并对已确认修复的工程项给出源码级证据。三、Creator Studioper-version 抽屉的界面打磨3.1 小窗口滚动条抽屉drawer承载 licensing/paid-access 侧栏内容在小窗口下内容溢出。修复为允许滚动——对应apps/creator-studio的抽屉组件。这条是纯 UI 收尾但它是付费配置区在窄屏可用性的基础。3.2 Save 按钮标签跟随模式抽屉中保存按钮的文案由当前选中的门禁模式决定选择Permanent永久付费→ 按钮显示Save paid access选择Timed计时→ 按钮显示Save early access。评审会上 Justin 曾提议统一为 Save access fee最终采用模式相关标签mode-specific label。这一决定与付费门禁的二分法保持一致永久门禁与计时门禁在PaidAccess表中共享同一行仅由timeframeDays/endsAt区分但面向创作者的语言必须明确当前配置的是哪一种。3.3 不显示 0 / 过期费用问题一个版本渲染出 0 / 10 的 licensing fee。根因Justin ~11:37该版本曾设置捐赠目标达标后提前结束了 early access 窗口费用随之消失但 UI 仍显示残值。修复语义为fee 为 0 时不显示Off——即一个已退出/已过期的门禁不渲染任何费用。这背后对应endsAt的语义过期 ≠ 无门禁过期行是 tombstone但费用为 0 时对购买者而言与 Off 等价UI 应当以当前可购买状态为准而不是显示历史残值。四、Creator Studio批量付费Bulk Paid Access输入优化批量操作涉及两个输入打磨均源于评审现场的真实误读Buzz 图标前缀价格输入框access gen-only 两个输入加上 Buzz 图标前缀使其明确读作 Buzz 金额而非人数/次数——Ellie 曾把 100 读成 100 人/100 次生成。更清晰的输入标签由 Access/Gen-only 改为Access fee / Gen-only fee与抽屉中单版本编辑的术语保持一致。从实现看批量路径由apps/creator-studio/src/routes/(app)/models/page.svelte的BulkBar.svelte与BulkActionDialog.svelte承载写路径为page.server.ts的bulkSetPaidAccessaction详见 paid-access-current-state.md。批量操作还受usage-type 过滤?usagedownload|generation驱动列表与全选保证价格字段语义无歧义当选中数量超过当月剩余额度、或 owner 低于资格线creator score ≥ 10k时对话框会发出警告。五、模型列表定价一览at-a-glance5.1 桌面端表格待办仍未落地的条目桌面端将模型/版本列表渲染为表格列包括version, status, licensing fee, access Buzz price让创作者无需打开面板即可一览所有价格移动端保留当前卡片布局。这是清单中少数开放中的 UI 项之一。5.2 移动端徽章折叠价格已完成已完成的移动端打磨Justin ~9:54, ~10:42early/paid-access 徽章现在折叠 Buzz 访问价格accessBadge()输出 Permanent · 500 ⚡ 或 Early access · 500 ⚡移动端版本行堆叠布局状态徽章右对齐到标题行释放第二行给价格 费用chips桌面端保持单行。这与付费门禁的两种形态一一对应Permanent 对应endsAt IS NULLtimeframeDays IS NULLEarly access 对应未过期的计时窗口。六、Creator Program从 Studio 加入/join新能力合格成员可直接从 Creator Studio 加入 Creator Program。判定条件是拥有 Civitai 会员 创作者分数但尚未加入满足时在 studio 的/join页面浮现 Join 流程镜像主应用 Buzz 仪表盘的 Join now。这条与 R3 月度定价规则见 monetization-rules.md衔接会员等级决定每月可设置的新价格数量Free 3 / Bronze 10 / Silver 25 / Gold 无限而不是旧的并发永久门禁上限。因此从 studio 加入是打通成为创作者 → 获得定价额度链路的关键入口。七、主应用集成两条已完成的主应用侧收尾用户导航加入 Creator Studio 链接主应用用户导航user navigation新增指向 Creator Studio 的入口。Licensing fee 整数化licensing fee 统一为整数每 N 次生成多少 Buzz的比例而非按图的小数与 studio 一致。这一改动消除了主应用与 spoke 之间对费用语义的认知分裂。八、产品规则确认与验证Verify / Product这一节是清单中规则确认密度最高的部分——评审会暴露的困惑多数被验证为设计如此或已由构造满足。8.1 永久付费购买端到端测试待办早期访问购买已验证可用但永久付费购买的端到端流程尚未被实际演练Justin ~6:15。这是清单中明确的测试空缺需要覆盖永久门禁 → 购买 → 权限授予download3 / generation1→ 永不过期的完整链路。8.2 捐赠目标启动后不可关闭待确认捐赠目标donation goal被设计为create-once端点从不更新或移除它。Justin ~12:30 提出目标一旦启动是否可关闭的问题待产品确认——或增加关闭途径。参考 monetization-rules.md 的 R6active: false只在目标完成时写入没有取消路径创作者和版主都没有。注意永久门禁对目标完成豁免isTimedGateActive因此被资助的目标不会抹掉永久付费墙。8.3 有付费则不可删除模型——确认是 buyer protection已完成确认Ellie 报告的无法删除有付费访问的模型被确认是有意设计买家保护。关键实现事实门禁键基于实际购买而非仅仅存在门禁版本meta.hadEarlyAccessPurchase在任何购买发生时置位通过earlyAccessPurchase计时或永久购买都会置位——它不按timeframeDays分支。非版主被阻止调用deleteModelById、unpublishModelById、deleteVersionById以及版本合并…has had early access purchases…版主绕过这些限制。零购买的门禁版本仍可删除。源码证据位于 model-version.service.ts写 meta 时使用条件更新——UPDATE ModelVersion SET meta jsonb_set(COALESCE(meta, {}::jsonb), {hadEarlyAccessPurchase}, to_jsonb(${true})) WHERE id ${id} AND COALESCE((meta-hadEarlyAccessPurchase)::boolean, false) false;即仅在尚未置位时置位幂等。相关测试可见 model-early-access-refund.service.test.ts其中注释明确门禁完全依赖hadEarlyAccessPurchase因为PaidAccess已不在谓词中与 model-version.unpublish-refund.service.test.ts。8.4 EA 天数上限读取 owner 的分数——已由构造满足无需改码Justin 以版主身份看到 30 天上限而非模型所有者真实的 9 天上限。验证结论已由构造满足无需代码变更model-version.router.ts的isOwnerOrModeratorsrc/server/routers/model-version.router.tsownershipGuard({ authorizeInputModelId: true })拒绝任何非版主且非模型所有者的调用者版主在表单isModerator分支与服务端assertUserEarlyAccessLimits提前返回都被豁免于 EA 上限。因此只要上限被应用操作者必然就是 owner此时ctx.user.meta.scores.models读取的必然是 owner 的分数版主看到的是全部 tier 解锁而非 owner 的上限这正是演示中的困惑来源。注意 monetization-rules.md 的 R3 更新自 2026-09-04 起所有对用户展示的creator score统一读取User.meta.scores.total经creatorScoreFromMeta早期访问阶梯的入门门槛为 10,000 分与定价资格线一致。8.5 Justin 文章更新为月度定价额度待办待办把 Justin 的文章更新为月度定价额度口径——Free 3 / Bronze 10 / Silver 25 / Gold 每月无限。这些数字取代了旧的并发永久门禁上限数字相似但含义完全不同文章必须表述为每自然月的新价格而不是处于付费访问的模型数。见 monetization-rules.md 的 R3。配套的PricingSlot账本按(entityType, entityId)记账listPricingSlots回答什么花掉了额度资格线score ≥ 10k读取的是当前状态而额度读取的是本自然月已花费的 slot 账本。九、工程遗留项两个已修复缺陷的源码验证清单中两个疑似缺陷经过本轮验证均确认已修复无需再改码。以下是逐行证据。9.1 Scheduled Early Access 永不 materializeendsAt已修复验证原缺陷计划scheduled发布的计时门禁永远不会物化endsAt——publishedAt在未来时版本进入Scheduled状态跳过了需要Published的 EA 分支materializePaidAccessEndsAt从未执行随后process-scheduled-publishing再次发布时不带publishedAt又被跳过。结果endsAt永远为 NULL 永久门禁且process-ending-early-access过滤endsAt NOW()永远不会释放它。现实现验证publishModelVersionsWithEarlyAccessmodel-version.service.ts现在用 else-branch 覆盖 scheduled 情形} else if (currentVersion.publishedAt ! null) { // Caller didnt pass publishedAt (the scheduled-publishing job sets it at schedule time and // only flips status here). Materialize the pending timed gate from the versions already-set // publishedAt — otherwise a scheduled EA version keeps endsAt NULL and becomes a PERMANENT // gate that never releases. materializePaidAccessEndsAt no-ops on permanent/tombstoned gates. await materializePaidAccessEndsAt(currentVersion.id, currentVersion.publishedAt, dbClient); }同时发布路径遵循anti-bump guardWHERE publishedAt IS NULL OR publishedAt NOW()仅在publishedAt实际被重设置时才物化endsAt publishedAt timeframeDays——无操作的重新发布不会覆盖已物化的endsAt。materializePaidAccessEndsAt对永久/已墓碑门禁为 no-op。结论无需代码变更清单已勾选。9.2mini/[id].ts免费试用额度 SQL 谓词错误已修复验证原缺陷mini/[id].ts的 free-trial-limit SQL 以terms-generation-price IS NOT NULL为谓词但常见路径download bundle 或 gen-only发出的generation: { trialLimit: N }没有price于是 SQL 返回 NULL 免费试用额度——免费预览计数无法上达 orchestrator。现实现验证src/pages/api/v1/model-versions/mini/[id].ts) AS checkPermission, -- 谓词terms 有 generation 且 free ! true ( CASE WHEN pa.terms-generation IS NOT NULL AND COALESCE(pa.terms-generation-free, ) true THEN COALESCE(CAST(pa.terms-generation-trialLimit AS int), ${DEFAULT_GENERATION_TRIAL_LIMIT})::int ELSE NULL END ) AS freeTrialLimitcheckPermissionline 137-141与freeTrialLimitline 164-171现在都以terms-generation IS NOT NULL AND COALESCE(terms-generation-free,) true为门控条件与paidGenerationGrant()镜像。结论无需代码变更清单已勾选。文档还建议将零调用点的paidAccessActiveSql/isPaidAccessGated共享 helper 收编约 6 处手写 active gate 原始 SQL以消灭此类问题待办非阻塞。9.3 免费预览 clear 语义跨应用对齐已完成两个应用对清空免费预览的语义不一致spoke 清空 → 0主应用清空 → 默认 10。两者编辑同一批版本必须统一语义。清单标注已对齐pick one and align。十、剩余开放项与运行注意事项10.1 CSV 导出/导入增加付费列待办CSV 导出/导入尚不包含paid/early-access 列。推荐方案先导出后导入export-first导出列包含付费访问相关字段捐赠目标列只读因捐赠目标是 create-once。导入本质上是经由端点的 CSV 驱动批量变更需带上 cap/会员资格/usage 强制。10.2 运行时冒烟测试抽取的 Svelte 组件待办付费编辑器与批量条被抽取为独立 Svelte 组件后需要运行时冒烟测试覆盖抽屉重开时的 state 重新播种re-seed以及批量条之间共享selected的响应式reactivity——类型检查无法捕获响应式回归。对应组件路径为apps/creator-studio/src/lib/components/PaidAccessEditor.svelte、BulkBar.svelte、BulkActionDialog.svelte。10.3 dev-gate 移除已完成待提交layout.server.ts的 dev-gate 移除尚未提交当前未提交状态。一旦提交它将把 Creator Studio 开放给所有已认证用户移除 moderator/testing-id 门禁。这是上线前的最后一扇门。10.4 命名漂移提醒Creator Studio spoke 的写 API 仍沿用earlyAccess*命名setEarlyAccessConfig、?/setEarlyAccess、EarlyAccessConfig、hasEarlyAccess尽管它们现在也覆盖永久付费访问Svelte 组件已重命名为PaidAccess*API 重命名是推迟的后续项。阅读 spoke 代码时需注意这一历史命名。十一、小结这份清单展示了付费访问功能从评审会发现 → 规则确认 → 缺陷修复验证的完整闭环界面层抽屉滚动、模式化按钮、Buzz 前缀、清晰标签、移动端徽章折叠价格——消除创作者对价格的误读产品规则层删除保护键在hadEarlyAccessPurchase实际购买而非门禁存在、EA 上限天然读取 owner 分数、捐赠目标 create-once 且永久门禁豁免——三条规则均有源码与测试支撑工程层scheduled EA 的endsAt物化与mini/[id].ts的 trial-limit 谓词均已通过当前源码验证为已修复无需再改码。继续深入可阅读 paid-access-current-state.md代码位置与 Gotchas、paid-access-schema.md迁移设计记录与 monetization-rules.md规则权威定义。【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考