5.9 KiB
5.9 KiB
Arquitectura — CLUB-001 · Fase 1 Core backend
Análisis de arquitectura existente
Superficies del proyecto
- Backend API:
project/src/app/build-app.tsregistra módulos Fastify desacoplados bajoproject/src/modules/*. - Frontend tienda:
project/frontend/consume la API vía rutas proxy Next.js. - Admin panel:
project/apps/admin/usa endpoints backoffice/admin ya existentes. - TPV/POS:
project/apps/pos/usa backend POS y órdenes como fuente de ventas.
Patrones que debemos reutilizar
- Módulo aislado por carpeta:
api/,application/,domain/,infrastructure/,index.ts. - Rutas finas: validación con
zod+parseJson, errores conAppError, Swagger conerrorSchema. - Persistencia PostgreSQL: migraciones
project/migrations/*.jsy repositoriosPg*Repository. - Auth desacoplada por inyección: módulos reciben
authenticatedesdebuild-app.ts; no importan internals de identity. - Configuración editable:
store_settingsya actúa como KV-store para ajustes globales del negocio. - Tests reales de integración:
project/src/app/tests/*.itest.tsrecrean DB, aplican migraciones y prueban la app completa.
Decisiones técnicas para Fase 1
1) Nuevo módulo club
Se crea project/src/modules/club/ con registro de rutas propio desde build-app.ts.
2) Ledger como fuente de verdad
club_transactionsserá el source of truth.club_members.current_balance_centsexistirá solo como cache/optimización.- Cada escritura de ledger actualizará ambos dentro de la misma transacción.
- El balance podrá reconstruirse con
SUM(balance_delta_cents).
3) Configuración reutilizando store_settings
No se crea un sistema nuevo de configuración. Se añaden claves:
club_enabledclub_cashback_bpsclub_allow_anonymous_membersclub_allow_recovery_codesclub_minimum_redeem_cents
Esto mantiene consistencia con la arquitectura actual y simplifica futura UI admin.
4) Dispositivo anónimo con token opaco hasheado
- El backend genera
device_tokenopaco. - Solo se persiste
device_token_hashenclub_devices. - El raw token se devuelve al cliente una sola vez en
POST /club/join. - Las rutas de lectura de Club aceptarán el token mediante header/cookie para no acoplar la PWA todavía.
5) Modelo preparado para fases futuras
Aunque Fase 1 solo activa core backend, la migración deja base para próximas fases:
club_membersclub_devicesclub_transactionsclub_recovery_codesclub_rewardsclub_campaigns
6) Cashback configurable, no hardcoded
La lógica core leerá club_cashback_bps desde settings. El default inicial será 200 bps = 2%.
Alcance funcional de CLUB-001
Sí entra en Fase 1
- Crear socio anónimo.
- Emitir token de dispositivo.
- Consultar tarjeta/resumen del socio por token.
- Consultar movimientos del ledger.
- Configuración backend del Club.
- Infraestructura de migraciones y tests.
- Helper backend para registrar transacciones idempotentes sobre ledger.
No entra en Fase 1
- PWA visual
/club/*. - QR visual y endpoint TPV de identificación.
- Recovery codes funcionales.
- Vinculación a cuenta de usuario.
- Admin UI.
- Integración TPV completa de earn/redeem/refund.
Esquema inicial propuesto
club_members
id uuid pkuser_id uuid null -> identity_users(id)member_code text uniquestatus text(active|blocked|merged)tier_code text default 'base'current_balance_cents integer default 0created_at,updated_at
club_devices
id uuid pkmember_id uuid fk -> club_members(id)device_token_hash text uniquelast_used_at timestamptzcreated_at timestamptzrevoked_at timestamptz null
club_transactions
id uuid pkmember_id uuid fk -> club_members(id)sale_id uuid null -> orders_orders(id)store_id uuid null -> pos_stores(id)type text(earn|redeem|refund|bonus|adjustment)amount_cents integerbalance_delta_cents integeridempotency_key text unique nullmetadata jsonb not null default '{}'created_at
club_recovery_codes
- Tabla preparada para Fase 4.
- Guardará hash(es) del código, no plaintext.
club_rewards, club_campaigns
- Tablas scaffold para evolución posterior sin activar motor complejo aún.
Endpoints backend de Fase 1
Públicos / cliente Club
GET /club/config- Devuelve flags públicos del módulo.
POST /club/join- Crea socio anónimo + device token.
GET /club/me- Resuelve socio por device token.
GET /club/movements- Lista movimientos del socio actual.
Admin / configuración
GET /admin/club/settingsPATCH /admin/club/settings
Aplicación interna
- Servicio backend para registrar ledger idempotente y recalcular balance.
- Se deja listo para ser usado por TPV en CLUB-003.
Validaciones clave
- Rechazar
joinsiclub_enabled=falseoclub_allow_anonymous_members=false. - No aceptar tokens sin hash coincidente o revocados.
member_codeúnico y corto, formatoMDV-XXXXXXXX.typedel ledger restringido por CHECK.current_balance_centsnunca por debajo de 0 en operaciones que no lo permitan.idempotency_keyúnico para evitar dobles registros.
Estrategia de tests
- Unit tests para helpers de token/member code/config parsing.
- Boundary test para evitar imports indebidos del módulo.
- Integration test real PostgreSQL para:
- migraciones del Club
POST /club/joinGET /club/meGET /club/movementsGET/PATCH /admin/club/settings- escritura idempotente de ledger
Riesgos / deuda controlada
- La PWA aún no existe; por eso Fase 1 devolverá el
deviceTokenal cliente y además dejará la ruta preparada para header/cookie. - El QR opaco persistente se implementará en la fase TPV/PWA, sin bloquear el core del ledger.
- Recovery codes se dejan modelados pero no activados todavía para evitar complejidad prematura.