# Feature Specification: Ficha de Cliente 360 — CRUD Completo y Consistente

**Feature Branch**: `014-ficha-cliente-dashboard-crud`

**Created**: 2026-09-18

**Status**: Draft

**Input**: Auditoría del panel `/dashboard` (ficha de cliente 360): se identificaron operaciones de
gestión (crear/editar/eliminar) incompletas o inaccesibles para Cuentas Bancarias, Contactos y
Puntos de Suministro, patrones de guardado inconsistentes entre bloques, y falta de retroalimentación
visual (carga/vacío) por sección. Decisión del usuario: mantener el layout actual de tarjetas
(mejorado), sin pasar a pestañas ni acordeón.

> **Constitution (I. Spec-First)**: Este spec MUST ser agnóstico de stack.
> No mencionar Laravel, React, Inertia.js ni rutas de código. El CÓMO va en `plan.md`.

---

## Resumen del problema

El panel de ficha de cliente centraliza la búsqueda de un cliente y la gestión de todos sus datos
relacionados (cuentas bancarias, contactos, documentos, puntos de suministro) desde una sola
pantalla. La intención de diseño es correcta, pero hoy no todos los bloques permiten completar el
ciclo de vida de sus datos: dos de los cuatro bloques no permiten eliminar un registro, uno asume
que el cliente solo puede tener un contacto, y el bloque de puntos de suministro no permite dar de
baja ni activar/suspender un punto completo desde aquí, aunque esa capacidad ya existe en otra parte
del sistema. Además, cada bloque guarda sus cambios de una forma distinta internamente, lo que hace
más difícil mantener el panel y aumenta el riesgo de que una futura corrección se aplique de forma
inconsistente. Finalmente, la pantalla no distingue visualmente entre "todavía cargando", "no hay
datos" y "hubo un error" en cada bloque — todo depende de un indicador de carga global.

Esta feature completa el ciclo de vida de gestión de cada bloque, unifica la forma en que se guardan
los cambios, y mejora la retroalimentación visual de cada tarjeta, sin cambiar la disposición general
de la pantalla (se mantiene la cuadrícula de tarjetas ya conocida por los usuarios).

---

## User Scenarios & Testing *(mandatory)*

### User Story 1 — Eliminar una cuenta bancaria desde la ficha del cliente (Priority: P1)

Como usuario que gestiona los datos de cobro de un cliente, necesito poder eliminar una cuenta
bancaria que ya no corresponde, directamente desde la ficha del cliente, sin tener que buscar esa
opción en otro lugar del sistema.

**Why this priority**: Es la operación de ciclo de vida más básica que falta hoy; su ausencia
obliga a dejar cuentas bancarias obsoletas visibles indefinidamente en la ficha del cliente.

**Independent Test**: Abrir la ficha de un cliente con al menos dos cuentas bancarias, eliminar una
de ellas desde la tarjeta correspondiente, y verificar que desaparece de la lista sin afectar a la
otra ni a ningún otro bloque de la ficha.

**Acceptance Scenarios**:

1. **Given** un cliente con una o más cuentas bancarias, **When** el usuario elige eliminar una de
   ellas, **Then** el sistema pide confirmación explícita antes de proceder.
2. **Given** que el usuario confirma la eliminación, **When** la operación se completa, **Then** la
   cuenta desaparece de la lista sin necesidad de recargar toda la página.
3. **Given** que una cuenta bancaria está referenciada por otro proceso del sistema que impide su
   eliminación, **When** el usuario intenta eliminarla, **Then** el sistema explica el motivo del
   rechazo en vez de fallar sin explicación.

---

### User Story 2 — Gestionar varios contactos por cliente, incluida su eliminación (Priority: P1)

Como usuario que mantiene los datos de contacto de un cliente, necesito poder añadir más de un
contacto cuando el cliente lo requiere, y poder eliminar cualquiera de ellos, en vez de estar
limitado a gestionar uno solo.

