Tasks: Cancelación por el paciente (005)

Task list template for feature implementation

Input: Design documents from /specs/005-cancelacion-paciente/ (spec.md, plan.md, research.md, data-model.md, contracts/cancelar-cita.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 rechazos, bordes de 24 h y concurrencia con una sola aplicada (SC-001…SC-003) 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: Base de BD y verificación del punto de partida

✓- [X] T001 Verificar migración base y esquema actual en prisma/schema.prisma (ausencia de Clinica.telefono y de columnas de traza) ✓- [X] T002 [P] Añadir telefono a la semilla Eleva en prisma/seed.ts y lib/semilla.ts (número español verosímil)


Phase 2: Foundational (Blocking Prerequisites)

Purpose: Esquema, catálogo y decisión pura que bloquean todas las historias

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

✓- [X] T003 Crear migración prisma/migrations/XXXX_005_cancelacion_paciente/migration.sql (Clinica.telefono con DEFAULT '910123456' + backfill UPDATE de filas existentes antes de SET NOT NULL, Cita.cancelacionOrigen, Cita.canceladaEn) y aplicar en prisma/schema.prisma ✓- [X] T004 Añadir ESQUEMA_CANCELACION_PACIENTE en lib/validacion.ts (pacienteId uuid, origen portal|email) ✓- [X] T005 Implementar decidirCancelacion + AVISOS_CANCELACION en lib/cancelacion.ts (orden ENLACE_INVALIDO → CITA_AJENA → YA_CANCELADA/ESTADO_FINAL → PLAZO_VENCIDO, 006 FR-005, teléfono interpolado) ✓- [X] T006 [P] Test unitario del catálogo y bordes en tests/unit/test_cancelacion.test.ts (24 h 00 min dentro, 23 h 59 min fuera, textos con teléfono) — debe FALLAR antes de T005

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


Phase 3: User Story 1 - Cancelar en plazo desde cualquier canal (Priority: P1) 🎯 MVP

Goal: cancelarCita aplica reservada → cancelada con confirmación desde portal o email, libera el tramo RN1 y deja traza visible.

Independent Test: Cita reservada en plazo + confirmación por cada origen → aplicada, cancelada, tramo libre y ficha «Cancelada por el paciente desde el portal/email el DD/MM/AAAA a las HH:MM». Visita sin confirmación no muta.

Tests for User Story 1 ⚠️

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

✓- [X] T007 [US1] Test de integración aplicada por portal y email en tests/integration/test_cancelacion_paciente.test.ts (estado, tramo libre reutilizable con POST /api/citas, ficha con origen) ✓- [X] T008 [US1] Test de que GET/visualización no escribe en tests/integration/test_cancelacion_paciente.test.ts (mismo fichero que T007: redactar en secuencia, sin marcador [P])

Implementation for User Story 1

✓- [X] T009 [US1] Implementar ejecutarCancelarCita en lib/cancelacion.ts (transacción serializable, capturarAhora, escritura condicional updateMany, canceladaEn/cancelacionOrigen, reintento P2034) ✓- [X] T010 [US1] Implementar PATCH /api/citas/[id]/cancelar/route.ts (zod, identidad verificada 007, contrato contracts/cancelar-cita.md, fichaTexto con formatearFechaHora) ✓- [X] T011 [US1] Registrar solo rechazos en log de servidor con origen, instante y código en lib/cancelacion.ts

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


Phase 4: User Story 2 - Rechazos que nunca mutan (Priority: P1)

Goal: Matriz de rechazos con código y texto exactos sin mutar nada.

Independent Test: PLAZO_VENCIDO, ESTADO_FINAL/YA_CANCELADA, CITA_AJENA, ENLACE_INVALIDO, ORIGEN_INVALIDO → estado inmutable y aviso exacto.

Tests for User Story 2 ⚠️

✓- [X] T012 [US2] Test de matriz de rechazos en tests/integration/test_cancelacion_paciente.test.ts (cada caso verifica estado inmutable + texto con teléfono; mismo fichero que T007/T008: sin marcador [P])

Implementation for User Story 2

✓- [X] T013 [US2] Cubrir CITA_AJENA sin revelar datos y ENLACE_INVALIDO previo a toda lectura en lib/cancelacion.ts y app/api/citas/[id]/cancelar/route.ts ✓- [X] T014 [US2] Cubrir ORIGEN_INVALIDO (422, sin mutar) en app/api/citas/[id]/cancelar/route.ts

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


Phase 5: User Story 3 - Concurrencia que solo aplica una vez (Priority: P2)

Goal: Doble clic / doble petición / carrera con recepción → exactamente una aplicada.

Independent Test: N ejecuciones concurrentes → una aplicada, resto YA_CANCELADA/ESTADO_FINAL, cero dobles efectos.

Tests for User Story 3 ⚠️

✓- [X] T015 [US3] Test concurrente Promise.all doble PATCH en tests/integration/test_cancelacion_paciente.test.ts (exactamente una aplicada; mismo fichero: sin [P]) ✓- [X] T016 [US3] Test de carrera contra PATCH /api/citas/[id]/estado a completada en tests/integration/test_cancelacion_paciente.test.ts (mismo fichero: sin [P])

Implementation for User Story 3

✓- [X] T017 [US3] Endurecer reintento y relectura post-carrera en lib/cancelacion.ts (perdedora devuelve YA_CANCELADA o ESTADO_FINAL, sin estados intermedios)

Checkpoint: All user stories should now be independently functional


Phase 6: Polish & Cross-Cutting Concerns

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

✓- [X] T018 [P] Validar quickstart.md de la 005 (tabla de escenarios portal/email/rechazos/concurrente/RN1) ✓- [X] T019 [P] Verificar SC-004 por grep: portal/recordatorios no implementan su propia transición reservada → cancelada fuera de lib/cancelacion.ts ✓- [X] T020 [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): Can start after Foundational (Phase 2) - May integrate with US1/US2 but should be independently testable

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 T006 pueden ir en paralelo (distintos ficheros)
  • T007, T008, T012, T015, T016 comparten tests/integration/test_cancelacion_paciente.test.ts: redactar en secuencia (sin [P] entre ellos)
  • T018, T019, T020 (polish) pueden ir en paralelo

Parallel Example: User Story 1

# Redactar los tests de User Story 1 juntos:
Task: "Test de integración aplicada por portal y email en tests/integration/test_cancelacion_paciente.test.ts"
Task: "Test de que GET/visualización no escribe en tests/integration/test_cancelacion_paciente.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. 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-008: cancelacionOrigen/canceladaEn solo se informan en aplicada por paciente; cancelaciones de recepción dejan NULL