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)
- 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))"
- Force-push the rewritten history to your remote
git push --force-with-lease --all
git push --force-with-lease --tags
- 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
- Re-deploy
- Backend:
pip install -r backend/requirements.txt - Frontend:
npm ci && npm run build
- Quick verification
- Login now sets an HttpOnly cookie:
POST /api/v1/auth/loginreturns{ "expires_in": ... }(no token in JSON)POST /api/v1/auth/logoutclears 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)
Server deployment (recommended)
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 toDEPLOY_backend.env(local only)DEPLOY_frontend.env.example→ copy toDEPLOY_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
useMemoanduseCallbackfor 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:
- Frontend: http://localhost:3000
- Backend: http://localhost:8000
- API Docs: http://localhost:8000/docs
📁 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.completedcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.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 + 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