**Why this priority**: El modelo de datos ya admite varios contactos por cliente; la limitación es
únicamente de la pantalla, y bloquea un caso de uso real y frecuente (cliente con contacto
administrativo y contacto técnico, por ejemplo).

**Independent Test**: Abrir la ficha de un cliente con un contacto ya registrado, añadir un segundo
contacto, verificar que ambos se listan correctamente, y eliminar uno de los dos verificando que el
otro permanece intacto.

**Acceptance Scenarios**:

1. **Given** un cliente con un contacto ya registrado, **When** el usuario abre la opción de añadir
   contacto, **Then** el sistema permite registrar un contacto adicional sin reemplazar al existente.
2. **Given** un cliente con dos o más contactos, **When** el usuario elige eliminar uno, **Then** el
   sistema pide confirmación y, al aceptar, solo ese contacto desaparece de la lista.
3. **Given** un cliente sin ningún contacto, **When** el usuario abre la ficha, **Then** la opción de
   añadir el primer contacto sigue disponible exactamente igual que hoy.

---

### User Story 3 — Gestionar el ciclo de vida completo de un punto de suministro desde la ficha (Priority: P1)

Como usuario que administra los puntos de suministro de un cliente, necesito poder activar,
suspender o eliminar un punto de suministro completo desde la propia ficha del cliente, sin tener
que salir a otra sección del sistema para completar esa gestión.

**Why this priority**: Es la brecha de mayor impacto operativo detectada: la capacidad ya existe en
el sistema pero es inalcanzable desde el punto donde el usuario normalmente trabaja, obligando a una
navegación adicional innecesaria y propensa a error (buscar el mismo punto de suministro dos veces).

**Independent Test**: Desde la ficha de un cliente con un punto de suministro activo, suspenderlo y
verificar que su estado se refleja de inmediato en la tarjeta; repetir para reactivarlo y para
eliminarlo.

**Acceptance Scenarios**:

1. **Given** un punto de suministro activo listado en la ficha del cliente, **When** el usuario elige
   suspenderlo, **Then** el sistema pide confirmación y, tras aceptarla, el estado visible del punto
   cambia a "suspendido" sin recargar toda la página.
2. **Given** un punto de suministro suspendido, **When** el usuario elige reactivarlo, **Then** el
   sistema lo hace y refleja el nuevo estado de inmediato.
3. **Given** un punto de suministro sin referencias activas que impidan su baja, **When** el usuario
   elige eliminarlo, **Then** el sistema pide confirmación y, tras aceptarla, el punto desaparece de
   la lista.
4. **Given** un punto de suministro con datos que impiden su eliminación (por ejemplo, un contrato
   activo asociado), **When** el usuario intenta eliminarlo, **Then** el sistema explica el motivo
   del rechazo en vez de fallar sin contexto.

---

### User Story 4 — El guardado se comporta igual en todos los bloques de la ficha (Priority: P2)

Como usuario que alterna entre editar cuentas bancarias, contactos, documentos y puntos de
suministro dentro de la misma sesión de trabajo, necesito que el comportamiento al guardar (qué
pasa mientras se guarda, cómo se confirma el éxito, cómo se informa un error) sea el mismo en los
cuatro bloques, para no tener que aprender variaciones de comportamiento entre secciones de la misma
pantalla.

**Why this priority**: No es visible como un fallo puntual, pero es la causa de que corregir un
comportamiento (por ejemplo, un mensaje de error poco claro) hoy deba repetirse de formas distintas
en cada bloque, y de que un usuario nuevo perciba la pantalla como menos predecible.

**Independent Test**: Provocar un error de guardado (por ejemplo, dejar un campo obligatorio vacío)
en cada uno de los cuatro bloques y comparar que el comportamiento de aviso es el mismo en los
cuatro.

**Acceptance Scenarios**:

1. **Given** cualquiera de los cuatro bloques de la ficha, **When** el usuario guarda un cambio
   válido, **Then** el bloque muestra el mismo tipo de confirmación de éxito que los demás bloques.
