Saltar a contenido

ADR-028 — Completar y corregir datos del cliente desde la landing

  • Status: accepted (2026-08-23; feature nueva pedida por el operador — el cliente que vuelve debe poder sumar/corregir sus datos)
  • Context: Hoy el caso E (cliente ya registrado que vuelve) es una confirmación de un toque (Pantalla2Confirmar.tsx), sin editar nada. Dos huecos reales: (1) si el cliente no cargó email, no puede sumarlo nunca desde la landing; (2) si tipeó mal el celular, no puede corregirlo — y el celular es el canal para contactar al ganador: un celular mal cargado = premio no entregable. Corregir datos es sensible: el teléfono puede ser compartido, así que no cualquiera que llegue con un voucher debe ver/editar los datos de otro. Sub-caso crítico (origen de los datos): el alta puede ser por escaneo del DNI (los datos vienen del documento) o manual (la persona los tipea — la carga manual siempre está disponible, AC-22). Si el alta fue manual, nombre/apellido/sexo/fecha son tan falibles como el email: un "Gonzáles" por "González" tipeado a mano no puede quedar trabado para siempre. Hoy el backend no sabe si el alta fue por escaneo o a mano — recibe el mismo payload en ambos casos.
  • Alternatives:
  • No tocar nada (statu quo): el cliente nunca completa/corrige desde la landing; todo pasa por el operador en el gestor. Simple, pero un celular mal cargado queda mal para siempre salvo que el operador lo note (y no hay momento en que el cliente pida corregirlo).
  • Mostrar y editar todo siempre: flexible, pero expone datos en un celular potencialmente compartido y permite pisar el contacto de otra persona. Rechazado.
  • Editar gated por presentación del DNI, y con la identidad gobernada por el origen de los datos (elegido): el DNI es la identidad/auth del sistema. Quien presentó el DNI (escaneo o carga manual) puede ver/corregir lo suyo; el reconocimiento por dispositivo (ADR-027) no alcanza para editar. Los campos de identidad son de solo lectura solo cuando vinieron del escaneo (documento = verdad); si el alta fue manual, son corregibles.
  • Decision:
  • Agregar opcional vacío: el confirmar de caso E sigue siendo un toque. Debajo, un link discreto "Agregar {opcional}" aparece solo si el opcional está vacío (hoy el único opcional es email; el celular es obligatorio en el alta, AC-21). Campo inline, opcional, se puede confirmar sin llenarlo. El label dice "Agregar" (no "Modificar"): solo suma lo que falta, sin exponer lo existente.
  • Corregir dato existente: exige haber presentado el DNI en la sesión.
    • Path DNI (caso E del flujo actual — llegó ingresando/escaneando el DNI): aparece "Revisá tus datos" con los campos editables, enmascarados hasta tocar "editar".
    • Path reconocimiento (ADR-027 — reconocido sin pedir DNI): solo confirmar de un toque; para corregir, "Revisar mis datos" pide el DNI primero. En un celular compartido, nadie edita los datos de otro sin tener su DNI en la mano.
  • Origen de los datos (nuevo datos_origen en cliente): la landing YA sabe si escaneó (estado datosEscaneados en Pantalla1bAlta); manda un flag en el alta y el backend persiste datos_origen ∈ { escaneo, manual }. Gobierna la editabilidad de la identidad:

    Campo datos_origen = escaneo datos_origen = manual
    nombre/apellido/sexo/fecha_nacimiento solo lectura (documento = verdad; para cambiar, re-escanear) editable con DNI presentado
    email/celular editable con DNI presentado editable con DNI presentado
  • Re-escaneo corrige y verifica: un cliente manual que escanea el DNI corrige sus datos de identidad Y sube su datos_origen a escaneo (queda verificado por documento → identidad pasa a solo lectura). No se obliga (por eso existe la carga manual), pero es el mejor camino cuando hay cámara.

  • Transacción: un solo submit. "Confirmar y participar" guarda los datos corregidos y suma la chance en una transacción. Una edición NO permitida (identidad escaneada) se rechaza antes de consumir la chance (no gasta el voucher). Abandonar antes de confirmar no persiste cambios. Límite conocido (SCR-001): el consumo de chance vive en su propia transacción REQUIRES_NEW (garantía de AC-05, "un voucher = una chance", intocable). Por eso, en la rara colisión concurrente sobre el mismo cliente (landing vs gestor, o dos pestañas), la participación se registra (chance sumada) pero la corrección se rechaza con 409 y debe reintentarse — nunca hay doble chance ni corrupción silenciosa. Cerrar ese hueco exigiría tocar el aislamiento de consumirChance (riesgo a AC-05); se prioriza el invariante sobre el edge.
  • Auditoría: todo cambio de dato del cliente desde la landing genera un evento interno en tabla nueva evento_dato_cliente (cliente_id, campo, valor_anterior, valor_nuevo, cambiado_en, hash_token, ip) — cubre contacto E identidad manual. Guarda los valores reales (no enmascarados): es un registro interno para investigación antifraude, nunca expuesto por la API pública (mismo criterio que voucher_rechazado y AC-33). El display al usuario va enmascarado.
  • Concurrencia: el path de edición escribe sobre Cliente, que hoy no tiene @Version. Se agrega la columna version a cliente y @Version a la entidad (reusa el patrón de ADR-024). Edición de landing vs gestor sobre el mismo cliente → una gana, la otra 409; la landing re-lee y re-muestra. Sin lost update sobre el celular del ganador.
  • Validación: al corregir se reaplica la validación del alta — celular 10 dígitos normalizado, email con formato, sexo ∈ {M,F,X}, fecha DD/MM/AAAA (AC-21).
  • Consequences:
  • El ciclo se cierra: el cliente puede agregar lo que falta y corregir lo que tipeó mal (contacto siempre; identidad si el alta fue manual), siempre presentando el DNI.
  • El principio "documento = verdad" se aplica donde de verdad corresponde (cuando escaneó), sin trabar al cliente que se registró a mano.
  • El teléfono compartido queda protegido: editar exige el DNI, no basta el reconocimiento.
  • Trazabilidad completa de cambios de datos (antifraude).
  • Schema nuevo: evento_dato_cliente + cliente.version + cliente.datos_origen (migración V12).
  • Atomicidad acotada (SCR-001, aceptado): datos+chance atómicos en el caso común; bajo colisión concurrente, la chance cuenta y la corrección se rechaza 409 (reintentable). Daño real mínimo y recuperable (el cliente conserva su chance; el operador o el próximo voucher corrigen); AC-05 (no doble chance) queda intacto. Decisión del operador: enmendar AC-57, no destabilizar el núcleo.
  • La landing debe transmitir el flag de escaneo en el alta (dato que hoy se pierde).
  • Pantalla2Confirmar.tsx gana estados de UI (agregar / revisar / editar) — acotados, sin salir del presupuesto de la landing (AC-24); la edición no agrega peso crítico.

