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

10 KiB
Raw Blame History

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 12 semanas
Fase 1 fase-1-auth-colectivo.md 23 semanas
Fase 2a fase-2a-lista-compra-crud.md 2 semanas
Fase 2b fase-2b-realtime-modo-compra.md 23 semanas
Fase 3 fase-3-tareas-notas.md 12 semanas
Fase 4 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

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.