Add planning docs, design system, and Stitch mockups

- CLAUDE.md: project guidance (stack, domain model, auth, i18n, gotchas)
- DESIGN.md: full design system spec derived from Stitch mockups (slate
  monochrome, Inter, shadcn-svelte, screen patterns for all 5 views)
- README.md: development plan with Justfile commands
- analysis/: functional spec (domain model, use cases, business rules)
- plan/: phase-by-phase implementation plans (Fase 0–4)
- .stitch/designs/: generated mockups (lists, shopping session, notes,
  tasks, list detail with frequency chips)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-12 06:35:07 +02:00
commit f5903ef442
15 changed files with 2008 additions and 0 deletions

View File

@@ -0,0 +1,541 @@
# Análisis Funcional — App de Gestión del Colectivo
> **Propósito:** Base para generación de plan de desarrollo con Claude Code
> **Plataforma objetivo:** Web + Mobile (iOS / Android) — paridad desde el día uno
> **Enfoque:** Gestión colaborativa del colectivo: listas de la compra (núcleo), tareas y notas (complemento)
> **Usuarios principales:** Familias y parejas con uso compartido frecuente
> **Stack tecnológico:** A definir tras revisión del plan
---
## Contexto y Objetivo
Desarrollar una aplicación de gestión doméstica centrada en la colaboración familiar en tiempo real. El producto resuelve el problema concreto de coordinar la compra, las tareas del colectivo y las notas entre los miembros de una familia o pareja, desde cualquier dispositivo y sin fricciones.
La unidad organizativa central es el **Colectivo**: una entidad compartida a la que pertenecen todos los contenidos, en lugar del modelo usuario-céntrico habitual. Esto refleja la realidad de uso: la lista de la compra no es de una persona, es del colectivo.
---
## 1. Módulos del Sistema
### 1.1 Colectivo y Miembros
### 1.2 Lista de la Compra
### 1.3 Tareas
### 1.4 Notas
### 1.5 Autenticación y Usuarios
### 1.6 Sincronización y Offline
### 1.7 Búsqueda
---
## 2. Módulo: Colectivo y Miembros
Este módulo es la base de toda la arquitectura. Sin colectivo no hay contenido compartido.
### 2.1 Concepto de Colectivo
Un **Colectivo** es el espacio compartido de una familia o grupo de convivencia. Agrupa listas de la compra, tareas y notas. Cada usuario pertenece a uno o más colectivos, aunque el caso habitual es uno.
```
Colectivo
└── tiene muchos Miembros (con rol)
└── tiene muchas Listas de la Compra
└── tiene muchas Listas de Tareas
└── tiene muchas Notas
```
### 2.2 Roles dentro del Colectivo
| Rol | Descripción | Permisos |
|-----|-------------|----------|
| Administrador | Creador del colectivo o promovido por otro admin | CRUD completo + gestión de miembros + disolver colectivo |
| Miembro | Miembro activo del colectivo | CRUD sobre todo el contenido del colectivo |
| Invitado | Acceso temporal o de solo lectura | Solo lectura; no puede crear ni editar |
> **Decisión de diseño:** El modelo de permisos es deliberadamente simple. En un contexto familiar no tiene sentido granularidad fina por recurso. Si se necesita privacidad, el mecanismo es crear un colectivo adicional (ej: colectivo personal).
### 2.3 Atributos
```
Colectivo {
id: UUID
nombre: string
emoji: string | null ← identificador visual rápido
creado_por: UUID
creado_en: timestamp
}
MiembroColectivo {
colectivo_id: UUID
usuario_id: UUID
rol: enum(administrador | miembro | invitado)
unido_en: timestamp
invitado_por: UUID
}
InvitacionColectivo {
id: UUID
colectivo_id: UUID
email: string
token: string ← link de invitación único
rol_asignado: enum(miembro | invitado)
expira_en: timestamp ← 7 días por defecto
aceptada: boolean
}
```
### 2.4 Casos de Uso
| ID | Caso de uso | Actor | Descripción |
|----|-------------|-------|-------------|
| CU-H01 | Crear colectivo | Usuario autenticado | Define nombre y emoji; queda como administrador |
| CU-H02 | Invitar miembro | Administrador | Introduce email + rol → se envía link de invitación |
| CU-H03 | Aceptar invitación | Invitado | Accede al link → registra cuenta si no tiene → se une al colectivo |
| CU-H04 | Cambiar rol de miembro | Administrador | Promueve a administrador o degrada a invitado |
| CU-H05 | Expulsar miembro | Administrador | El miembro pierde acceso inmediato al colectivo y su contenido |
| CU-H06 | Abandonar colectivo | Miembro / Invitado | El usuario sale del colectivo; el contenido permanece |
| CU-H07 | Cambiar nombre / emoji | Administrador | Edición del colectivo visible para todos los miembros |
| CU-H08 | Disolver colectivo | Administrador | Elimina el colectivo y todo su contenido de forma permanente |
| CU-H09 | Cambiar de colectivo activo | Usuario con varios colectivos | Selector de colectivo visible en la navegación principal |
### 2.5 Flujo: Incorporación de nuevo miembro (CU-H02 → CU-H03)
```
[Administrador abre "Gestionar miembros" → "Invitar"]
Introduce email + selecciona rol (miembro / invitado)
Sistema genera link único con token (expira en 7 días)
Sistema envía email con link
¿El email ya tiene cuenta?
SÍ → Al abrir el link: confirmación de unión con un tap
NO → Al abrir el link: flujo de registro simplificado → confirmación de unión
Miembro queda activo en el colectivo
Todos los miembros reciben notificación: "[Nombre] se ha unido al colectivo"
El nuevo miembro ve inmediatamente todo el contenido del colectivo
```
---
## 3. Módulo: Lista de la Compra
Módulo principal del producto. Debe ser la experiencia más pulida y rápida de la app.
### 3.1 Modelo de Datos
```
ListaCompra {
id: UUID
colectivo_id: UUID
nombre: string
estado: enum(activa | completada | archivada)
creado_por: UUID
creado_en: timestamp
completada_en: timestamp | null
}
ItemCompra {
id: UUID
lista_id: UUID
nombre: string
cantidad: decimal | null
unidad: string | null ← "kg", "L", "uds", "paquetes"…
marcado: boolean ← comprado durante sesión de compra
marcado_por: UUID | null
marcado_en: timestamp | null
orden: integer ← posición en la lista
creado_por: UUID
creado_en: timestamp
}
```
### 3.2 Estados de una Lista
```
Activa → En sesión de compra → Completada → Archivada
```
**Reglas de negocio:**
- Solo puede haber una **sesión de compra activa** por lista a la vez.
- Completar una lista no elimina los ítems; quedan como historial.
- Una lista completada puede "reiniciarse": desmarca todos los ítems y vuelve a activa.
- Los ítems marcados durante la sesión registran quién los marcó y cuándo.
### 3.4 Modo "Ir de Compras"
Experiencia de UI dedicada para el momento de estar físicamente en el supermercado. Requisitos:
- **Ítems grandes y fáciles de marcar** con un tap — optimizado para pantalla de teléfono con una mano.
- **Ítems pendientes arriba, marcados abajo** — reordenamiento automático al marcar.
- **Indicador de presencia:** si otro miembro del colectivo también tiene la lista abierta, se muestra su avatar.
- **Sincronización agresiva:** cambios visibles en < 1 segundo entre dispositivos (sin esperar al intervalo normal de sync).
- **Funcional offline:** si se pierde cobertura en el súper, los cambios se sincronizan al recuperar red.
- Botón prominente **"Finalizar compra"** que marca la lista como completada.
### 3.5 Casos de Uso
| ID | Caso de uso | Actor | Descripción |
|----|-------------|-------|-------------|
| CU-C01 | Crear lista | Miembro | Nueva lista vacía |
| CU-C02 | Añadir ítem | Miembro | Nombre + cantidad/unidad opcional; guardado inmediato; muestra sugerencias de ítems frecuentes del colectivo |
| CU-C03 | Editar ítem | Miembro | Modifica nombre, cantidad o unidad |
| CU-C04 | Reordenar ítems | Miembro | Drag & drop manual para organizar por pasillos |
| CU-C05 | Eliminar ítem | Miembro | Borrado con confirmación por deslizamiento (swipe) |
| CU-C06 | Marcar ítem como comprado | Miembro (en sesión) | Tap en checkbox; ítem baja al fondo automáticamente |
| CU-C07 | Desmarcar ítem | Miembro (en sesión) | Tap en ítem marcado; vuelve a pendiente |
| CU-C08 | Iniciar sesión de compra | Miembro | Activa el "Modo ir de compras" con UX dedicada |
| CU-C09 | Finalizar compra | Miembro | Lista pasa a estado completada; se registra timestamp |
| CU-C10 | Reiniciar lista | Miembro | Desmarca todos los ítems; lista vuelve a activa |
| CU-C11 | Eliminar lista | Miembro | Mueve a papelera del colectivo (recuperable 7 días) |
| CU-C12 | Archivar lista completada | Sistema / Miembro | Lista completada pasa a archivo; libera espacio en vista principal |
### 3.6 Recomendaciones de ítems frecuentes
Al añadir un ítem a cualquier lista, el sistema sugiere ítems basándose en el historial de uso del colectivo. Sin IA — frecuencia pura de registros en base de datos.
- **Input vacío:** chips con los 5 ítems más usados del colectivo (acceso rápido)
- **Al escribir:** lista filtrada por prefijo (máx. 10), ordenada por frecuencia
- **Alcance:** compartido entre todos los miembros del colectivo
- **Registro:** trigger en `shopping_items` — automático en cada añadido, sin intervención de la app
- **Normalización:** los nombres se normalizan (`lower(trim(name))`) antes de acumular la frecuencia, evitando duplicados por mayúsculas o espacios
### 3.7 Flujo: Sesión de Compra (CU-C08)
```
[Miembro toca "Ir de compras" en lista activa]
App entra en Modo Compra:
- UI de ítems en formato grande
- Ítems pendientes arriba / marcados abajo
- Indicador de otros miembros presentes en la lista
- Sincronización reforzada (WebSocket activo)
Miembro va marcando ítems conforme los mete en el carro
¿Otro miembro añade ítem desde casa?
→ Aparece en la lista en tiempo real con indicador "Nuevo"
[Miembro toca "Finalizar compra"]
Confirmación: "¿Marcar lista como completada?"
SÍ → Lista pasa a estado completada
Se registra timestamp de finalización
Se sale del Modo Compra
Notificación a otros miembros: "La compra ha sido completada por [Nombre]"
NO → Se mantiene en Modo Compra
```
---
## 4. Módulo: Tareas
Módulo secundario. Gestión simple de tareas del colectivo, sin complejidad de project management.
### 4.1 Modelo de Datos
```
ListaTareas {
id: UUID
colectivo_id: UUID
nombre: string ← ej: "Tareas de la semana", "Reformas pendientes"
creado_por: UUID
creado_en: timestamp
}
Tarea {
id: UUID
lista_id: UUID
titulo: string
completada: boolean
completada_por: UUID | null
completada_en: timestamp | null
orden: integer
creado_por: UUID
creado_en: timestamp
}
```
> **Decisión deliberada:** Sin fechas límite, prioridades ni subtareas en el MVP. El foco es la simplicidad. Si el producto crece, estas features son candidatas naturales a v2.
### 4.2 Estados de una Tarea
```
Pendiente → Completada
(puede desmarcarse → vuelve a Pendiente)
```
### 4.3 Casos de Uso
| ID | Caso de uso | Actor | Descripción |
|----|-------------|-------|-------------|
| CU-T01 | Crear lista de tareas | Miembro | Nueva lista con nombre |
| CU-T02 | Añadir tarea | Miembro | Título; se guarda inmediatamente |
| CU-T03 | Completar tarea | Miembro | Tap en checkbox; registra quién y cuándo |
| CU-T04 | Descompletar tarea | Miembro | Tap en tarea completada; vuelve a pendiente |
| CU-T05 | Editar título de tarea | Miembro | Edición inline |
| CU-T06 | Reordenar tareas | Miembro | Drag & drop |
| CU-T07 | Eliminar tarea | Miembro | Swipe para eliminar con confirmación |
| CU-T08 | Eliminar lista de tareas | Miembro | Elimina la lista y todas sus tareas |
| CU-T09 | Ver quién completó una tarea | Miembro | Tooltip / detalle: "Completada por [Nombre] el [fecha]" |
### 4.4 Reglas de Negocio
- Las tareas completadas permanecen visibles en la lista (no se ocultan automáticamente), hundidas al fondo.
- No existe papelera para tareas individuales: la eliminación es inmediata con confirmación por swipe.
- Una lista de tareas solo puede eliminarse si está vacía o el miembro confirma borrado en cascada.
---
## 5. Módulo: Notas
Módulo de utilidad. Complementa los otros dos módulos para casos como recetas, instrucciones, información del colectivo, etc.
### 5.1 Modelo de Datos
```
Nota {
id: UUID
colectivo_id: UUID
titulo: string (opcional)
contenido: string ← texto plano con Markdown básico
color: enum(8 colores predefinidos) | null
fijada: boolean
archivada: boolean
eliminada: boolean
eliminada_en: timestamp | null
creado_por: UUID
creado_en: timestamp
modificado_por: UUID
modificado_en: timestamp
}
```
> **Scope reducido vs análisis original:** Se eliminan tipos de nota (imagen, audio), historial de versiones y comentarios. Las notas son texto con Markdown básico. Si el producto crece, estas features son candidatas a v2.
### 5.2 Estados de una Nota
```
Activa → [Fijada | Archivada | En papelera → Eliminada permanentemente]
```
**Reglas de negocio:**
- `Fijada` y `Archivada` son mutuamente excluyentes.
- La papelera retiene notas 7 días antes de eliminarlas permanentemente.
- Las notas en papelera no aparecen en búsquedas.
- El guardado es automático.
- Cualquier miembro del colectivo puede editar cualquier nota del colectivo.
### 5.3 Casos de Uso
| ID | Caso de uso | Actor | Descripción |
|----|-------------|-------|-------------|
| CU-N01 | Crear nota | Miembro | Abre editor, introduce contenido, se guarda automáticamente |
| CU-N02 | Editar nota | Miembro | Modifica contenido; se registra modificado_por y modificado_en |
| CU-N03 | Fijar nota | Miembro | Nota aparece en bloque superior del tablero |
| CU-N04 | Archivar nota | Miembro | Sale del tablero principal; accesible por búsqueda |
| CU-N05 | Mover a papelera | Miembro | Va a papelera con timestamp |
| CU-N06 | Restaurar nota | Miembro | Recupera desde papelera o archivo |
| CU-N07 | Eliminar permanentemente | Miembro | Borrado definitivo desde papelera |
| CU-N08 | Cambiar color | Miembro | Selección visual entre colores predefinidos |
| CU-N09 | Duplicar nota | Miembro | Crea copia independiente |
---
## 6. Módulo: Autenticación y Usuarios
### 6.1 Flujos de Autenticación
- Registro con email + contraseña
- Login con email + contraseña
- OAuth — Google (requerido) y Apple (requerido en iOS)
- Recuperación de contraseña vía email
- Sesión persistente con refresh token
- Flujo de registro simplificado al aceptar invitación a colectivo (el email queda prerellenado)
### 6.2 Atributos de Usuario
```
User {
id: UUID
email: string ← único, gestionado por Keycloak
display_name: string
language: enum(en | es) ← preferencia del usuario; default: idioma del navegador
avatar_type: enum(initials | emoji | upload)
avatar_emoji: string | null ← solo cuando avatar_type = emoji (e.g. "🐸")
avatar_url: string | null ← solo cuando avatar_type = upload (Supabase Storage)
created_at: timestamp
last_seen_at: timestamp
}
```
### 6.3 Configuración de usuario
Pantalla `/settings` accesible desde la navegación principal. Permite al usuario editar:
- **Display name** — nombre visible en el colectivo, presencia y avatares
- **Avatar** — tres opciones, excluyentes entre sí:
1. *Initials* (default) — inicial(es) del display name sobre fondo slate
2. *Emoji* — selector de emoji de una lista curada (~40 opciones)
3. *Upload* — foto propia; almacenada en Supabase Storage (bucket privado, URL firmada)
- **Language** — selector entre English y Español; efecto inmediato sin recargar
> **Nota:** El email y la contraseña se gestionan en Keycloak, no en esta pantalla. Incluir un enlace externo a la cuenta de Keycloak para esos cambios.
### 6.3 Reglas de Negocio
- Un usuario puede pertenecer a múltiples colectivos simultáneamente.
- Eliminar una cuenta no elimina el contenido del colectivo; los ítems/tareas/notas creados por ese usuario permanecen.
- Si el único administrador de un colectivo elimina su cuenta, el colectivo queda huérfano → el sistema debe promover automáticamente al miembro más antiguo como administrador antes de permitir la eliminación.
---
## 7. Módulo: Sincronización y Offline
### 7.1 Estrategia Offline-First
El escenario crítico es estar físicamente en un supermercado con cobertura inestable. La app debe ser completamente funcional sin conexión.
- Almacenamiento local: **IndexedDB** en web, **SQLite** en mobile.
- Todas las operaciones se ejecutan primero en local y se sincronizan en segundo plano.
- Al recuperar conexión, se sincronizan todos los cambios pendientes.
- **Resolución de conflictos:** last-write-wins con aviso visual al usuario cuando se detecta sobreescritura de cambios de otro miembro.
- Indicador de estado de sincronización siempre visible en la UI (sincronizado / sincronizando / sin conexión).
### 7.2 Sincronización en Tiempo Real
La sincronización en tiempo real es un requisito no negociable para la lista de la compra compartida.
- **WebSockets** para sesiones de compra activas (presencia + cambios en tiempo real).
- **Polling o SSE** para el resto del contenido (menor frecuencia, menor coste de infraestructura).
- **Indicador de presencia:** cuando dos miembros tienen la misma lista abierta simultáneamente, se muestran los avatares de los miembros presentes.
### 7.3 Prioridades de Sincronización
| Tipo de contenido | Mecanismo | Latencia objetivo |
|-------------------|-----------|-------------------|
| Ítems de lista en sesión de compra activa | WebSocket | < 1 segundo |
| Listas de la compra (fuera de sesión) | SSE / polling | < 5 segundos |
| Tareas | SSE / polling | < 5 segundos |
| Notas | Polling | < 30 segundos |
| Miembros del colectivo | Polling | < 60 segundos |
---
## 8. Módulo: Búsqueda
### 8.1 Alcance
| Ámbito | ¿Incluido? | Notas |
|--------|-----------|-------|
| Listas de la compra activas | ✅ | Busca también en nombres de ítems |
| Listas de la compra archivadas | ✅ | |
| Listas en papelera | ❌ | |
| Plantillas | ✅ | |
| Tareas | ✅ | Busca en títulos de tarea y nombre de lista |
| Notas activas | ✅ | Busca en título y contenido |
| Notas archivadas | ✅ | |
| Notas en papelera | ❌ | |
### 8.2 Filtros
- Por tipo de contenido (lista de compra / tareas / notas)
- Por miembro creador
- Por rango de fechas
- Por estado (activo / archivado / completado)
---
## 9. Reglas de Negocio Globales
| # | Regla |
|---|-------|
| RN-01 | Todo el contenido pertenece al Colectivo, no a un usuario individual. |
| RN-02 | Cualquier miembro activo del colectivo puede crear, editar y eliminar contenido. |
| RN-03 | Solo los administradores pueden gestionar miembros e invitaciones. |
| RN-04 | Solo los administradores pueden disolver el colectivo. |
| RN-05 | El guardado es automático en todos los módulos. No existe botón "Guardar". |
| RN-06 | Offline-first: los cambios locales se aplican inmediatamente y se sincronizan en segundo plano. |
| RN-07 | Los conflictos de sincronización se registran y son visibles al usuario afectado. |
| RN-08 | La búsqueda no opera sobre la papelera. |
| RN-09 | Eliminar una cuenta de usuario no elimina el contenido del colectivo. |
| RN-10 | Un colectivo debe tener siempre al menos un administrador activo. |
| RN-11 | Solo puede existir una sesión de compra activa por lista a la vez. |
| RN-12 | Las plantillas de lista son inmutables durante una sesión de compra activa basada en ellas. |
---
## 10. Requerimientos No Funcionales
- **Sincronización en sesión de compra:** cambios visibles en < 1 segundo entre dispositivos.
- **Sincronización general:** cambios visibles en < 5 segundos entre dispositivos.
- **Offline:** la app debe ser 100% funcional sin conexión en todos los módulos.
- **Seguridad:** datos cifrados en tránsito (TLS) y en reposo; aislamiento estricto entre colectivos.
- **Multiplataforma:** paridad de funcionalidades entre web y mobile desde el día uno.
- **Rendimiento mobile:** el Modo Compra debe funcionar con fluidez en gama media (60fps, respuesta a tap < 100ms).
- **Stack tecnológico:** a definir — el plan de desarrollo debe ser agnóstico al stack.
---
## 11. Entidades del Dominio (Resumen)
```
Usuario
└── pertenece a muchos Colectivos (a través de MiembroColectivo)
Colectivo
├── tiene muchos MiembroColectivo
├── tiene muchas ListasCompra
├── tiene muchas ListasTareas
└── tiene muchas Notas
MiembroColectivo
├── referencia Usuario
├── referencia Colectivo
└── tiene rol: enum(administrador | miembro | invitado)
ListaCompra
├── pertenece a Colectivo
├── tiene muchos ItemCompra
└── puede ser Plantilla (es_plantilla = true)
ItemCompra
└── pertenece a ListaCompra
ListaTareas
├── pertenece a Colectivo
└── tiene muchas Tareas
Tarea
└── pertenece a ListaTareas
Nota
└── pertenece a Colectivo
InvitacionColectivo
└── referencia Colectivo
```
---
## 12. Pantallas Principales del MVP
Esta sección orienta el plan de desarrollo sobre el alcance de UI esperado.
| Pantalla | Descripción |
|----------|-------------|
| Onboarding | Login + creación o unión a colectivo |
| Home | Vista principal con listas activas, tareas pendientes destacadas y notas fijadas |
| Lista de la compra — vista normal | Ítems con cantidad/unidad, opción de editar, añadir y reordenar |
| Lista de la compra — Modo Compra | UI dedicada: ítems grandes, marcado fácil, indicador de presencia |
| Tareas | Lista de tareas con checkboxes |
| Notas | Tablero de notas del colectivo |
| Editor de nota | Editor de texto con Markdown básico |
| Gestión del colectivo | Miembros, roles, invitaciones |
| Búsqueda | Búsqueda global con filtros |
| Configuración de usuario (`/settings`) | Display name, avatar (initials / emoji / upload), idioma |
---
*Documento generado como base para plan de desarrollo. Stack tecnológico a definir tras revisión del plan.*