Implementation Plan

  • Affected paths:
  • backend/.../db/migration/V11__reconocimiento_y_datos_cliente.sqlALTER TABLE cliente ADD version (NOT NULL default 0) + ALTER TABLE cliente ADD datos_origen (CHECK IN ('escaneo','manual'), NOT NULL, default por back-fill según lo que se sepa del padrón existente — o 'manual' conservador) + tabla evento_dato_cliente.
  • backend/.../dominio/Cliente.java@Version Long version + datos_origen (enum STRING).
  • backend/.../dominio/EventoDatoCliente.java (entity) + repositorio.
  • backend/.../participacion/ParticipacionService.java — el alta persiste datos_origen desde el flag del request; método confirmarConDatos(token, dni, cambios, ip) que, en una transacción, valida el DNI presentado, aplica solo los cambios permitidos según datos_origen, escribe evento_dato_cliente y consume la chance (caso E). Rechaza cambios de identidad si el origen es escaneo. El re-escaneo con datos nuevos actualiza identidad y sube datos_origen a escaneo.
  • backend/.../api/ParticipacionController.java — extender POST /api/participacion/confirmar y .../alta para transportar el flag de escaneo y los cambios editados opcionales.
  • backend/.../api/dto/*AltaRequest/ConfirmarRequest: flag datosDeEscaneo + cambios opcionales.
  • landing/src/screens/Pantalla1bAlta.tsx — enviar datosDeEscaneo según datosEscaneados.
  • landing/src/screens/Pantalla2Confirmar.tsx — "Agregar {email}" (solo si vacío) + "Revisá tus datos" (editable según DNI presentado + datos_origen) + enmascarado hasta editar + "escaneá para corregir" cuando origen manual.
  • landing/src/api/client.ts + types/api.ts — extender los requests con el flag y los cambios.
  • Patterns: @Version optimista = ADR-024. Registro interno no expuesto = voucher_rechazado. Validación de campos = la del alta (AC-21).
  • Tests: editar celular por path DNI → guardado + evento_dato_cliente escrito; editar apellido con datos_origen=manual → permitido; editar apellido con datos_origen=escaneo → rechazado; re-escaneo de cliente manual → identidad actualizada + datos_origen pasa a escaneo; editar por path reconocimiento sin DNI → rechazado; edición concurrente landing/gestor → una 409; confirmar guarda datos y chance atómicamente.

Verification

  • [ ] AC-54 — Caso E con opcional vacío: "Agregar {email}" aparece solo si email está vacío; se puede confirmar sin completarlo; completarlo lo guarda junto con la chance en la misma transacción.
  • [ ] AC-55 — Corregir datos exige DNI presentado: por el path DNI los campos permitidos son editables (enmascarados hasta editar); por el path reconocimiento (sin DNI), "Revisar mis datos" exige presentar el DNI antes de editar.
  • [ ] AC-56 — Con datos_origen = escaneo, nombre/apellido/sexo/fecha_nacimiento son de solo lectura en la landing (un intento de modificarlos es rechazado por el backend); email y celular editables con DNI presentado.
  • [ ] AC-57 — Confirmar en caso E guarda los datos corregidos y suma la chance en una sola transacción atómica; abandonar antes de confirmar no persiste cambios.
  • [ ] AC-58 — Todo cambio de dato del cliente genera un evento_dato_cliente interno (cliente, campo, valor anterior→nuevo, timestamp, voucher/ip); nunca aparece en una respuesta de la API pública.
  • [ ] AC-59 — Concurrencia: edición landing vs gestor sobre el mismo cliente → una gana, la otra 409 (bloqueo optimista @Version en Cliente), sin lost update; la corrección reaplica la validación de celular (10 dígitos) y email.
  • [ ] AC-60 — Con datos_origen = manual, nombre/apellido/sexo/fecha_nacimiento son editables con DNI presentado (el cliente corrige su propio typo); escanear el DNI actualiza esos datos y sube datos_origen a escaneo, tras lo cual quedan de solo lectura (AC-56).