2. **Given** cualquiera de los cuatro bloques, **When** ocurre un error al guardar, **Then** el
   mensaje de error se presenta de la misma forma (ubicación, estilo, duración) en los cuatro.
3. **Given** que una operación de guardado está en curso en un bloque, **When** el usuario interactúa
   con otro bloque distinto, **Then** puede seguir operando en ese otro bloque con normalidad.

---

### User Story 5 — Cada tarjeta comunica con claridad si está cargando, vacía o con error (Priority: P2)

Como usuario que abre la ficha de un cliente, necesito distinguir de un vistazo si una sección
todavía está cargando sus datos, si no tiene ningún dato que mostrar, o si hubo un problema al
obtenerlos, sin depender de un único indicador de carga para toda la pantalla.

**Why this priority**: Mejora directa de la percepción de fiabilidad de la pantalla — hoy toda la
ficha depende de un solo indicador global, lo que no permite saber si un bloque en particular está
vacío porque el cliente no tiene datos o porque algo falló al cargarlos.

**Independent Test**: Abrir la ficha de un cliente que no tiene ninguna cuenta bancaria registrada y
verificar que la tarjeta correspondiente muestra un estado "sin datos" distinto, visualmente, del
estado de carga y del estado de error.

**Acceptance Scenarios**:

1. **Given** que la ficha del cliente se está cargando, **When** el usuario la abre, **Then** cada
   tarjeta muestra su propio indicador de carga mientras espera sus datos.
2. **Given** un bloque sin ningún registro asociado al cliente, **When** termina de cargar, **Then**
   la tarjeta muestra un mensaje de "sin datos" con la acción para añadir el primero, distinguible
   del estado de carga.
3. **Given** que la carga de los datos de la ficha falla, **When** el usuario ve la pantalla,
   **Then** se le informa del error con la opción de reintentar, sin necesidad de recargar la página
   completa.

---

### Edge Cases

- ¿Qué ocurre si el usuario elimina el único contacto de un cliente que tenía exactamente uno? La
  ficha vuelve al estado "sin contactos" con la opción de añadir el primero, igual que si nunca
  hubiera tenido ninguno.
- ¿Qué pasa si dos personas gestionan la misma ficha de cliente al mismo tiempo y una elimina un
  registro que la otra está editando en ese momento? La segunda persona recibe un aviso claro de que
  el registro ya no existe al intentar guardar, en vez de un error genérico.
- ¿Cómo se comporta la eliminación de un punto de suministro que tiene CUPS eléctrico y de gas
  asociados? El sistema debe dejar claro si la eliminación también afecta a esas referencias o si
  primero deben eliminarse por separado.
- ¿Qué pasa si el usuario intenta eliminar una cuenta bancaria, un contacto o un punto de suministro
  y pierde la conexión durante la operación? El sistema no debe dar por completada la eliminación en
  pantalla hasta confirmar la respuesta del servidor.

---

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: El sistema MUST permitir eliminar una cuenta bancaria de un cliente desde la ficha del
  cliente, con confirmación explícita previa.
- **FR-002**: El sistema MUST permitir registrar más de un contacto por cliente desde la ficha del
  cliente, sin límite artificial de uno solo.
- **FR-003**: El sistema MUST permitir eliminar cualquier contacto de un cliente desde la ficha del
  cliente, con confirmación explícita previa, afectando solo al contacto seleccionado.
- **FR-004**: El sistema MUST permitir cambiar el estado (activar/suspender) de un punto de
  suministro desde la ficha del cliente, reflejando el nuevo estado sin recargar la página completa.
- **FR-005**: El sistema MUST permitir eliminar un punto de suministro completo desde la ficha del
  cliente, con confirmación explícita previa.
- **FR-006**: Cuando una eliminación es rechazada por una restricción de negocio (referencias
  activas que impiden el borrado), el sistema MUST explicar el motivo al usuario en vez de fallar
  sin contexto.
