"""Sitemap & robots.txt API: tenant-aware SEO files served by the backend. Because this is a white-label app where each tenant has its own domain (set via KMTN_WEBSITE_URL), sitemap.xml and robots.txt are generated on-the-fly from the station config — no static files needed. This matches the reviewer feedback: 'This is a whitelabel app - this file may need to be dynaimcally generated...' Follows the same pattern as theme_export.py: content is derived from KMTN_WEBSITE_URL at runtime, so every tenant gets their own correct URL. """ from typing import Any, Dict from fastapi import APIRouter, Depends, Response, status as http_status from app.auth import get_current_admin_user from app.config import settings from app.sitemap_export import build_robots_txt, build_sitemap_xml from app.user_models import User router = APIRouter() @router.get("/sitemap.xml") async def get_sitemap() -> Response: """Return a dynamically-generated sitemap.xml. Public endpoint. Uses KMTN_WEBSITE_URL so each tenant gets the correct domain. """ xml = build_sitemap_xml(settings.WEBSITE_URL) return Response(content=xml, media_type="application/xml") @router.get("/robots.txt") async def get_robots() -> Response: """Return a dynamically-generated robots.txt. Public endpoint. Uses KMTN_WEBSITE_URL so the Sitemap directive points to the correct tenant domain. """ txt = build_robots_txt(settings.WEBSITE_URL) return Response(content=txt, media_type="text/plain") @router.post("/regenerate", status_code=http_status.HTTP_200_OK) async def regenerate_sitemap( _: User = Depends(get_current_admin_user), ) -> Dict[str, Any]: """Force regenerate the sitemap cache. Admin only. In the dynamic model this is a no-op (files are generated per-request), but kept for API consistency with the theme endpoint. """ return { "status": "ok", "note": "sitemap and robots.txt are dynamically generated per-request using KMTN_WEBSITE_URL", "base_url": settings.WEBSITE_URL, }