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>
This commit is contained in:
2026-04-12 14:37:51 +02:00
parent f5903ef442
commit 973f9e413c
57 changed files with 2508 additions and 1 deletions

60
supabase/seed.sql Normal file
View File

@@ -0,0 +1,60 @@
-- seed.sql — development seed data
-- Mirrors Keycloak test users (UUIDs must match realm-export.json)
-- Password for all users: test1234
-- ── Users ─────────────────────────────────────────────────────────────────────
-- Inserted into the public.users table (synced from Keycloak via trigger in Fase 1)
-- For Fase 0 we insert directly since the trigger isn't written yet.
INSERT INTO public.users (id, email, display_name, language, avatar_type)
VALUES
('11111111-1111-1111-1111-111111111111', 'ana@dev.local', 'Ana García', 'es', 'initials'),
('22222222-2222-2222-2222-222222222222', 'borja@dev.local', 'Borja López', 'es', 'initials'),
('33333333-3333-3333-3333-333333333333', 'carmen@dev.local', 'Carmen Martínez', 'es', 'initials'),
('44444444-4444-4444-4444-444444444444', 'david@dev.local', 'David Fernández', 'es', 'initials'),
('55555555-5555-5555-5555-555555555555', 'eva@dev.local', 'Eva Ruiz', 'es', 'initials')
ON CONFLICT (id) DO NOTHING;
-- ── Sample collective ──────────────────────────────────────────────────────────
INSERT INTO public.collectives (id, name, emoji, created_by)
VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Casa García-López', '🏠', '11111111-1111-1111-1111-111111111111')
ON CONFLICT (id) DO NOTHING;
-- ── Collective members ─────────────────────────────────────────────────────────
-- Ana: admin, Borja: member, Carmen: member, David: guest
-- Eva has no collective (for onboarding testing)
INSERT INTO public.collective_members (collective_id, user_id, role)
VALUES
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '11111111-1111-1111-1111-111111111111', 'admin'),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '22222222-2222-2222-2222-222222222222', 'member'),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '33333333-3333-3333-3333-333333333333', 'member'),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '44444444-4444-4444-4444-444444444444', 'guest')
ON CONFLICT (collective_id, user_id) DO NOTHING;
-- ── Sample shopping list ───────────────────────────────────────────────────────
INSERT INTO public.shopping_lists (id, collective_id, name, status, created_by)
VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Weekly shop', 'active', '11111111-1111-1111-1111-111111111111')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.shopping_items (list_id, name, quantity, unit, sort_order, created_by)
VALUES
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Milk', 2, 'L', 1, '11111111-1111-1111-1111-111111111111'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Bread', 1, NULL, 2, '22222222-2222-2222-2222-222222222222'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Eggs', 1, 'doz', 3, '11111111-1111-1111-1111-111111111111'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Coffee', 1, NULL, 4, '33333333-3333-3333-3333-333333333333'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Apples', 6, NULL, 5, '22222222-2222-2222-2222-222222222222')
ON CONFLICT DO NOTHING;
-- ── Item frequency baseline (from pre-existing items above) ────────────────────
INSERT INTO public.item_frequency (collective_id, name, use_count, last_used_at)
VALUES
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'milk', 5, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'bread', 4, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'eggs', 3, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'coffee', 3, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'apples', 2, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'butter', 2, now()),
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'yogurt', 1, now())
ON CONFLICT (collective_id, name) DO UPDATE SET
use_count = EXCLUDED.use_count,
last_used_at = EXCLUDED.last_used_at;