Files
collective-lists/README.md
Oier Bravo Urtasun 973f9e413c Fase 0: scaffold monorepo, SvelteKit skeleton, and dev infrastructure
- Turborepo + pnpm workspaces with apps/web and packages/types
- SvelteKit app: Tailwind, Paraglide i18n (en/es), keycloak-js, Supabase client,
  auth/collective stores, PWA service worker skeleton, all route placeholders
- packages/types: domain types (User, Collective, ShoppingList, etc.) and
  database.ts placeholder for generated types
- Justfile with dev, db-*, kc-*, build, backup, restore, deploy recipes
- infra/docker-compose.dev.yml: Postgres 15, GoTrue, PostgREST, Realtime v2.83,
  Storage, Kong (port 8001), Studio, Keycloak 24
- infra/docker-compose.prod.yml, kong.yml, db-init scripts, backup/deploy scripts
- keycloak/realm-export.json with colectivo realm and 5 dev test users
- supabase/config.toml and seed.sql with sample collective and items
- GitHub Actions: ci.yml (lint+typecheck+build) and deploy.yml (GHCR + SSH)
- .env.example documenting all required variables
- Fixed docker-compose issues: Studio image tag, Kong port conflict (8001),
  internal role passwords init script, Realtime METRICS_JWT_SECRET/APP_NAME

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 14:37:51 +02:00

