Quickstart — validar la 005 de punta a punta

Guía runnable (sin código de implementación; este se genera en /speckit.tasks + /speckit.implement). Referencias: contracts/cancelar-cita.md, data-model.md.

Requisitos

Node 22, Docker + Compose, Postgres 16. Variables: DATABASE_URL, TZ=Europe/Madrid.

Arranque

cd tema5/citaclara
cp .env.example .env
docker compose up -d db
npm install
npx prisma migrate dev   # incluye XXXX_005_cancelacion_paciente (telefono + cancelacionOrigen + canceladaEn)
npm run seed             # Eleva con telefono
npm run dev

Validación por historia (trazable a spec)

ID Escenario Comando / pasos Esperado
US1/portal Cita reservada con inicio − ahora ≥ 24 h, confirmar desde portal PATCH /api/citas/[id]/cancelar {pacienteId, origen: portal} 200 aplicada, estado cancelada, ficha «…desde el portal el DD/MM/AAAA a las HH:MM»
US1/email Idéntico desde enlace vigente con confirmación mismo PATCH con origen: email 200 aplicada, ficha «…desde el email el …»
US1/sin-confirmación Visitar página/enlace sin confirmar (GET) GET ficha/enlace reservada, tramo ocupado, sin escritura
US2/plazo inicio − ahora = 23 h 59 min PATCH en plazo vencido 422 PLAZO_VENCIDO + teléfono, sigue reservada
US2/borde inicio − ahora = 24 h 00 min PATCH al borde 200 aplicada (borde incluido, 006 FR-005)
US2/final completada/no_asistida PATCH 409 ESTADO_FINAL + teléfono, sin mutar
US2/duplicada segunda cancelación PATCH ×2 primera aplicada, segunda YA_CANCELADA
US2/ajena cita de otra ficha PATCH con pacienteId propio 403 CITA_AJENA genérico, sin mutar ni revelar
US2/enlace sin verificación PATCH sin sesión/token ENLACE_INVALIDO + teléfono, sin mutar
US3/concurrente doble PATCH en Promise.all npm test -- cancelacion exactamente una aplicada, otra YA_CANCELADA
US3/carrera paciente confirma mientras recepción marca completada PATCH cancelar ∥ PATCH estado una aplica, la otra ESTADO_FINAL/YA_CANCELADA
RN1 tramo liberado reutilizable POST /api/citas mismo tramo tras aplicada 201 (cero solapes vigentes)

Suites

npm test                    # Vitest unit + integración (incl. concurrente) — todo verde para merge
npm run comprobar:es        # ningún string visible fuera de es-ES; catálogo con teléfono

Puerta de merge (constitución): suite verde + prueba concurrente verde + textos es-ES + grep de que portal/recordatorios no implementan su propia transición reservada → cancelada (SC-004) + revisión de simplicidad (sin tablas/endpoints fuera de data-model.md/contracts/).