pounce/README.md

19 KiB

pounce — Domain Intelligence Platform

A professional full-stack platform for domain hunters, investors, and portfolio managers. Features live auction aggregation, TLD price tracking, domain marketplace, and intelligent monitoring.


Security remediation (required)

This repo previously contained accidentally committed secrets (DEPLOY_backend.env, DEPLOY_frontend.env) and session cookies (backend/data/cookies/session_cookies.json). The codebase was updated to Cookie-based auth (HttpOnly) and the git history was rewritten to remove the leaked files.

Do this now (simple checklist)

  1. Rotate ALL secrets (treat old values as compromised)
  • Backend secrets: SECRET_KEY
  • Stripe: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, price IDs if necessary
  • OAuth: GOOGLE_CLIENT_SECRET, GITHUB_CLIENT_SECRET (and IDs if you want)
  • Email: SMTP_PASSWORD
  • Other integrations (if used): DROPCATCH_CLIENT_SECRET, SEDO_SIGN_KEY, MOZ_SECRET_KEY

Generate a new SECRET_KEY locally:

python3 -c "import secrets; print(secrets.token_hex(32))"
  1. Force-push the rewritten history to your remote
git push --force-with-lease --all
git push --force-with-lease --tags
  1. Re-clone on every server/CI machine

Because history changed, do not git pull on old clones. The simplest safe path:

rm -rf pounce
git clone <your-repo> pounce
  1. Re-deploy
  • Backend: pip install -r backend/requirements.txt
  • Frontend: npm ci && npm run build
  1. Quick verification
  • Login now sets an HttpOnly cookie:
    • POST /api/v1/auth/login returns { "expires_in": ... } (no token in JSON)
    • POST /api/v1/auth/logout clears the cookie

Deployment note (keep it simple)

