README: Alpha-Status + bekannte offene Punkte dokumentiert
Stack-Skelett ist drin (compose, Dockerfile, kong.yml, nginx.conf, sync- Script, generate-keys-Skript), aber End-to-End noch nicht lauffähig. Beim ersten lokalen Bring-up sind aufgefallen: - auth.users-Schema fehlt beim Init (Migration 0001 referenziert FK) - Healthcheck-User: supabase/postgres default ist supabase_admin - auth.uid()/auth.role() müssen vor Migrations existieren - Standard-Init-SQL (roles, _supabase, realtime, jwt, …) aus supabase/supabase docker fehlt Punkte sind in separater Iteration zu adressieren — Self-Host-Init in Production-Qualität ist nicht in einem Rutsch zu bauen. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# rapport-server
|
||||
# RAPPORT-SERVER
|
||||
|
||||
> ⚠️ **Status: Alpha — noch nicht End-to-End-getestet.** Die Files in diesem Repo sind ein Skelett (Docker-Compose, Init-Skripte, Frontend-Build), aber der Stack startet noch nicht out-of-the-box. Vor produktivem Einsatz ist die Supabase-Init-Reihenfolge auszubauen (siehe «Bekannte offene Punkte» unten).
|
||||
|
||||
Self-Hosting-Stack für [Rapport](https://git.kgva.ch/karim/RAPPORT) — die Studio-Management-Software für Architekturbüros.
|
||||
|
||||
@@ -135,6 +137,17 @@ docker compose exec storage tar -czf - /var/lib/storage > storage-$(date +%Y%m%d
|
||||
|
||||
---
|
||||
|
||||
## Bekannte offene Punkte
|
||||
|
||||
Beim ersten End-to-End-Versuch (lokal mit Docker Compose + alternativen Ports) sind diese Probleme aufgefallen:
|
||||
|
||||
1. **`auth.users`-Schema fehlt beim Postgres-Init**: Die Rapport-Migrationen (`0001_initial.sql`) referenzieren `auth.users(id)` als Foreign Key. In Karims `supabase start`-Setup wird das von der Supabase-CLI vorab initialisiert; hier in `docker-compose` muss das per Init-Script (vor den App-Migrationen) explizit angelegt werden — analog zum offiziellen [supabase/supabase Self-Host-Setup](https://github.com/supabase/supabase/tree/master/docker/volumes/db/init). Stub-Variante in `volumes/db/init/00-init.sh` ist drin, aber nicht ausreichend.
|
||||
2. **Healthcheck-User**: `supabase/postgres` Image hat als Default-User `supabase_admin` (nicht `postgres`). Compose-Healthchecks und SQL-Skripte müssen das berücksichtigen.
|
||||
3. **`auth.uid()` und `auth.role()` als Stub-Funktionen** brauchen Pre-Migration, damit RLS-Policies + RPCs (`is_studio_member`, `create_studio_with_admin`, …) im Init durchlaufen.
|
||||
4. **Standard-Init-SQL aus dem offiziellen Supabase Self-Host kopieren**: `roles.sql`, `_supabase.sql`, `realtime.sql`, `webhooks.sql`, `jwt.sql`, `logs.sql` — diese fehlen aktuell.
|
||||
|
||||
Diese Punkte sind in einer separaten Iteration zu adressieren, nicht in einem Schritt. Empfehlung: Sich Schritt für Schritt am offiziellen Supabase-Self-Host-Compose orientieren.
|
||||
|
||||
## Lizenz
|
||||
|
||||
GNU AGPL-3.0-or-later — identisch zur Rapport-App.
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ services:
|
||||
SUPABASE_URL: ${API_EXTERNAL_URL}
|
||||
SUPABASE_ANON_KEY: ${ANON_KEY}
|
||||
image: rapport-app:${RAPPORT_APP_TAG:-latest}
|
||||
container_name: rapport-app
|
||||
container_name: rapport-server-app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${APP_PORT:-8080}:80"
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env node
|
||||
// Generiert ANON_KEY und SERVICE_ROLE_KEY (JWTs, HS256 signiert) aus dem
|
||||
// JWT_SECRET in der .env. Ohne diese Keys können GoTrue, PostgREST, Storage
|
||||
// und Realtime nicht miteinander reden.
|
||||
//
|
||||
// Aufruf:
|
||||
// node scripts/generate-keys.mjs # liest JWT_SECRET aus .env
|
||||
// node scripts/generate-keys.mjs <secret> # explizit übergeben
|
||||
//
|
||||
// Output: zwei JWTs auf stdout, die du in .env als ANON_KEY und
|
||||
// SERVICE_ROLE_KEY einsetzen kannst.
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
|
||||
function base64url(input) {
|
||||
return Buffer.from(input).toString("base64")
|
||||
.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
||||
}
|
||||
|
||||
function signJwt(payload, secret) {
|
||||
const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
||||
const body = base64url(JSON.stringify(payload));
|
||||
const sig = base64url(crypto.createHmac("sha256", secret).update(`${header}.${body}`).digest());
|
||||
return `${header}.${body}.${sig}`;
|
||||
}
|
||||
|
||||
let secret = process.argv[2];
|
||||
if (!secret) {
|
||||
try {
|
||||
const env = fs.readFileSync(".env", "utf8");
|
||||
const m = env.match(/^JWT_SECRET=(.+)$/m);
|
||||
if (m) secret = m[1].trim().replace(/^["']|["']$/g, "");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!secret || secret.length < 32 || secret.includes("CHANGE-ME")) {
|
||||
console.error("✗ Kein gültiges JWT_SECRET gefunden (mind. 32 Zeichen, nicht der Placeholder).");
|
||||
console.error(" Setze JWT_SECRET in .env oder gib es als Argument:");
|
||||
console.error(" node scripts/generate-keys.mjs $(openssl rand -hex 32)");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const tenYears = now + 10 * 365 * 24 * 3600;
|
||||
|
||||
const anonKey = signJwt({ role: "anon", iss: "supabase", iat: now, exp: tenYears }, secret);
|
||||
const serviceKey = signJwt({ role: "service_role", iss: "supabase", iat: now, exp: tenYears }, secret);
|
||||
|
||||
console.log("ANON_KEY=" + anonKey);
|
||||
console.log("SERVICE_ROLE_KEY=" + serviceKey);
|
||||
console.error("");
|
||||
console.error("→ Werte in .env eintragen (überschreibt CHANGE-ME-Placeholder).");
|
||||
Reference in New Issue
Block a user