prompt 4G
This commit is contained in:
121
sprints/sprint-4/ETAPA_4G_PROMPT.md
Normal file
121
sprints/sprint-4/ETAPA_4G_PROMPT.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# ETAPA 4G — Submit con instance_id + validación de integridad server-side
|
||||
|
||||
## 1. Objetivo
|
||||
Escribir el submit de v3: persiste las respuestas (incluyendo instancias) y VALIDA la
|
||||
integridad en el servidor contra el esquema antes de insertar. La validación server-side
|
||||
es REQUISITO NO NEGOCIABLE (BRIEF decisión 15). El cliente no es confiable; datos de salud.
|
||||
|
||||
## 2. Contexto previo
|
||||
- El submit de v2 (`app/actions/submit-survey.ts`) NO está conectado y está desactualizado:
|
||||
- `WITH CHECK (true)` en RLS de answers → acepta cualquier insert (sin validación real).
|
||||
- payload plano `Record<code,value>` — sin noción de `instance_id`.
|
||||
- códigos qi_* apuntan a A1/A4/A5 (v2), no existen en v3 (son 2.1/2.4/2.5).
|
||||
- 3 INSERTs sueltos sin transacción → si answers falla, responses/consent quedan huérfanos.
|
||||
- El motor `lib/form-engine.ts` es PURO → se puede correr SERVER-SIDE para validar.
|
||||
NO reescribir la lógica de flujo: reusar el motor.
|
||||
- `answers.instance_id` existe (4A), constraint UNIQUE(response_id, question_id, instance_id).
|
||||
- El estado del wizard ya tiene claves `code:instanceId` (4C/4D).
|
||||
- Se usa anon key respetando RLS (regla 9 de CLAUDE.md) — NUNCA service_role.
|
||||
|
||||
## 3. DECISIONES YA TOMADAS — no consultar de nuevo
|
||||
- Validación de integridad SERVER-SIDE, no negociable.
|
||||
- Reusar `lib/form-engine.ts` en el servidor para validar coherencia de flujo — no duplicar lógica.
|
||||
- El submit rechaza el envío ENTERO si algo no valida — no inserta datos parciales ni inyectados.
|
||||
- El payload del cliente pasa a ser consciente de instancia: `{code, instanceId, value}[]`
|
||||
(o equivalente que preserve la clave compuesta).
|
||||
- Transaccionalidad: las inserciones (consent_records → responses → answers) deben ser atómicas.
|
||||
Evaluar función RPC transaccional (SECURITY DEFINER con validaciones) vs. inserts en el
|
||||
Server Action. Proponé el enfoque más robusto dado que anon no puede hacer múltiples
|
||||
inserts atómicos fácilmente — una RPC transaccional es probablemente lo correcto.
|
||||
- Códigos qi_* actualizados a v3 (2.1 zona, 2.4 edad, 2.5 sector — verificar contra el seed).
|
||||
|
||||
## 4. Validaciones server-side mandatorias
|
||||
Por cada submit recibido, el servidor valida CONTRA EL ESQUEMA de la DB (no contra el cliente):
|
||||
1. **Survey válido y activo:** el `survey_id` existe y está en estado que admite respuestas.
|
||||
2. **Preguntas legítimas:** cada `code` recibido existe y pertenece a ESE survey.
|
||||
3. **Valores válidos:** cada valor es una opción válida de su pregunta (para single/multiple_choice),
|
||||
respeta `max_select`, tipo correcto.
|
||||
4. **Visibilidad coherente:** usando el motor (`resolveScreens`/`resolveVisibility`) con las
|
||||
respuestas recibidas, cada respuesta enviada corresponde a una pregunta que DEBÍA estar
|
||||
visible. Rechazar respuestas a preguntas que el flujo nunca debió mostrar (ej. responder
|
||||
3.2 cuando 3.1='No' las oculta).
|
||||
5. **Instancias legítimas:** cada `instance_id` (familiar_N) corresponde a una instancia
|
||||
realmente generada por su `instance_generator` (4.1) según la respuesta real recibida para 4.1.
|
||||
Rechazar instancias inventadas.
|
||||
6. **Consentimiento requerido presente:** el consentimiento operativo (requerido) está.
|
||||
7. **Requeridas presentes:** las preguntas required visibles tienen respuesta.
|
||||
|
||||
Si CUALQUIERA falla: rechazar el submit completo, no insertar nada, devolver error claro.
|
||||
|
||||
## 5. Tareas
|
||||
### 5.1 Definir el contrato del payload v3
|
||||
Shape consciente de instancia. El wizard ya tiene `state.answers` con claves `code:instanceId`.
|
||||
Definir el payload que el cliente envía y el validador consume.
|
||||
|
||||
### 5.2 Validador server-side (reusando el motor)
|
||||
Módulo/función que recibe el payload + carga el esquema desde la DB + corre las 7 validaciones
|
||||
del punto 4, reusando `lib/form-engine.ts`. Puro y testeable donde se pueda.
|
||||
|
||||
### 5.3 Persistencia transaccional
|
||||
Implementar la inserción atómica (consent_records → responses → answers con instance_id).
|
||||
Proponer e implementar RPC transaccional o mecanismo equivalente. Si una RPC SECURITY DEFINER
|
||||
es el camino, documentar por qué y qué valida internamente.
|
||||
|
||||
### 5.4 Conectar el wizard al submit
|
||||
El botón "Enviar (próximamente)" pasa a enviar de verdad. Manejar estados éxito/error
|
||||
(los stage que 4D dejó sin implementar). Mensajes de error accionables, nunca trace crudo.
|
||||
|
||||
### 5.5 Tests
|
||||
- Validación: submit con respuesta a pregunta oculta → rechazado.
|
||||
- Validación: valor fuera de opciones → rechazado.
|
||||
- Validación: instancia inventada → rechazada.
|
||||
- Validación: sin consentimiento requerido → rechazado.
|
||||
- Happy path: submit completo válido (con instancias) → persiste correctamente con instance_id.
|
||||
- Atomicidad: fallo a mitad → no quedan datos parciales.
|
||||
|
||||
## 6. Entregables (DoD)
|
||||
- [ ] Validación server-side completa (7 validaciones) reusando el motor.
|
||||
- [ ] Submit rechaza envío entero si algo no valida; sin datos parciales.
|
||||
- [ ] Persistencia transaccional (sin huérfanos ante fallo).
|
||||
- [ ] instance_id persistido correctamente por instancia.
|
||||
- [ ] Códigos qi_* actualizados a v3.
|
||||
- [ ] Wizard conectado al submit, estados éxito/error funcionando.
|
||||
- [ ] Tests de las validaciones + happy path + atomicidad.
|
||||
- [ ] anon key, nunca service_role (salvo dentro de RPC SECURITY DEFINER justificada).
|
||||
- [ ] **Validación del director** antes de aplicar a producción.
|
||||
|
||||
## 7. Qué reportar
|
||||
```
|
||||
Verificado:
|
||||
- Validación server-side: 7/7 implementadas, reusando lib/form-engine.ts ✓
|
||||
- Casos rechazados probados: pregunta oculta, valor inválido, instancia falsa, sin consentimiento
|
||||
- Persistencia transaccional vía [RPC / mecanismo] ✓ — atomicidad probada
|
||||
- instance_id persistido: [ejemplo real de filas answers con familiar_1/familiar_2]
|
||||
- Códigos qi_* actualizados a v3 ✓
|
||||
- Wizard conectado, estados éxito/error ✓
|
||||
- Tests: N/N
|
||||
Asumido / decisiones:
|
||||
- [enfoque transaccional y por qué]
|
||||
Hallazgos:
|
||||
- [lo que aparezca]
|
||||
```
|
||||
Reporte con datos concretos (C.4): mostrá filas reales de answers con instance_id tras un
|
||||
submit de prueba con 2 familiares.
|
||||
|
||||
## 8. Qué NO hacer
|
||||
- ❌ No confiar en validación de cliente para integridad (es UX, no seguridad).
|
||||
- ❌ No duplicar la lógica de flujo — reusar el motor server-side.
|
||||
- ❌ No insertar datos parciales si la validación falla.
|
||||
- ❌ No usar service_role fuera de una RPC SECURITY DEFINER justificada y documentada.
|
||||
- ❌ No aplicar a producción sin validación del director.
|
||||
- ❌ No tocar v2.1.0-stable, el seed, ni el motor (salvo para CONSUMIRLO en validación).
|
||||
|
||||
## 9. Versionado
|
||||
```
|
||||
feat(submit): submit v3 con validación de integridad server-side [4G]
|
||||
|
||||
Validación server-side (no negociable) reusando el motor: rechaza respuestas
|
||||
a preguntas ocultas, valores inválidos, instancias falsas, sin consentimiento.
|
||||
Persistencia transaccional con instance_id por instancia. Conecta el wizard.
|
||||
Cierra la falla de WITH CHECK(true): el cliente ya no es fuente de verdad.
|
||||
```
|
||||
Reference in New Issue
Block a user