# 恢复 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,需运营确认是否回溯)。