- 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>
21 KiB
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:
FijadayArchivadason 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í:
- Initials (default) — inicial(es) del display name sobre fondo slate
- Emoji — selector de emoji de una lista curada (~40 opciones)
- 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.