Files
Musify/deploy/up.ps1
T
Admin c4f5e6754c feat(deploy): consolidated dev stack with auto-provisioned Zitadel
Single docker-compose stack for local development (Postgres, Zitadel,
RabbitMQ, SeaweedFS + bucket init, Jaeger) plus an optional overlay to run
the .NET apps in Docker. up.ps1 orchestrates the full bootstrap: stack up,
stream-ticket keys, EF Core migrations and Zitadel provisioning.

- Zitadel is provisioned automatically (service-account PAT -> project +
  OIDC app with JWT access token); the generated ClientId is wired into
  Musify.Api user-secrets and .env. No manual console steps.
- ZITADEL_EXTERNAL_DOMAIN=host.docker.internal so token validation works
  both with local apps and full-docker.
- App Dockerfiles copy AppSettings*.json to lowercase so config loads on
  case-sensitive Linux; Worker image ships ffmpeg.
- Scripts split by responsibility (common/stream-keys/migrate/provision);
  apps overlay de-duped via YAML anchors.
- Remove the superseded standalone seaweedfs compose; point docs/development
  at the unified stack.
2026-07-05 20:32:40 +02:00

122 lines
5.1 KiB
PowerShell

#requires -Version 5.1
<#
.SYNOPSIS
Brings up the Musify development environment.
.DESCRIPTION
Starts the infrastructure stack, generates the stream-ticket keys, applies EF
Core migrations and provisions Zitadel (project + OIDC app + ClientId).
.EXAMPLE
./up.ps1 # Bring everything up
./up.ps1 -SkipMigrations # Skip the database migration step
./up.ps1 -Down # Stop and remove containers (keep volumes)
./up.ps1 -Destroy # Stop and remove containers + volumes (wipe data)
#>
[CmdletBinding()]
param(
[switch]$Down,
[switch]$Destroy,
[switch]$SkipMigrations
)
$ErrorActionPreference = "Stop"
$deployDir = $PSScriptRoot
$composeFile = Join-Path $deployDir "docker-compose.yml"
. (Join-Path $deployDir "scripts\common.ps1")
# Teardown -------------------------------------------------------------------
if ($Down -or $Destroy) {
if ($Destroy) {
Write-Step "Stopping the stack and REMOVING volumes (data is wiped)"
docker compose -f $composeFile down -v --remove-orphans
# Drop the Zitadel init secrets (PAT) so the next start re-initializes cleanly.
Get-ChildItem (Join-Path $deployDir "zitadel\.output") -File -ErrorAction SilentlyContinue | Remove-Item -Force
} else {
Write-Step "Stopping the stack (volumes are kept)"
docker compose -f $composeFile down --remove-orphans
}
return
}
# Config ---------------------------------------------------------------------
$envFile = Join-Path $deployDir ".env"
if (-not (Test-Path $envFile)) {
Write-Step "Creating .env from .env.example"
Copy-Item (Join-Path $deployDir ".env.example") $envFile
}
$cfg = Read-DotEnv $envFile
$streamKeysDir = if ($cfg['STREAM_KEYS_DIR']) { $cfg['STREAM_KEYS_DIR'] } else { "D:/weed" }
$workerTempDir = if ($cfg['WORKER_TEMP_DIR']) { $cfg['WORKER_TEMP_DIR'] } else { "D:/tempsFilesDev" }
# Infrastructure -------------------------------------------------------------
Write-Step "Starting the infrastructure stack"
docker compose -f $composeFile up -d
if ($LASTEXITCODE -ne 0) { throw "docker compose up failed" }
Write-Step "Waiting for Postgres to become healthy"
$deadline = (Get-Date).AddMinutes(2)
do {
Start-Sleep -Seconds 2
$status = docker inspect --format '{{.State.Health.Status}}' musify-postgres 2>$null
} until ($status -eq "healthy" -or (Get-Date) -gt $deadline)
if ($status -ne "healthy") { throw "Postgres did not become healthy in time" }
# Stream-ticket keys ---------------------------------------------------------
Write-Step "Ensuring stream-ticket keys"
& (Join-Path $deployDir "scripts\stream-keys.ps1") -KeysDir $streamKeysDir
# Worker temp directory ------------------------------------------------------
if (-not (Test-Path $workerTempDir)) {
Write-Step "Creating the Worker temp directory: $workerTempDir"
New-Item -ItemType Directory -Path $workerTempDir | Out-Null
}
# Database migrations --------------------------------------------------------
if ($SkipMigrations) {
Write-Host "`nSkipping migrations (-SkipMigrations)."
} else {
Write-Step "Applying EF Core migrations"
$conn = "Host=localhost;Port=$($cfg['POSTGRES_HOST_PORT']);Database=$($cfg['POSTGRES_DB']);Username=$($cfg['POSTGRES_USER']);Password=$($cfg['POSTGRES_PASSWORD'])"
& (Join-Path $deployDir "scripts\migrate.ps1") -ConnectionString $conn
}
# Zitadel provisioning -------------------------------------------------------
Write-Step "Provisioning Zitadel (project + OIDC app + ClientId)"
try {
& (Join-Path $deployDir "zitadel\provision.ps1")
} catch {
Write-Host "Warning: Zitadel provisioning failed: $($_.Exception.Message)" -ForegroundColor Yellow
}
# Summary --------------------------------------------------------------------
$zDomain = $cfg['ZITADEL_EXTERNAL_DOMAIN']
$zPort = $cfg['ZITADEL_EXTERNAL_PORT']
Write-Host @"
============================================================
Musify development environment READY
============================================================
Service URL / port
------------------ --------------------------------------
PostgreSQL localhost:$($cfg['POSTGRES_HOST_PORT']) (db: $($cfg['POSTGRES_DB']))
Zitadel console http://$zDomain`:$zPort/ui/console
RabbitMQ mgmt http://localhost:15672 ($($cfg['RABBITMQ_DEFAULT_USER'])/$($cfg['RABBITMQ_DEFAULT_PASS']))
SeaweedFS S3 http://localhost:8333 (bucket: $($cfg['S3_BUCKET']))
SeaweedFS filer http://localhost:8888
SeaweedFS master http://localhost:9333
Jaeger traces http://localhost:16686 (OTLP: localhost:4317)
Zitadel admin: $($cfg['ZITADEL_ADMIN_USERNAME'])@zitadel.$zDomain / $($cfg['ZITADEL_ADMIN_PASSWORD'])
Auth is provisioned automatically; ClientId is in Musify.Api user-secrets and .env.
Log in via Scalar: http://localhost:5111/scalar/v1
Run the apps from the IDE or:
dotnet run --project backend/Musify.Api # :5111
dotnet run --project backend/Musify.StreamingGateway # :8081
dotnet run --project backend/Musify.Worker # background
============================================================
"@ -ForegroundColor Green