# pounce — Domain Availability Monitoring A professional full-stack application for monitoring domain name availability with TLD price tracking and intelligence. ## 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 --- ## Quick Start ### Prerequisites - Python 3.12+ - Node.js 18+ - npm or yarn ### 🚀 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 ```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 and add to .env python -c "import secrets; print(f'SECRET_KEY={secrets.token_hex(32)}')" # Edit .env with your SECRET_KEY # Initialize database python scripts/init_db.py ``` 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. Access Application - **Frontend:** http://localhost:3000 - **Backend API:** http://localhost:8000 - **API Docs:** http://localhost:8000/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