Tasks: Identidad compartida del paciente (007)

Task list template for feature implementation

Input: Design documents from /specs/007-identidad-paciente/ (spec.md, plan.md, research.md, data-model.md, contracts/identidad.md, quickstart.md)

Prerequisites: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/

Tests: La spec exige matriz de variantes equivalentes, gemelas denegadas sin fugas, sesión que caduca/cierra y enlace que solo opera sobre su cita (SC-001…SC-004) y la constitución VI exige test trazable por regla. Se incluyen tareas de test obligatorias.

Organization: Tasks are grouped by user story to enable independent implementation and testing of each story.

Format: [ID] [P?] [Story] Description

  • [P]: Can run in parallel (different files, no dependencies)
  • [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
  • Include exact file paths in descriptions

Path Conventions

  • Monolito Next.js: app/, lib/, prisma/, tests/ en la raíz (tema5/citaclara/)

Phase 1: Setup (Shared Infrastructure)

Purpose: Verificación del punto de partida (sin migración en esta feature)

  • T001 Verificar esquema actual y ausencia de tablas/columnas nuevas necesarias en prisma/schema.prisma (se usa Paciente de la 001 tal cual, FR-009)
  • T002 [P] Verificar catálogos y patrones reutilizables en lib/auth.ts (firma HMAC), lib/validacion.ts (ESQUEMA_EMAIL, ESQUEMA_TELEFONO_ES) y lib/cancelacion.ts (catálogo ENLACE_INVALIDO)

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Normalización única, resolución y avisos que bloquean todas las historias

⚠️ CRITICAL: No user story work can begin until this phase is complete

  • T003 Implementar normalizarCorreo, normalizarTelefono, validadores y AVISO_IDENTIDAD_* en lib/identidad.ts (FR-002, FR-008; Q1/Q5)
  • T004 Implementar resolverPacientePorCredenciales (incorrecto/duplicado/ok, comparación en memoria, sin enumerar fichas) en lib/identidad.ts (FR-001, FR-003, FR-004)
  • T005 [P] Test unitario de la matriz de normalización y resolución en tests/unit/test_identidad.test.ts (variantes US1 + no-válidos como «incorrecto» + gemelas como «duplicado») — debe FALLAR antes de T003/T004

Checkpoint: Foundation ready - user story implementation can now begin in parallel


Phase 3: User Story 1 - Una sola normalización para todos los canales (Priority: P1) 🎯 MVP

Goal: Portal y recordatorios resuelven con el mismo algoritmo; las variantes equivalentes dan la misma ficha y las no válidas son «incorrecto».

Independent Test: Matriz de variantes (mayúsculas, espacios, +34, 0034, guiones) sobre una ficha conocida resuelve a la misma ficha en portal y en recordatorios; las no válidas dan el aviso único.

Tests for User Story 1 ⚠️

NOTE: Write these tests FIRST, ensure they FAIL before implementation

  • T006 [US1] Test de resolución portal + recordatorio con la matriz de variantes en tests/integration/test_identidad_canales.test.ts (misma ficha en ambos canales, no-válidas como «incorrecto»)

Implementation for User Story 1

  • T007 [US1] Implementar POST /api/portal/sesion/route.ts usando resolverPacientePorCredenciales de lib/identidad.ts (sin normalización propia; portal importa el algoritmo único)
  • T008 [US1] Exponer decidirEnvioRecordatorio en lib/identidad.ts (envuelve a resolverPacientePorCredenciales para recordatorios; sin algoritmo propio; verificación por grep SC-005)

Checkpoint: At this point, User Story 1 should be fully functional and testable independently


Phase 4: User Story 2 - Duplicados que nunca filtran entre fichas (Priority: P1)

Goal: Correo + teléfono ambiguo deniega en todos los canales sin mostrar ni mutar nada y sin enumerar fichas; recordatorios no envían y anotan duplicado.

Independent Test: Dos fichas gemelas → portal deniega sin citas, enlace deniega, recordatorios no envían y queda incidencia duplicado.

Tests for User Story 2 ⚠️

  • T009 [US2] Test de gemelas en tests/integration/test_identidad_canales.test.ts (portal 409 sin citas + enlace denegado + cero envíos con incidencia duplicado; mismo fichero que T006: sin marcador [P])

Implementation for User Story 2

  • T010 [US2] Cubrir denegación por duplicado sin fugas en app/api/portal/sesion/route.ts y lib/enlace-verificado.ts (aviso FR-004 + teléfono, sin mostrar ni cancelar ninguna cita)
  • T011 [US2] Cubrir rama duplicado/incorrecto sin envío vía decidirEnvioRecordatorio en lib/identidad.ts (devuelve enviar: false + motivo para el informe de incidencias)

Checkpoint: At this point, User Stories 1 AND 2 should both work independently


Phase 5: User Story 3 - Sesión que caduca y cierra de verdad (Priority: P2)

Goal: Cookie firmada con 30 min deslizantes, «Cerrar sesión» instantáneo, sin persistencia más allá de la cookie.

Independent Test: 30 min sin actividad exige reidentificación; cerrar sesión invalida el token al instante; cero restos en navegador.

Tests for User Story 3 ⚠️

  • T012 [P] [US3] Test unitario de sesión en tests/unit/test_sesion_paciente.test.ts (caducidad 30 min, renovación con uso, cierre instantáneo, firma inválida rechazada)
  • T013 [US3] Test de rutas de sesión en tests/integration/test_identidad_canales.test.ts (cookie citaclara_portal, cierre limpia cookie, token reutilizado rechazado; mismo fichero que T006/T009: sin [P])

Implementation for User Story 3

  • T014 [US3] Implementar crearSesionPortal, verificarSesionPortal, renovarSesionPortal y cerrarSesionPortal en lib/sesion-paciente.ts (HMAC + Map en memoria + limpieza perezosa, FR-005)
  • T015 [US3] Implementar DELETE /api/portal/sesion/route.ts y emisión/renovación de cookie en app/api/portal/sesion/route.ts (httpOnly, SameSite=Lax, Max-Age=1800, sin localStorage)

Checkpoint: All user stories should now be independently functional


Phase 6: User Story 4 - Enlace verificado que cierra la deuda (Priority: P2)

Goal: Token firmado citaId + pacienteId con caducidad min(inicio, envío+72h) y antiflood 10/h que ejecuta cancelarCita solo sobre su cita.

Independent Test: Enlace vigente sin sesión opera solo sobre su cita; caducado o con flood se rechaza sin mutar.

Tests for User Story 4 ⚠️

  • T016 [P] [US4] Test unitario de enlace en tests/unit/test_enlace.test.ts (vigente verifica, caducado por inicio y por 72 h rechaza, token de otra cita no cruza, >10/h bloquea)
  • T017 [US4] Test de extremo a extremo del enlace contra cancelarCita en tests/integration/test_identidad_canales.test.ts (vigente aplica solo su cita, caducado/flood/ajeno no mutan; mismo fichero: sin [P])

Implementation for User Story 4

  • T018 [US4] Implementar crearEnlaceVerificado, verificarEnlace y registrarIntentoEnlace en lib/enlace-verificado.ts (firma HMAC, caducidad min(inicio, +72h), antiflood en memoria, FR-006)
  • T019 [US4] Aceptar token de enlace verificado para origen: email en app/api/citas/[id]/cancelar/route.ts (verifica firma/caducidad/flood/coincidencia citaId, deriva pacienteIdVerificado a ejecutarCancelarCita; sin transición propia)

Checkpoint: All user stories should now be independently functional


Phase 7: Polish & Cross-Cutting Concerns

Purpose: Puertas de merge de la constitución y la spec

  • T020 [P] Validar quickstart.md de la 007 (matriz US1, gemelas US2, caducidad/cierre US3, vigente/caducado/flood/ajeno US4, grep SC-005)
  • T021 [P] Verificar SC-005 por grep: unicidad de normalización en lib/identidad.ts, cero merge/fusión, ningún canal con avisos propios fuera del catálogo
  • T022 [P] Pasar npm run typecheck, npm run lint, npm test y npm run comprobar:es en verde

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): No dependencies - can start immediately
  • Foundational (Phase 2): Depends on Setup completion - BLOCKS all user stories
  • User Stories (Phase 3+): All depend on Foundational phase completion
    • User stories can then proceed in parallel (if staffed)
    • Or sequentially in priority order (P1 → P2 → P3)
  • Polish (Final Phase): Depends on all desired user stories being complete