For the new cookie-auth to “just work”, the recommended setup is:

  • Serve the frontend on your main domain
  • Route /api/v1/* to the backend via reverse proxy (nginx/caddy/Next rewrite)

See SERVER_DEPLOYMENT.md.

Env files (important)

  • Never commit any of these:
    • DEPLOY_backend.env, DEPLOY_frontend.env, backend/data/cookies/*.json
  • Use templates:
    • DEPLOY_backend.env.example → copy to DEPLOY_backend.env (local only)
    • DEPLOY_frontend.env.example → copy to DEPLOY_frontend.env (local only)

🚀 What's New (v2.0)

User Command Center

A complete redesign of the authenticated user experience:

Feature Description
Dashboard Personal overview with quick stats, trending TLDs, and activity
Watchlist Monitor domain availability with 4-layer health checks (DNS, HTTP, SSL, WHOIS)
Portfolio Track owned domains, valuations, and manage listings
Auctions Live aggregated auctions from GoDaddy, Sedo, NameJet, DropCatch
Marketplace Browse "For Sale" listings from other users
My Listings Manage your own domain listings for sale
TLD Pricing Compare prices across 886+ TLDs with trends and alerts
Sniper Alerts Personalized auction alerts based on custom criteria
SEO Juice Domain authority & backlink analysis (Tycoon only)

Public Pages

Page Route Description
Landing / Hero, features, pricing preview
Auctions /auctions Public auction browser (blurred Deal Score)
TLD Pricing /tld-pricing TLD overview (preview for non-auth)
TLD Detail /tld-pricing/[tld] Registrar comparison, price chart
Marketplace /buy Browse domains for sale
Listing Detail /buy/[slug] View listing, contact seller

Admin Panel (/admin)

Dedicated admin interface with its own sidebar:

  • User Management (bulk upgrade, export CSV)
  • Platform Statistics
  • Auction & TLD Stats
  • Scheduler Monitoring
  • Email Testing
  • Activity Logs

Technical Highlights

  • Performance Optimized: All pages use useMemo and useCallback for minimal re-renders
  • Consistent UI Components: PremiumTable, StatCard, SearchInput, TabBar, ActionButton
  • Responsive Design: Mobile-first with collapsible sidebar
  • Keyboard Shortcuts: ⌘K search, navigation shortcuts

⚠️ After Fresh Clone / Database Reset

cd backend
source venv/bin/activate

# 1. Initialize database (creates ALL tables)
python scripts/init_db.py

# 2. Scrape TLD prices (886+ TLDs from Porkbun)
python scripts/seed_tld_prices.py

# 3. Scrape auctions (or let 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:
        await scraper.scrape_all_platforms(db)
    await scraper.close()

asyncio.run(scrape())
"

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:


📁 Updated Project Structure

pounce/
├── backend/
│   ├── app/
│   │   ├── api/
│   │   │   ├── auth.py              # Authentication
│   │   │   ├── oauth.py             # Google/GitHub OAuth
│   │   │   ├── check.py             # Domain availability
│   │   │   ├── domains.py           # Watchlist CRUD
│   │   │   ├── portfolio.py         # Portfolio management
│   │   │   ├── tld_prices.py        # TLD pricing API
│   │   │   ├── auctions.py          # Live auction aggregator
│   │   │   ├── listings.py          # For Sale marketplace
│   │   │   ├── sniper_alerts.py     # Personalized alerts
│   │   │   ├── seo.py               # SEO Juice Detector
│   │   │   ├── subscription.py      # Stripe payments
│   │   │   └── admin.py             # Admin endpoints
│   │   ├── models/
│   │   │   ├── user.py
│   │   │   ├── domain.py
│   │   │   ├── subscription.py
│   │   │   ├── tld_price.py
│   │   │   ├── portfolio.py
│   │   │   ├── auction.py
│   │   │   ├── listing.py           # NEW: For Sale listings
│   │   │   ├── sniper_alert.py      # NEW: Alert configurations
│   │   │   └── seo_data.py          # NEW: SEO cache
│   │   ├── services/
│   │   │   ├── domain_checker.py
│   │   │   ├── domain_health.py     # 4-layer health monitoring
│   │   │   ├── auction_scraper.py   # Multi-platform scraping
│   │   │   ├── seo_analyzer.py      # Moz API / estimation
│   │   │   ├── stripe_service.py
│   │   │   └── email_service.py
│   │   └── scheduler.py             # APScheduler cron jobs
│   └── scripts/
│       ├── init_db.py
│       └── seed_tld_prices.py
├── frontend/
│   ├── src/
│   │   ├── app/
│   │   │   ├── page.tsx             # Landing page
│   │   │   ├── auctions/            # Public auctions
│   │   │   ├── tld-pricing/         # Public TLD pricing
│   │   │   ├── buy/                 # Public marketplace
│   │   │   ├── pricing/             # Subscription plans
│   │   │   ├── login/
│   │   │   ├── register/
│   │   │   ├── command/             # 🆕 User Command Center
│   │   │   │   ├── dashboard/
│   │   │   │   ├── watchlist/
│   │   │   │   ├── portfolio/
│   │   │   │   ├── auctions/
│   │   │   │   ├── marketplace/
│   │   │   │   ├── listings/
│   │   │   │   ├── alerts/
│   │   │   │   ├── pricing/
│   │   │   │   │   └── [tld]/       # TLD detail
│   │   │   │   ├── seo/
│   │   │   │   ├── settings/
│   │   │   │   └── welcome/         # Post-payment onboarding
│   │   │   └── admin/               # Admin panel
│   │   ├── components/
│   │   │   ├── Header.tsx
│   │   │   ├── Footer.tsx
│   │   │   ├── Sidebar.tsx          # Command Center nav
│   │   │   ├── AdminLayout.tsx      # Admin nav
│   │   │   ├── CommandCenterLayout.tsx
│   │   │   ├── PremiumTable.tsx     # Reusable table + UI components
│   │   │   └── DomainChecker.tsx
│   │   └── lib/
│   │       ├── api.ts               # API client
│   │       └── store.ts             # Zustand state
│   └── tailwind.config.ts
├── DATABASE_MIGRATIONS.md           # 🆕 Migration guide
├── DEPLOYMENT.md
└── README.md

🗄️ Database Tables

Core Tables (Existing)

Table Description
users User accounts
subscriptions Plan tiers (Scout/Trader/Tycoon)
domains Watchlist
domain_checks Check history
tld_prices Price data
tld_info TLD metadata
portfolio_domains Owned domains
domain_valuations Valuation history
domain_auctions Scraped auctions
price_alerts TLD price alerts

NEW Tables (v2.0)

Table Description
domain_listings For Sale marketplace listings
listing_inquiries Buyer contact messages
listing_views View analytics
sniper_alerts Personalized alert configs
sniper_alert_matches Matched auctions
domain_seo_data SEO metrics cache

See DATABASE_MIGRATIONS.md for full SQL schemas.


🔧 Server Deployment Guide

1. Clone & Install

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

# Backend
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp env.example .env
# Edit .env with your secrets

# Frontend
cd ../frontend
npm install
echo "NEXT_PUBLIC_API_URL=https://api.pounce.ch" > .env.local

2. Environment Variables

Backend .env:

# Core
SECRET_KEY=your-32-char-secret-key
DATABASE_URL=postgresql+asyncpg://user:pass@localhost/pounce
ALLOWED_ORIGINS=https://pounce.ch,https://www.pounce.ch
SITE_URL=https://pounce.ch

# SMTP (Zoho)
SMTP_HOST=smtp.zoho.eu
SMTP_PORT=465
SMTP_USER=hello@pounce.ch
SMTP_PASSWORD=your-password
SMTP_FROM_EMAIL=hello@pounce.ch
SMTP_USE_SSL=true

# Stripe
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_PRICE_TRADER=price_xxx
STRIPE_PRICE_TYCOON=price_xxx

# OAuth
GOOGLE_CLIENT_ID=xxx
GOOGLE_CLIENT_SECRET=xxx
GOOGLE_REDIRECT_URI=https://api.pounce.ch/api/v1/oauth/google/callback
GITHUB_CLIENT_ID=xxx
GITHUB_CLIENT_SECRET=xxx
GITHUB_REDIRECT_URI=https://api.pounce.ch/api/v1/oauth/github/callback

# SEO (Optional - uses estimation if not set)
MOZ_ACCESS_ID=your-moz-id
MOZ_SECRET_KEY=your-moz-secret

Frontend .env.local:

NEXT_PUBLIC_API_URL=https://api.pounce.ch

3. Initialize Database

cd backend
source venv/bin/activate

# Create all tables
python scripts/init_db.py

# Seed TLD prices
python scripts/seed_tld_prices.py

4. Start Services

With PM2 (Recommended):

# 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

# Save & auto-restart
pm2 save
pm2 startup

With Docker:

docker-compose up -d --build

5. Nginx Configuration

# API
server {
    listen 443 ssl http2;
    server_name api.pounce.ch;
    
    ssl_certificate /etc/letsencrypt/live/api.pounce.ch/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.pounce.ch/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Frontend
server {
    listen 443 ssl http2;
    server_name pounce.ch www.pounce.ch;
    
    ssl_certificate /etc/letsencrypt/live/pounce.ch/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pounce.ch/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

6. Stripe Webhook

Configure Stripe to send webhooks to:

https://api.pounce.ch/api/v1/webhooks/stripe

Events to enable:

  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.payment_succeeded
  • invoice.payment_failed

📊 Scheduler Jobs (Automatic)

The backend includes APScheduler that runs automatically:

Job Schedule Description
TLD Price Scrape 03:00 & 15:00 UTC Scrapes 886+ TLDs from Porkbun + 4 registrars
Auction Scrape Every 2h at :30 Scrapes from ExpiredDomains
Domain Check (Scout) Daily 06:00 UTC Checks all watched domains
Domain Check (Trader) Hourly :00 Checks Trader domains
Domain Check (Tycoon) Every 10 min Checks Tycoon domains
Health Checks Daily 06:00 UTC DNS/HTTP/SSL health analysis
Expiry Warnings Weekly Mon 08:00 Warns about domains <30 days
Weekly Digest Weekly Sun 10:00 Summary email to all users
Price Alerts 04:00 & 16:00 UTC Sends email for >5% changes
Sniper Match Every 30 min Matches auctions to alerts
Auction Cleanup Every 15 min Removes expired auctions

📧 Email Notifications & Monitoring

What Gets Monitored

The Watchlist automatically monitors domains and sends alerts:

Alert Type Trigger Email Subject
Domain Available Domain becomes free 🐆 POUNCE NOW: domain.com just dropped
Expiry Warning Domain expires in <30 days ⏰ 3 domains expiring soon
Health Critical Domain goes offline/critical 🐆 POUNCE NOW: domain.com
Price Change TLD price changes >5% 💰 .ai moved down 12%
Sniper Match Auction matches your criteria 🎯 Sniper Alert: 5 matching domains found!
Weekly Digest Every Sunday 📊 Your week in domains

Check Frequency by Subscription

Tier Frequency Use Case
Scout (Free) Daily Hobby monitoring
Trader ($9) Hourly Active domain hunters
Tycoon ($29) Every 10 min Professional investors

⚠️ Required: Email Configuration

Email notifications will NOT work without SMTP configuration!

Add these to your .env file:

# SMTP Configuration (Required for email alerts)
SMTP_HOST=smtp.zoho.eu          # Your SMTP server
SMTP_PORT=465                    # Usually 465 (SSL) or 587 (TLS)
SMTP_USER=hello@pounce.ch       # SMTP username
SMTP_PASSWORD=your-password      # SMTP password
SMTP_FROM_EMAIL=hello@pounce.ch # Sender address
SMTP_FROM_NAME=pounce           # Sender name
SMTP_USE_SSL=true               # Use SSL (port 465)
SMTP_USE_TLS=false              # Use STARTTLS (port 587)

Recommended SMTP Providers:

  • Zoho Mail (Free tier available) - Port 465 SSL
  • Resend (Developer-friendly) - Port 587 TLS
  • SendGrid (10k free/month) - Port 587 TLS
  • Amazon SES (Cheap at scale) - Port 587 TLS

Verify Email is Working

cd backend && source venv/bin/activate

python3 -c "
from app.services.email_service import email_service
print('Email configured:', email_service.is_configured())
"

Test Email Manually

python3 -c "
import asyncio
from app.services.email_service import email_service

async def test():
    result = await email_service.send_email(
        to_email='your@email.com',
        subject='Test from Pounce',
        html_content='<h1>It works!</h1>'
    )
    print('Sent:', result)

asyncio.run(test())
"

💳 Subscription Tiers

Feature Scout (Free) Trader (€9/mo) Tycoon (€29/mo)
Watchlist Domains 5 50 500
Portfolio Domains 25 Unlimited
Marketplace Listings 3 25
Sniper Alerts 3 25
TLD Pricing Preview Full Full
Auction Deal Score Blurred Full Full
SEO Juice Detector
Health Monitoring Basic Advanced Advanced
Notifications Email Email + SMS All + Webhook

🔗 API Endpoints (New)

Listings (For Sale)

Method Endpoint Auth
GET /api/v1/listings No
GET /api/v1/listings/{slug} No
POST /api/v1/listings/{slug}/inquire No
GET /api/v1/listings/my Yes
POST /api/v1/listings Yes
PUT /api/v1/listings/{id} Yes
DELETE /api/v1/listings/{id} Yes
POST /api/v1/listings/{id}/verify-dns Yes

Sniper Alerts

Method Endpoint Auth
GET /api/v1/sniper-alerts Yes
POST /api/v1/sniper-alerts Yes
PUT /api/v1/sniper-alerts/{id} Yes
DELETE /api/v1/sniper-alerts/{id} Yes
POST /api/v1/sniper-alerts/{id}/test Yes
GET /api/v1/sniper-alerts/{id}/matches Yes

SEO Data (Tycoon Only)

Method Endpoint Auth
GET /api/v1/seo/{domain} Tycoon
POST /api/v1/seo/batch Tycoon
GET /api/v1/seo/{domain}/quick Trader+

🎨 UI Components

The Command Center uses these reusable components from PremiumTable.tsx:

Component Usage
PremiumTable Elegant data tables with sorting
StatCard Stats display with icons
PageContainer Consistent max-width wrapper
SearchInput Search with clear button
TabBar Tab navigation with counts
FilterBar Row of filter controls
SelectDropdown Styled select inputs
ActionButton Primary/secondary/ghost buttons
Badge Status badges with variants
TableActionButton Icon buttons for table rows

🐛 Troubleshooting

Common Console Warnings (Ignore)

Warning Explanation
SES Removing unpermitted intrinsics MetaMask browser extension
PostHog CORS blocked Normal on localhost
-webkit-text-size-adjust error Old CSS prefixes

Actual Errors

Error Solution
CORS request did not succeed to localhost:8000 Start the backend!
500 Internal Server Error on /seo/ Run init_db.py to create tables
404 on /listings/my API routes ordered correctly in v2.0

📄 License

MIT License


📧 Support

For issues and feature requests, please open a GitHub issue or contact support@pounce.ch