2026-10-11-restore-basic-and-diet-share-design.md 4.2 KB

恢复 BASIC 体验会员 + 饮食打卡分享 + 图片解析配额

日期:2026-10-11 状态:实现中

背景

  • 提交 f86dd164b(2026-10-09)「remove BASIC trial membership」移除了 9.9 元/月的 BASIC 体验会员等级:
    • 删除 membership_levels 的 BASIC 行、membership_benefits 的 4 条 BASIC 权益;
    • 将存量 users.member_level='BASIC' 迁移为 FREE;
    • BasicQuotaService.consumeQuota 去掉 isActiveBasicMember 前置校验;
    • MembershipService.listActiveBasicMemberUserIds() 改为返回空列表;
    • backfillMembershipLevelOrder()(迁移 351)level_order 改为 FREE=1 FAMILY=2 PROVIDER=3 PREMIUM=4 LIFETIME=5。
  • 需求:恢复 9.9 元/月 BASIC 体验会员级别;饮食打卡分享(他人点击分享注册后自动绑定推荐人);图片解析(食材识别)改为需 BASIC 会员并做配额校验。

恢复范围(依据 f86dd164b 反向还原)

1. BASIC 会员等级(数据库)

  • membership_levels 重新插入 BASIC:
    • level_name='体验会员',level_desc='9.9元/月体验版,解锁核心功能,限次使用AI与报告解读',price_monthly=990, features='["free_activities","free_courses","discount_purchase","invite_family","mascot_ai_lite","ai_report_reading_lite","assessment_quota_lite","health_report_upload_lite","growth_plan_lite","task_template_lite","referral_commission"]', max_children=3,max_tasks_per_day=3,level_order=2。
  • membership_benefits 重新插入 4 条:
    • AI_CHAT_LITE(限3次/月)、REPORT_READING_LITE(限1次/月)、GROWTH_PLAN_LITE、ASSESSMENT_QUOTA_LITE(限1次)。
  • level_order 还原为 FREE=1 BASIC=2 FAMILY=3 PROVIDER=4 PREMIUM=5 LIFETIME=6(相对顺序不变,仅在 FREE 与 FAMILY 之间插入 BASIC)。

2. 服务层还原

  • BasicQuotaService:恢复 isActiveBasicMember(userId)、getExpireTime(userId)、refreshMonthlyQuota() 完整实现。
  • MembershipService:
    • canUseFeature 恢复 BASIC 分支;
    • getMemberLevel 个人会员到期判断恢复 FAMILY || BASIC;
    • listActiveBasicMemberUserIds() 恢复真实查询(供到期提醒定时任务使用);
    • activateMembership 开通 BASIC 时调用 activationQuotaService.activateBasicQuota(userId, familyId) 初始化当月配额。
  • ActivationQuotaService.activateBasicQuota 仍存在,无需改动。

3. 图片解析配额(新需求)

  • 新增配额类型 FOOD_RECOGNIZE,BASIC 每月 3 次。
  • 规则(BasicQuotaService.consumeFoodRecognizeQuota(userId)):
    • level_order > BASIC(FAMILY/PROVIDER/PREMIUM/LIFETIME)→ 不限次放行;
    • level_order == BASIC → 走 consumeQuota(userId, "FOOD_RECOGNIZE");
    • level_order < BASIC(FREE)→ 拒绝并提示升级。
  • DietRecordController./recognize 注入 BasicQuotaService,取 @RequestAttribute("userId") 后调用 consumeFoodRecognizeQuota(userId);失败返回 Result.error(403, toast)(AiGateway/DietRecordService 签名不变)。

饮食打卡分享

  • 复用既有分享链路:share-mixin.js(setShareInfo + loadReferralCode)、App.vue.captureReferralParams/handleScene、login.vue.handleReferralBind、getShareQrCode。
  • 在 pages/growth/diet-checkin.vue、pages/diet/records.vue、pages/diet/record-detail.vue 接入 shareMixin 并调用 onShareAppMessage / 生成带 refCode 的分享链接,使新用户点击后注册自动绑定推荐人。

迁移编号

  • 现有最新迁移:迁移359(sso_ticket)。
  • 本次新增:迁移360 restoreBasicMembershipLevel()(幂等:INSERT IGNORE + 幂等 UPDATE level_order)。

风险

  • level_order 全局位移会影响商品/分类可见性、会员折扣判定、有效等级解析。相对顺序保持不变,仅插入 BASIC,按代码(level_code)匹配的逻辑不受影响。
  • 不恢复 consumeQuota 内原有的 isActiveBasicMember 前置校验(避免误伤 FREE/FAMILY 的 AI 对话),图片解析的会员门槛改由 consumeFoodRecognizeQuota 显式控制。
  • 生产库需确认是否存在历史 BASIC 用户,本迁移不自动回填(用户已迁移为 FREE,需运营确认是否回溯)。