User Story Dependencies

  • User Story 1 (P1): Can start after Foundational (Phase 2) - No dependencies on other stories
  • User Story 2 (P1): Can start after Foundational (Phase 2) - May integrate with US1 but should be independently testable
  • User Story 3 (P2): Depends on Foundational + US1/US2 (sesión presupone identidad); independently testable con reloj controlado
  • User Story 4 (P2): Depends on Foundational + US1–US3 (enlace requiere identidad y cancelarCita 005); independently testable con token

Within Each User Story

  • Tests (if included) MUST be written and FAIL before implementation
  • Models before services
  • Services before endpoints
  • Core implementation before integration
  • Story complete before moving to next priority

Parallel Opportunities

  • T002 y T005 pueden ir en paralelo (distintos ficheros)
  • T012 y T016 pueden ir en paralelo (distintos ficheros unitarios)
  • T006, T009, T013, T017 comparten tests/integration/test_identidad_canales.test.ts: redactar en secuencia (sin [P] entre ellos)
  • T020, T021, T022 (polish) pueden ir en paralelo

Parallel Example: User Story 1

# Redactar los tests de User Story 1 juntos:
Task: "Test de resolución portal + recordatorio con la matriz de variantes en tests/integration/test_identidad_canales.test.ts"

Implementation Strategy

MVP First (User Story 1 Only)

  1. Complete Phase 1: Setup
  2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
  3. Complete Phase 3: User Story 1
  4. STOP and VALIDATE: Test User Story 1 independently
  5. Deploy/demo if ready

Incremental Delivery

  1. Complete Setup + Foundational → Foundation ready
  2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
  3. Add User Story 2 → Test independently → Deploy/Demo
  4. Add User Story 3 → Test independently → Deploy/Demo
  5. Add User Story 4 → Test independently → Deploy/Demo
  6. Each story adds value without breaking previous stories

Notes

  • [P] tasks = different files, no dependencies
  • [Story] label maps task to specific user story for traceability
  • Each user story should be independently completable and testable
  • Verify tests fail before implementing
  • Commit after each task or logical group
  • Stop at any checkpoint to validate story independently
  • Trazabilidad FR-007: ninguna tarea fusiona ni reasigna fichas/citas/envíos; la fusión queda fuera para spec posterior