From d4752159fb891a2467dd95a45572c9f0d2af2b0d Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 10 Jun 2026 15:04:52 +0200 Subject: [PATCH] chore: add migration tooling --- CHANGELOG.md | 1 + Makefile | 14 +++- README.md | 13 ++- TODO.md | 7 +- migrations/.gitkeep | 1 - migrations/0001_migration_baseline.down.sql | 2 + migrations/0001_migration_baseline.up.sql | 3 + scripts/migrate.sh | 93 +++++++++++++++++++++ 8 files changed, 126 insertions(+), 8 deletions(-) delete mode 100644 migrations/.gitkeep create mode 100644 migrations/0001_migration_baseline.down.sql create mode 100644 migrations/0001_migration_baseline.up.sql create mode 100755 scripts/migrate.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c1238..d6c4265 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- `golang-migrate`-Setup mit Baseline-Migration und Make-Targets fuer Up/Down/Version angelegt. - Gemeinsames Go-Modul `platform/` mit ENV-Konfiguration und strukturiertem JSON-Logging angelegt. - Forgejo-Actions-CI mit Go/Frontend-Verifikation und Gitleaks-Secret-Scan angelegt. - E0-T01 begonnen: Monorepo-Grundstruktur, Root-Dokumentation, Env-Beispiel und minimale Service-Startpunkte angelegt. diff --git a/Makefile b/Makefile index 9a19e89..3b98bab 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,9 @@ GOCACHE ?= $(CURDIR)/.tmp/go-build GO := env GOCACHE=$(GOCACHE) go COMPOSE := docker compose SUPABASE_DIR := deploy/supabase +MIGRATE := ./scripts/migrate.sh -.PHONY: dev dev-down dev-logs migrate test lint build frontend-build verify clean +.PHONY: dev dev-down dev-logs migrate migrate-up migrate-down migrate-version test lint build frontend-build verify clean dev: cd $(SUPABASE_DIR) && $(COMPOSE) up -d @@ -17,7 +18,16 @@ dev-logs: cd $(SUPABASE_DIR) && $(COMPOSE) logs -f migrate: - @echo "No migrations configured yet. E2-T01 will wire golang-migrate." + $(MIGRATE) up + +migrate-up: + $(MIGRATE) up + +migrate-down: + $(MIGRATE) down 1 + +migrate-version: + $(MIGRATE) version test: env GOCACHE="$(GOCACHE)" go test ./platform/... ./backend/... ./worker/... ./console-proxy/... diff --git a/README.md b/README.md index 04dd535..8a60613 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,15 @@ Multi-Tenant-Konsole fuer Proxmox auf Basis von Go, Supabase Postgres/Auth, Redi 5. Abhaengigkeiten installieren: `npm install --prefix frontend`. 6. Go-Abhaengigkeiten installieren: `go work sync`. 7. Lokale Infrastruktur starten: `make dev`. -8. Backend starten: `go run ./backend/cmd/api`. -9. Console-Proxy starten: `go run ./console-proxy/cmd/console-proxy`. -10. Frontend starten: `npm run dev --prefix frontend`. +8. Migrationen ausfuehren: `make migrate`. +9. Backend starten: `go run ./backend/cmd/api`. +10. Console-Proxy starten: `go run ./console-proxy/cmd/console-proxy`. +11. Frontend starten: `npm run dev --prefix frontend`. Supabase self-hosted liegt unter `deploy/supabase/`. Die lokale `deploy/supabase/.env` wird aus der offiziellen Vorlage erzeugt und nicht committed. Fuer App-`.env` die Werte `POSTGRES_PASSWORD`, `ANON_KEY` und `SERVICE_ROLE_KEY` aus `deploy/supabase/.env` uebernehmen. +Migrationen nutzen `MIGRATE_DATABASE_URL`, falls gesetzt. Andernfalls wird `DATABASE_DIRECT_URL` aus `.env` oder eine lokale Supavisor-URL aus `deploy/supabase/.env` verwendet. + Lokale Dienste: - Supabase API Gateway: `http://localhost:8000` @@ -43,7 +46,9 @@ Aktuelle Targets: - `make verify`: Lint, Tests und Builds - `make dev-down`: Supabase-Stack stoppen - `make dev-logs`: Supabase-Logs verfolgen -- `make migrate`: Platzhalter bis E2-T01 `golang-migrate` einbindet +- `make migrate`: Migrationen auf den aktuellen Stand bringen +- `make migrate-down`: letzte Migration zurueckrollen +- `make migrate-version`: aktuelle Migrationsversion anzeigen ## CI diff --git a/TODO.md b/TODO.md index a88364a..5d2fb9c 100644 --- a/TODO.md +++ b/TODO.md @@ -29,7 +29,11 @@ Arbeitsliste auf Basis von `proxmox-console-entwicklungsplan.md`. Die Entwurfsda ## Naechste Aufgaben -- [ ] E2-T01: Migrations-Setup mit `golang-migrate` +- [x] E2-T01: Migrations-Setup mit `golang-migrate` + - [x] Versioniertes SQL-Namensschema unter `migrations/` angelegt + - [x] `make migrate`, `make migrate-down` und `make migrate-version` verdrahtet + - [x] Migrationen laufen lokal per `migrate`-Binary oder Docker-Image `migrate/migrate:v4.18.3` + - [x] DB-URL wird aus `.env`, `deploy/supabase/.env` oder `MIGRATE_DATABASE_URL` abgeleitet ## MVP-Backlog @@ -68,3 +72,4 @@ Arbeitsliste auf Basis von `proxmox-console-entwicklungsplan.md`. Die Entwurfsda - 2026-06-10: CI-Workflow fuer Forgejo Actions angelegt; lokales `make verify` erfolgreich. - 2026-06-10: Gitleaks-Secret-Scan lokal mit `zricethezav/gitleaks:v8.28.0` erfolgreich; keine Leaks gefunden. - 2026-06-10: Gemeinsamer Go-Config-/Logging-Layer angelegt; Tests fuer Config-Defaults und Validierung ergaenzt. +- 2026-06-10: `golang-migrate`-Setup mit Baseline-Migration angelegt; lokaler Up/Down-Lauf gegen Supabase verifiziert. diff --git a/migrations/.gitkeep b/migrations/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/migrations/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - diff --git a/migrations/0001_migration_baseline.down.sql b/migrations/0001_migration_baseline.down.sql new file mode 100644 index 0000000..87e495f --- /dev/null +++ b/migrations/0001_migration_baseline.down.sql @@ -0,0 +1,2 @@ +-- Baseline rollback for golang-migrate. +SELECT 1; diff --git a/migrations/0001_migration_baseline.up.sql b/migrations/0001_migration_baseline.up.sql new file mode 100644 index 0000000..21fa24c --- /dev/null +++ b/migrations/0001_migration_baseline.up.sql @@ -0,0 +1,3 @@ +-- Baseline migration for golang-migrate. +-- Schema tables start with E2-T02. +SELECT 1; diff --git a/scripts/migrate.sh b/scripts/migrate.sh new file mode 100755 index 0000000..6bff36e --- /dev/null +++ b/scripts/migrate.sh @@ -0,0 +1,93 @@ +#!/bin/sh +set -eu + +usage() { + echo "Usage: $0 up|down|force|version [argument]" >&2 + exit 2 +} + +if [ "$#" -lt 1 ]; then + usage +fi + +command="$1" +shift + +case "$command" in + up|down|force|version) ;; + *) usage ;; +esac + +repo_root="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +migrations_dir="$repo_root/migrations" + +env_file_value() { + file="$1" + key="$2" + if [ ! -f "$file" ]; then + return 0 + fi + + awk -F= -v key="$key" ' + $1 == key { + sub(/^[^=]*=/, "") + gsub(/^[ \t047"]+|[ \t047"]+$/, "") + print + exit + } + ' "$file" +} + +root_env="$repo_root/.env" +supabase_env="$repo_root/deploy/supabase/.env" + +env_value() { + key="$1" + eval "current=\${$key:-}" + if [ -n "$current" ]; then + printf '%s' "$current" + return 0 + fi + + value="$(env_file_value "$root_env" "$key")" + if [ -n "$value" ]; then + printf '%s' "$value" + return 0 + fi + + env_file_value "$supabase_env" "$key" +} + +pooler_tenant_id="$(env_value POOLER_TENANT_ID)" +if [ -z "$pooler_tenant_id" ]; then + pooler_tenant_id="proxui" +fi + +database_url="$(env_value MIGRATE_DATABASE_URL)" +if [ -z "$database_url" ]; then + database_url="$(env_value DATABASE_DIRECT_URL)" + if [ -z "$database_url" ]; then + postgres_password="$(env_value POSTGRES_PASSWORD)" + fi + + if [ -n "${postgres_password:-}" ]; then + MIGRATE_DATABASE_URL="postgres://postgres.${pooler_tenant_id}:${postgres_password}@localhost:6543/postgres?sslmode=disable" + else + echo "MIGRATE_DATABASE_URL, DATABASE_DIRECT_URL or POSTGRES_PASSWORD must be set." >&2 + exit 1 + fi + database_url="$MIGRATE_DATABASE_URL" +fi + +if command -v migrate >/dev/null 2>&1; then + exec migrate -path "$migrations_dir" -database "$database_url" "$command" "$@" +fi + +docker_database_url="$(printf '%s' "$database_url" | sed 's/@localhost:/@host.docker.internal:/')" + +exec docker run --rm \ + -v "$migrations_dir:/migrations:ro" \ + migrate/migrate:v4.18.3 \ + -path=/migrations \ + -database "$docker_database_url" \ + "$command" "$@"