Polls /auth/dev-login until the app responds, then opens an incognito/private window — same pattern as padelnomics. Tries flatpak Chrome → flatpak Firefox → system Chrome → Chromium → Firefox in that order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
192 lines
6.6 KiB
Bash
192 lines
6.6 KiB
Bash
#!/usr/bin/env bash
|
|
# Start all BeanFlows dev processes with colored, labeled output.
|
|
#
|
|
# Usage: ./scripts/dev_run.sh
|
|
#
|
|
# On each start: runs migrations (idempotent), builds CSS, optionally starts
|
|
# ngrok for Paddle webhook forwarding, then starts app (port 5000),
|
|
# background worker, and CSS watcher.
|
|
# Ctrl-C stops everything cleanly.
|
|
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
# -- Colors & helpers --------------------------------------------------------
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
COLOR_APP='\033[0;36m' # cyan
|
|
COLOR_WORKER='\033[0;33m' # yellow
|
|
COLOR_CSS='\033[0;35m' # magenta
|
|
|
|
info() { echo -e "${BLUE}==>${NC} ${BOLD}$1${NC}"; }
|
|
ok() { echo -e "${GREEN} ✓${NC} $1"; }
|
|
warn() { echo -e "${YELLOW} !${NC} $1"; }
|
|
fail() { echo -e "${RED} ✗${NC} $1"; exit 1; }
|
|
|
|
# -- Preflight ---------------------------------------------------------------
|
|
|
|
if [ ! -f .env ]; then
|
|
fail ".env not found. Run ./scripts/dev_setup.sh first."
|
|
fi
|
|
|
|
# Load config from .env
|
|
PADDLE_API_KEY=$(grep '^PADDLE_API_KEY=' .env 2>/dev/null | cut -d= -f2- || true)
|
|
PADDLE_NOTIFICATION_SETTING_ID=$(grep '^PADDLE_NOTIFICATION_SETTING_ID=' .env 2>/dev/null | cut -d= -f2- || true)
|
|
|
|
# -- Preparation -------------------------------------------------------------
|
|
|
|
info "Running migrations"
|
|
uv run --package beanflows python -m beanflows.migrations.migrate
|
|
ok "Migrations applied"
|
|
|
|
info "Seeding dev accounts"
|
|
uv run --package beanflows python -m beanflows.dev_seed
|
|
ok "Dev accounts ready"
|
|
|
|
info "Building CSS"
|
|
make css-build
|
|
ok "CSS built"
|
|
|
|
# -- Pipeline (first-time only) ----------------------------------------------
|
|
# Runs extract → transform → export_serving from the repo root if analytics.duckdb
|
|
# does not exist yet. Subsequent dev_run.sh invocations skip this — delete
|
|
# analytics.duckdb from the repo root to force a full re-run.
|
|
|
|
REPO_ROOT="$(cd .. && pwd)"
|
|
PIPELINE_LANDING="$REPO_ROOT/data/landing"
|
|
PIPELINE_DUCKDB="$REPO_ROOT/local.duckdb"
|
|
PIPELINE_SERVING="$REPO_ROOT/analytics.duckdb"
|
|
|
|
if [ ! -f "$PIPELINE_SERVING" ]; then
|
|
info "First run — fetching and transforming data (this may take a few minutes)"
|
|
if (
|
|
cd "$REPO_ROOT"
|
|
LANDING_DIR="$PIPELINE_LANDING" DUCKDB_PATH="$PIPELINE_DUCKDB" \
|
|
uv run materia pipeline run extract &&
|
|
LANDING_DIR="$PIPELINE_LANDING" DUCKDB_PATH="$PIPELINE_DUCKDB" \
|
|
uv run materia pipeline run transform &&
|
|
DUCKDB_PATH="$PIPELINE_DUCKDB" SERVING_DUCKDB_PATH="$PIPELINE_SERVING" \
|
|
uv run materia pipeline run export_serving
|
|
); then
|
|
ok "Pipeline complete — dashboard ready"
|
|
else
|
|
warn "Pipeline did not complete — dashboard will show empty data"
|
|
fi
|
|
else
|
|
ok "Data ready (delete $PIPELINE_SERVING to force a pipeline re-run)"
|
|
fi
|
|
|
|
# -- Process management ------------------------------------------------------
|
|
|
|
PIDS=()
|
|
|
|
cleanup() {
|
|
echo ""
|
|
echo -e "${BOLD}Stopping all processes...${NC}"
|
|
for pid in "${PIDS[@]}"; do
|
|
pkill -P "$pid" 2>/dev/null || true
|
|
kill "$pid" 2>/dev/null || true
|
|
done
|
|
wait 2>/dev/null || true
|
|
echo "Done."
|
|
exit 0
|
|
}
|
|
|
|
trap cleanup SIGINT SIGTERM
|
|
|
|
# Prefix each line of a command's output with a colored label.
|
|
run_with_label() {
|
|
local color="$1" label="$2"
|
|
shift 2
|
|
"$@" > >(while IFS= read -r line; do echo -e "${color}[${label}]${NC} ${line}"; done) 2>&1 &
|
|
PIDS+=($!)
|
|
}
|
|
|
|
# -- Ngrok tunnel (if Paddle is configured) ----------------------------------
|
|
|
|
TUNNEL_URL=""
|
|
|
|
if [ -n "$PADDLE_API_KEY" ] && [ -n "$PADDLE_NOTIFICATION_SETTING_ID" ]; then
|
|
if command -v ngrok >/dev/null 2>&1; then
|
|
info "Starting ngrok tunnel for Paddle webhooks"
|
|
ngrok http 5001 --log=stdout --log-level=warn > /tmp/beanflows-ngrok.log 2>&1 &
|
|
NGROK_PID=$!
|
|
PIDS+=($NGROK_PID)
|
|
|
|
# Wait for ngrok to be ready (up to 10 seconds)
|
|
WAIT_SECONDS=10
|
|
for i in $(seq 1 $WAIT_SECONDS); do
|
|
TUNNEL_URL=$(curl -s http://localhost:4040/api/tunnels 2>/dev/null \
|
|
| python3 -c "import sys,json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])" 2>/dev/null) \
|
|
&& break
|
|
sleep 1
|
|
done
|
|
|
|
if [ -n "$TUNNEL_URL" ]; then
|
|
ok "ngrok tunnel: $TUNNEL_URL"
|
|
else
|
|
warn "ngrok started but tunnel URL not available — webhooks won't reach localhost"
|
|
fi
|
|
else
|
|
warn "ngrok not installed — Paddle webhooks won't reach localhost"
|
|
warn "Install: https://ngrok.com/download"
|
|
fi
|
|
elif [ -n "$PADDLE_API_KEY" ]; then
|
|
warn "PADDLE_NOTIFICATION_SETTING_ID not set — webhook forwarding disabled"
|
|
fi
|
|
|
|
# -- Start processes ---------------------------------------------------------
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Starting BeanFlows dev environment${NC}"
|
|
echo ""
|
|
echo " app: http://localhost:5001"
|
|
echo ""
|
|
echo " Login shortcuts (dev only):"
|
|
echo " admin: http://localhost:5001/auth/dev-login?email=admin@beanflows.coffee"
|
|
echo " free: http://localhost:5001/auth/dev-login?email=trader@beanflows.coffee"
|
|
echo " starter: http://localhost:5001/auth/dev-login?email=starter@beanflows.coffee"
|
|
echo " pro: http://localhost:5001/auth/dev-login?email=pro@beanflows.coffee"
|
|
if [ -n "$TUNNEL_URL" ]; then
|
|
echo " tunnel: $TUNNEL_URL"
|
|
fi
|
|
echo ""
|
|
echo "Press Ctrl-C to stop all processes."
|
|
echo ""
|
|
|
|
run_with_label "$COLOR_APP" "app " uv run --package beanflows python -m beanflows.app
|
|
run_with_label "$COLOR_WORKER" "worker" uv run --package beanflows python -m beanflows.worker
|
|
run_with_label "$COLOR_CSS" "css " make css-watch
|
|
|
|
# Open a private/incognito browser window once the server is ready.
|
|
# Polls /auth/dev-login until it responds (up to 10 seconds), then launches.
|
|
(
|
|
DEV_URL="http://localhost:5001/auth/dev-login?email=pro@beanflows.coffee"
|
|
for i in $(seq 1 20); do
|
|
sleep 0.5
|
|
if curl -s -o /dev/null -w "%{http_code}" "$DEV_URL" 2>/dev/null | grep -qE "^[23]"; then
|
|
break
|
|
fi
|
|
done
|
|
if flatpak info com.google.Chrome >/dev/null 2>&1; then
|
|
flatpak run com.google.Chrome --incognito "$DEV_URL" &>/dev/null &
|
|
elif flatpak info org.mozilla.firefox >/dev/null 2>&1; then
|
|
flatpak run org.mozilla.firefox --private-window "$DEV_URL" &>/dev/null &
|
|
elif command -v google-chrome >/dev/null 2>&1; then
|
|
google-chrome --incognito "$DEV_URL" &>/dev/null &
|
|
elif command -v chromium >/dev/null 2>&1; then
|
|
chromium --incognito "$DEV_URL" &>/dev/null &
|
|
elif command -v firefox >/dev/null 2>&1; then
|
|
firefox --private-window "$DEV_URL" &>/dev/null &
|
|
fi
|
|
) &
|
|
|
|
wait
|