yves.gugger 76d1d88abc feat: Marketplace command page + SEO disabled state + Pricing update
MARKETPLACE:
- Created /command/marketplace for authenticated users
- Shows all listings with search, sort, and filters
- Grid layout with domain cards, scores, and verification badges
- Links to 'My Listings' for quick access to management

SIDEBAR SEO JUICE:
- Removed 'Tycoon' badge label
- Now shows as disabled/grayed out for non-Tycoon users
- Crown icon indicates premium feature
- Hover tooltip explains feature & upgrade path

PRICING PAGE:
- Added new features to tier cards:
  - Scout: 2 domain listings
  - Trader: 10 listings, 5 Sniper Alerts
  - Tycoon: 50 listings, unlimited alerts, SEO Juice
- Updated comparison table with:
  - For Sale Listings row
  - Sniper Alerts row
  - SEO Juice Detector row
2025-12-10 12:22:01 +01:00

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:

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:

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

Access:

⚠️ 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 FormulaValue = 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
  • OAuth Login — Sign in with Google or GitHub
  • 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

Blog System (v1.3)

  • Blog Posts — Create and manage blog articles
  • Categories & Tags — Organize content
  • Featured Posts — Highlight posts on homepage
  • View Tracking — Analytics for post views
  • SEO Metadata — Custom meta titles and descriptions
  • Draft/Publish — Content workflow management

Admin Panel (v1.3)

  • User Management — List, search, upgrade, and manage users
  • Bulk Operations — Upgrade multiple users at once
  • User Export — Export all users to CSV
  • Price Alerts — View all active TLD price alerts
  • Domain Health — Manually trigger domain checks
  • Scheduler Status — Monitor background jobs and last runs
  • Email Test — Verify SMTP configuration
  • Activity Log — Track admin actions
  • Blog Management — Full CRUD for blog posts

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 posts listing No
/blog/{slug} Blog post detail No
/admin Admin panel Yes (Admin)
/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)

# 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)

# 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)

chmod +x start.sh
./start.sh

Option C: PM2 (Production)

# 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

git clone https://git.6bit.ch/yvg/pounce.git
cd pounce

2. Backend Setup

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:

uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

3. Frontend Setup

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

# 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

OAuth

Method Endpoint Description
GET /api/v1/oauth/providers List enabled OAuth providers
GET /api/v1/oauth/google/login Initiate Google OAuth
GET /api/v1/oauth/google/callback Handle Google callback
GET /api/v1/oauth/github/login Initiate GitHub OAuth
GET /api/v1/oauth/github/callback Handle GitHub callback

Blog

Method Endpoint Description
GET /api/v1/blog/posts List published posts
GET /api/v1/blog/posts/featured Get featured posts
GET /api/v1/blog/posts/categories Get all categories
GET /api/v1/blog/posts/{slug} Get single post
GET /api/v1/blog/admin/posts Admin: List all posts
POST /api/v1/blog/admin/posts Admin: Create post
GET /api/v1/blog/admin/posts/{id} Admin: Get post
PATCH /api/v1/blog/admin/posts/{id} Admin: Update post
DELETE /api/v1/blog/admin/posts/{id} Admin: Delete post
POST /api/v1/blog/admin/posts/{id}/publish Admin: Publish post
POST /api/v1/blog/admin/posts/{id}/unpublish Admin: Unpublish post

Admin

Method Endpoint Description
GET /api/v1/admin/stats Get platform statistics
GET /api/v1/admin/users List all users
GET /api/v1/admin/users/export Export users as CSV
POST /api/v1/admin/users/bulk-upgrade Bulk upgrade users
GET /api/v1/admin/users/{id} Get user details
PATCH /api/v1/admin/users/{id} Update user
DELETE /api/v1/admin/users/{id} Delete user
POST /api/v1/admin/users/{id}/upgrade Upgrade single user
GET /api/v1/admin/price-alerts List all price alerts
POST /api/v1/admin/domains/check-all Trigger domain checks
GET /api/v1/admin/newsletter List newsletter subs
GET /api/v1/admin/newsletter/export Export newsletter
POST /api/v1/admin/scrape-tld-prices Trigger TLD scrape
GET /api/v1/admin/tld-prices/stats Get TLD stats
GET /api/v1/admin/system/health System health check
GET /api/v1/admin/system/scheduler Scheduler status
POST /api/v1/admin/system/test-email Send test email
GET /api/v1/admin/activity-log Get activity log

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

