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
+12 -1
View File
@@ -3,7 +3,18 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ping River Live Monitor</title>
<title>Ping River Live Monitor · Chiang Mai Water Levels &amp; Flood Forecast</title>
<meta name="description" content="Live water levels, discharge, rainfall and ML flood forecasts for the Ping River in Chiang Mai and Northern Thailand. Hourly data from 16 RID gauges and 400+ ThaiWater/HII stations, with official inundation-stage outlooks for Chiang Mai city.">
<link rel="canonical" href="https://water.buildfor.life/">
<meta name="theme-color" content="#f3f7f5">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E%F0%9F%8C%8A%3C/text%3E%3C/svg%3E">
<meta property="og:type" content="website">
<meta property="og:title" content="Ping River Live Monitor · Chiang Mai Flood Watch">
<meta property="og:description" content="Live water levels, rainfall and flood-risk forecasts for the Ping River basin, Northern Thailand.">
<meta property="og:url" content="https://water.buildfor.life/">
<meta property="og:site_name" content="Ping River Live Monitor">
<meta name="twitter:card" content="summary">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebApplication","name":"Ping River Live Monitor","url":"https://water.buildfor.life/","description":"Live water levels, discharge, rainfall and flood forecasts for the Ping River, Chiang Mai, Thailand.","applicationCategory":"Weather","operatingSystem":"Web","offers":{"@type":"Offer","price":"0","priceCurrency":"THB"},"creator":{"@type":"Organization","name":"B4L","url":"https://buildfor.life"}}</script>
<link rel="preconnect" href="https://unpkg.com">
<link rel="preconnect" href="https://tile.openstreetmap.org">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha384-sHL9NAb7lN7rfvG5lfHpm643Xkcjzp4jFvuavGOndn6pjVqS6ny56CAt3nsEVT4H" crossorigin="anonymous">
+34
View File
@@ -0,0 +1,34 @@
# Ping River Live Monitor
> Live water levels, discharge, rainfall and machine-learning flood forecasts for
> the Ping River basin in Northern Thailand, centered on Chiang Mai (gauge P.1,
> Nawarat Bridge). Open-source, hourly data since 2018, operated by B4L
> (https://buildfor.life).
Flood context: Chiang Mai city flooding begins when P.1 reaches 3.70 m
(official inundation stage 1); the record peak was 5.30 m on 2024-10-05.
## Data
- Hourly water level (m) and discharge (m³/s) from 16 Royal Irrigation
Department (RID) telemetry gauges in the Ping basin, 2018-present.
- Hourly rainfall and water level for 400+ ThaiWater/HII stations (Ping basin),
including historical water levels back to 2019.
- ML flood-risk forecasts (probability of warning/danger level within 6/12/24 h)
per station, plus Chiang Mai inundation-stage probabilities.
## API (no key required)
- https://water.buildfor.life/docs : interactive OpenAPI reference
- /stations : station metadata (code, names, coordinates)
- /measurements/latest?limit=N : latest readings
- /measurements/history/{station_code}?hours=N or ?start=YYYY-MM-DD&end=YYYY-MM-DD : history
- /forecast : flood-risk forecasts for all stations
- /api/stats : database coverage statistics
- /api/hii/rainfall/latest : latest rainfall per ThaiWater/HII station
- /api/hii/waterlevel/latest : latest water level per ThaiWater/HII station (m MSL)
## Source
- https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor : code, docs,
and the full data-source catalog (docs/DATA_SOURCES.md).
+6
View File
@@ -0,0 +1,6 @@
User-agent: *
Allow: /
Disallow: /metrics
Disallow: /scrape/
Sitemap: https://water.buildfor.life/sitemap.xml
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://water.buildfor.life/</loc>
<changefreq>hourly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://water.buildfor.life/docs</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
+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"""