pounce/DATABASE_MIGRATIONS.md
yves.gugger 18d50e96f4 feat: Add For Sale Marketplace + Sniper Alerts
BACKEND - New Models:
- DomainListing: For sale landing pages with DNS verification
- ListingInquiry: Contact form submissions from buyers
- ListingView: Analytics tracking
- SniperAlert: Hyper-personalized auction filters
- SniperAlertMatch: Matched auctions for alerts

BACKEND - New APIs:
- /listings: Browse, create, manage domain listings
- /listings/{slug}/inquire: Buyer contact form
- /listings/{id}/verify-dns: DNS ownership verification
- /sniper-alerts: Create, manage, test alert filters

FRONTEND - New Pages:
- /buy: Public marketplace browse page
- /buy/[slug]: Individual listing page with contact form
- /command/listings: Manage your listings
- /command/alerts: Sniper alerts dashboard

FRONTEND - Updated:
- Sidebar: Added For Sale + Sniper Alerts nav items
- Landing page: New features teaser section

DOCS:
- DATABASE_MIGRATIONS.md: Complete SQL for new tables

From analysis_3.md:
- Strategie 2: Micro-Marktplatz (For Sale Pages)
- Strategie 4: Alerts nach Maß (Sniper Alerts)
- Säule 2: DNS Ownership Verification
2025-12-10 11:44:56 +01:00

7.2 KiB

Database Migrations Guide

Overview

This document lists all database tables that need to be created when deploying Pounce to a new server.

Required Tables

Core Tables (Already Implemented)

Table Model Description
users User User accounts and authentication
subscriptions Subscription User subscription plans (Scout, Trader, Tycoon)
domains Domain Tracked domains in watchlists
domain_checks DomainCheck Domain availability check history
tld_prices TLDPrice TLD price history
tld_info TLDInfo TLD metadata
portfolio_domains PortfolioDomain User-owned domains
domain_valuations DomainValuation Domain valuation history
domain_auctions DomainAuction Scraped auction listings
auction_scrape_logs AuctionScrapeLog Scraping job logs
newsletter_subscribers NewsletterSubscriber Email newsletter list
price_alerts PriceAlert TLD price change alerts
admin_activity_logs AdminActivityLog Admin action audit log
blog_posts BlogPost Blog content

NEW Tables (To Be Created)

These tables were added for the "For Sale" Marketplace and Sniper Alerts features:

1. Domain Listings (For Sale Marketplace)

-- Main listing table
CREATE TABLE domain_listings (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id),
    domain VARCHAR(255) NOT NULL UNIQUE,
    slug VARCHAR(300) NOT NULL UNIQUE,
    title VARCHAR(200),
    description TEXT,
    asking_price FLOAT,
    min_offer FLOAT,
    currency VARCHAR(3) DEFAULT 'USD',
    price_type VARCHAR(20) DEFAULT 'fixed',
    pounce_score INTEGER,
    estimated_value FLOAT,
    verification_status VARCHAR(20) DEFAULT 'not_started',
    verification_code VARCHAR(64),
    verified_at TIMESTAMP,
    status VARCHAR(30) DEFAULT 'draft',
    show_valuation BOOLEAN DEFAULT TRUE,
    allow_offers BOOLEAN DEFAULT TRUE,
    featured BOOLEAN DEFAULT FALSE,
    view_count INTEGER DEFAULT 0,
    inquiry_count INTEGER DEFAULT 0,
    expires_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    published_at TIMESTAMP
);

CREATE INDEX idx_listings_user_id ON domain_listings(user_id);
CREATE INDEX idx_listings_domain ON domain_listings(domain);
CREATE INDEX idx_listings_slug ON domain_listings(slug);
CREATE INDEX idx_listings_status ON domain_listings(status);
-- Contact inquiries from potential buyers
CREATE TABLE listing_inquiries (
    id SERIAL PRIMARY KEY,
    listing_id INTEGER NOT NULL REFERENCES domain_listings(id) ON DELETE CASCADE,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL,
    phone VARCHAR(50),
    company VARCHAR(200),
    message TEXT NOT NULL,
    offer_amount FLOAT,
    status VARCHAR(20) DEFAULT 'new',
    ip_address VARCHAR(45),
    user_agent VARCHAR(500),
    created_at TIMESTAMP DEFAULT NOW(),
    read_at TIMESTAMP,
    replied_at TIMESTAMP
);

