"""`/sitemap?kind=companies|industries|countries&page=` — only companies worth indexing (spec §84: no thin profiles).""" from __future__ import annotations from typing import Any from fastapi import APIRouter, Query, Request from companyatlas.api import aggregates as agg from companyatlas.api.common import cached, cached_response from companyatlas.config import settings from companyatlas.db import connection, fetch_all, fetch_val ORDER = 10 router = APIRouter(prefix="/api/v1", tags=["exports"]) PAGE_SIZE = 5000 INDEXED_SQL = """ with ev as (select company_id, count(*) as n from events where status = 'active' group by company_id), se as (select company_id, count(*) as n from sensors where status in ('active', 'failing', 'stale') group by company_id) select c.slug, greatest(c.updated_at, coalesce(c.last_event_at, c.updated_at), coalesce(c.last_observed_at, c.updated_at)) as updated_at from companies c left join ev on ev.company_id = c.id left join se on se.company_id = c.id where c.status = 'ACTIVE' and (c.indexed or (coalesce(ev.n, 0) >= :min_events and coalesce(se.n, 0) >= :min_sensors)) order by c.slug limit :lim offset :off """ INDEXED_COUNT_SQL = """ with ev as (select company_id, count(*) as n from events where status = 'active' group by company_id), se as (select company_id, count(*) as n from sensors where status in ('active', 'failing', 'stale') group by company_id) select count(*) from companies c left join ev on ev.company_id = c.id left join se on se.company_id = c.id where c.status = 'ACTIVE' and (c.indexed or (coalesce(ev.n, 0) >= :min_events and coalesce(se.n, 0) >= :min_sensors)) """ @router.get("/sitemap", summary="Sitemap entries") async def sitemap(request: Request, kind: str = Query("companies", pattern="^(companies|industries|countries)$"), page: int = Query(1, ge=1)) -> Any: async def produce() -> dict[str, Any]: if kind == "industries": rows = await agg.cached_industry_rows() return {"kind": kind, "items": [{"slug": r["slug"], "updated_at": None} for r in rows if r["companies"] > 0], "pages": 1, "page": 1} if kind == "countries": rows = await agg.cached_country_rows() return {"kind": kind, "items": [{"slug": r["slug"], "code": r["code"], "updated_at": None} for r in rows if r["companies"] > 0], "pages": 1, "page": 1} async with connection() as conn: params = {"min_events": settings.seo_min_events, "min_sensors": settings.seo_min_sensors} total = int(await fetch_val(conn, INDEXED_COUNT_SQL, **params) or 0) rows = await fetch_all(conn, INDEXED_SQL, **params, lim=PAGE_SIZE, off=(page - 1) * PAGE_SIZE) return {"kind": kind, "items": [{"slug": r["slug"], "updated_at": r["updated_at"]} for r in rows], "pages": max(1, -(-total // PAGE_SIZE)), "page": page, "total": total} return cached_response(request, await cached(f"sitemap:{kind}:{page}", 600, produce), 600)