orch-add-feature  ·  NutriFlow SaaS

Añadir notificación email al completar plan semanal
orquestar-nueva-funcionalidad COMPLETADO
6
Fases ejecutadas
17
Tests nuevos
81%
Cobertura total
+347
Líneas añadidas
Solicitud
Cuando un paciente complete su plan semanal, el dietista debe recibir un email automático con los macros cumplidos, porcentaje de adherencia y enlace al historial.
$ /orch-add-feature: add weekly-plan completion email notification to NutriFlow
Pipeline — 6 fases · 2 puertas de aprobación
0
Classify size
1
Research
2
Plan
G1
Gate 1 — Plan ✓
4
TDD
5
Review
G2
Gate 2 — Commit ✓
6
Commit
Fase 0 Clasificación de Tamaño
STANDARD (M)
📐
La feature requiere integración externa nueva (Resend API), nuevo módulo de servicio, cambios en el modelo de datos (tabla notif_log) y tests de integración. Tamaño: Standard — M. Pipeline completo: fases 0 → 1 → 2 → Gate1 → 4 → 5 → Gate2 → 6.
Fase 1 Research — Investigación técnica
✓ completado
🔍
Codebase scan: Resend ya está en package.json (v2.1.0) — no hay que añadir dependencia. El hook plan.service.js:markComplete() es el punto de inyección natural.
🔍
Patrón existente: El proyecto usa el patrón service → repository. La notificación debe vivir en src/services/notification.service.js, invocado desde plan.service.js.
🔍
Riesgo de seguridad: El email expone datos de salud (macros, adherencia). Se activa security-reviewer en la fase de revisión.
Opción considerada Pros Veredicto
Resend API (ya instalado) Sin dependencia nueva, SDK tipado, plantillas React Email ✓ ELEGIDO
Nodemailer + SMTP Más flexible Descartado — ya hay Resend
Queue async (Bull) Retry automático V2 — fuera de scope
Fase 2 Plan — Lista de tareas
✓ completado
🔒 GATE 1 — Aprobación del Plan
El orquestador se detiene aquí y presenta el plan al humano.
Responde y para continuar, n para revisar, o sugiere cambios.

"Plan correcto. Añade en T-03 que si RESEND_API_KEY no está configurada, el servicio debe lanzar un ConfigError en boot, no en runtime."
✓ APROBADO — con comentario incorporado
Fase 4 TDD — Tests primero, luego implementación
✓ 17/17 passing
// notification.service.test.js — tests escritos ANTES de implementar

describe('NotificationService.sendWeeklyCompletionEmail', () => {
  it('should send email and log to DB on success', async () => {
    const resendMock = jest.fn().mockResolvedValue({ id: 'res_abc123' });
    const result = await sendWeeklyCompletionEmail({
      patientName: 'Ana García',
      dietistEmail: 'dra.gomez@nutriflow.app',
      macros: { calorias: 2100, proteinas: 142, carbos: 230, grasas: 65 },
      adherencia: 87, patientId: 'pat_01'
    });
    expect(resendMock).toHaveBeenCalledOnce();
    expect(result.status).toBe('sent');
  });

  it('should NOT throw when Resend fails — silent catch', async () => {
    const resendMock = jest.fn().mockRejectedValue(new Error('API 500'));
    await expect(sendWeeklyCompletionEmail({...})).resolves.toBeDefined();
    // plan.markComplete() no debe fallar si el email falla
  });

  it('should throw ConfigError at boot if RESEND_API_KEY missing', () => {
    delete process.env.RESEND_API_KEY;
    expect(() => require('./notification.service')).toThrow('ConfigError');
  });
});
✓ 17 tests passed coverage: 81% (+7pp) Jest 3.2s
Fase 5 Code Review + Security Reviewer (activado — health data path)
✓ 0 bloqueantes
OK
Aislamiento de fallos: El try/catch en plan.service.js es independiente — un fallo de Resend no propaga excepción al flujo de markComplete(). Correcto.
OK
ConfigError en boot: Incorporada la sugerencia del Gate 1. La validación de RESEND_API_KEY ocurre en la inicialización del módulo, no en runtime.
WARN
[Security] PII en logs: El logger en notification.service.js:L48 registra payload.dietistEmail en debug. Datos de salud no deben aparecer en logs de producción. Fix: enmascarar con email.replace(/@.+/, '@***').
INFO
Mejora futura: Considerar idempotency key en el log de notif_log para evitar duplicados si markComplete() se llama dos veces.
Fix aplicado por el agente
src/services/notification.service.js — L48
logger.debug('Sending email to', payload.dietistEmail);
logger.debug('Sending email to', maskEmail(payload.dietistEmail));
🔒 GATE 2 — Aprobación Pre-Commit
El orquestador presenta el diff completo y el resumen de revisión.
1 warning resuelto (PII en logs). 0 bloqueantes. Tests en verde.

"Perfecto. Hace el commit."
✓ APROBADO — proceder al commit
Fase 6 Commit
✓ main — fa8c3d1
fa8c3d1
feat(notifications): send weekly plan completion email to dietist
- Add notification.service.js with Resend integration
- Add notification.repository.js + notif_log migration
- Hook sendWeeklyCompletionEmail in plan.service.markComplete()
- Silent catch: email failure does not break plan completion
- ConfigError thrown at boot if RESEND_API_KEY missing
- Mask dietistEmail in debug logs (security-reviewer)
- 17 new tests; coverage 74% → 81%

Co-Authored-By: orch-add-feature (orquestar-nueva-funcionalidad)
+347 -12 7 archivos cambiados
Archivos modificados
git diff --stat HEAD~1
src/services/notification.service.js      +124
src/repositories/notification.repository.js +48
src/migrations/009_notif_log.sql         +22
src/templates/weekly-completion.html      +89
tests/notification.service.test.js       +64
src/services/plan.service.js             -12 +18
src/config/resend.js                    +20