From 77da44f3c8c837d6d3c22c6bc6b2929f4b7f1161 Mon Sep 17 00:00:00 2001 From: Deeman Date: Wed, 18 Feb 2026 12:16:37 +0100 Subject: [PATCH] add dev setup/run scripts and Resend test email docs Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 11 +++ padelnomics/.env.example | 13 ++- padelnomics/README.md | 31 +++++++ padelnomics/scripts/dev_run.sh | 62 ++++++++++++++ padelnomics/scripts/dev_setup.sh | 135 +++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 1 deletion(-) create mode 100755 padelnomics/scripts/dev_run.sh create mode 100755 padelnomics/scripts/dev_setup.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 237933a..c3ff4db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Added +- **Dev setup script** (`scripts/dev_setup.sh`) — interactive bootstrap that + checks prerequisites, installs deps, creates `.env` with auto-generated + `SECRET_KEY`, runs migrations, seeds test data, optionally sets up Paddle + sandbox products, and builds CSS +- **Dev run script** (`scripts/dev_run.sh`) — starts app, worker, and CSS + watcher in parallel with colored/labeled output and clean Ctrl-C shutdown +- **Resend test email docs** — documented Resend test addresses + (`delivered@resend.dev`, `bounced@resend.dev`, etc.) in `.env.example` and + README for testing email flows without a verified domain + ### Fixed - **Quote wizard state loss** — `_accumulated` hidden input used `"` attribute delimiters which broke on `tojson` output containing literal `"` characters; diff --git a/padelnomics/.env.example b/padelnomics/.env.example index de4e09a..2ed1b1a 100644 --- a/padelnomics/.env.example +++ b/padelnomics/.env.example @@ -12,7 +12,18 @@ DATABASE_PATH=data/app.db MAGIC_LINK_EXPIRY_MINUTES=15 SESSION_LIFETIME_DAYS=30 -# Email (Resend) — leave blank for dev (emails print to console) +# Email (Resend) +# Leave blank for dev — emails print to console (no Resend account needed). +# +# Resend test addresses (work with any valid API key, no verified domain needed): +# delivered@resend.dev — accepted, simulates successful delivery +# bounced@resend.dev — simulates a hard bounce +# complained@resend.dev — simulates a spam complaint +# suppressed@resend.dev — simulates a suppressed recipient +# These support +label syntax: delivered+test1@resend.dev +# You can also send FROM onboarding@resend.dev without a verified domain. +# +# Dev login shortcut (no email needed): /auth/dev-login?email=dev@localhost RESEND_API_KEY= EMAIL_FROM=hello@padelnomics.io ADMIN_EMAIL=leads@padelnomics.io diff --git a/padelnomics/README.md b/padelnomics/README.md index 7bf5f74..b07731d 100644 --- a/padelnomics/README.md +++ b/padelnomics/README.md @@ -2,6 +2,18 @@ Plan, finance, and build your padel business. +## Quick Start + +```bash +./scripts/dev_setup.sh # one-time: deps, .env, migrations, seed data, CSS +./scripts/dev_run.sh # start app + worker + CSS watcher +``` + +Then open: +- **App**: http://localhost:5000 +- **Dev login**: http://localhost:5000/auth/dev-login?email=dev@localhost +- **Admin**: http://localhost:5000/admin (password: `admin`) + ## Local Development Setup ### Prerequisites @@ -224,6 +236,25 @@ print('Test data seeded') " ``` +### Resend Test Emails + +When `RESEND_API_KEY` is blank (default), all emails print to the console — +no Resend account needed. + +When you have a Resend API key, you can use their test addresses to simulate +delivery outcomes without a verified domain: + +| Address | Behavior | +|---------|----------| +| `delivered@resend.dev` | Accepted, simulates successful delivery | +| `bounced@resend.dev` | Simulates a hard bounce | +| `complained@resend.dev` | Simulates a spam complaint | +| `suppressed@resend.dev` | Simulates a suppressed recipient | + +These support `+label` syntax (e.g. `delivered+test1@resend.dev`) for unique +recipients. You can also send **from** `onboarding@resend.dev` without a +verified domain. + --- ## Architecture Overview diff --git a/padelnomics/scripts/dev_run.sh b/padelnomics/scripts/dev_run.sh new file mode 100755 index 0000000..e61a85e --- /dev/null +++ b/padelnomics/scripts/dev_run.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# Start all Padelnomics dev processes with colored, labeled output. +# +# Usage: ./scripts/dev_run.sh +# +# Starts: app (port 5000), background worker, CSS watcher. +# Ctrl-C stops everything cleanly. + +set -euo pipefail + +cd "$(dirname "$0")/.." + +# -- Colors for each process ------------------------------------------------- + +COLOR_APP='\033[0;36m' # cyan +COLOR_WORKER='\033[0;33m' # yellow +COLOR_CSS='\033[0;35m' # magenta +NC='\033[0m' +BOLD='\033[1m' + +PIDS=() + +cleanup() { + echo "" + echo -e "${BOLD}Stopping all processes...${NC}" + for pid in "${PIDS[@]}"; do + 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. +# Usage: run_with_label COLOR LABEL COMMAND... +run_with_label() { + local color="$1" label="$2" + shift 2 + "$@" 2>&1 | while IFS= read -r line; do + echo -e "${color}[${label}]${NC} ${line}" + done & + PIDS+=($!) +} + +# -- Start processes --------------------------------------------------------- + +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" +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 diff --git a/padelnomics/scripts/dev_setup.sh b/padelnomics/scripts/dev_setup.sh new file mode 100755 index 0000000..7e04588 --- /dev/null +++ b/padelnomics/scripts/dev_setup.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# Bootstrap a local dev environment for Padelnomics. +# +# Usage: ./scripts/dev_setup.sh +# +# Checks prerequisites, installs deps, creates .env, runs migrations, +# seeds test data, and builds CSS. + +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' + +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; } + +# -- Prerequisites ----------------------------------------------------------- + +info "Checking prerequisites" + +command -v python3 >/dev/null 2>&1 || fail "python3 not found. Install Python 3.12+." +command -v uv >/dev/null 2>&1 || fail "uv not found. Install: https://docs.astral.sh/uv/getting-started/installation/" + +PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') +ok "python3 ${PYTHON_VERSION}" +ok "uv $(uv --version 2>/dev/null | head -1)" + +# -- Install dependencies ---------------------------------------------------- + +info "Installing Python dependencies" +uv sync +ok "Dependencies installed" + +# -- .env -------------------------------------------------------------------- + +if [ -f .env ]; then + warn ".env already exists — skipping creation" +else + info "Creating .env from .env.example" + cp .env.example .env + + # Auto-generate SECRET_KEY + SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))") + sed -i "s/^SECRET_KEY=.*/SECRET_KEY=${SECRET_KEY}/" .env + ok "SECRET_KEY generated" + + # Prompt for optional keys + echo "" + echo -e "${BOLD}Optional API keys${NC} (press Enter to skip — everything works without them)" + echo "" + + read -rp " Paddle API key (for checkout testing): " PADDLE_API_KEY + if [ -n "$PADDLE_API_KEY" ]; then + sed -i "s/^PADDLE_API_KEY=.*/PADDLE_API_KEY=${PADDLE_API_KEY}/" .env + ok "PADDLE_API_KEY set" + + read -rp " Paddle client token: " PADDLE_CLIENT_TOKEN + [ -n "$PADDLE_CLIENT_TOKEN" ] && sed -i "s/^PADDLE_CLIENT_TOKEN=.*/PADDLE_CLIENT_TOKEN=${PADDLE_CLIENT_TOKEN}/" .env + + read -rp " Paddle webhook secret: " PADDLE_WEBHOOK_SECRET + [ -n "$PADDLE_WEBHOOK_SECRET" ] && sed -i "s/^PADDLE_WEBHOOK_SECRET=.*/PADDLE_WEBHOOK_SECRET=${PADDLE_WEBHOOK_SECRET}/" .env + fi + + read -rp " Resend API key (for email testing): " RESEND_API_KEY + if [ -n "$RESEND_API_KEY" ]; then + sed -i "s/^RESEND_API_KEY=.*/RESEND_API_KEY=${RESEND_API_KEY}/" .env + ok "RESEND_API_KEY set" + fi + + echo "" + ok ".env created" +fi + +# -- Migrations --------------------------------------------------------------- + +info "Running database migrations" +uv run python -m padelnomics.migrations.migrate +ok "Migrations applied" + +# -- Seed data ---------------------------------------------------------------- + +info "Seeding development data" +uv run python -m padelnomics.scripts.seed_dev_data +ok "Dev data seeded" + +# -- Paddle setup (optional) -------------------------------------------------- + +if grep -q '^PADDLE_API_KEY=.\+' .env 2>/dev/null; then + echo "" + read -rp "$(echo -e "${BLUE}==>${NC} Set up Paddle sandbox products? [y/N] ")" SETUP_PADDLE + if [[ "$SETUP_PADDLE" =~ ^[Yy]$ ]]; then + uv run python -m padelnomics.scripts.setup_paddle + ok "Paddle products created" + fi +fi + +# -- CSS build ---------------------------------------------------------------- + +info "Building CSS" +make css-build +ok "CSS built" + +# -- Summary ------------------------------------------------------------------ + +echo "" +echo -e "${GREEN}${BOLD}Setup complete!${NC}" +echo "" +echo " Start all services: ./scripts/dev_run.sh" +echo "" +echo " URLs:" +echo " App: http://localhost:5000" +echo " Dev login: http://localhost:5000/auth/dev-login?email=dev@localhost" +echo " Admin: http://localhost:5000/admin (password: admin)" +echo "" +echo " Seeded accounts:" +echo " dev@localhost — dev user (use dev-login link above)" +echo "" +echo " Email:" +if grep -q '^RESEND_API_KEY=.\+' .env 2>/dev/null; then + echo " Resend configured — emails sent via API" + echo " Test addresses: delivered@resend.dev, bounced@resend.dev" +else + echo " No Resend key — emails print to console" +fi +echo ""