Open
Conversation
Implement a full referral/invite system that lets users invite others and earn rewards when their invitees register. ## Backend ### Data model - New Ent schemas: `UserReferralProfile` (per-user referral code) and `ReferralRelation` (inviter↔invitee binding with reward amounts). `invitee_id` carries a UNIQUE constraint to prevent duplicate grants. - New migrations 064/065: create tables and add performance indexes (inviter_id, invitee_id, reward_granted) in a non-transactional file so they work with MySQL's implicit-commit DDL. ### Service layer (`referral.go` / `referral_service.go`) - `ReferralRepository` interface covers profile CRUD, relation CRUD, reward helpers, and list/stats queries. - `ReferralService.ProcessReferralRegistration` wraps reward grants in a single DB transaction; rolls back atomically on any failure. - `GrantRewardsInTx` updates both balances then sets `reward_granted` via `MarkRewardGranted`, giving an application-level idempotency flag. - Cache invalidation for inviter/invitee reward totals after commit. ### Repository (`referral_repo.go`) - All methods (including read-only list/stats) use `clientFromContext` so they participate in the caller's transaction when one is active. - `CreateRelation` back-fills `relation.ID` via pointer mutation so the subsequent `MarkRewardGranted` call uses the correct row ID. ### Auth integration (`auth_service.go`) - Registration flow accepts an optional `ref` query parameter. - Referral code is normalised (`strings.ToUpper` + `TrimSpace`) before lookup to tolerate lowercase user input. - Self-referral is rejected; invalid codes are silently ignored so registration is never blocked by a bad referral code. - On successful referral processing the caller receives the updated user object (balance already incremented). ### Settings (`setting_service.go`) - New keys: `referral_enabled`, `referral_inviter_reward`, `referral_invitee_reward`. Default reward values are **0** so rewards are opt-in; admins must explicitly configure amounts. - DB errors in `GetReferralRewards` are now propagated (previously swallowed), preventing silent 0-reward record creation. ### HTTP layer - `GET /api/v1/referral` — user fetches own referral info + stats. - `GET /api/v1/referral/invitees` — paginated invitee list. - `GET /api/v1/admin/referral/stats` — platform-wide stats for admins. ## Frontend ### User page (`ReferralView.vue`) - Displays referral code and full invite link (built from `window.location.origin` to work behind any reverse proxy). - Copy buttons support Clipboard API with `execCommand` fallback for HTTP environments. - Paginated invitee table with per-table error state (`inviteesError`) so a failed list request does not break the whole page. - Full-page error state with retry button for the initial load. ### Register page (`RegisterView.vue` / `EmailVerifyView.vue`) - Reads `?ref=CODE` from the URL and pre-fills the referral code field. ### Admin settings (`SettingsView.vue`) - New "Referral Program" section: enable/disable toggle, inviter reward amount, invitee reward amount. - Form defaults changed to 0/0 (was 10/5) to match backend semantics. ### Navigation & routing - Sidebar entry for `/referral` shown only when `referral_enabled`. - Vue Router route added for the new page. ### i18n - Full translations for all referral strings in `en.ts` and `zh.ts`.
- 运行 go generate ./ent/... 生成 referralrelation 和 userreferralprofile 两个新实体的 ent 客户端代码(predicates、builder、mutation 等) - 修复 wire_gen.go:注入 ReferralRepository、ReferralService、 AdminReferralHandler 和 ReferralHandler 依赖 - 修复 NewAuthService 调用方签名(新增 referralService 参数): cmd/jwtgen/main.go、admin_auth_test.go、jwt_auth_test.go、 auth_service_register_test.go、auth_service_turnstile_register_test.go - 修复 ent/schema/user_referral_profile.go 中未使用的 dialect 导入
5e22511 to
c556208
Compare
- 为所有 BillingCache 测试桩补充 SetAPIKeyRateLimit、 UpdateAPIKeyRateLimitUsage、InvalidateAPIKeyRateLimit 方法 - 为所有 APIKeyRepository 测试桩补充 GetRateLimitData、 IncrementRateLimitUsage、ResetRateLimitWindows 方法 - 修复 api_contract_test.go 中 POST/GET /api/v1/keys 响应快照 缺失 rate_limit/usage/window 字段 - 修复 subscription_calculate_progress_test.go 中时间敏感的 ExpiresInDays 断言(允许 29 或 30 天) - 修复 gofmt 格式问题
双方均在测试桩中添加了相同的接口方法,合并时保留上游方法顺序: - APIKeyRepository: IncrementRateLimitUsage / ResetRateLimitWindows / GetRateLimitData - BillingCache: GetAPIKeyRateLimit / SetAPIKeyRateLimit / UpdateAPIKeyRateLimitUsage / InvalidateAPIKeyRateLimit - api_key_auth_test: 统一返回 nil 而非 errors.New
_notx.sql 文件不能包含 goose 指令(-- +goose StatementBegin 含 BEGIN 字样会被误判为事务控制语句),应仅包含裸 SQL。 参考 062_add_scheduler_and_usage_composite_indexes_notx.sql 的格式。
- 将 064_add_referral_system.sql 重命名为 066_add_referral_system.sql
- 避免与主干已有 064_add_api_key_rate_limits.sql 的编号冲突
- 去除 goose Up/Down 指令(自定义 runner 会执行整个文件内容,
导致 DROP TABLE 紧跟 CREATE TABLE 执行,表立即被删除)
- 改用 IF NOT EXISTS 保证幂等性
- 将 065_add_referral_indexes_notx.sql 重命名为 067_add_referral_indexes_notx.sql
- 新增 backend/internal/service/referral_service_test.go(35 个单元测试)
- 覆盖纯函数:maskEmail、buildReferralLink、isUniqueConflict、generateReferralCode
- 覆盖服务方法:GetOrCreateProfile(含重试逻辑)、ValidateReferralCode、
GrantRewardsInTx、GetMyReferralInfo、ListMyInvitees、GetPlatformStats、
InvalidateRewardCaches
- 使用 function-field stub 模式实现 ReferralRepository 和 UserRepository 桩
- 在 backend/internal/server/api_contract_test.go 中补充 referral API contract 测试
- 新增 stubReferralRepoForContract 及默认数据配置
- 注册路由:GET /api/v1/referral、GET /api/v1/referral/invitees、
GET /api/v1/admin/referral/stats
- 新增 3 个 contract 测试用例验证响应结构和状态码
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
功能概述
实现用户邀请裂变推广系统,支持用户通过专属邀请码/链接邀请新用户注册,双方均可获得奖励。
新增特性
后端
新增数据模型
ReferralRelation:记录邀请关系(邀请人 ID、被邀请人 ID、双方奖励金额、奖励发放状态)UserReferralProfile:每位用户的专属邀请码(8 位大写字母+数字,懒加载创建)新增 API
用户端:
GET /api/user/referral— 获取我的邀请码和专属链接GET /api/user/referral/invitees— 分页获取被邀请人列表GET /api/user/referral/rewards— 获取我的奖励汇总(已发放/待发放)管理员端:
GET /admin/api/referral/stats— 获取平台邀请统计数据GET /admin/api/referral/list— 分页查询所有邀请关系记录奖励机制
referral_code,自动关联邀请关系新增系统设置(管理后台可配置)
referral_enabled— 功能总开关referral_inviter_reward— 邀请人奖励金额(元)referral_invitee_reward— 被邀请人奖励金额(元)前端
用户端新增页面
/user/referral):展示专属邀请码、一键复制邀请链接、被邀请人列表、奖励历史记录管理员端
代码质量
clientFromContext支持事务CI 修复说明
兼容上游主分支并入后的接口变更:
BillingCache接口新增方法:SetAPIKeyRateLimit、UpdateAPIKeyRateLimitUsage、InvalidateAPIKeyRateLimitAPIKeyRepository接口新增方法:GetRateLimitData、IncrementRateLimitUsage、ResetRateLimitWindowsapi_contract_test.go中 API Key 响应快照,补充 rate limit / usage / window 字段NewBillingCacheService新增APIKeyRepository参数导致的测试编译错误NewAuthService新增ReferralService参数后所有调用方的签名go generate ./ent/...生成 ent ORM 代码并提交gofmt格式问题