CREATE INDEX idx_inquiries_listing_id ON listing_inquiries(listing_id);
-- Analytics: page views
CREATE TABLE listing_views (
    id SERIAL PRIMARY KEY,
    listing_id INTEGER NOT NULL REFERENCES domain_listings(id) ON DELETE CASCADE,
    ip_address VARCHAR(45),
    user_agent VARCHAR(500),
    referrer VARCHAR(500),
    user_id INTEGER REFERENCES users(id),
    viewed_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_views_listing_id ON listing_views(listing_id);

2. Sniper Alerts

-- Saved filter configurations for personalized alerts
CREATE TABLE sniper_alerts (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id),
    name VARCHAR(100) NOT NULL,
    description VARCHAR(500),
    filter_criteria JSONB NOT NULL DEFAULT '{}',
    tlds VARCHAR(500),
    keywords VARCHAR(500),
    exclude_keywords VARCHAR(500),
    max_length INTEGER,
    min_length INTEGER,
    max_price FLOAT,
    min_price FLOAT,
    max_bids INTEGER,
    ending_within_hours INTEGER,
    platforms VARCHAR(200),
    no_numbers BOOLEAN DEFAULT FALSE,
    no_hyphens BOOLEAN DEFAULT FALSE,
    exclude_chars VARCHAR(50),
    notify_email BOOLEAN DEFAULT TRUE,
    notify_sms BOOLEAN DEFAULT FALSE,
    notify_push BOOLEAN DEFAULT FALSE,
    max_notifications_per_day INTEGER DEFAULT 10,
    cooldown_minutes INTEGER DEFAULT 30,
    is_active BOOLEAN DEFAULT TRUE,
    matches_count INTEGER DEFAULT 0,
    notifications_sent INTEGER DEFAULT 0,
    last_matched_at TIMESTAMP,
    last_notified_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_alerts_user_id ON sniper_alerts(user_id);
CREATE INDEX idx_alerts_active ON sniper_alerts(is_active);
-- Matched auctions for each alert
CREATE TABLE sniper_alert_matches (
    id SERIAL PRIMARY KEY,
    alert_id INTEGER NOT NULL REFERENCES sniper_alerts(id) ON DELETE CASCADE,
    domain VARCHAR(255) NOT NULL,
    platform VARCHAR(50) NOT NULL,
    current_bid FLOAT NOT NULL,
    end_time TIMESTAMP NOT NULL,
    auction_url VARCHAR(500),
    notified BOOLEAN DEFAULT FALSE,
    clicked BOOLEAN DEFAULT FALSE,
    matched_at TIMESTAMP DEFAULT NOW(),
    notified_at TIMESTAMP
);

CREATE INDEX idx_matches_alert_id ON sniper_alert_matches(alert_id);

Migration Commands

cd backend

# Generate migration
alembic revision --autogenerate -m "Add marketplace and sniper alert tables"

# Apply migration
alembic upgrade head

Manual SQL (Alternative)

Run the SQL statements above in order on your PostgreSQL database.


Verification

After running migrations, verify tables exist:

SELECT table_name 
FROM information_schema.tables 
WHERE table_schema = 'public' 
AND table_name IN (
    'domain_listings',
    'listing_inquiries', 
    'listing_views',
    'sniper_alerts',
    'sniper_alert_matches'
);

Feature References

These tables implement features from:

  • analysis_3.md - "Micro-Marktplatz" (For Sale Landing Pages)
  • analysis_3.md - "Sniper Alerts" (Strategie 4: Alerts nach Maß)
  • concept.md - "For Sale Pages" marketplace feature

API Endpoints

Listings (For Sale)

Method Endpoint Description
GET /api/v1/listings Browse public listings
GET /api/v1/listings/{slug} View listing details
POST /api/v1/listings/{slug}/inquire Contact seller
POST /api/v1/listings Create listing (auth)
GET /api/v1/listings/my Get my listings (auth)
PUT /api/v1/listings/{id} Update listing (auth)
DELETE /api/v1/listings/{id} Delete listing (auth)
POST /api/v1/listings/{id}/verify-dns Start verification
GET /api/v1/listings/{id}/verify-dns/check Check verification

Sniper Alerts

Method Endpoint Description
GET /api/v1/sniper-alerts Get my alerts
POST /api/v1/sniper-alerts Create alert
PUT /api/v1/sniper-alerts/{id} Update alert
DELETE /api/v1/sniper-alerts/{id} Delete alert
GET /api/v1/sniper-alerts/{id}/matches Get matched auctions
POST /api/v1/sniper-alerts/{id}/test Test alert criteria