feat: search-engine indexing — robots.txt, sitemap.xml, llms.txt, SEO meta
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 25s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
Documentation / Generate API Documentation (push) Successful in 9s
Documentation / Build Sphinx Documentation (push) Successful in 16s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 13s
Documentation / Validate Documentation (push) Failing after 8s
Documentation / Documentation Summary (push) Successful in 2s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s

robots.txt (sitemap pointer, /metrics and /scrape/ disallowed),
sitemap.xml (/ and /docs), and llms.txt (site + API summary for LLM
crawlers) served at the domain root. Dashboard head gains title with
keywords, meta description, canonical, Open Graph/Twitter tags,
schema.org WebApplication JSON-LD, theme-color, and an inline SVG
favicon (also silences the /favicon.ico 404).
This commit is contained in:
2026-08-11 16:33:44 +07:00
parent bd3353e2dc
commit 09c1c84153
6 changed files with 107 additions and 2 deletions
+22 -1
View File
@@ -16,7 +16,7 @@ from typing import Any, Dict, List, Optional
import requests
from fastapi import BackgroundTasks, Depends, FastAPI, Header, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from fastapi.responses import FileResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from .config import Config
@@ -276,6 +276,27 @@ async def root():
return HTMLResponse(content=DASHBOARD_HTML)
# Crawler/indexing files must live at the domain root (served from src/static)
_STATIC_DIR = os.path.dirname(_DASHBOARD_HTML_PATH)
@app.get("/robots.txt", include_in_schema=False)
async def robots_txt():
return FileResponse(os.path.join(_STATIC_DIR, "robots.txt"), media_type="text/plain")
@app.get("/llms.txt", include_in_schema=False)
async def llms_txt():
return FileResponse(os.path.join(_STATIC_DIR, "llms.txt"), media_type="text/plain")
@app.get("/sitemap.xml", include_in_schema=False)
async def sitemap_xml():
return FileResponse(
os.path.join(_STATIC_DIR, "sitemap.xml"), media_type="application/xml"
)
@app.get("/health", response_model=HealthResponse)
async def get_health():
"""Get system health status"""