205 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan de Desarrollo — App Gestión del Colectivo
> **Stack:** SvelteKit + Supabase self-hosted + PWA
> **Infraestructura:** Docker Compose (dev local + producción VPS)
> **Última actualización:** Abril 2026
---
## Índice de Fases
| Fase | Archivo | Duración estimada |
|------|---------|-------------------|
| Fase 0 | [fase-0-infraestructura.md](fase-0-infraestructura.md) | 12 semanas |
| Fase 1 | [fase-1-auth-colectivo.md](fase-1-auth-colectivo.md) | 23 semanas |
| Fase 2a | [fase-2a-lista-compra-crud.md](fase-2a-lista-compra-crud.md) | 2 semanas |
| Fase 2b | [fase-2b-realtime-modo-compra.md](fase-2b-realtime-modo-compra.md) | 23 semanas |
| Fase 3 | [fase-3-tareas-notas.md](fase-3-tareas-notas.md) | 12 semanas |
| Fase 4 | [fase-4-busqueda-pulido.md](fase-4-busqueda-pulido.md) | 1 semana |
**Total estimado: 913 semanas**
---
## Stack Tecnológico Confirmado
| Capa | Tecnología | Justificación |
|------|-----------|---------------|
| Frontend / PWA | SvelteKit 2 | Reactividad nativa, bundle pequeño, PWA de primera clase |
| Backend / BaaS | Supabase self-hosted | Realtime, RLS, Storage — Auth delegada a Keycloak |
| Identidad / Auth | Keycloak self-hosted | IdP OIDC/OAuth2, gestión de usuarios, federación futura |
| Base de datos | PostgreSQL 15 (vía Supabase) | Full-text search nativo, `pg_cron` para jobs |
| Tiempo real | Supabase Realtime (WebSocket) | Presencia + cambios en < 1s sin infraestructura extra |
| Offline | IndexedDB vía `idb` | PWA-compatible, sin dependencias nativas |
| PWA | `@vite-pwa/sveltekit` + Workbox | Service Worker, caché offline, instalable |
| Infraestructura dev | Docker Compose + Supabase CLI | Entorno local con Studio + Keycloak + usuarios de prueba |
| Infraestructura prod | Docker Compose + nginx (existente) | Reverse proxy ya operativo en el VPS, gestionado externamente |
| CI/CD | GitHub Actions | Lint, test, deploy vía SSH |
| Email transaccional | Resend | SMTP para invitaciones (Keycloak también lo usa para reset) |
| Backups | `pg_dump` → Backblaze B2 (S3) | Retención 30 días, coste mínimo |
---
## Estructura del Repositorio
```
colectivo/
├── apps/
│ └── web/ # SvelteKit — web + PWA
│ ├── src/
│ │ ├── lib/
│ │ │ ├── supabase.ts # cliente Supabase singleton
│ │ │ ├── auth.ts # cliente OIDC (keycloak-js) + helpers de sesión
│ │ │ ├── stores/ # Svelte stores globales
│ │ │ ├── sync/ # lógica offline + cola de operaciones
│ │ │ └── components/ # componentes UI reutilizables
│ │ ├── routes/ # rutas SvelteKit
│ │ └── service-worker.ts # SW personalizado (Workbox)
│ ├── static/
│ │ ├── manifest.webmanifest
│ │ └── icons/ # iconos PWA (512, 192, 180...)
│ └── vite.config.ts
├── packages/
│ └── types/ # tipos TypeScript compartidos
│ └── src/
│ ├── database.ts # tipos generados desde schema Supabase
│ └── domain.ts # tipos de dominio (Colectivo, Item, etc.)
├── supabase/
│ ├── migrations/ # migraciones SQL versionadas
│ ├── seed.sql # datos de prueba para dev
│ ├── functions/ # Edge Functions (invitaciones, etc.)
│ └── config.toml # configuración Supabase CLI + OIDC Keycloak
├── keycloak/
│ ├── realm-export.json # realm "colectivo" exportado — importado al arrancar dev
│ └── themes/ # tema personalizado (opcional, v2)
├── infra/
│ ├── docker-compose.dev.yml # Supabase + Keycloak dev (Kong en puerto 8001)
│ ├── docker-compose.prod.yml # producción en VPS
│ ├── kong.yml # Kong declarativo (rutas API)
│ ├── db-init/
│ │ └── 00-role-passwords.sh # ajusta passwords de roles internos de Supabase al arrancar
│ └── scripts/
│ ├── backup.sh # backup manual de una BD concreta
│ ├── backup-cron.sh # ejecutado por cron: decide tipo (diario/semanal/mensual) y purga
│ ├── restore.sh # restaura un dump concreto en una BD
│ └── deploy.sh # SSH + docker compose pull + up
├── .github/
│ └── workflows/
│ ├── ci.yml # lint + test en PR
│ └── deploy.yml # deploy en push a main
├── .env.example # todas las variables documentadas con valores de ejemplo
├── Justfile # comandos de desarrollo frecuentes
├── turbo.json # Turborepo pipeline
└── package.json # workspaces
```
---
## Justfile — Comandos de referencia
```bash
just dev # levanta docker-compose.dev.yml + SvelteKit dev server
just dev-stop # para el entorno local
just db-reset # drop + migrate + seed (dev)
just db-migrate # aplica migraciones pendientes (dev)
just db-seed # aplica supabase/seed.sql a la BD dev en marcha
just db-types # genera tipos TS desde schema Supabase → packages/types
just kc-export # exporta realm de Keycloak → keycloak/realm-export.json
just kc-open # abre Keycloak Admin Console en el navegador (localhost:8080)
just deploy # ejecuta infra/scripts/deploy.sh (prod)
just backup supabase # backup manual inmediato de supabase
just backup keycloak # backup manual inmediato de keycloak
just restore supabase <file> # restaura un dump concreto en supabase
just restore keycloak <file> # restaura un dump concreto en keycloak
just logs # docker compose logs -f (prod)
```
---
## Endpoints en desarrollo local
| Servicio | URL | Notas |
|----------|-----|-------|
| App SvelteKit | http://localhost:5173 | |
| Supabase Studio | http://localhost:54323 | |
| Supabase API (Kong) | http://localhost:8001 | Puerto 8000 puede estar ocupado por otros servicios |
| Keycloak Admin | http://localhost:8080/admin | admin / admin (solo dev) |
| PostgreSQL | localhost:5432 | postgres / postgres (solo dev) |
---
## Decisiones Previas al Inicio
Antes de arrancar la Fase 0, confirmar:
| Decisión | Estado |
|----------|--------|
| Estrategia JWT Keycloak → Supabase (Opción A vs B) | Pendiente — **Opción A recomendada** |
| Base de datos de Keycloak en prod | ✅ **PostgreSQL independiente** |
| Entorno de producción dockerizado | ✅ **Ya operativo** |
| Reverse proxy en producción | ✅ **nginx existente, gestionado externamente** |
| Self-registration habilitado en Keycloak o invitación obligatoria | Pendiente |
| Proveedor SMTP para Keycloak y Resend (emails de invitación) | Pendiente — **Resend recomendado** |
| Almacenamiento de backups | Pendiente — **Backblaze B2 recomendado** |
| Dominio y DNS del VPS | Pendiente |
| Subdominio para Keycloak | Pendiente — `auth.tudominio.com` recomendado |
| Registry de imágenes Docker | Pendiente — **GitHub Container Registry recomendado** |
| OAuth Google (federated en Keycloak) | Pendiente — configurar en Keycloak, no en Supabase |
| OAuth Apple (federated en Keycloak) | Pendiente — requiere Apple Developer Program ($99/año) |
---
## Advertencias Técnicas
**Keycloak y JWT con Supabase RLS:**
- Supabase RLS usa `auth.uid()` que lee el claim `sub` del JWT. Verificar que el `sub` de Keycloak es un UUID v4 estándar — por defecto lo es, pero algunos realms lo configuran diferente.
- En la Opción A (JWT directo), la clave pública de Keycloak (RS256) debe estar en `JWT_SECRET` de Supabase. Si rotas las claves de firma en Keycloak, debes actualizar Supabase también.
- Keycloak tiene sesiones propias independientes de Supabase. Un `logout()` debe invalidar en ambos lados: llamar a `keycloak.logout()` (que invalida en Keycloak) y limpiar el cliente de Supabase localmente.
**Keycloak self-hosted en producción:**
- Keycloak 24+ requiere mínimo 512MB de RAM asignados. En un VPS pequeño (2GB), monitorizar el consumo conjunto con Supabase.
- El endpoint `/realms/{realm}/.well-known/openid-configuration` debe ser accesible públicamente para que Supabase pueda validar tokens. No poner Keycloak detrás de autenticación básica.
- Habilitar `SSL Required: external requests` en el realm de producción. Nunca desactivarlo.
**OAuth federado (Google, Apple):**
- Con Keycloak, Google y Apple se configuran como Identity Providers en Keycloak, no en Supabase. El flujo es: usuario → Keycloak → Google/Apple → Keycloak → app. Supabase solo ve el token de Keycloak.
- Esto simplifica la configuración de Supabase pero requiere configurar los Identity Providers en Keycloak Admin Console.
**iOS Safari y PWA:**
- Background Sync API no está soportada en Safari. Implementar fallback manual con el evento `online`.
- Push notifications solo disponibles desde iOS 16.4 y únicamente con la PWA instalada en pantalla de inicio.
- `keycloak-js` usa iframes para el refresco silencioso del token (`checkLoginIframe`). Deshabilitarlo en la config (`checkLoginIframe: false`) porque Safari bloquea cookies de terceros en iframes — usar `updateToken()` manual en su lugar.
- Probar el Modo Compra en un iPhone real en paralelo al desarrollo, no solo en DevTools.
**Supabase Realtime self-hosted:**
- Revisar `MAX_REPLICATION_SLOTS` en PostgreSQL y `REALTIME_MAX_CONNECTIONS` antes de producción.
- Las suscripciones de Presence consumen más recursos que Postgres Changes. Limitar a listas con sesión activa.
**Conflictos de sincronización:**
- Last-write-wins es suficiente para este dominio. No implementar CRDT en el MVP.
- Registrar conflictos detectados en tabla `sync_conflicts` para depuración.
---
## Estimación Total
| Fase | Duración |
|------|----------|
| Fase 0 — Infraestructura | 12 semanas |
| Fase 1 — Auth y Colectivo | 23 semanas |
| Fase 2a — Lista de Compra CRUD | 2 semanas |
| Fase 2b — Realtime y Modo Compra | 23 semanas |
| Fase 3 — Tareas y Notas | 12 semanas |
| Fase 4 — Búsqueda y Pulido | 1 semana |
| **Total** | **913 semanas** |
---
*Plan generado como base para Claude Code. Stack: SvelteKit + Supabase self-hosted + Keycloak + PWA. Cada fase puede usarse como contexto independiente para sesiones de trabajo.*