Required Cron Jobs Summary

Job Frequency Command
TLD Prices Daily 03:00 UTC python scripts/seed_tld_prices.py
Domain Check Daily 06:00 UTC Built-in scheduler
Auction Scrape Hourly :30 Built-in scheduler
Price Alerts Daily 04:00 UTC Built-in scheduler

Note: All cron jobs run automatically via APScheduler when the backend is running. External cron is only needed if you disable the built-in scheduler.

# 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 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 (Built-in APScheduler)

The backend includes a built-in scheduler that starts automatically with the application. No external cron jobs needed!

Job Schedule Description
Domain Check Daily at configured hour (default: 06:00 UTC) Checks all watched domains for availability
TLD Price Scrape Daily at 03:00 UTC Scrapes 886+ TLD prices from Porkbun API
Price Change Alerts Daily at 04:00 UTC Sends email for price changes >5%
Auction Scrape Every hour at :30 Scrapes domain auctions from ExpiredDomains

Scheduler is enabled by default. When you run uvicorn app.main:app, the scheduler starts automatically via the lifespan handler.

External Cron Jobs (Production - Optional)

If you want more control, you can disable the built-in scheduler and use system cron:

# Disable built-in scheduler by setting env var
DISABLE_SCHEDULER=true

# Add to crontab (crontab -e)
# TLD prices daily at 03:00 UTC
0 3 * * * cd /path/to/pounce/backend && source venv/bin/activate && python scripts/seed_tld_prices.py >> /var/log/pounce/tld_scrape.log 2>&1

# Domain check daily at 06:00 UTC  
0 6 * * * cd /path/to/pounce/backend && source venv/bin/activate && python -c "import asyncio; from app.scheduler import check_all_domains; asyncio.run(check_all_domains())" >> /var/log/pounce/domain_check.log 2>&1

# Auction scrape hourly at :30
30 * * * * cd /path/to/pounce/backend && source venv/bin/activate && python -c "import asyncio; from app.scheduler import scrape_auctions; asyncio.run(scrape_auctions())" >> /var/log/pounce/auction_scrape.log 2>&1

# Price alerts daily at 04:00 UTC
0 4 * * * cd /path/to/pounce/backend && source venv/bin/activate && python -c "import asyncio; from app.scheduler import check_price_changes; asyncio.run(check_price_changes())" >> /var/log/pounce/price_alerts.log 2>&1

The easiest production setup is PM2 which keeps the backend running with its built-in scheduler:

cd backend && source venv/bin/activate
pm2 start "uvicorn app.main:app --host 0.0.0.0 --port 8000" --name pounce-api
pm2 save
pm2 startup

This way, the APScheduler handles all cron jobs automatically.

Manual Scrape

Trigger a manual TLD price scrape:

curl -X POST http://localhost:8000/api/v1/admin/scrape-tld-prices

Response:

{
  "message": "TLD price scrape completed",
  "status": "success",
  "tlds_scraped": 886,
  "prices_saved": 886,
  "sources_succeeded": 1
}

Database Stats

Get current TLD price data statistics:

curl http://localhost:8000/api/v1/admin/tld-prices/stats

Response:

{
  "total_records": 886,
  "unique_tlds": 886,
  "unique_registrars": 1,
  "latest_record": "2025-12-08T08:04:54",
  "data_range_days": 0
}

Price Data Model

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:

# 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:

# 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

# 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

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

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

Description
No description provided
Readme 8.2 MiB
Languages
TypeScript 60.8%
Python 38.2%
Shell 0.6%
JavaScript 0.2%
CSS 0.1%