- **FR-007**: El sistema MUST aplicar el mismo comportamiento de confirmación de éxito y de aviso de
  error al guardar en los cuatro bloques de la ficha (cuentas bancarias, contactos, documentos,
  puntos de suministro).
- **FR-008**: Una operación de guardado o eliminación en un bloque de la ficha MUST NOT bloquear la
  interacción del usuario con los demás bloques mientras está en curso.
- **FR-009**: Cada bloque de la ficha MUST mostrar su propio estado de carga mientras obtiene sus
  datos, independiente del estado de los demás bloques.
- **FR-010**: Cada bloque de la ficha MUST distinguir visualmente entre "sin datos" y "cargando", y
  ofrecer la acción de crear el primer registro cuando el bloque está vacío.
- **FR-011**: Si la carga de los datos de la ficha del cliente falla, el sistema MUST informar del
  error y ofrecer una forma de reintentar sin recargar la página completa.
- **FR-012**: La disposición general de la ficha del cliente (cuadrícula de tarjetas, una por
  bloque, visibles simultáneamente) MUST mantenerse tal como está hoy — esta feature no introduce
  navegación por pestañas ni acordeones.

### Key Entities

- **Ficha de Cliente**: Vista consolidada de un cliente y sus datos relacionados, organizada en
  bloques independientes (Datos del cliente, Puntos de Suministro, Contactos, Cuentas Bancarias,
  Documentos).
- **Cuenta Bancaria**: Dato de cobro asociado a un cliente; un cliente puede tener varias.
- **Contacto**: Persona de contacto asociada a un cliente; un cliente puede tener varios (hoy
  limitado a uno solo por la pantalla, no por el modelo de datos).
- **Punto de Suministro**: Ubicación de consumo asociada a un cliente, con un estado (activo,
  suspendido) y referencias CUPS propias.

---

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: Los cuatro bloques de la ficha del cliente (cuentas bancarias, contactos, documentos,
  puntos de suministro) permiten completar el ciclo crear → editar → eliminar sin salir de la ficha,
  frente a los 2 de 4 que lo permiten hoy.
- **SC-002**: Un cliente puede tener registrados y gestionados (añadir/eliminar) 2 o más contactos
  desde la ficha, frente al límite de 1 actual.
- **SC-003**: El 100% de las acciones de eliminación en la ficha piden confirmación explícita antes
  de ejecutarse.
- **SC-004**: El comportamiento de aviso de éxito y de error al guardar es idéntico (mismo
  componente, misma ubicación) en los cuatro bloques.
- **SC-005**: Al abrir la ficha de un cliente, cada tarjeta muestra su propio estado de carga en vez
  de depender únicamente del indicador global de la aplicación.

## Assumptions

- El layout general de la ficha (cuadrícula de tarjetas) se mantiene sin cambios de disposición;
  la mejora es de comportamiento y de retroalimentación visual dentro de cada tarjeta, no de
  reestructuración de la navegación.
- Las capacidades de cambiar estado y eliminar un punto de suministro, y de eliminar una cuenta
  bancaria o un contacto, ya existen como operación en el sistema para otros puntos de acceso; esta
  feature las expone desde la ficha del cliente, no las crea desde cero.
- Las reglas de negocio que determinan cuándo una eliminación debe rechazarse (por ejemplo, un
  contrato activo que impide eliminar un punto de suministro) ya existen o se definirán como parte
  del detalle técnico en `plan.md`; este spec no las redefine, solo exige que su resultado se
  comunique con claridad al usuario.
- No se aborda en esta feature la corrección de la inconsistencia de tipado del bloque de
  Documentos ni ninguna otra deuda técnica de tipado detectada en la auditoría, salvo que sea
  estrictamente necesaria para implementar los requisitos anteriores.
- Esta feature no cubre los hallazgos de integridad de datos (valores nulos inesperados, longitudes
  de texto no validadas) ya tratados en la feature `013-blindaje-backend-integridad-datos`; ambas
  features son complementarias pero independientes.
