# Start PostgreSQL with data directory = project/data/postgres (no Docker required) param([string]$Root = '') . "$PSScriptRoot\db-local.ps1" function Start-PostgresWithWait { param( [string]$PgBin, [string]$PgData, [int]$Port, [int]$TimeoutSec = 120 ) $postgres = Join-Path $PgBin 'postgres.exe' if (-not (Test-Path $postgres)) { Write-Host ' [ERROR] postgres.exe not found' return $false } Write-Host ' Launching postgres...' [Console]::Out.Flush() # pg_ctl stdout/stderr를 PowerShell 파이프·캡처하면 Windows에서 영구 블로킹될 수 있음 → postgres 직접 기동 Start-Process -FilePath $postgres -ArgumentList @('-D', $PgData, '-p', "$Port") -WindowStyle Hidden | Out-Null for ($i = 1; $i -le $TimeoutSec; $i++) { if (Test-DbPortOpen -Port $Port) { Write-Host " PostgreSQL ready (${i}s)" return $true } if ($i -eq 1 -or $i % 5 -eq 0) { Write-Host " ... waiting for port $Port ($i/${TimeoutSec}s)" [Console]::Out.Flush() } Start-Sleep -Seconds 1 } return $false } if (-not $Root) { $Root = Get-ProjectRoot -FromScript $PSScriptRoot } $pgBin = Find-PgBin if (-not $pgBin) { Write-Host '[ERROR] PostgreSQL not found. Install PostgreSQL 16 or Docker Desktop.' return 1 } $pgData = Get-PgDataDir -Root $Root New-Item -ItemType Directory -Force -Path $pgData | Out-Null $initdb = Join-Path $pgBin 'initdb.exe' $pgCtl = Join-Path $pgBin 'pg_ctl.exe' $logFile = Get-PgCtlLogPath -Root $Root $hasData = Test-Path (Join-Path $pgData 'PG_VERSION') if ($hasData) { Write-Host ' Existing DB found: data\postgres (keeping your data)' } else { Write-Host ' No DB yet - will create data\postgres' } Ensure-BackendEnv -Root $Root Set-PostgresPort -PgData $pgData -Port $LocalDbPort Clear-StalePostmasterLock -PgData $pgData if (Test-DbPortOpen -Port $LocalDbPort) { Write-Host " PostgreSQL already running on port $LocalDbPort" return 0 } # pid file only, process dead -> stop cleanly before restart if (Test-Path (Join-Path $pgData 'postmaster.pid')) { Write-Host ' Cleaning up previous postgres instance...' [Console]::Out.Flush() $stopArgs = @('-D', $pgData, 'stop', '-m', 'fast', '-W', '-t', '5') $null = Start-Process -FilePath $pgCtl -ArgumentList $stopArgs -WindowStyle Hidden -Wait Start-Sleep -Seconds 1 Clear-StalePostmasterLock -PgData $pgData } if (-not $hasData) { Write-Host ' Local DB init (data\postgres)...' $migrated = $false try { $migrated = & "$PSScriptRoot\migrate-legacy-db.ps1" -Root $Root -PgBin $pgBin -PgData $pgData -Port $LocalDbPort } catch { Write-Warning $_.Exception.Message if (Test-Path $pgData) { Get-ChildItem $pgData -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } New-Item -ItemType Directory -Force -Path $pgData | Out-Null } if (-not $migrated) { & $initdb -D $pgData -U $LocalDbUser -E UTF8 --locale=C -A trust if ($LASTEXITCODE -ne 0) { Write-Host '[ERROR] initdb failed' return 1 } Set-PostgresPort -PgData $pgData -Port $LocalDbPort Clear-StalePostmasterLock -PgData $pgData Write-Host ' Starting PostgreSQL (new database)...' if (-not (Start-PostgresWithWait -PgBin $pgBin -PgData $pgData -Port $LocalDbPort)) { Write-Host '[ERROR] PostgreSQL did not start — see data\pg_ctl.log' return 1 } try { Invoke-Psql -PgBin $pgBin -Port $LocalDbPort -Sql "ALTER USER $LocalDbUser WITH PASSWORD '$LocalDbPassword';" Invoke-Psql -PgBin $pgBin -Port $LocalDbPort -Sql "CREATE DATABASE $LocalDbName OWNER $LocalDbUser;" } catch { Write-Host "[ERROR] $($_.Exception.Message)" return 1 } return 0 } } Write-Host ' Starting PostgreSQL (recovery after move may take 1-2 min)...' if (-not (Start-PostgresWithWait -PgBin $pgBin -PgData $pgData -Port $LocalDbPort)) { Write-Host '[ERROR] PostgreSQL did not start — see data\pg_ctl.log' Write-Host ' 1) 서버종료.bat db 2) 5초 대기 3) 서버시작.bat' Write-Host ' PC 종료 전 서버종료.bat db 로 DB 정상 종료 권장' Write-Host ' OneDrive/백신에서 data\postgres 제외' return 1 } return 0