From fad47df6421cfa561fae524ad15645ed9c8613a8 Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Sat, 18 Oct 2025 16:10:16 +0100 Subject: [PATCH] Better dev script --- backend/handlers/services/services.go | 2 +- local-dev.sh | 176 +++++++++++++++++++++++--- 2 files changed, 156 insertions(+), 22 deletions(-) diff --git a/backend/handlers/services/services.go b/backend/handlers/services/services.go index c34ab9e..aba6269 100644 --- a/backend/handlers/services/services.go +++ b/backend/handlers/services/services.go @@ -74,7 +74,7 @@ func ToggleService(w http.ResponseWriter, r *http.Request) { }) } -// CreateServiceHandler handles creating a new service +// POST /api/admin/services func CreateServiceHandler(w http.ResponseWriter, r *http.Request) { // Parse and validate request var req CreateServiceRequest diff --git a/local-dev.sh b/local-dev.sh index cf80715..f61a6f7 100755 --- a/local-dev.sh +++ b/local-dev.sh @@ -1,6 +1,7 @@ #!/usr/bin/env zsh SESSION_NAME="crussell-dev" +BACKEND_PORT="8080" # --- Load root .env into environment --- set -a @@ -8,11 +9,11 @@ source .env set +a echo "✅ Loaded environment from .env" -# --- Check if Docker is running, auto-start if necessary --- +# --- Check if Docker is running --- if ! docker info > /dev/null 2>&1; then echo "🐳 Docker daemon is not running. Attempting to start it..." sudo systemctl start docker - sleep 2 + sleep 1 if ! docker info > /dev/null 2>&1; then echo "❌ Failed to start Docker. Exiting." exit 1 @@ -25,10 +26,10 @@ echo "🗑️ Resetting PostgreSQL container..." docker compose down -v postgres docker compose up postgres -d -echo "⏳ Waiting 5 seconds for DB init..." -sleep 5 +echo "⏳ Waiting 3 seconds for DB init..." +sleep 3 -# --- Kill existing tmux session (optional clean start) --- +# --- Kill existing tmux session --- tmux has-session -t $SESSION_NAME 2>/dev/null if [ $? -eq 0 ]; then echo "⚠️ Existing tmux session detected — killing it..." @@ -37,29 +38,162 @@ fi # --- Start new tmux session --- echo "🎛️ Starting tmux session: $SESSION_NAME" -tmux new-session -d -s $SESSION_NAME -n DB +tmux new-session -d -s $SESSION_NAME -n "DB" -# Pane 1: DB (already named `DB` via -n) -tmux send-keys -t $SESSION_NAME "docker exec -it postgres psql -U myuser -d mydb -c \"\\dt\"" C-m +# Pane 0: DB +tmux send-keys -t $SESSION_NAME "docker exec -it postgres psql -U myuser -d mydb -c \"\dt\"" C-m -# Split for Frontend -tmux split-window -h -t $SESSION_NAME -tmux select-pane -t $SESSION_NAME:0.1 -T "Frontend" -tmux send-keys -t $SESSION_NAME:0.1 "cd frontend && npm run dev -- --host" C-m +# Split for Backend (pane 1) - split horizontally first +tmux split-window -v -t $SESSION_NAME +tmux send-keys -t $SESSION_NAME:0.1 "cd backend && go run -tags dev ./main.go" C-m -# Split for Backend -tmux split-window -h -t $SESSION_NAME -tmux select-pane -t $SESSION_NAME:0.2 -T "Backend" -tmux send-keys -t $SESSION_NAME:0.2 "cd backend && go run -tags dev ./main.go" C-m +# Split for Frontend (pane 2) - split the backend pane vertically +tmux split-window -h -t $SESSION_NAME:0.1 +tmux send-keys -t $SESSION_NAME:0.2 "cd frontend && npm run dev -- --host" C-m -# Balance layout -tmux select-layout -t $SESSION_NAME even-horizontal +# Create a temporary script for seeding with correct field names +cat > /tmp/seed_data.sh << 'EOF' +#!/bin/bash -# Ensure pane 0 is labeled correctly +ADMIN_EMAIL="admin@example.com" +ADMIN_PASS="password" +BASE_URL="http://localhost:8080/api" + +echo "⏳ Waiting for backend to be ready..." +# Wait for backend to start responding +for i in {1..30}; do + if curl -s http://localhost:8080/health > /dev/null 2>&1 || curl -s http://localhost:8080/api/health > /dev/null 2>&1; then + echo "✅ Backend is ready!" + break + fi + if [ $i -eq 30 ]; then + echo "❌ Backend failed to start within 30 seconds" + exit 1 + fi + echo "Waiting for backend... ($i/30)" + sleep 1 +done + +echo "1️⃣ Registering Admin User: $ADMIN_EMAIL" +REGISTER_JSON='{"firstName":"Admin","lastName":"User","email":"'$ADMIN_EMAIL'","password":"'$ADMIN_PASS'","phone":"+447000000000","dateOfBirth":"1985-01-01","agreedToPolicy":true}' +REGISTER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST -H 'Content-Type: application/json' -d "$REGISTER_JSON" $BASE_URL/register) +HTTP_CODE=$(echo "$REGISTER_RESPONSE" | tail -n1) +RESPONSE_BODY=$(echo "$REGISTER_RESPONSE" | sed '$d') + +if [ "$HTTP_CODE" = "201" ]; then + echo '✅ Registration successful.' +else + echo "❌ Registration failed with HTTP $HTTP_CODE" + echo "Response: $RESPONSE_BODY" +fi + +echo "2️⃣ Upgrading to Admin Role via psql..." +docker exec postgres psql -U myuser -d mydb -c "UPDATE users SET account_role = 'admin' WHERE email = '$ADMIN_EMAIL'" + +echo "⏳ Waiting 1 seconds for role update to propagate..." +sleep 1 + +echo "3️⃣ Logging in to get JWT token..." +LOGIN_JSON='{"email":"'$ADMIN_EMAIL'","password":"'$ADMIN_PASS'"}' +LOGIN_RESPONSE=$(curl -s -X POST -H 'Content-Type: application/json' -d "$LOGIN_JSON" $BASE_URL/login) + +# Extract token without jq (using grep and sed) +TOKEN=$(echo "$LOGIN_RESPONSE" | grep -o '"token":"[^"]*' | sed 's/"token":"//') + +if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then + echo '❌ Login failed. Cannot proceed with service creation.' + echo "Login response: $LOGIN_RESPONSE" + exit 1 +fi +echo '✅ Login successful. Token obtained.' +echo "Token (first 30 chars): ${TOKEN:0:30}..." + +# Add extra delay to ensure token is fully processed +echo "⏳ Waiting 1 seconds before creating services..." +sleep 1 + +echo '4️⃣ Creating 6 Nail Bar Services...' + +# Updated services with correct field names based on CreateServiceRequest struct +# Note: description is optional (omitempty), all other fields are required +SERVICES=( + '{"name":"Classic Manicure","description":"Nail shaping, cuticle care, hand massage, and polish.","price":25.00,"duration_minutes":45,"patch_test_duration_hours":0,"minimum_age_required":0}' + '{"name":"Gel Manicure (BIAB)","description":"Hard-wearing gel polish with Builder In A Bottle base.","price":35.00,"duration_minutes":60,"patch_test_duration_hours":0,"minimum_age_required":0}' + '{"name":"Luxury Pedicure","description":"Foot soak, scrub, mask, extended massage, and polish.","price":45.00,"duration_minutes":75,"patch_test_duration_hours":0,"minimum_age_required":0}' + '{"name":"Express Mani & Pedi","description":"Quick file, shape, and polish for both hands and feet.","price":40.00,"duration_minutes":60,"patch_test_duration_hours":0,"minimum_age_required":0}' + '{"name":"Gel Polish Removal","description":"Safe removal of existing gel polish.","price":10.00,"duration_minutes":20,"patch_test_duration_hours":0,"minimum_age_required":0}' + '{"name":"Nail Art Add-on","description":"Custom nail art, per two fingers.","price":5.00,"duration_minutes":15,"patch_test_duration_hours":0,"minimum_age_required":0}' +) + +SUCCESS_COUNT=0 +FAIL_COUNT=0 +for SERVICE_JSON in "${SERVICES[@]}"; do + SERVICE_NAME=$(echo "$SERVICE_JSON" | grep -o '"name":"[^"]*' | cut -d'"' -f4) + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Creating: $SERVICE_NAME" + echo "Request JSON: $SERVICE_JSON" + + CREATE_RESPONSE=$(curl -v -X POST \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer $TOKEN" \ + -d "$SERVICE_JSON" \ + "$BASE_URL/admin/services" 2>&1) + + # Extract HTTP code from verbose output + HTTP_CODE=$(echo "$CREATE_RESPONSE" | grep "< HTTP" | awk '{print $3}') + + # Get the response body (last few lines after headers) + RESPONSE_BODY=$(echo "$CREATE_RESPONSE" | sed -n '/^{/,$p' | grep '^{') + + if [ "$HTTP_CODE" = "201" ]; then + SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) + echo "✅ Created: $SERVICE_NAME" + else + FAIL_COUNT=$((FAIL_COUNT + 1)) + echo "❌ Failed to create: $SERVICE_NAME (HTTP $HTTP_CODE)" + echo "Full curl output:" + echo "$CREATE_RESPONSE" + if [ -n "$RESPONSE_BODY" ]; then + echo "Response body: $RESPONSE_BODY" + fi + fi + sleep 0.15 # Small delay between requests +done + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✅ Successfully created: $SUCCESS_COUNT services" +echo "❌ Failed: $FAIL_COUNT services" +EOF + +chmod +x /tmp/seed_data.sh + +echo "🌱 Starting data seeding in background..." +# Run seeding in a temporary window +tmux new-window -t $SESSION_NAME -n "Seeding" "bash /tmp/seed_data.sh; echo 'Seeding completed. Press any key to close...'; read -n1" + +# Monitor the seeding window and close it when done +( + # Wait for the seeding window process to complete + while tmux list-windows -t $SESSION_NAME | grep -q "Seeding"; do + sleep 1 + done +) & + +# Set pane titles tmux select-pane -t $SESSION_NAME:0.0 -T "DB" +tmux select-pane -t $SESSION_NAME:0.1 -T "Backend" +tmux select-pane -t $SESSION_NAME:0.2 -T "Frontend" -# Focus the DB pane before attaching +# Use even-vertical layout for better proportions +tmux select-layout -t $SESSION_NAME even-vertical + +# Focus on the DB pane tmux select-pane -t $SESSION_NAME:0.0 -# Attach +# Clean up temp file on exit +trap 'rm -f /tmp/seed_data.sh' EXIT + +# Attach to session tmux attach-session -t $SESSION_NAME \ No newline at end of file