Files
collective-lists/apps/web/vite.config.ts
Oier Bravo Urtasun 74e919aa71 feat(deploy): ambrosio production stack (erosi.oier.ovh)
Self-contained compose for a single-VPS deploy behind the host's Caddy.
App + Supabase API share erosi.oier.ovh; Keycloak on auth.oier.ovh.

- infra/docker-compose.erosi.yml — full stack bound to 127.0.0.1 only
  (db, auth, rest, realtime, storage, imgproxy, kong, meta, keycloak, app)
- infra/caddy/erosi.Caddyfile — host-Caddy snippet with TLS + path routing
  (/auth /rest /storage /realtime /graphql → kong, rest → app)
- infra/scripts/deploy-erosi.sh — rsync + first-run secret generation +
  build + migrations + Caddy snippet install
- keycloak/realm-export.erosi.json — prod redirect URIs, registration on,
  client secret as __KEYCLOAK_CLIENT_SECRET__ placeholder (deploy sub'd)
- .env.erosi.example — env template with placeholders

Supporting fixes to make the deploy work on a clean Supabase-postgres volume:

- infra/db-init/00-role-passwords.sh — rewrote as idempotent bootstrap:
  CREATE the Supabase service roles if missing, set passwords on pre-existing
  ones, enable pg_cron/pgcrypto/uuid-ossp, create auth/storage/graphql_public/
  _realtime/realtime schemas, create empty supabase_realtime publication,
  set per-role search_path (auth→auth, storage→storage). Old version only
  ALTERed passwords and relied on the roles already existing — worked for a
  grandfathered dev volume, failed on a fresh prod init.

- infra/db-init/00-role-passwords.sql — removed (folded into .sh).

- apps/web/vite.config.ts — PWA strategy generateSW (was injectManifest).
  The plugin's injectManifest hardcodes the SW source filename to
  service-worker.js and ignores the filename: 'sw.ts' override, making the
  production build fail. generateSW's auto-generated precache-only SW is
  functionally equivalent to our 5-line src/sw.ts.

Tested end-to-end on ambrosio: all 9 containers up, 11 migrations applied,
https://erosi.oier.ovh returns 200, Keycloak OIDC discovery serves the
correct issuer, /auth/v1/settings lists Keycloak as the sole external
provider.
2026-04-14 19:41:33 +02:00

63 lines
2.2 KiB
TypeScript

import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import { paraglide } from '@inlang/paraglide-sveltekit/vite';
export default defineConfig({
plugins: [
paraglide({
project: './project.inlang',
outdir: './src/lib/paraglide'
}),
sveltekit(),
SvelteKitPWA({
// `generateSW` strategy: the plugin auto-generates a Workbox SW that
// precaches the built shell. Equivalent behavior to our previous
// `src/sw.ts` (a 5-line precacheAndRoute wrapper) without the
// injectManifest path, which in @vite-pwa/sveltekit 0.6.8 hardcodes
// the SW source filename to `service-worker.js` and breaks on any
// custom filename. The $lib/sync pending_ops queue handles offline
// writes; SyncBanner surfaces offline state to the user.
strategies: 'generateSW',
scope: '/',
base: '/',
manifest: {
name: 'Colectivo',
short_name: 'Colectivo',
description: 'Gestión colaborativa del hogar',
theme_color: '#0f172a',
background_color: '#f7f9fb',
display: 'standalone',
orientation: 'portrait',
scope: '/',
start_url: '/',
icons: [
{ src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png' },
{ src: '/icons/icon-512-maskable.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }
]
},
workbox: {
globPatterns: ['client/**/*.{js,css,ico,png,svg,webp,woff,woff2}'],
// Supabase paths: never cache — always hit the network.
navigateFallbackDenylist: [/^\/auth\//, /^\/rest\//, /^\/realtime\//, /^\/storage\//]
},
devOptions: {
enabled: true,
suppressWarnings: true,
type: 'module',
navigateFallback: '/'
}
})
],
server: {
port: 5173,
// Bind to all interfaces so the LAN (phone, tablet, other laptops on
// the same Wi-Fi) can reach the dev server at http://<LAN-IP>:5173.
// Auth flows will fail from non-laptop clients because Keycloak's
// issuer URL resolves to `keycloak:8080` only on the laptop's /etc/hosts
// — use this for layout/CSS visual checks, not for full login tests.
host: true
}
});