RF16: Usuario registra ingresos mensuales
Descripción
Como usuario autenticado, quiero registrar mis ingresos mensuales recurrentes (sueldo, renta, etc.) para que Finnova calcule mi presupuesto y capacidad de ahorro.
A diferencia de un ingreso puntual (RF19), aquí se define un ingreso recurrente con periodicidad mensual. El monto se cifra a nivel de campo.
| Campo | Valor |
|---|---|
| Módulo | Finance Data Collection (FDC) Module |
| Actor | Usuario autenticado |
| Endpoint | POST /finance/recurring-incomes |
| Precondiciones | Sesión activa |
| Prioridad | Alta (MVP) |
| Etapa | MVP |
| Requisitos relacionados | RF17, RF19, RF12 |
Reglas de negocio
- RN-16.1 — Un ingreso mensual tiene concepto, monto, día del mes y (opcional) fecha de fin.
- RN-16.2 — El monto se cifra a nivel de campo (AES-256-GCM, clave por usuario).
- RN-16.3 — Los ingresos recurrentes se proyectan al presupuesto del periodo actual y futuros.
- RN-16.4 — El usuario puede editar o eliminar un ingreso recurrente.
Validaciones de entrada
| Campo | Reglas | Mensaje de error |
|---|---|---|
concept | Obligatorio. 2–80 caracteres. | "Ingresa un concepto válido." |
amount | Obligatorio. Numérico > 0. Máx. 2 decimales. | "Ingresa un monto válido mayor a 0." |
dayOfMonth | Obligatorio. Entero 1–31. | "Selecciona un día válido del mes." |
currency | ISO 4217 (default MXN). | "Moneda no válida." |
Se valida que
amountsea numérico (no texto) y se usan consultas parametrizadas; no se aceptan inyecciones SQL.
Criterios de aceptación
Escenario 1: Registro exitoso
Dado que ingreso un concepto, monto positivo y día del mes válidos,
Cuando guardo el ingreso mensual,
Entonces el sistema lo persiste (monto cifrado) y responde 201 Created,
Y el dashboard refleja el ingreso recurrente en el presupuesto.
Escenario 2: Monto inválido
Dado que ingreso un monto ≤ 0, no numérico o con más de 2 decimales,
Cuando intento guardar,
Entonces el sistema responde 400 con "Ingresa un monto válido mayor a 0".
Escenario 3: Campos obligatorios faltantes
Dado que dejo el concepto o el día del mes vacíos,
Cuando intento guardar,
Entonces el sistema responde 400 con el mensaje del campo afectado.
Escenario 4: Entrada no esperada (seguridad)
Dado que ingreso letras en el monto o una cadena con inyección SQL en el concepto, Cuando el backend valida, Entonces la entrada se rechaza y la inyección no se ejecuta.
Criterios no funcionales
- Monto cifrado en reposo; respuesta < 1 s.
- Comunicación TLS 1.2+.