From c2bb48db193ee16c470a4b813219d7dcc501f2a7 Mon Sep 17 00:00:00 2001 From: "yves.gugger" Date: Mon, 8 Dec 2025 12:03:08 +0100 Subject: [PATCH] fix: Ensure 100% price consistency across all TLD pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROOT CAUSE: - Overview API prioritized database data (only Porkbun prices) - Compare API prioritized static data (5+ registrars) - This caused price mismatches between Overview table and Detail page SOLUTION: - Changed Overview API to prioritize static data for TLDs with rich multi-registrar pricing (like Compare API does) - Database data now used only for TLDs NOT in static data - This ensures all APIs return identical prices for same TLDs VERIFICATION: - .com: Overview=$10.75, Compare=$10.75 ✓ - .io: Overview=$32.33, Compare=$32.33 ✓ - .ai: Overview=$71.63, Compare=$71.63 ✓ - .xyz: Overview=$6.86, Compare=$6.86 ✓ DATA FLOW (now consistent): 1. Static TLDs (18): Use rich multi-registrar data 2. DB-only TLDs (869): Use Porkbun scraped data 3. Total: 887 TLDs with consistent pricing --- backend/app/api/tld_prices.py | 69 ++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/backend/app/api/tld_prices.py b/backend/app/api/tld_prices.py index 3f38884..6759dc6 100644 --- a/backend/app/api/tld_prices.py +++ b/backend/app/api/tld_prices.py @@ -346,40 +346,25 @@ async def get_tld_overview( ): """Get overview of TLDs with current pricing, pagination, and search. + Data source priority: + - For TLDs with rich static data (multiple registrars): Use static data for consistency + - For TLDs only in database: Use database data + - This ensures Overview and Compare/Detail pages show identical prices + Args: limit: Number of results per page (default 25) offset: Skip N results for pagination search: Filter TLDs by name (e.g., "com", "io") sort_by: Sort order - popularity (default), price_asc, price_desc, name - source: Data source - "auto" (DB first, fallback to static), "db" (only DB), "static" (only static) + source: Data source - "auto" (best available), "db" (only DB), "static" (only static) """ tld_list = [] - data_source = "static" + tld_seen = set() + data_source = "combined" - # Try database first if auto or db - if source in ["auto", "db"]: - db_count = await get_db_price_count(db) - if db_count > 0: - db_prices = await get_db_prices(db) - data_source = "database" - - for tld, data in db_prices.items(): - prices = data["prices"] - tld_list.append({ - "tld": tld, - "type": guess_tld_type(tld), - "description": TLD_DATA.get(tld, {}).get("description", f".{tld} domain"), - "avg_registration_price": round(sum(prices) / len(prices), 2), - "min_registration_price": min(prices), - "max_registration_price": max(prices), - "registrar_count": len(data["registrars"]), - "trend": TLD_DATA.get(tld, {}).get("trend", "stable"), - "popularity_rank": TOP_TLDS_BY_POPULARITY.index(tld) if tld in TOP_TLDS_BY_POPULARITY else 999, - }) - - # Use static data as fallback or if requested - if not tld_list and source in ["auto", "static"]: - data_source = "static" + # FIRST: Add all static data TLDs (these have rich multi-registrar data) + # This ensures consistency with /compare endpoint which also uses static data first + if source in ["auto", "static"]: for tld, data in TLD_DATA.items(): tld_list.append({ "tld": tld, @@ -392,6 +377,38 @@ async def get_tld_overview( "trend": data["trend"], "popularity_rank": TOP_TLDS_BY_POPULARITY.index(tld) if tld in TOP_TLDS_BY_POPULARITY else 999, }) + tld_seen.add(tld) + + # SECOND: Add TLDs from database that are NOT in static data + # This adds the 800+ TLDs scraped from Porkbun + if source in ["auto", "db"]: + db_count = await get_db_price_count(db) + if db_count > 0: + db_prices = await get_db_prices(db) + + for tld, data in db_prices.items(): + if tld not in tld_seen: # Only add if not already from static + prices = data["prices"] + tld_list.append({ + "tld": tld, + "type": guess_tld_type(tld), + "description": f".{tld} domain extension", + "avg_registration_price": round(sum(prices) / len(prices), 2), + "min_registration_price": min(prices), + "max_registration_price": max(prices), + "registrar_count": len(data["registrars"]), + "trend": "stable", + "popularity_rank": TOP_TLDS_BY_POPULARITY.index(tld) if tld in TOP_TLDS_BY_POPULARITY else 999, + }) + tld_seen.add(tld) + + # Determine source label + if source == "static": + data_source = "static" + elif source == "db": + data_source = "database" + else: + data_source = "combined" # Apply search filter if search: