205 lines
7.1 KiB
PowerShell
205 lines
7.1 KiB
PowerShell
#requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Set up, start and stop the entire TravelHub stack on Docker. A new developer
|
|
needs only Docker Desktop -- no local Go, Node, or PostgreSQL.
|
|
|
|
.DESCRIPTION
|
|
Wraps docker compose for the three services (PostgreSQL + Go API + Angular
|
|
via nginx). Database credentials are read from backend/.env, so there is one
|
|
source of truth and no secret is duplicated.
|
|
|
|
URLs once up:
|
|
App -> http://localhost:4200 (nginx serves the SPA and proxies /api)
|
|
API -> http://localhost:8080
|
|
|
|
Demo sign-in: any seeded account, password demo1234
|
|
(e.g. agent@skyline.test, agency "skyline").
|
|
|
|
.PARAMETER Action
|
|
setup Build images and bring everything up, waiting until healthy. The
|
|
database is created and seeded on this first run. One command to
|
|
onboard.
|
|
start Bring the stack up (images already built).
|
|
stop Stop and remove the containers; the database volume is kept.
|
|
restart stop then start.
|
|
reset Stop and DELETE the database volume, then start fresh (re-seeds).
|
|
rebuild Rebuild images (use after pulling code changes) and start.
|
|
status Show container state.
|
|
logs Tail logs (-Follow to stream; -Service to pick one).
|
|
|
|
.PARAMETER Service
|
|
logs: which service (postgres | api | web). Default: all.
|
|
|
|
.PARAMETER Follow
|
|
logs: stream instead of printing the tail once.
|
|
|
|
.EXAMPLE
|
|
.\docker.ps1 setup
|
|
.EXAMPLE
|
|
.\docker.ps1 logs -Service api -Follow
|
|
.EXAMPLE
|
|
.\docker.ps1 reset # wipe data and re-seed with fresh flight dates
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Position = 0)]
|
|
[ValidateSet('setup', 'start', 'stop', 'restart', 'reset', 'rebuild', 'status', 'logs', 'help')]
|
|
[string]$Action = 'help',
|
|
|
|
[ValidateSet('postgres', 'api', 'web')]
|
|
[string]$Service,
|
|
|
|
[switch]$Follow
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$Root = $PSScriptRoot
|
|
|
|
# Refresh PATH from the registry so `docker` resolves even in a terminal opened
|
|
# before Docker Desktop was installed (a common first-run gotcha).
|
|
$env:Path = (@(
|
|
[Environment]::GetEnvironmentVariable('Path', 'Machine'),
|
|
[Environment]::GetEnvironmentVariable('Path', 'User')
|
|
) | Where-Object { $_ }) -join ';'
|
|
|
|
function Write-Step($m) { Write-Host "==> $m" -ForegroundColor Cyan }
|
|
function Write-Ok($m) { Write-Host " + $m" -ForegroundColor Green }
|
|
function Write-Warn2($m){ Write-Host " ! $m" -ForegroundColor Yellow }
|
|
|
|
# --- docker availability ---------------------------------------------------
|
|
|
|
function Require-Docker {
|
|
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
|
|
throw "Docker not found. Install Docker Desktop and ensure it is running: https://www.docker.com/products/docker-desktop/"
|
|
}
|
|
# `docker info` fails fast if the engine/daemon is not running.
|
|
docker info *> $null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Docker is installed but the engine is not running. Start Docker Desktop and retry.'
|
|
}
|
|
# Compose v2 (the `docker compose` subcommand) is required.
|
|
docker compose version *> $null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "This script needs Docker Compose v2 (the 'docker compose' subcommand). Update Docker Desktop."
|
|
}
|
|
}
|
|
|
|
# --- credentials from backend/.env -----------------------------------------
|
|
|
|
# Load DB_USER / DB_PASSWORD / DB_NAME from backend/.env into this process so
|
|
# docker compose can substitute them. Nothing is printed or copied to disk.
|
|
function Import-DbEnv {
|
|
$envFile = Join-Path $Root 'backend\.env'
|
|
if (-not (Test-Path $envFile)) {
|
|
throw "backend\.env not found. Copy backend\.env.example to backend\.env and set DB_PASSWORD first."
|
|
}
|
|
foreach ($line in Get-Content $envFile) {
|
|
$t = $line.Trim()
|
|
if ($t -eq '' -or $t.StartsWith('#')) { continue }
|
|
$i = $t.IndexOf('=')
|
|
if ($i -lt 1) { continue }
|
|
$key = $t.Substring(0, $i).Trim()
|
|
$val = $t.Substring($i + 1).Trim().Trim('"').Trim("'")
|
|
if ($key -in @('DB_USER', 'DB_PASSWORD', 'DB_NAME')) {
|
|
Set-Item -Path "Env:$key" -Value $val
|
|
}
|
|
}
|
|
if (-not $env:DB_PASSWORD) {
|
|
throw 'DB_PASSWORD is not set in backend\.env.'
|
|
}
|
|
if (-not $env:DB_USER) { $env:DB_USER = 'postgres' }
|
|
if (-not $env:DB_NAME) { $env:DB_NAME = 'travelhub' }
|
|
}
|
|
|
|
# --- compose helpers -------------------------------------------------------
|
|
|
|
function Compose {
|
|
param([Parameter(ValueFromRemainingArguments = $true)] $ComposeArgs)
|
|
Push-Location $Root
|
|
try { & docker compose @ComposeArgs } finally { Pop-Location }
|
|
}
|
|
|
|
function Wait-ForUrl($url, $timeoutSec) {
|
|
$deadline = (Get-Date).AddSeconds($timeoutSec)
|
|
while ((Get-Date) -lt $deadline) {
|
|
try { Invoke-WebRequest $url -UseBasicParsing -TimeoutSec 3 | Out-Null; return $true }
|
|
catch { Start-Sleep -Seconds 2 }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Show-Ready {
|
|
Write-Host ''
|
|
if (Wait-ForUrl 'http://localhost:8080/api/health' 90) { Write-Ok 'API healthy -> http://localhost:8080' }
|
|
else { Write-Warn2 'API not healthy yet -- check: .\docker.ps1 logs -Service api' }
|
|
if (Wait-ForUrl 'http://localhost:4200/' 60) { Write-Ok 'App ready -> http://localhost:4200' }
|
|
else { Write-Warn2 'Web not ready yet -- check: .\docker.ps1 logs -Service web' }
|
|
Write-Host ''
|
|
Write-Host 'Sign in with any demo account, password demo1234 (e.g. agent@skyline.test / skyline).'
|
|
Write-Host 'Note: stop any native .\app.ps1 first -- it uses the same ports.' -ForegroundColor DarkGray
|
|
}
|
|
|
|
# --- actions ---------------------------------------------------------------
|
|
|
|
switch ($Action) {
|
|
'setup' {
|
|
Require-Docker; Import-DbEnv
|
|
Write-Step 'Building images (first run downloads base images)'
|
|
Compose build
|
|
Write-Step 'Starting stack and seeding the database'
|
|
Compose up -d
|
|
Show-Ready
|
|
Write-Ok 'Setup complete.'
|
|
}
|
|
'start' {
|
|
Require-Docker; Import-DbEnv
|
|
Write-Step 'Starting stack'
|
|
Compose up -d
|
|
Show-Ready
|
|
}
|
|
'stop' {
|
|
Require-Docker; Import-DbEnv
|
|
Write-Step 'Stopping stack (database volume kept)'
|
|
Compose down
|
|
Write-Ok 'Stopped.'
|
|
}
|
|
'restart' {
|
|
Require-Docker; Import-DbEnv
|
|
Compose down
|
|
Compose up -d
|
|
Show-Ready
|
|
}
|
|
'reset' {
|
|
Require-Docker; Import-DbEnv
|
|
Write-Warn2 'This DELETES the database volume. All data will be lost.'
|
|
Write-Step 'Removing containers and the data volume'
|
|
Compose down -v
|
|
Write-Step 'Starting fresh (re-seeds with current flight dates)'
|
|
Compose up -d
|
|
Show-Ready
|
|
Write-Ok 'Reset complete.'
|
|
}
|
|
'rebuild' {
|
|
Require-Docker; Import-DbEnv
|
|
Write-Step 'Rebuilding images'
|
|
Compose build --no-cache
|
|
Compose up -d
|
|
Show-Ready
|
|
}
|
|
'status' {
|
|
Require-Docker; Import-DbEnv
|
|
Compose ps
|
|
}
|
|
'logs' {
|
|
Require-Docker; Import-DbEnv
|
|
$logArgs = @('logs')
|
|
if ($Follow) { $logArgs += '-f' } else { $logArgs += @('--tail', '80') }
|
|
if ($Service) { $logArgs += $Service }
|
|
Compose @logArgs
|
|
}
|
|
default {
|
|
Get-Help $PSCommandPath -Detailed
|
|
}
|
|
}
|