Programa de referidos — Referencia técnica
← Volver a Programa de referidos
Construido de cero (Fase D.7 / roadmap 4.15). Antes de esto, el único rastro de referidos era una línea de JSDoc desactualizada @method processReferralBonus sin ninguna implementación detrás.
Dónde vive esto
Backend
apps/backend/database/migrations/20260717100000-add-referral-program.js— agregausers.referral_code(único) +users.referred_by_id(FK a sí misma) y dos columnas ensystem_settingpara los montos del bono (idempotente).apps/backend/database/models/user.js— atributosreferralCode,referredById.SystemSetting.js—referralReferrerBonusCoins,referralReferredBonusCoins(ambos por defecto 0).apps/backend/managers/user-managers/referral.manager.js—ensureReferralCode(generación perezosa de código único, alfabeto sin ambigüedades),getMyReferralInfo(código + conteo de referidos + total ganado),applyReferralAtSignup(registra al referente una sola vez y otorga ambos bonos víacoinTransactionManager.createTransactioncon tiporeward/ relatedTypereferral; best-effort, idempotente). Cuando se otorga el bono del referente, también se le envía una notificaciónreferral_bonusvíanotificationManager.createNotification(notification.manager.js) —referral_bonuses un valor del enumNotificationType(notification.type.js) también aceptado pornotification.validator.js. El nuevo usuario no recibe una notificación por su bono de bienvenida.apps/backend/managers/user-managers/authentication.manager.js—registerextraereferralCodedel input y llama aapplyReferralAtSignupdespués de crear la cuenta (best-effort — un fallo de referido nunca bloquea el registro).apps/backend/graphql/types/referral.type.js+resolvers/referral.resolver.js— el tipoReferralInfo, la querymyReferralInfo, yextend input UserRegistrationInput { referralCode }.apps/backend/graphql/types/admin/payout-admin.type.js+managers/admin-managers/payout-settings.manager.js— los dos montos de bono se exponen enPayoutSettings/PayoutSettingsInputy se validan (enteros no negativos) enupdateSettings.
Frontend
apps/frontend-nextjs/src/page-components/settings/ReferralPage.tsx(ruta/settings/referrals, enlazada desde el menú de configuración) — consultamyReferralInfo, muestra el código + un enlace copiable…/login?ref=CODE+ estadísticas de referidos/ganancias, además de botones de compartir con un solo toque (hoja de compartir nativa, WhatsApp, Facebook, X).apps/frontend-nextjs/src/components/Login.tsx— lee?ref=CODEde la URL al montar y pasareferralCodeen el input de la mutationRegister.apps/frontend-admin/src/app/payments/settings/page.tsx— dos campos numéricos para fijar los montos de bono del referente / usuario nuevo.
Checklist de implementación técnica
-
referralCode/referredByIden users; código único generado perezosamente - Query
myReferralInfo—ReferralPage.tsx -
referralCodeenUserRegistrationInput; capturado desde?ref=y aplicado al registrarse - Bonos configurables en
SystemSetting, editables desde la página de configuración de pagos del admin - Bonos otorgados por la vía estándar de transacción de monedas (
reward/ relatedTypereferral), idempotente - Referente notificado (notificación
referral_bonus) cuando se otorga su bono - Comisión de afiliado sobre compras recurrentes — no construido (solo bono único de registro)
API de GraphQL
# El código de referido + estadísticas de quien llama (el código se genera en el primer acceso)
query MyReferralInfo {
myReferralInfo { referralCode referralCount totalEarnedCoins }
}
# El input de registro ganó un referralCode opcional
mutation Register($input: UserRegistrationInput!) {
register(input: $input) { token user { id username } }
}
# input: { username, email, password, dateOfBirth, referralCode: "ABCD2345" }
Notas de diseño
- Bono único de registro, no una comisión recurrente. La recompensa se otorga una vez, cuando un usuario referido se registra. Una comisión de afiliado real (un porcentaje de todo lo que el usuario referido compre después) necesitaría hooks en cada flujo de compra (compras de monedas, suscripciones, tienda, posts exclusivos) y su propia contabilidad — deliberadamente fuera de alcance en esta pasada; el modelo registra
referredByIdde forma permanente, así que ese dato está disponible si se agrega la comisión más adelante. - Desactivado por defecto. Ambos montos de bono son 0 por defecto, así que no se mueve ninguna moneda hasta que un administrador los fije — el mismo patrón "configurable por admin, desactivado por defecto" que
verificationPriceCoins. - Idempotente y best-effort.
referredByIdsolo se fija una vez (un segundo intento de registro con un código es un no-op), y todo el paso de aplicación está envuelto para que un fallo de referido nunca bloquee un registro exitoso. - Los bonos usan la vía estándar de monedas.
coinTransactionManager.createTransaction({ transactionType: 'reward', relatedType: 'referral' })maneja el balance + la contabilidad deUserCoinBalance, así que las ganancias por referidos aparecen en el historial de ganancias y cuentan exactamente como cualquier otra recompensa.