talent-unlock-quota

人才解锁与配额管控

在 YouTeacher 的 profile(档案) 服务里,教师(talent)档案可被检索,但联系方式是被"锁住"的。招聘方的查看者——已认证的雇主(employer)已批准的招聘顾问(recruiter)——需要消耗解锁配额(unlock quota),才能揭示某位教师的联系方式。本节讲的就是这道门:判定一次解锁是否被允许的领域规则,以及记录这次解锁的流程。

三条领域规则

判定逻辑集中在一个领域服务 UnlockService 里。它按固定顺序校验查看者与教师,返回第一条不满足的规则(以带错误码的结果返回,而非抛异常)。两类查看者走的是并行的检查:

  • 资格 —— 雇主必须已认证,招聘顾问必须已批准。两者皆非,则谁也解锁不了(employer_not_verified / recruiter_not_approved)。
  • 可见性 —— 教师必须对该受众可见。雇主对照的是"对学校可见",招聘顾问对照的是"对招聘顾问可见"。对其隐藏的教师无法被解锁(talent_not_visible)。
  • 配额 —— 查看者必须仍有剩余解锁配额。用尽即拒绝(quota_exceeded)。

只有三条全部通过,服务才报告 canUnlock: true

作为值对象的配额

配额被建模为一个不可变值对象,持有 total(总额)与 used(已用)两个计数,remaining(剩余)由 total − used 推导得出——从不单独存储,保持单一真相来源。它的不变式在构造时强制:两个计数都不得为负,且 used 永远不得超过 total。消耗配额不会修改原对象,而是返回一个 used 加一的配额对象;无余量可用时则拒绝消耗。另有一个调整操作,可重设总额或已用数。因为 remaining 始终是算出来的,这个对象永远不会漂移到不一致的"剩余"值上。

解锁流程

雇主与招聘顾问的应用层处理器几乎一样。每个 execute(userId, talentId) 都走同一序列:

  1. 用 user id 解析出查看者档案;没有则以 not-found 失败。
  2. 用 id 解析出教师;没有则 not-found。
  3. 幂等检查 —— 查这对(教师、查看者、查看者类型)是否已有解锁记录。若已存在,原样返回。同一位教师绝不会被重复扣费。
  4. 跑三条领域规则。失败则以 forbidden 响应返回,带上该规则的说明。
  5. 扣减该查看者的配额。
  6. 记录这次解锁并返回。

一条解锁记录是一个很小的事实:一个 id、教师 id、查看者 id、查看者类型(雇主或招聘顾问),以及一个时间戳。

持久化与并发安全

解锁记录存在自己的表里,以(教师、查看者、查看者类型)三元组作为唯一键。写入使用针对该唯一键的 upsert,因此同一对的两个并发解锁请求会收敛到同一条记录,而非产生重复。仓储还支持把一个查看者的解锁记录迁移给另一个查看者——迁移前会跳过目标方已持有的那些,再从源方删除。

一些说明与接缝

  • 幂等检查加上配额扣减,意味着重复解锁一位已揭示的教师是免费的;配额只在首次揭示时消耗一次。
  • 在处理器里,配额扣减与解锁记录写入是两个独立的持久化步骤;upsert 保护记录本身不重复,幂等检查则防止重复扣费。
  • 资格(认证 / 批准)在上游决定——profile 服务在应用规则时只读取查看者当前的状态。

本组件内

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →