From 163c8d6ec73790af6893fe121b967fd6a5a12782 Mon Sep 17 00:00:00 2001 From: "yves.gugger" Date: Mon, 8 Dec 2025 16:54:14 +0100 Subject: [PATCH] feat: Server deployment scripts + Database init NEW FILES: - deploy.sh: One-command setup script (installs deps, creates venv, init db) - start.sh: Quick start script (launches both backend & frontend) - backend/scripts/init_db.py: Database initialization with schema + seed data CHANGES: - README: Added one-command setup instructions - All scripts made executable SERVER DEPLOYMENT: 1. git pull 2. chmod +x deploy.sh && ./deploy.sh 3. ./start.sh (or use PM2/Docker) The init_db.py script: - Creates all database tables - Seeds basic TLD info (com, net, org, io, etc.) - Works with both SQLite and PostgreSQL --- README.md | 37 ++++++--- backend/scripts/init_db.py | 105 +++++++++++++++++++++++++ deploy.sh | 156 +++++++++++++++++++++++++++++++++++++ start.sh | 65 ++++++++++++++++ 4 files changed, 353 insertions(+), 10 deletions(-) create mode 100755 backend/scripts/init_db.py create mode 100755 deploy.sh create mode 100755 start.sh diff --git a/README.md b/README.md index 0d4b112..8d96f14 100644 --- a/README.md +++ b/README.md @@ -204,14 +204,34 @@ pounce/ - Node.js 18+ - npm or yarn -### 1. Clone Repository +### 🚀 One-Command Setup (Recommended) + +```bash +# Clone repository +git clone https://git.6bit.ch/yvg/pounce.git +cd pounce + +# Run deployment script (sets up everything) +chmod +x deploy.sh +./deploy.sh + +# Start both services +chmod +x start.sh +./start.sh +``` + +That's it! Open http://localhost:3000 + +### Manual Setup + +#### 1. Clone Repository ```bash git clone https://git.6bit.ch/yvg/pounce.git cd pounce ``` -### 2. Backend Setup +#### 2. Backend Setup ```bash cd backend @@ -229,13 +249,10 @@ cp env.example .env # Generate secret key and add to .env python -c "import secrets; print(f'SECRET_KEY={secrets.token_hex(32)}')" -``` +# Edit .env with your SECRET_KEY -Edit `.env`: -```env -DATABASE_URL=sqlite+aiosqlite:///./domainwatch.db -SECRET_KEY=your-generated-secret-key -CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 +# Initialize database +python scripts/init_db.py ``` Start backend: @@ -243,7 +260,7 @@ Start backend: uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` -### 3. Frontend Setup +#### 3. Frontend Setup ```bash cd frontend @@ -258,7 +275,7 @@ echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local npm run dev ``` -### 4. Access Application +#### 4. Access Application - **Frontend:** http://localhost:3000 - **Backend API:** http://localhost:8000 diff --git a/backend/scripts/init_db.py b/backend/scripts/init_db.py new file mode 100755 index 0000000..1aa0837 --- /dev/null +++ b/backend/scripts/init_db.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +""" +Database initialization script. +Creates all tables and seeds initial data. + +Usage: + python scripts/init_db.py +""" + +import asyncio +import sys +import os + +# Add parent directory to path +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from app.database import engine, Base + +# Import all models to register them with SQLAlchemy +from app.models import user, domain, tld_price, newsletter, portfolio, price_alert + + +async def init_database(): + """Initialize database tables.""" + print("🔧 Initializing database...") + + async with engine.begin() as conn: + # Create all tables + await conn.run_sync(Base.metadata.create_all) + + print("✅ Database tables created successfully!") + print("") + print("Tables created:") + for table in Base.metadata.tables.keys(): + print(f" - {table}") + + +async def seed_tld_data(): + """Seed initial TLD data.""" + from sqlalchemy.ext.asyncio import AsyncSession + from sqlalchemy.orm import sessionmaker + from app.models.tld_price import TLDInfo + from sqlalchemy import select + + AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + + # Basic TLD data + tld_data = [ + {"tld": "com", "type": "generic", "description": "Commercial", "popularity_rank": 1}, + {"tld": "net", "type": "generic", "description": "Network", "popularity_rank": 2}, + {"tld": "org", "type": "generic", "description": "Organization", "popularity_rank": 3}, + {"tld": "io", "type": "country", "description": "Tech startups", "popularity_rank": 4}, + {"tld": "co", "type": "country", "description": "Company/Colombia", "popularity_rank": 5}, + {"tld": "ai", "type": "country", "description": "AI/Anguilla", "popularity_rank": 6}, + {"tld": "dev", "type": "generic", "description": "Developers", "popularity_rank": 7}, + {"tld": "app", "type": "generic", "description": "Applications", "popularity_rank": 8}, + {"tld": "xyz", "type": "generic", "description": "Generation XYZ", "popularity_rank": 9}, + {"tld": "me", "type": "country", "description": "Personal/Montenegro", "popularity_rank": 10}, + {"tld": "ch", "type": "country", "description": "Switzerland", "popularity_rank": 11}, + {"tld": "de", "type": "country", "description": "Germany", "popularity_rank": 12}, + {"tld": "uk", "type": "country", "description": "United Kingdom", "popularity_rank": 13}, + {"tld": "fr", "type": "country", "description": "France", "popularity_rank": 14}, + {"tld": "nl", "type": "country", "description": "Netherlands", "popularity_rank": 15}, + ] + + async with AsyncSessionLocal() as session: + for data in tld_data: + # Check if exists + result = await session.execute( + select(TLDInfo).where(TLDInfo.tld == data["tld"]) + ) + existing = result.scalar_one_or_none() + + if not existing: + tld_info = TLDInfo(**data) + session.add(tld_info) + print(f" Added: .{data['tld']}") + + await session.commit() + + print("✅ TLD data seeded!") + + +async def main(): + """Run all initialization steps.""" + print("=" * 50) + print("POUNCE Database Initialization") + print("=" * 50) + print("") + + await init_database() + print("") + + print("🌱 Seeding initial data...") + await seed_tld_data() + print("") + + print("=" * 50) + print("✅ Database initialization complete!") + print("=" * 50) + + +if __name__ == "__main__": + asyncio.run(main()) + diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..cff5d9e --- /dev/null +++ b/deploy.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# +# POUNCE Deployment Script +# Usage: ./deploy.sh [dev|prod] +# + +set -e + +MODE=${1:-dev} +echo "================================================" +echo " POUNCE Deployment - Mode: $MODE" +echo "================================================" +echo "" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Functions +log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } + +# ============================================ +# 1. Check prerequisites +# ============================================ +log_info "Checking prerequisites..." + +if ! command -v python3 &> /dev/null; then + log_error "Python3 not found. Please install Python 3.10+" + exit 1 +fi + +if ! command -v node &> /dev/null; then + log_error "Node.js not found. Please install Node.js 18+" + exit 1 +fi + +if ! command -v npm &> /dev/null; then + log_error "npm not found. Please install npm" + exit 1 +fi + +log_info "Prerequisites OK!" +echo "" + +# ============================================ +# 2. Setup Backend +# ============================================ +log_info "Setting up Backend..." + +cd backend + +# Create virtual environment if not exists +if [ ! -d "venv" ]; then + log_info "Creating Python virtual environment..." + python3 -m venv venv +fi + +# Activate venv +source venv/bin/activate + +# Install dependencies +log_info "Installing Python dependencies..." +pip install -q --upgrade pip +pip install -q -r requirements.txt + +# Create .env if not exists +if [ ! -f ".env" ]; then + log_warn ".env file not found, copying from env.example..." + if [ -f "env.example" ]; then + cp env.example .env + log_warn "Please edit backend/.env with your settings!" + else + log_error "env.example not found!" + fi +fi + +# Initialize database +log_info "Initializing database..." +python scripts/init_db.py + +cd .. +log_info "Backend setup complete!" +echo "" + +# ============================================ +# 3. Setup Frontend +# ============================================ +log_info "Setting up Frontend..." + +cd frontend + +# Install dependencies +log_info "Installing npm dependencies..." +npm install --silent + +# Create .env.local if not exists +if [ ! -f ".env.local" ]; then + log_warn ".env.local not found, creating..." + echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local +fi + +# Build for production +if [ "$MODE" == "prod" ]; then + log_info "Building for production..." + npm run build +fi + +cd .. +log_info "Frontend setup complete!" +echo "" + +# ============================================ +# 4. Start Services +# ============================================ +if [ "$MODE" == "dev" ]; then + echo "" + echo "================================================" + echo " Development Setup Complete!" + echo "================================================" + echo "" + echo "To start the services:" + echo "" + echo " Backend (Terminal 1):" + echo " cd backend && source venv/bin/activate" + echo " uvicorn app.main:app --reload --host 0.0.0.0 --port 8000" + echo "" + echo " Frontend (Terminal 2):" + echo " cd frontend && npm run dev" + echo "" + echo "Then open: http://localhost:3000" + echo "" +else + echo "" + echo "================================================" + echo " Production Setup Complete!" + echo "================================================" + echo "" + echo "To start with PM2:" + echo "" + echo " # Backend" + echo " cd backend && source venv/bin/activate" + echo " pm2 start 'uvicorn app.main:app --host 0.0.0.0 --port 8000' --name pounce-backend" + echo "" + echo " # Frontend" + echo " cd frontend" + echo " pm2 start 'npm start' --name pounce-frontend" + echo "" + echo "Or use Docker:" + echo " docker-compose up -d" + echo "" +fi + diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..1f4de39 --- /dev/null +++ b/start.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# POUNCE Quick Start Script +# Starts both backend and frontend for development +# + +set -e + +echo "🐆 Starting POUNCE..." +echo "" + +# Check if backend venv exists +if [ ! -d "backend/venv" ]; then + echo "❌ Backend not set up. Run ./deploy.sh first!" + exit 1 +fi + +# Kill any existing processes on our ports +echo "🔧 Cleaning up old processes..." +lsof -ti:8000 | xargs kill -9 2>/dev/null || true +lsof -ti:3000 | xargs kill -9 2>/dev/null || true +sleep 1 + +# Start Backend +echo "🚀 Starting Backend on port 8000..." +cd backend +source venv/bin/activate +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 & +BACKEND_PID=$! +cd .. + +# Wait for backend to start +sleep 3 + +# Check if backend is running +if curl -s http://localhost:8000/health > /dev/null 2>&1; then + echo "✅ Backend running!" +else + echo "❌ Backend failed to start. Check logs." + exit 1 +fi + +# Start Frontend +echo "🚀 Starting Frontend on port 3000..." +cd frontend +npm run dev & +FRONTEND_PID=$! +cd .. + +echo "" +echo "================================================" +echo " POUNCE is starting..." +echo "================================================" +echo "" +echo " Backend: http://localhost:8000" +echo " Frontend: http://localhost:3000" +echo " API Docs: http://localhost:8000/docs" +echo "" +echo " Press Ctrl+C to stop all services" +echo "" + +# Wait for both processes +trap "kill $BACKEND_PID $FRONTEND_PID 2>/dev/null" EXIT +wait +