git mv all tracked files from the nested padelnomics/ workspace directory to the git repo root. Merged .gitignore files. No code changes — pure path rename. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
173 lines
5.6 KiB
Bash
Executable File
173 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Start all Padelnomics dev processes with colored, labeled output.
|
|
#
|
|
# Usage: ./scripts/dev_run.sh
|
|
#
|
|
# On each start: resets the DB, runs migrations, seeds data, 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
|
|
COLOR_NGROK='\033[0;32m' # green
|
|
|
|
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 (|| true prevents set -e from aborting on empty values)
|
|
DATABASE_PATH=$(grep '^DATABASE_PATH=' .env 2>/dev/null | cut -d= -f2- || true)
|
|
DATABASE_PATH=${DATABASE_PATH:-data/app.db}
|
|
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)
|
|
PADDLE_ENVIRONMENT=$(grep '^PADDLE_ENVIRONMENT=' .env 2>/dev/null | cut -d= -f2- || true)
|
|
PADDLE_ENVIRONMENT=${PADDLE_ENVIRONMENT:-sandbox}
|
|
|
|
# -- Preparation -------------------------------------------------------------
|
|
|
|
info "Resetting database"
|
|
rm -f "$DATABASE_PATH"
|
|
ok "Removed $DATABASE_PATH"
|
|
|
|
info "Running migrations"
|
|
uv run python -m padelnomics.migrations.migrate
|
|
ok "Migrations applied"
|
|
|
|
info "Seeding development data"
|
|
uv run python -m padelnomics.scripts.seed_dev_data
|
|
ok "Dev data seeded"
|
|
|
|
if [ -n "$PADDLE_API_KEY" ]; then
|
|
info "Syncing Paddle products to DB"
|
|
uv run python -m padelnomics.scripts.setup_paddle --sync
|
|
ok "Paddle products synced"
|
|
fi
|
|
|
|
info "Building CSS"
|
|
make css-build
|
|
ok "CSS built"
|
|
|
|
# -- Process management ------------------------------------------------------
|
|
|
|
PIDS=()
|
|
|
|
cleanup() {
|
|
echo ""
|
|
echo -e "${BOLD}Stopping all processes...${NC}"
|
|
for pid in "${PIDS[@]}"; do
|
|
# Kill children first (e.g. make → tailwind), then the process itself
|
|
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.
|
|
# Uses process substitution so $! is the actual command PID (not the formatter).
|
|
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 5000 --log=stdout --log-level=warn > /tmp/padelnomics-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"
|
|
|
|
# Update Paddle notification destination with tunnel URL
|
|
WEBHOOK_URL="${TUNNEL_URL}/billing/webhook/paddle"
|
|
info "Updating Paddle webhook destination → $WEBHOOK_URL"
|
|
uv run python -c "
|
|
import os
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
from paddle_billing import Client, Environment, Options
|
|
from paddle_billing.Resources.NotificationSettings.Operations import UpdateNotificationSetting
|
|
|
|
env = Environment.SANDBOX if '${PADDLE_ENVIRONMENT}' == 'sandbox' else Environment.PRODUCTION
|
|
paddle = Client('${PADDLE_API_KEY}', options=Options(env))
|
|
paddle.notification_settings.update(
|
|
'${PADDLE_NOTIFICATION_SETTING_ID}',
|
|
UpdateNotificationSetting(destination='${WEBHOOK_URL}'),
|
|
)
|
|
print(' Updated.')
|
|
"
|
|
ok "Paddle webhooks → $WEBHOOK_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 (or brew install ngrok)"
|
|
fi
|
|
elif [ -n "$PADDLE_API_KEY" ]; then
|
|
warn "PADDLE_NOTIFICATION_SETTING_ID not set — run setup_paddle to create webhook destination"
|
|
fi
|
|
|
|
# -- Start processes ---------------------------------------------------------
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Starting Padelnomics dev environment${NC}"
|
|
echo ""
|
|
echo " app: http://localhost:5000"
|
|
echo " admin: http://localhost:5000/admin"
|
|
echo " login: http://localhost:5000/auth/dev-login?email=dev@localhost"
|
|
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 python -m padelnomics.app
|
|
run_with_label "$COLOR_WORKER" "worker" uv run python -m padelnomics.worker
|
|
run_with_label "$COLOR_CSS" "css " make css-watch
|
|
|
|
wait
|