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
- Added important notice about database initialization after fresh clone - Added TLD price scraping command (886+ TLDs from Porkbun) - Added auction scraping command - Explains what happens without these steps (only 18 TLDs, 0 auctions) - Notes that scheduler auto-scrapes daily/hourly
903 lines
28 KiB
Markdown
903 lines
28 KiB
Markdown
# pounce — Domain Availability Monitoring
|
||
|
||
A professional full-stack application for monitoring domain name availability with TLD price tracking and intelligence.
|
||
|
||
---
|
||
|
||
## ⚠️ Important: After Fresh Clone / Database Reset
|
||
|
||
If you just cloned the repo or reset the database, run these commands to populate data:
|
||
|
||
```bash
|
||
cd backend
|
||
source venv/bin/activate
|
||
|
||
# 1. Initialize database (creates tables)
|
||
python scripts/init_db.py
|
||
|
||
# 2. Scrape TLD prices (886+ TLDs from Porkbun)
|
||
python scripts/seed_tld_prices.py
|
||
|
||
# 3. (Optional) Scrape auctions immediately
|
||
python3 -c "
|
||
import asyncio
|
||
from app.services.auction_scraper import AuctionScraperService
|
||
from app.database import AsyncSessionLocal
|
||
|
||
async def scrape():
|
||
scraper = AuctionScraperService()
|
||
async with AsyncSessionLocal() as db:
|
||
await scraper.scrape_all_platforms(db)
|
||
await scraper.close()
|
||
|
||
asyncio.run(scrape())
|
||
"
|
||
```
|
||
|
||
Without these steps:
|
||
- TLD Pricing page shows only 18 TLDs (instead of 886+)
|
||
- Auctions page shows 0 auctions
|
||
- The scheduler will auto-scrape TLDs daily at 03:00 UTC and auctions hourly
|
||
|
||
---
|
||
|
||
## ⚡ Quick Start (Local Development)
|
||
|
||
**Terminal 1 - Backend:**
|
||
```bash
|
||
cd backend
|
||
source venv/bin/activate
|
||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
**Terminal 2 - Frontend:**
|
||
```bash
|
||
cd frontend
|
||
npm run dev
|
||
```
|
||
|
||
**Access:**
|
||
- Frontend: http://localhost:3000
|
||
- Backend: http://localhost:8000
|
||
- API Docs: http://localhost:8000/docs
|
||
|
||
### ⚠️ Common Console Warnings (Can be ignored)
|
||
|
||
| Warning | Explanation |
|
||
|---------|-------------|
|
||
| `SES Removing unpermitted intrinsics` | MetaMask/browser extension - harmless |
|
||
| `PostHog CORS blocked` | Normal on localhost, works in production |
|
||
| `-webkit-text-size-adjust` error | Old CSS prefixes - harmless |
|
||
| `-moz-column-gap` unknown | Old Firefox prefix - harmless |
|
||
| `preloaded font not used` | Next.js optimization - harmless |
|
||
|
||
### ❌ Actual Errors to Fix
|
||
|
||
| Error | Solution |
|
||
|-------|----------|
|
||
| `CORS request did not succeed` to localhost:8000 | **Start the backend!** |
|
||
| `500 Internal Server Error` | Check backend logs, run `python scripts/init_db.py` |
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
### Core Functionality
|
||
- **Domain Availability Monitoring** — Track any domain and get notified when it becomes available
|
||
- **Domain Portfolio Management** — Track domains you own with purchase price, value, and ROI
|
||
- **Domain Valuation Engine** — 100% transparent algorithmic valuation with detailed breakdown
|
||
- **Smart Pounce Auctions** — Aggregated auctions from GoDaddy, Sedo, NameJet & more
|
||
- **TLD Price Intelligence** — Compare prices across 886+ TLDs from Porkbun API
|
||
- **Automated Price Scraping** — Daily cronjob scrapes real TLD prices from public APIs
|
||
- **Price Change Alerts** — Email notifications when TLD prices change >5%
|
||
- **Expiration Tracking** — Monitor domain expiration dates and plan ahead
|
||
- **Real-time Checks** — RDAP, WHOIS, and DNS-based availability verification
|
||
- **Swiss Domain Support** — Special RDAP integration for .ch/.li domains via nic.ch
|
||
- **Historical Data** — Track price trends and availability history over time (12 months)
|
||
- **Email Notifications** — Domain available alerts, price changes, weekly digests
|
||
|
||
### Smart Pounce Auction Aggregator
|
||
- **Multi-Platform Search** — GoDaddy, Sedo, NameJet, SnapNames, DropCatch
|
||
- **Ending Soon** — Auctions ending in < 1 hour for sniping opportunities
|
||
- **Hot Auctions** — Most-bid domains across all platforms
|
||
- **Smart Opportunities** — AI-powered detection of undervalued domains
|
||
- **Affiliate Integration** — Click through to bid (no payment handling = Swiss GwG compliant)
|
||
- **Filters** — Search by keyword, TLD, platform, price range
|
||
|
||
### Domain Valuation (Transparent)
|
||
- **Clear Formula** — `Value = Base × Length × TLD × Keyword × Brand`
|
||
- **Factor Breakdown** — Each multiplier explained (e.g., "4-letter domain ×5.0")
|
||
- **Confidence Levels** — High/Medium/Low based on score consistency
|
||
- **Real TLD Costs** — Registration cost context from database
|
||
- **Value-to-Cost Ratio** — Investment decision metric
|
||
- **Disclaimer** — Clear limitations of algorithmic valuation
|
||
|
||
### User Experience
|
||
- **Modern UI** — Clean, minimalist dark-mode design with smooth animations
|
||
- **Responsive** — Fully optimized for desktop, tablet, and mobile
|
||
- **Authentication** — Secure JWT-based auth with subscription tiers
|
||
- **Dashboard** — Personal watchlist with status indicators and actions
|
||
|
||
### Security Features (v1.1)
|
||
- **Password Reset** — Secure token-based password recovery via email
|
||
- **Email Verification** — Optional email confirmation for new accounts
|
||
- **Rate Limiting** — Protection against brute-force attacks (slowapi)
|
||
- **Stripe Payments** — Secure subscription payments with Stripe Checkout
|
||
- **Stripe Customer Portal** — Manage billing, view invoices, cancel subscriptions
|
||
- **Contact Form** — With email confirmation and spam protection
|
||
- **Newsletter** — Subscribe/unsubscribe with double opt-in
|
||
|
||
### CI/CD Pipeline (v1.2)
|
||
- **GitHub Actions** — Automated CI/CD on push to main
|
||
- **Frontend Lint** — ESLint + TypeScript type checking
|
||
- **Backend Lint** — Ruff linter for Python
|
||
- **Docker Build** — Multi-stage build verification
|
||
- **Security Scan** — Trivy vulnerability scanner
|
||
- **Automated Deploy** — SSH deployment to production server
|
||
|
||
### TLD Detail Page (Professional)
|
||
- **Price Hero** — Instant view of cheapest price with direct registration link
|
||
- **Price Alert System** — Subscribe to email notifications for price changes
|
||
- **Interactive Price Chart** — 1M/3M/1Y/ALL time periods with hover tooltips
|
||
- **Domain Search** — Check availability directly on the TLD page
|
||
- **Registrar Comparison** — Full table with Register/Renew/Transfer prices + external links
|
||
- **Savings Calculator** — Shows how much you save vs most expensive registrar
|
||
- **Renewal Warning** — ⚠️ indicator when renewal price is >1.5x registration price
|
||
- **Related TLDs** — Smart suggestions based on current TLD (e.g., .com → .net, .org, .io)
|
||
- **Quick Stats** — Average price, price range, 30-day change, registrar count
|
||
|
||
---
|
||
|
||
## Tech Stack
|
||
|
||
### Backend
|
||
| Technology | Purpose |
|
||
|------------|---------|
|
||
| **Python 3.12+** | Runtime |
|
||
| **FastAPI** | Async web framework |
|
||
| **SQLAlchemy 2.0** | Async ORM |
|
||
| **SQLite/PostgreSQL** | Database |
|
||
| **APScheduler** | Background job scheduling |
|
||
| **python-whois** | WHOIS domain lookups |
|
||
| **whodap** | RDAP domain lookups |
|
||
| **httpx** | Async HTTP client (for custom RDAP) |
|
||
| **BeautifulSoup4** | Web scraping (backup) |
|
||
| **Pydantic** | Data validation |
|
||
| **JWT (python-jose)** | Authentication |
|
||
|
||
### Frontend
|
||
| Technology | Purpose |
|
||
|------------|---------|
|
||
| **Next.js 14** | React framework (App Router) |
|
||
| **TypeScript** | Type safety |
|
||
| **Tailwind CSS** | Styling |
|
||
| **Zustand** | State management |
|
||
| **Lucide React** | Icons (outlined style) |
|
||
| **clsx** | Conditional classes |
|
||
|
||
---
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
pounce/
|
||
├── backend/
|
||
│ ├── app/
|
||
│ │ ├── api/ # API endpoints
|
||
│ │ │ ├── auth.py # Authentication (register, login, me)
|
||
│ │ │ ├── check.py # Domain availability check
|
||
│ │ │ ├── domains.py # Domain watchlist CRUD
|
||
│ │ │ ├── subscription.py # User subscription management
|
||
│ │ │ ├── tld_prices.py # TLD pricing data
|
||
│ │ │ └── admin.py # Admin endpoints
|
||
│ │ ├── models/ # SQLAlchemy models
|
||
│ │ │ ├── user.py # User model
|
||
│ │ │ ├── domain.py # Domain watchlist model
|
||
│ │ │ ├── subscription.py # Subscription tiers
|
||
│ │ │ └── tld_price.py # TLD pricing model
|
||
│ │ ├── schemas/ # Pydantic schemas
|
||
│ │ ├── services/ # Business logic
|
||
│ │ │ ├── auth.py # Auth service (JWT, hashing)
|
||
│ │ │ ├── domain_checker.py # RDAP/WHOIS/DNS checks
|
||
│ │ │ ├── email_service.py # Email notifications (SMTP)
|
||
│ │ │ ├── price_tracker.py # Price change detection & alerts
|
||
│ │ │ └── tld_scraper/ # TLD price scraping
|
||
│ │ │ ├── __init__.py
|
||
│ │ │ ├── base.py # Base scraper class
|
||
│ │ │ ├── porkbun.py # Porkbun API scraper
|
||
│ │ │ ├── tld_list.py # TLD-List scraper (placeholder)
|
||
│ │ │ └── aggregator.py # Combines sources, saves to DB
|
||
│ │ ├── config.py # Environment settings
|
||
│ │ ├── database.py # Database connection
|
||
│ │ ├── main.py # FastAPI app entry
|
||
│ │ └── scheduler.py # Background jobs
|
||
│ ├── scripts/ # Utility scripts
|
||
│ │ ├── seed_tld_prices.py # Initial TLD data scrape
|
||
│ │ ├── export_tld_prices.py # Export DB to JSON
|
||
│ │ ├── import_tld_prices.py # Import JSON to DB
|
||
│ │ └── tld_prices_export.json # Price data backup
|
||
│ ├── requirements.txt
|
||
│ ├── Dockerfile
|
||
│ └── env.example
|
||
├── frontend/
|
||
│ ├── src/
|
||
│ │ ├── app/ # Next.js App Router pages
|
||
│ │ │ ├── page.tsx # Homepage with domain checker
|
||
│ │ │ ├── layout.tsx # Root layout
|
||
│ │ │ ├── dashboard/ # User dashboard
|
||
│ │ │ ├── login/ # Login page
|
||
│ │ │ ├── register/ # Registration page
|
||
│ │ │ ├── pricing/ # Pricing plans
|
||
│ │ │ └── tld-pricing/ # TLD price intelligence
|
||
│ │ │ ├── page.tsx # TLD overview
|
||
│ │ │ └── [tld]/ # TLD detail page
|
||
│ │ ├── components/ # React components
|
||
│ │ │ ├── Header.tsx # Navigation header
|
||
│ │ │ ├── Footer.tsx # Site footer
|
||
│ │ │ └── DomainChecker.tsx # Domain search component
|
||
│ │ └── lib/ # Utilities
|
||
│ │ ├── api.ts # API client
|
||
│ │ └── store.ts # Zustand store
|
||
│ ├── tailwind.config.ts # Tailwind configuration
|
||
│ ├── package.json
|
||
│ ├── Dockerfile
|
||
│ └── env.example
|
||
├── docker-compose.yml # Docker deployment
|
||
├── DEPLOYMENT.md # Deployment guide
|
||
└── README.md
|
||
```
|
||
|
||
---
|
||
|
||
## Pages Overview
|
||
|
||
| Route | Description | Auth Required |
|
||
|-------|-------------|---------------|
|
||
| `/` | Homepage with domain checker, features, pricing preview | No |
|
||
| `/login` | User login | No |
|
||
| `/register` | User registration | No |
|
||
| `/forgot-password` | Request password reset | No |
|
||
| `/reset-password` | Reset password with token | No |
|
||
| `/verify-email` | Verify email with token | No |
|
||
| `/dashboard` | Personal domain watchlist | Yes |
|
||
| `/pricing` | Subscription plans with Stripe checkout | No |
|
||
| `/tld-pricing` | TLD price overview with trends | No* |
|
||
| `/tld-pricing/[tld]` | TLD detail with registrar comparison | Yes |
|
||
| `/auctions` | Smart Pounce auction aggregator | No* |
|
||
| `/contact` | Contact form | No |
|
||
| `/about` | About us | No |
|
||
| `/blog` | Blog & Newsletter signup | No |
|
||
| `/privacy` | Privacy policy | No |
|
||
| `/terms` | Terms of service | No |
|
||
| `/imprint` | Legal imprint | No |
|
||
|
||
*Unauthenticated users see limited data with shimmer effects
|
||
|
||
---
|
||
|
||
## Full Setup Guide
|
||
|
||
### Prerequisites
|
||
- Python 3.12+
|
||
- Node.js 18+
|
||
- npm or yarn
|
||
|
||
### 🚀 One-Command Setup (Fresh Install)
|
||
|
||
```bash
|
||
# Clone repository
|
||
git clone https://git.6bit.ch/yvg/pounce.git
|
||
cd pounce
|
||
|
||
# Run deployment script (installs everything + initializes database)
|
||
chmod +x deploy.sh
|
||
./deploy.sh
|
||
```
|
||
|
||
### 🏃 Starting the Application
|
||
|
||
**Option A: Two Terminals (Recommended for Development)**
|
||
|
||
```bash
|
||
# Terminal 1 - Backend
|
||
cd backend
|
||
source venv/bin/activate
|
||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||
|
||
# Terminal 2 - Frontend
|
||
cd frontend
|
||
npm run dev
|
||
```
|
||
|
||
**Option B: Single Command (Quick)**
|
||
|
||
```bash
|
||
chmod +x start.sh
|
||
./start.sh
|
||
```
|
||
|
||
**Option C: PM2 (Production)**
|
||
|
||
```bash
|
||
# Backend
|
||
cd backend && source venv/bin/activate
|
||
pm2 start "uvicorn app.main:app --host 0.0.0.0 --port 8000" --name pounce-api
|
||
|
||
# Frontend
|
||
cd frontend
|
||
npm run build
|
||
pm2 start "npm start" --name pounce-web
|
||
```
|
||
|
||
### 🔧 Manual Setup (Step by Step)
|
||
|
||
#### 1. Clone Repository
|
||
|
||
```bash
|
||
git clone https://git.6bit.ch/yvg/pounce.git
|
||
cd pounce
|
||
```
|
||
|
||
#### 2. Backend Setup
|
||
|
||
```bash
|
||
cd backend
|
||
|
||
# Create virtual environment
|
||
python3 -m venv venv
|
||
source venv/bin/activate # Linux/macOS
|
||
# .\venv\Scripts\activate # Windows
|
||
|
||
# Install dependencies
|
||
pip install -r requirements.txt
|
||
|
||
# Create environment file
|
||
cp env.example .env
|
||
|
||
# Generate secret key
|
||
python -c "import secrets; print(secrets.token_hex(32))"
|
||
# Copy the output and paste into .env as SECRET_KEY=...
|
||
|
||
# Initialize database (creates tables + seeds basic data)
|
||
python scripts/init_db.py
|
||
|
||
# Scrape TLD prices from Porkbun API (886+ TLDs)
|
||
python scripts/seed_tld_prices.py
|
||
|
||
# (Optional) Scrape auctions - or let the scheduler do it hourly
|
||
python3 -c "
|
||
import asyncio
|
||
from app.services.auction_scraper import AuctionScraperService
|
||
from app.database import AsyncSessionLocal
|
||
|
||
async def scrape():
|
||
scraper = AuctionScraperService()
|
||
async with AsyncSessionLocal() as db:
|
||
result = await scraper.scrape_all_platforms(db)
|
||
print(f'Scraped auctions: {result}')
|
||
await scraper.close()
|
||
|
||
asyncio.run(scrape())
|
||
"
|
||
```
|
||
|
||
Start backend:
|
||
```bash
|
||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
#### 3. Frontend Setup
|
||
|
||
```bash
|
||
cd frontend
|
||
|
||
# Install dependencies
|
||
npm install
|
||
|
||
# Create environment file
|
||
echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local
|
||
|
||
# Start development server
|
||
npm run dev
|
||
```
|
||
|
||
#### 4. Verify Everything Works
|
||
|
||
```bash
|
||
# Check backend health
|
||
curl http://localhost:8000/health
|
||
# Should return: {"status":"healthy","service":"DomainWatch","version":"1.0.0"}
|
||
|
||
# Open frontend
|
||
open http://localhost:3000
|
||
```
|
||
|
||
### 📍 Application URLs
|
||
|
||
| Service | URL | Description |
|
||
|---------|-----|-------------|
|
||
| Frontend | http://localhost:3000 | Main application |
|
||
| Backend API | http://localhost:8000 | REST API |
|
||
| API Docs (Swagger) | http://localhost:8000/docs | Interactive API docs |
|
||
| API Docs (ReDoc) | http://localhost:8000/redoc | Alternative docs |
|
||
|
||
---
|
||
|
||
## API Endpoints
|
||
|
||
### Authentication
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| POST | `/api/v1/auth/register` | Register new user (sends verification email) |
|
||
| POST | `/api/v1/auth/login` | Login (returns JWT) |
|
||
| GET | `/api/v1/auth/me` | Get current user |
|
||
| PUT | `/api/v1/auth/me` | Update current user |
|
||
| POST | `/api/v1/auth/forgot-password` | Request password reset |
|
||
| POST | `/api/v1/auth/reset-password` | Reset password with token |
|
||
| POST | `/api/v1/auth/verify-email` | Verify email with token |
|
||
| POST | `/api/v1/auth/resend-verification` | Resend verification email |
|
||
|
||
### Domain Check
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| POST | `/api/v1/check` | Check domain availability |
|
||
|
||
### Domain Watchlist
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/domains` | List watched domains |
|
||
| POST | `/api/v1/domains` | Add domain to watchlist |
|
||
| DELETE | `/api/v1/domains/{id}` | Remove domain |
|
||
| POST | `/api/v1/domains/{id}/refresh` | Refresh domain status |
|
||
| GET | `/api/v1/domains/{id}/history` | Get check history |
|
||
|
||
### TLD Prices
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/tld-prices/overview` | Get all TLDs overview |
|
||
| GET | `/api/v1/tld-prices/trending` | Get trending TLDs |
|
||
| GET | `/api/v1/tld-prices/{tld}` | Get TLD details |
|
||
| GET | `/api/v1/tld-prices/{tld}/history` | Get price history |
|
||
| GET | `/api/v1/tld-prices/{tld}/compare` | Compare registrar prices |
|
||
|
||
#### Price Data Consistency
|
||
|
||
All TLD price endpoints use a unified pricing strategy:
|
||
|
||
1. **Static TLDs (18 popular)**: Rich multi-registrar data (5+ registrars per TLD)
|
||
- .com, .net, .org, .io, .ai, .dev, .app, .xyz, .tech, .online, .store, .me, .info, .biz, .ch, .de, .uk, .co
|
||
|
||
2. **Database TLDs (869+)**: Scraped from Porkbun API (single registrar)
|
||
|
||
**Price Calculation** (consistent across all endpoints):
|
||
```
|
||
avg_price = sum(registrar_prices) / count(registrars)
|
||
min_price = min(registrar_prices)
|
||
max_price = max(registrar_prices)
|
||
```
|
||
|
||
This ensures identical prices on:
|
||
- Overview table (`/overview`)
|
||
- Detail page (`/{tld}`)
|
||
- Compare page (`/{tld}/compare`)
|
||
- Trending cards (`/trending`)
|
||
|
||
### Subscription & Payments
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/subscription` | Get current subscription |
|
||
| GET | `/api/v1/subscription/tiers` | Get available tiers |
|
||
| GET | `/api/v1/subscription/features` | Get current features |
|
||
| POST | `/api/v1/subscription/checkout` | Create Stripe checkout session |
|
||
| POST | `/api/v1/subscription/portal` | Create Stripe customer portal |
|
||
| POST | `/api/v1/subscription/cancel` | Cancel subscription |
|
||
|
||
### Price Alerts
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/price-alerts` | List user's price alerts |
|
||
| POST | `/api/v1/price-alerts` | Create new price alert |
|
||
| GET | `/api/v1/price-alerts/status/{tld}` | Check alert status for TLD |
|
||
| GET | `/api/v1/price-alerts/{tld}` | Get alert for specific TLD |
|
||
| PUT | `/api/v1/price-alerts/{tld}` | Update alert settings |
|
||
| DELETE | `/api/v1/price-alerts/{tld}` | Delete alert |
|
||
| POST | `/api/v1/price-alerts/{tld}/toggle` | Toggle alert on/off |
|
||
|
||
### Contact & Newsletter
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| POST | `/api/v1/contact` | Submit contact form |
|
||
| POST | `/api/v1/contact/newsletter/subscribe` | Subscribe to newsletter |
|
||
| POST | `/api/v1/contact/newsletter/unsubscribe` | Unsubscribe from newsletter |
|
||
| GET | `/api/v1/contact/newsletter/status` | Check subscription status |
|
||
|
||
### Webhooks
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| POST | `/api/v1/webhooks/stripe` | Stripe webhook handler |
|
||
|
||
### Smart Pounce (Auctions)
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/auctions` | Search auctions across platforms |
|
||
| GET | `/api/v1/auctions/ending-soon` | Auctions ending within X hours |
|
||
| GET | `/api/v1/auctions/hot` | Most-bid auctions |
|
||
| GET | `/api/v1/auctions/opportunities` | AI-powered opportunities (auth) |
|
||
| GET | `/api/v1/auctions/stats` | Platform statistics |
|
||
|
||
### Admin
|
||
| Method | Endpoint | Description |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/v1/admin/users` | List all users |
|
||
| POST | `/api/v1/admin/upgrade-user` | Upgrade user subscription |
|
||
| POST | `/api/v1/admin/scrape-tld-prices` | Manually trigger TLD price scrape |
|
||
| GET | `/api/v1/admin/tld-prices/stats` | Get TLD price database stats |
|
||
|
||
---
|
||
|
||
## Subscription Tiers
|
||
|
||
| Feature | Scout (Free) | Trader (€19/mo) | Tycoon (€49/mo) |
|
||
|---------|--------------|-----------------|------------------|
|
||
| Watchlist Domains | 5 | 50 | 500 |
|
||
| Portfolio Domains | — | 25 | Unlimited |
|
||
| Check Frequency | Daily | Hourly | 10 min |
|
||
| Notifications | Email | SMS/Telegram | + Webhooks |
|
||
| Domain Valuation | — | ✓ | ✓ |
|
||
| SEO Metrics | — | — | ✓ |
|
||
| Check History | — | 90 days | Unlimited |
|
||
| API Access | — | — | ✓ |
|
||
| Bulk Tools | — | — | ✓ |
|
||
|
||
---
|
||
|
||
## Environment Variables
|
||
|
||
### Backend (.env)
|
||
|
||
| Variable | Description | Default |
|
||
|----------|-------------|---------|
|
||
| `DATABASE_URL` | Database connection string | `sqlite+aiosqlite:///./domainwatch.db` |
|
||
| `SECRET_KEY` | JWT signing key (min 32 chars) | **Required** |
|
||
| `ALLOWED_ORIGINS` | Allowed origins (comma-separated) | `http://localhost:3000` |
|
||
| `ACCESS_TOKEN_EXPIRE_MINUTES` | JWT token lifetime | `10080` (7 days) |
|
||
| `SITE_URL` | Frontend URL (for email links) | `http://localhost:3000` |
|
||
| `REQUIRE_EMAIL_VERIFICATION` | Require email verification | `false` |
|
||
| `SCHEDULER_CHECK_INTERVAL_HOURS` | Domain check interval | `24` |
|
||
| **SMTP Settings (Zoho)** | | |
|
||
| `SMTP_HOST` | Email server host | `smtp.zoho.eu` |
|
||
| `SMTP_PORT` | Email server port | `465` |
|
||
| `SMTP_USER` | Email username | `hello@pounce.ch` |
|
||
| `SMTP_PASSWORD` | Email password | **Required** |
|
||
| `SMTP_FROM_EMAIL` | Sender email | `hello@pounce.ch` |
|
||
| `SMTP_USE_SSL` | Use SSL (port 465) | `true` |
|
||
| `SMTP_USE_TLS` | Use STARTTLS (port 587) | `false` |
|
||
| `CONTACT_EMAIL` | Contact form recipient | `hello@pounce.ch` |
|
||
| **Stripe Settings** | | |
|
||
| `STRIPE_SECRET_KEY` | Stripe API secret key | Optional |
|
||
| `STRIPE_WEBHOOK_SECRET` | Stripe webhook secret | Optional |
|
||
| `STRIPE_PRICE_TRADER` | Trader plan Price ID | Optional |
|
||
| `STRIPE_PRICE_TYCOON` | Tycoon plan Price ID | Optional |
|
||
|
||
### Frontend (.env.local)
|
||
|
||
| Variable | Description | Default |
|
||
|----------|-------------|---------|
|
||
| `NEXT_PUBLIC_API_URL` | Backend API URL | `http://localhost:8000` |
|
||
|
||
---
|
||
|
||
## Production Deployment
|
||
|
||
### Docker (Recommended)
|
||
|
||
```bash
|
||
# Clone repository
|
||
git clone https://git.6bit.ch/yvg/pounce.git
|
||
cd pounce
|
||
|
||
# Set environment variables
|
||
export SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
|
||
|
||
# Build and start
|
||
docker-compose up -d --build
|
||
```
|
||
|
||
### Manual Deployment
|
||
|
||
See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed instructions including:
|
||
- Systemd service setup
|
||
- PM2 for Node.js
|
||
- Nginx reverse proxy configuration
|
||
- SSL/HTTPS with Let's Encrypt
|
||
- PostgreSQL database setup
|
||
|
||
---
|
||
|
||
## Domain Checking Methods
|
||
|
||
pounce uses multiple methods to verify domain availability:
|
||
|
||
1. **Custom RDAP** — For TLDs with own RDAP servers (e.g., `.ch`, `.li` via `rdap.nic.ch`)
|
||
2. **RDAP via whodap** — Modern protocol with detailed data, supported by major registries
|
||
3. **WHOIS (Fallback)** — Traditional protocol for domains without RDAP support
|
||
4. **DNS (Quick check)** — Fast initial availability check via DNS queries
|
||
|
||
The system automatically falls back to the next method if one fails.
|
||
|
||
### Supported TLDs with Custom RDAP
|
||
|
||
| TLD | RDAP Server | Notes |
|
||
|-----|-------------|-------|
|
||
| `.ch` | `rdap.nic.ch` | Swiss domains - WHOIS blocked |
|
||
| `.li` | `rdap.nic.ch` | Liechtenstein - same registry |
|
||
|
||
### Standard RDAP TLDs
|
||
|
||
`.com`, `.net`, `.org`, `.info`, `.biz`, `.io`, `.co`, `.ai`, `.app`, `.dev`, `.xyz`, `.me`, and many more.
|
||
|
||
---
|
||
|
||
## TLD Price Scraping
|
||
|
||
pounce automatically scrapes TLD prices from public sources for price intelligence and trend tracking.
|
||
|
||
### Data Source
|
||
|
||
**Primary:** Porkbun Public API (no API key required!)
|
||
|
||
```
|
||
POST https://api.porkbun.com/api/json/v3/pricing/get
|
||
```
|
||
|
||
- ✅ **886+ TLDs** with pricing
|
||
- ✅ Registration, Renewal, Transfer prices
|
||
- ✅ No authentication needed
|
||
- ✅ Updated daily via scheduler
|
||
|
||
### Scheduler Jobs
|
||
|
||
| Job | Schedule | Description |
|
||
|-----|----------|-------------|
|
||
| **Domain Check** | Configurable (default: daily) | Checks all watched domains |
|
||
| **TLD Price Scrape** | Daily at 03:00 UTC | Scrapes current TLD prices |
|
||
| **Price Change Alerts** | Daily at 04:00 UTC | Sends email for price changes >5% |
|
||
|
||
### Manual Scrape
|
||
|
||
Trigger a manual TLD price scrape:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/api/v1/admin/scrape-tld-prices
|
||
```
|
||
|
||
Response:
|
||
```json
|
||
{
|
||
"message": "TLD price scrape completed",
|
||
"status": "success",
|
||
"tlds_scraped": 886,
|
||
"prices_saved": 886,
|
||
"sources_succeeded": 1
|
||
}
|
||
```
|
||
|
||
### Database Stats
|
||
|
||
Get current TLD price data statistics:
|
||
|
||
```bash
|
||
curl http://localhost:8000/api/v1/admin/tld-prices/stats
|
||
```
|
||
|
||
Response:
|
||
```json
|
||
{
|
||
"total_records": 886,
|
||
"unique_tlds": 886,
|
||
"unique_registrars": 1,
|
||
"latest_record": "2025-12-08T08:04:54",
|
||
"data_range_days": 0
|
||
}
|
||
```
|
||
|
||
### Price Data Model
|
||
|
||
```python
|
||
TLDPrice:
|
||
- tld: str # e.g., "com", "io", "ai"
|
||
- registrar: str # e.g., "porkbun"
|
||
- registration_price: float
|
||
- renewal_price: float
|
||
- transfer_price: float
|
||
- currency: str # "USD"
|
||
- recorded_at: datetime # For historical tracking
|
||
```
|
||
|
||
### Future Data Sources
|
||
|
||
The scraper architecture supports multiple sources:
|
||
|
||
1. **Porkbun API** ✅ (active)
|
||
2. **TLD-List.com** (blocked - placeholder)
|
||
3. **Namecheap Affiliate** (requires signup)
|
||
4. **Cloudflare** (requires account)
|
||
|
||
---
|
||
|
||
## Email Notifications
|
||
|
||
pounce supports automated email notifications for domain availability and price changes.
|
||
|
||
### Setup (Zoho Mail)
|
||
|
||
Configure SMTP settings in your `.env`:
|
||
|
||
```env
|
||
# Zoho Mail Configuration (Recommended)
|
||
SMTP_HOST=smtp.zoho.eu
|
||
SMTP_PORT=465
|
||
SMTP_USER=hello@pounce.ch
|
||
SMTP_PASSWORD=your-zoho-app-password
|
||
SMTP_FROM_EMAIL=hello@pounce.ch
|
||
SMTP_FROM_NAME=pounce
|
||
SMTP_USE_TLS=false
|
||
SMTP_USE_SSL=true
|
||
CONTACT_EMAIL=hello@pounce.ch
|
||
```
|
||
|
||
Alternative providers:
|
||
```env
|
||
# Gmail (port 587, STARTTLS)
|
||
SMTP_HOST=smtp.gmail.com
|
||
SMTP_PORT=587
|
||
SMTP_USE_SSL=false
|
||
SMTP_USE_TLS=true
|
||
```
|
||
|
||
### Notification Types
|
||
|
||
| Type | Trigger | Description |
|
||
|------|---------|-------------|
|
||
| **Domain Available** | Watched domain becomes available | Instant alert to domain owner |
|
||
| **Price Change Alert** | TLD price changes >5% | Daily batch after price scrape |
|
||
| **Weekly Digest** | Every Sunday | Summary of watched domains & price trends |
|
||
|
||
### Email Templates
|
||
|
||
All emails feature:
|
||
- Dark mode branded design matching the app
|
||
- Clear call-to-action buttons
|
||
- Direct links to register domains
|
||
- Unsubscribe options
|
||
|
||
### Test Email
|
||
|
||
```bash
|
||
# Via Python
|
||
cd backend && python3 -c "
|
||
import asyncio
|
||
from app.services.email_service import email_service
|
||
|
||
async def test():
|
||
result = await email_service.send_domain_available_alert(
|
||
'test@example.com',
|
||
'example.com',
|
||
'Test User'
|
||
)
|
||
print('Email sent:', result)
|
||
|
||
asyncio.run(test())
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## Design System
|
||
|
||
### Colors
|
||
- **Background:** Dark (`#0a0a0a`)
|
||
- **Foreground:** Light (`#fafafa`)
|
||
- **Accent:** Teal (`#00d4aa`)
|
||
- **Warning:** Orange (`#f97316`)
|
||
- **Success:** Green (same as accent)
|
||
|
||
### Typography
|
||
- **Display:** Playfair Display (serif)
|
||
- **Body:** Inter (sans-serif)
|
||
- **Mono:** JetBrains Mono (code)
|
||
|
||
### Components
|
||
- All icons use outlined style (Lucide React)
|
||
- Minimalist, award-winning aesthetic
|
||
- Smooth animations and transitions
|
||
- Responsive design (mobile-first)
|
||
|
||
---
|
||
|
||
## Development
|
||
|
||
### Backend
|
||
|
||
```bash
|
||
cd backend
|
||
source venv/bin/activate
|
||
|
||
# Run with auto-reload
|
||
uvicorn app.main:app --reload
|
||
|
||
# API docs available at:
|
||
# http://localhost:8000/docs (Swagger)
|
||
# http://localhost:8000/redoc (ReDoc)
|
||
```
|
||
|
||
### Frontend
|
||
|
||
```bash
|
||
cd frontend
|
||
|
||
# Development server
|
||
npm run dev
|
||
|
||
# Lint
|
||
npm run lint
|
||
|
||
# Build for production
|
||
npm run build
|
||
|
||
# Start production server
|
||
npm start
|
||
```
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### Backend won't start
|
||
|
||
1. Check Python version: `python3 --version` (needs 3.12+)
|
||
2. Ensure virtual environment is activated
|
||
3. Check `.env` file exists and has valid `SECRET_KEY`
|
||
4. Check for syntax errors in config files
|
||
|
||
### Frontend can't connect to backend
|
||
|
||
1. Ensure backend is running on port 8000
|
||
2. Check `NEXT_PUBLIC_API_URL` in `.env.local`
|
||
3. Verify CORS origins in backend `.env`
|
||
4. Check browser console for CORS errors
|
||
|
||
### Domain checks failing
|
||
|
||
1. Some TLDs may have rate limits
|
||
2. Certain ccTLDs require special handling (see below)
|
||
3. Check backend logs for specific errors
|
||
|
||
**Swiss/Liechtenstein domains (.ch, .li):**
|
||
- WHOIS is blocked for automated requests
|
||
- pounce uses the official `rdap.nic.ch` API instead
|
||
- This is automatic - no configuration needed
|
||
|
||
**Other ccTLDs:**
|
||
- Some country code TLDs don't support RDAP
|
||
- pounce falls back to DNS checking
|
||
- Results may be less detailed (no registrar info)
|
||
|
||
### Database errors
|
||
|
||
1. Delete `domainwatch.db` to reset (dev only)
|
||
2. Check database URL format in `.env`
|
||
3. Ensure write permissions on database directory
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
MIT License
|
||
|
||
---
|
||
|
||
## Support
|
||
|
||
For issues and feature requests, please open a GitHub issue or contact support@pounce.dev
|