feat: Server deployment scripts + Database init
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
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
This commit is contained in:
37
README.md
37
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
|
||||
|
||||
105
backend/scripts/init_db.py
Executable file
105
backend/scripts/init_db.py
Executable file
@ -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())
|
||||
|
||||
156
deploy.sh
Executable file
156
deploy.sh
Executable file
@ -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
|
||||
|
||||
65
start.sh
Executable file
65
start.sh
Executable file
@ -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
|
||||
|
||||
Reference in New Issue
Block a user