From 619e83acb6b247c5334ddb82affa3ab0cc010838 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Sun, 5 Apr 2026 15:53:02 -0400 Subject: [PATCH] Add unified deploy.sh and systemd service unit - Merge setup.sh and deploy.sh into single deploy.sh - First run (no .env): creates DB user/database, deploys schema + functions, builds UI, installs systemd service - Subsequent runs: optionally change DB target, redeploy functions, rebuild UI, restart service - Add dataflow.service systemd unit for process management - Remove setup.sh Co-Authored-By: Claude Sonnet 4.6 --- dataflow.service | 15 ++++ deploy.sh | 199 +++++++++++++++++++++++++++++++++++++++++++++++ setup.sh | 129 ------------------------------ 3 files changed, 214 insertions(+), 129 deletions(-) create mode 100644 dataflow.service create mode 100755 deploy.sh delete mode 100755 setup.sh diff --git a/dataflow.service b/dataflow.service new file mode 100644 index 0000000..4baf932 --- /dev/null +++ b/dataflow.service @@ -0,0 +1,15 @@ +[Unit] +Description=Dataflow API Server +After=network.target postgresql.service + +[Service] +Type=simple +User=pt +WorkingDirectory=/opt/dataflow +EnvironmentFile=/opt/dataflow/.env +ExecStart=/home/pt/.nvm/versions/node/v24.11.1/bin/node api/server.js +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..5fca253 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,199 @@ +#!/bin/bash +# +# Dataflow Deploy Script +# First run: creates DB user/database, deploys schema, builds UI, installs service +# Subsequent runs: updates functions, rebuilds UI, restarts service +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "Dataflow Deploy" +echo "===============" +echo "" + +# ── First-time setup ────────────────────────────────────────────────────────── +if [ ! -f .env ]; then + echo "No .env found — running first-time setup." + echo "" + + # Admin credentials (needed to create user/database) + echo "PostgreSQL Admin Credentials" + read -p " Admin username [postgres]: " ADMIN_USER; ADMIN_USER=${ADMIN_USER:-postgres} + read -s -p " Admin password: " ADMIN_PASS; echo "" + echo "" + + # App credentials + echo "Application Database" + read -p " Host [localhost]: " DB_HOST; DB_HOST=${DB_HOST:-localhost} + read -p " Port [5432]: " DB_PORT; DB_PORT=${DB_PORT:-5432} + read -p " Database name [dataflow]: " DB_NAME; DB_NAME=${DB_NAME:-dataflow} + read -p " App username [dataflow]: " DB_USER; DB_USER=${DB_USER:-dataflow} + read -s -p " App password: " DB_PASSWORD; echo "" + echo "" + + # API config + echo "API Configuration" + read -p " Port [3020]: " API_PORT; API_PORT=${API_PORT:-3020} + read -p " Environment [production]: " NODE_ENV; NODE_ENV=${NODE_ENV:-production} + echo "" + + # Install Node dependencies + echo "Installing Node.js dependencies..." + npm install --prefix . --omit=dev -q + cd ui && npm install -q && cd .. + echo "✓ Dependencies installed" + echo "" + + # Test admin connection + echo "Testing admin connection..." + export PGPASSWORD="$ADMIN_PASS" + if ! psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -c '\q' 2>/dev/null; then + echo "✗ Cannot connect as $ADMIN_USER — check credentials" + exit 1 + fi + echo "✓ Admin connection OK" + + # Create app user + if psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -tAc \ + "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then + echo "✓ User '$DB_USER' already exists" + else + psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres \ + -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';" > /dev/null + echo "✓ User '$DB_USER' created" + fi + + # Create database + if psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -lqt \ + | cut -d'|' -f1 | grep -qw "$DB_NAME"; then + echo "✓ Database '$DB_NAME' already exists" + else + psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres \ + -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" > /dev/null + echo "✓ Database '$DB_NAME' created" + fi + unset PGPASSWORD + + # Write .env + cat > .env << ENVEOF +# Database Configuration +DB_HOST=$DB_HOST +DB_PORT=$DB_PORT +DB_NAME=$DB_NAME +DB_USER=$DB_USER +DB_PASSWORD=$DB_PASSWORD + +# API Configuration +API_PORT=$API_PORT +NODE_ENV=$NODE_ENV +ENVEOF + echo "✓ .env written" + echo "" + + # Deploy schema (first time only) + export PGPASSWORD="$DB_PASSWORD" + echo "Deploying schema..." + psql -U "$DB_USER" -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -f database/schema.sql -q + echo "✓ Schema deployed" + + DEPLOY_FN=y + BUILD_UI=y + INSTALL_SERVICE=y + RESTART=y + +# ── Update mode ─────────────────────────────────────────────────────────────── +else + export $(cat .env | grep -v '^#' | xargs) + + echo "Current database: ${DB_USER}@${DB_HOST}:${DB_PORT}/${DB_NAME}" + read -p "Change database target? [y/N]: " IN + if [[ "$IN" =~ ^[Yy]$ ]]; then + echo "" + read -p " Host [${DB_HOST}]: " IN; DB_HOST=${IN:-$DB_HOST} + read -p " Port [${DB_PORT}]: " IN; DB_PORT=${IN:-$DB_PORT} + read -p " Database name [${DB_NAME}]: " IN; DB_NAME=${IN:-$DB_NAME} + read -p " User [${DB_USER}]: " IN; DB_USER=${IN:-$DB_USER} + read -s -p " Password (blank = keep current): " IN; echo "" + if [ -n "$IN" ]; then DB_PASSWORD=$IN; fi + + cat > .env << ENVEOF +# Database Configuration +DB_HOST=$DB_HOST +DB_PORT=$DB_PORT +DB_NAME=$DB_NAME +DB_USER=$DB_USER +DB_PASSWORD=$DB_PASSWORD + +# API Configuration +API_PORT=${API_PORT:-3020} +NODE_ENV=${NODE_ENV:-production} +ENVEOF + echo "✓ .env updated" + fi + echo "" + + export PGPASSWORD="$DB_PASSWORD" + echo "Testing database connection..." + if ! psql -U "$DB_USER" -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -c '\q' 2>/dev/null; then + echo "✗ Cannot connect — check credentials" + exit 1 + fi + echo "✓ Connected to ${DB_NAME} on ${DB_HOST}:${DB_PORT}" + echo "" + + read -p "Redeploy SQL functions? [Y/n]: " DEPLOY_FN + read -p "Rebuild UI? [Y/n]: " BUILD_UI + read -p "Restart API server? [Y/n]: " RESTART + INSTALL_SERVICE=n +fi + +# ── Shared steps ────────────────────────────────────────────────────────────── + +if [[ ! "$DEPLOY_FN" =~ ^[Nn]$ ]]; then + echo "" + echo "Deploying SQL functions..." + export PGPASSWORD="$DB_PASSWORD" + psql -U "$DB_USER" -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -f database/functions.sql -q + echo "✓ Functions deployed" +fi + +if [[ ! "$BUILD_UI" =~ ^[Nn]$ ]]; then + echo "" + echo "Building UI..." + cd ui && npm run build && cd .. + echo "✓ UI built" +fi + +# Systemd service +echo "" +SERVICE_FILE="/etc/systemd/system/dataflow.service" +if [ ! -f "$SERVICE_FILE" ] && [[ "$INSTALL_SERVICE" =~ ^[Yy]$ ]]; then + read -p "Install systemd service? (requires sudo) [Y/n]: " IN + if [[ ! "$IN" =~ ^[Nn]$ ]]; then + sudo cp "$SCRIPT_DIR/dataflow.service" "$SERVICE_FILE" + sudo systemctl daemon-reload + sudo systemctl enable dataflow + echo "✓ Service installed and enabled" + fi +fi + +if [[ ! "$RESTART" =~ ^[Nn]$ ]]; then + echo "" + if [ -f "$SERVICE_FILE" ]; then + sudo systemctl restart dataflow + sleep 1 + if systemctl is-active --quiet dataflow; then + echo "✓ Service restarted and running" + else + echo "✗ Service failed — check: journalctl -u dataflow -n 30" + fi + else + echo " Systemd service not installed. Start manually: node api/server.js" + fi +fi + +echo "" +echo "✓ Done — http://localhost:${API_PORT}" diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 9ffa37a..0000000 --- a/setup.sh +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/bash -# -# Dataflow Setup Script -# Quick setup for development -# - -set -e - -echo "🚀 Dataflow Setup" -echo "=================" -echo "" - -# Load .env if it exists -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | xargs) -fi - -# Prompt for admin credentials -echo "📋 PostgreSQL Admin Credentials" -echo " (Used to create user and database)" -echo "" -read -p "Admin username [postgres]: " ADMIN_USER -ADMIN_USER=${ADMIN_USER:-postgres} -read -s -p "Admin password: " ADMIN_PASS -echo "" -echo "" - -# Prompt for app user and database -echo "📋 Application Credentials" -echo "" -read -p "App username [dataflow]: " APP_USER -APP_USER=${APP_USER:-dataflow} -read -s -p "App password: " APP_PASS -echo "" -read -p "Database name [dataflow]: " DB_NAME -DB_NAME=${DB_NAME:-dataflow} -read -p "Database host [localhost]: " DB_HOST -DB_HOST=${DB_HOST:-localhost} -read -p "Database port [5432]: " DB_PORT -DB_PORT=${DB_PORT:-5432} -echo "" - -# Prompt for API configuration -echo "📋 API Configuration" -echo "" -read -p "API port [3000]: " API_PORT -API_PORT=${API_PORT:-3000} -read -p "Node environment [development]: " NODE_ENV -NODE_ENV=${NODE_ENV:-development} -echo "" - -# Install dependencies -echo "" -echo "📦 Installing Node.js dependencies..." -npm install -echo "" - -# Test admin connection -echo "🔍 Testing PostgreSQL admin connection..." -export PGPASSWORD="$ADMIN_PASS" -if psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -c '\q' 2>/dev/null; then - echo "✓ PostgreSQL connection successful" -else - echo "✗ Cannot connect to PostgreSQL" - echo " Please check your admin credentials" - exit 1 -fi - -# Create user if it doesn't exist -echo "" -echo "👤 Creating PostgreSQL user..." -if psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -tAc "SELECT rolname FROM pg_roles WHERE rolname='$APP_USER'" | grep -q "^$APP_USER$"; then - echo "✓ User '$APP_USER' already exists" -else - psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -c "CREATE USER $APP_USER WITH PASSWORD '$APP_PASS';" - echo "✓ User '$APP_USER' created" -fi - -# Create database if it doesn't exist -echo "" -echo "🗄️ Creating database..." -if psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -lqt | cut -d \| -f 1 | grep -qw "$DB_NAME"; then - echo "✓ Database '$DB_NAME' exists" -else - psql -U "$ADMIN_USER" -h "$DB_HOST" -p "$DB_PORT" -d postgres -c "CREATE DATABASE $DB_NAME OWNER $APP_USER;" - echo "✓ Database '$DB_NAME' created" -fi - -unset PGPASSWORD - -# Set password for app user -export PGPASSWORD="$APP_PASS" - -# Save credentials to .env -echo "" -echo "💾 Saving credentials to .env..." -cat > .env << EOF -# Database Configuration -DB_HOST=$DB_HOST -DB_PORT=$DB_PORT -DB_NAME=$DB_NAME -DB_USER=$APP_USER -DB_PASSWORD=$APP_PASS - -# API Configuration -API_PORT=$API_PORT -NODE_ENV=$NODE_ENV -EOF -echo "✓ Credentials saved" - -# Deploy schema -echo "" -echo "📋 Deploying database schema..." -psql -U "$APP_USER" -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -f database/schema.sql -echo "✓ Schema deployed" - -echo "" -echo "⚙️ Deploying database functions..." -psql -U "$APP_USER" -h "$DB_HOST" -p "$DB_PORT" -d "$DB_NAME" -f database/functions.sql -echo "✓ Functions deployed" - -echo "" -echo "✅ Setup complete!" -echo "" -echo "Next steps:" -echo " 1. Start the server: npm start" -echo " 2. Test the API: curl http://localhost:$API_PORT/health" -echo " 3. Follow the guide: examples/GETTING_STARTED.md" -echo ""