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

View File

@@ -0,0 +1,18 @@
{
"name": "@colectivo/types",
"version": "0.0.1",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"import": "./src/index.ts"
}
},
"scripts": {
"check": "tsc --noEmit"
},
"devDependencies": {
"typescript": "^5.5.0"
}
}

View File

@@ -0,0 +1,14 @@
// AUTO-GENERATED — do not edit manually.
// Run `just db-types` to regenerate from Supabase schema.
// Placeholder until migrations exist and `supabase gen types typescript` can run.
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
export interface Database {
public: {
Tables: Record<string, never>;
Views: Record<string, never>;
Functions: Record<string, never>;
Enums: Record<string, never>;
};
}

View File

@@ -0,0 +1,127 @@
// Domain types for the Colectivo app.
// These are hand-written and represent business concepts.
// database.ts is generated — never edit it manually.
export type AvatarType = 'initials' | 'emoji' | 'upload';
export type MemberRole = 'admin' | 'member' | 'guest';
export type ListStatus = 'active' | 'completed' | 'archived';
export type NoteColor =
| 'default'
| 'slate'
| 'rose'
| 'orange'
| 'amber'
| 'emerald'
| 'cyan'
| 'violet';
export type TaskPriority = 'none' | 'low' | 'medium' | 'high' | 'urgent';
export type Language = 'en' | 'es';
export interface User {
id: string;
email: string;
display_name: string;
language: Language;
avatar_type: AvatarType;
avatar_emoji: string | null;
avatar_url: string | null;
created_at: string;
}
export interface Collective {
id: string;
name: string;
emoji: string;
created_by: string;
created_at: string;
}
export interface CollectiveMember {
collective_id: string;
user_id: string;
role: MemberRole;
joined_at: string;
}
export interface CollectiveInvitation {
id: string;
collective_id: string;
invited_by: string;
email: string;
token: string;
role: MemberRole;
expires_at: string;
accepted_at: string | null;
created_at: string;
}
export interface ShoppingList {
id: string;
collective_id: string;
name: string;
status: ListStatus;
created_by: string;
created_at: string;
completed_at: string | null;
deleted_at: string | null;
}
export interface ShoppingItem {
id: string;
list_id: string;
name: string;
quantity: number | null;
unit: string | null;
is_checked: boolean;
checked_by: string | null;
checked_at: string | null;
sort_order: number;
created_by: string;
created_at: string;
deleted_at: string | null;
}
export interface ItemFrequency {
collective_id: string;
name: string; // normalized: lower(trim())
use_count: number;
last_used_at: string;
}
export interface TaskList {
id: string;
collective_id: string;
name: string;
created_by: string;
created_at: string;
deleted_at: string | null;
}
export interface Task {
id: string;
task_list_id: string;
name: string;
is_completed: boolean;
completed_by: string | null;
completed_at: string | null;
priority: TaskPriority;
due_date: string | null;
sort_order: number;
created_by: string;
created_at: string;
deleted_at: string | null;
}
export interface Note {
id: string;
collective_id: string;
title: string | null;
content: string;
color: NoteColor;
is_pinned: boolean;
is_archived: boolean;
created_by: string;
created_at: string;
updated_at: string;
deleted_at: string | null;
}

View File

@@ -0,0 +1,2 @@
export * from './domain.js';
export * from './database.js';

View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}