Saltar al contenido principal

RF01: Usuario registra cuenta

Descripción

Como usuario no registrado, quiero crear una cuenta en Finnova con mi nombre, correo y contraseña para acceder a la aplicación y empezar a administrar mi salud financiera.

El registro crea el usuario en la Finnova DB, abre la primera sesión del esquema de doble token y registra el consentimiento de privacidad exigido por la LFPDPPP (los datos financieros son datos sensibles que requieren consentimiento explícito). La contraseña nunca se almacena en claro: se hashea con Argon2id según la Estrategia de Cifrado y Almacenamiento.

CampoValor
MóduloAuth Module
ActorUsuario no registrado
EndpointPOST /auth/register
PrecondicionesNo existe una cuenta activa con el mismo correo
PrioridadAlta (MVP)
EtapaMVP
Requisitos relacionadosRF02 (login), RF03 / RF04 (login social), RF11 (recuperar contraseña), RF70 (consentimientos)

Reglas de negocio

  • RN-01.1 — Un correo solo puede estar asociado a una cuenta activa. Si ya existe, el registro se rechaza.
  • RN-01.2 — El registro requiere aceptar el aviso de privacidad y otorgar consentimiento explícito de tratamiento de datos financieros sensibles. Sin consentimiento no se crea la cuenta (ver Compliance y Privacidad §6). Este consentimiento se persiste como el registro privacy del modelo de consentimientos granulares (RF70); los consentimientos opcionales (análisis con IA, conexión bancaria, marketing) se otorgan por separado y no se asumen en el registro.
  • RN-01.3 — Al registrarse se crea automáticamente la primera sesión (par access token + refresh token) ligada al dispositivo, según el Control de Sesiones.
  • RN-01.4 — El usuario nuevo inicia en el plan Gratuito (límite de 2 dispositivos).
  • RN-01.5 — La contraseña se almacena únicamente como hash Argon2id; jamás se registra en logs ni se devuelve en la respuesta.

Validaciones de entrada

CampoReglasMensaje de error
firstNameObligatorio. 2–50 caracteres. Solo letras (incl. acentos), espacios, guion y apóstrofo."Ingresa un nombre válido."
lastNameObligatorio. 2–50 caracteres. Mismo conjunto de caracteres que firstName."Ingresa apellidos válidos."
emailObligatorio. Formato RFC 5322. Máx. 254 caracteres. Se normaliza a minúsculas."Ingresa un correo electrónico válido."
passwordObligatorio. 8–64 caracteres. Al menos 1 mayúscula, 1 minúscula y 1 número."La contraseña debe tener al menos 8 caracteres, una mayúscula, una minúscula y un número."
privacyConsentObligatorio. Debe ser true."Debes aceptar el aviso de privacidad para continuar."

Toda la entrada se valida en el backend con el DTO del módulo (auth.dto.ts) usando consultas parametrizadas; no se aceptan inyecciones SQL ni payloads con caracteres de control. La validación de cliente es solo para UX y nunca sustituye la del servidor.

Criterios de aceptación

Escenario 1: Registro exitoso (happy path)

Dado que soy un usuario no registrado y completé nombre, apellidos, un correo no usado y una contraseña válida, Y acepté el aviso de privacidad, Cuando envío el formulario de registro, Entonces el sistema crea mi usuario con la contraseña hasheada con Argon2id, Y registra la fecha de consentimiento de privacidad, Y crea la primera sesión asociada a mi dispositivo, Y recibo un access_token (JWT, 15 min) y un refresh_token (opaco, 30 días) con respuesta 201 Created, Y quedo autenticado en el plan Gratuito.

Escenario 2: Correo ya registrado

Dado que ya existe una cuenta con el correo ana@ejemplo.com, Cuando intento registrarme con ese mismo correo, Entonces el sistema rechaza el registro con 409 Conflict, Y muestra el mensaje "Este correo ya está registrado. ¿Quieres iniciar sesión?", Y no se crea ningún usuario ni sesión.

Escenario 3: Validación de campos

Dado que estoy en el formulario de registro, Cuando dejo un campo obligatorio vacío o ingreso un valor con formato inválido (correo sin @, contraseña corta, nombre con números), Entonces el sistema no envía la solicitud o responde 400 Bad Request, Y muestra el mensaje de error correspondiente del campo afectado, Y ningún dato se persiste.

Escenario 4: Consentimiento de privacidad no otorgado

Dado que completé todos los campos correctamente pero no marqué la casilla de aviso de privacidad, Cuando intento enviar el formulario, Entonces el botón de registro permanece deshabilitado (o el backend responde 400), Y se muestra "Debes aceptar el aviso de privacidad para continuar".

Escenario 5: Entradas no esperadas y seguridad

Dado que envío campos excesivamente largos (p. ej. correo > 254 caracteres) o cadenas con intento de inyección SQL (' OR 1=1 --), Cuando el backend procesa la solicitud, Entonces la entrada se rechaza con 400 Bad Request por validación de longitud/formato, Y la consulta usa parámetros enlazados, por lo que la inyección no se ejecuta, Y el evento se registra en logs sin exponer datos sensibles.

Criterios no funcionales

  • La respuesta del endpoint debe completarse en < 1.5 s en condiciones normales (el costo de Argon2id es intencional: memoryCost: 64MB, timeCost: 3).
  • Toda la comunicación viaja sobre TLS 1.2+ (HTTPS Listener del Load Balancer).
  • El refresh_token se guarda en SecureStore del dispositivo; el access_token solo en memoria (ver Cifrado §7).
  • La contraseña no aparece en logs, en la respuesta ni en mensajes de error.

Diagrama de secuencia