feat(affiliate): migration 0026 — affiliate_products + affiliate_clicks tables
Adds affiliate product catalog and click tracking tables. UNIQUE(slug, language) mirrors articles schema for multi-language support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"""Migration 0026: Affiliate product catalog + click tracking tables.
|
||||
|
||||
affiliate_products: admin-managed product catalog for editorial affiliate cards.
|
||||
- slug+language uniqueness mirrors articles (same slug can exist in DE + EN
|
||||
with different affiliate URLs, copy, and pros/cons).
|
||||
- retailer: display name (Amazon, Padel Nuestro, etc.) — stored in full URL
|
||||
with tracking params already baked into affiliate_url.
|
||||
- cta_label: per-product override; empty → use i18n default "Zum Angebot".
|
||||
- status: draft/active/archived — only active products are baked into articles.
|
||||
|
||||
affiliate_clicks: one row per /go/<slug> redirect hit.
|
||||
- ip_hash: SHA256(ip + YYYY-MM-DD + SECRET_KEY[:16]), daily rotation for GDPR.
|
||||
- article_slug: best-effort extraction from Referer header.
|
||||
"""
|
||||
|
||||
|
||||
def up(conn) -> None:
|
||||
conn.execute("""
|
||||
CREATE TABLE affiliate_products (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slug TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
brand TEXT NOT NULL DEFAULT '',
|
||||
category TEXT NOT NULL DEFAULT 'accessory',
|
||||
retailer TEXT NOT NULL DEFAULT '',
|
||||
affiliate_url TEXT NOT NULL,
|
||||
image_url TEXT NOT NULL DEFAULT '',
|
||||
price_cents INTEGER,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
rating REAL,
|
||||
pros TEXT NOT NULL DEFAULT '[]',
|
||||
cons TEXT NOT NULL DEFAULT '[]',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
cta_label TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'draft',
|
||||
language TEXT NOT NULL DEFAULT 'de',
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT,
|
||||
UNIQUE(slug, language)
|
||||
)
|
||||
""")
|
||||
conn.execute("""
|
||||
CREATE TABLE affiliate_clicks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
product_id INTEGER NOT NULL REFERENCES affiliate_products(id),
|
||||
article_slug TEXT,
|
||||
referrer TEXT,
|
||||
ip_hash TEXT NOT NULL,
|
||||
clicked_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)
|
||||
""")
|
||||
# Queries: products by category+status, clicks by product and time
|
||||
conn.execute(
|
||||
"CREATE INDEX idx_affiliate_products_category_status"
|
||||
" ON affiliate_products(category, status)"
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX idx_affiliate_clicks_product_id"
|
||||
" ON affiliate_clicks(product_id)"
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX idx_affiliate_clicks_clicked_at"
|
||||
" ON affiliate_clicks(clicked_at)"
|
||||
)
|
||||
Reference in New Issue
Block a user