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

```bash
python3 -c "import secrets; print(secrets.token_hex(32))"
```

2) **Force-push the rewritten history to your remote**

```bash
git push --force-with-lease --all
git push --force-with-lease --tags
```

3) **Re-clone on every server/CI machine**

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

```bash
rm -rf pounce
git clone <your-repo> pounce
```

4) **Re-deploy**
- **Backend**: `pip install -r backend/requirements.txt`
- **Frontend**: `npm ci && npm run build`

5) **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)

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

```bash
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:**
```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

---

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

```bash
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`:**
```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`:**
```env
NEXT_PUBLIC_API_URL=https://api.pounce.ch
```

### 3. Initialize Database

```bash
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):**
```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

# Save & auto-restart
pm2 save
pm2 startup
```

**With Docker:**
```bash
docker-compose up -d --build
```

### 5. Nginx Configuration

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

```env
# 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

```bash
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

```bash
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
