pounce/README.md
yves.gugger cab8cef679 feat: Professional TLD detail page overhaul
- Hero section with prominent pricing and quick registration link
- Interactive line chart with 1M/3M/1Y/ALL time period selection
- Integrated domain search directly on TLD page
- Smart registrar comparison table with external links
- Savings calculator showing cost savings vs most expensive registrar
- Renewal price warning indicator (⚠️) for high renewal fees
- Related TLDs section with smart suggestions
- Price alert modal for email notifications
- Responsive design for all screen sizes
- Loading skeletons and error states
2025-12-08 10:15:44 +01:00

607 lines
18 KiB
Markdown

# 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
- **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
### 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
### 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 |
| `/dashboard` | Personal domain watchlist | Yes |
| `/pricing` | Subscription plans with FAQ | No |
| `/tld-pricing` | TLD price overview with trends | No* |
| `/tld-pricing/[tld]` | TLD detail with registrar comparison | Yes |
*Unauthenticated users see limited data with shimmer effects
---
## Quick Start
### Prerequisites
- Python 3.12+
- Node.js 18+
- npm or yarn
### 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`:
```env
DATABASE_URL=sqlite+aiosqlite:///./domainwatch.db
SECRET_KEY=your-generated-secret-key
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
```
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 |
| POST | `/api/v1/auth/login` | Login (returns JWT) |
| GET | `/api/v1/auth/me` | Get current user |
### 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 |
### Subscription
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/subscription` | Get current subscription |
| POST | `/api/v1/subscription/upgrade` | Upgrade plan |
### 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 | Starter (Free) | Professional ($4.99/mo) | Enterprise ($9.99/mo) |
|---------|----------------|------------------------|----------------------|
| Domains | 3 | 25 | 100 |
| Check Frequency | Daily | Daily | Hourly |
| Notifications | Email | Priority Email | Priority Email |
| WHOIS Data | Basic | Full | Full |
| Check History | — | 30 days | Unlimited |
| Expiration Tracking | — | ✓ | ✓ |
| API Access | — | — | ✓ |
---
## 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** |
| `CORS_ORIGINS` | Allowed origins (comma-separated) | `http://localhost:3000` |
| `ACCESS_TOKEN_EXPIRE_MINUTES` | JWT token lifetime | `10080` (7 days) |
| `SCHEDULER_CHECK_INTERVAL_HOURS` | Domain check interval | `24` |
| `SMTP_HOST` | Email server host | Optional |
| `SMTP_PORT` | Email server port | `587` |
| `SMTP_USER` | Email username | Optional |
| `SMTP_PASSWORD` | Email password | 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
Configure SMTP settings in your `.env`:
```env
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
```
### 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