SPB Git forge

spb/api-ka

Public

API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com

48commits 1branches 0releases
5.9 MBsize
maindefault branch
19 days agolast push
Python 60.9% HTML 21% TypeScript 7.3% JavaScript 5.2% CSS 4.8% Shell 0.8%

SEO : robots.txt + sitemap.xml + canonical/hreflang/JSON-LD sur le site de doc

- src/api/main.py : routes /robots.txt (Disallow /api/, /docs) et
  /sitemap.xml (/, /contact, /stats)
- web/{index,contact,stats}.html : canonical, hreflang fr-ca, og:site_name,
  og:locale, JSON-LD WebSite + Organization + BreadcrumbList
- la negociation de contenu existante est conservee : les clients API
  recoivent toujours le statut JSON a la racine

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 1 mo ago (Aug 23, 2026) parent b648cb5

4 changed files +50 −1

modified src/api/main.py +30 −1
@@ -20,7 +20,7 @@ from typing import Any
20 20
21 21 from fastapi import FastAPI, Request
22 22 from fastapi.middleware.cors import CORSMiddleware
23 −from fastapi.responses import FileResponse
23 +from fastapi.responses import FileResponse, PlainTextResponse, Response
24 24 from fastapi.staticfiles import StaticFiles
25 25
26 26 from src.api import reqstats
@@ -166,6 +166,35 @@ def stats_page() -> FileResponse:
166 166 return FileResponse(WEB_STATS, media_type="text/html")
167 167
168 168
169 +# --- Référencement du site de documentation (www.api-ka.com) -------------------
170 +
171 +BASE_URL = "https://www.api-ka.com"
172 +
173 +
174 +@app.get("/robots.txt", include_in_schema=False)
175 +def robots_txt() -> PlainTextResponse:
176 + return PlainTextResponse(
177 + "User-agent: *\n"
178 + "Allow: /\n"
179 + "Disallow: /api/\n"
180 + "Disallow: /docs\n"
181 + "Disallow: /openapi.json\n"
182 + f"\nSitemap: {BASE_URL}/sitemap.xml\n")
183 +
184 +
185 +@app.get("/sitemap.xml", include_in_schema=False)
186 +def sitemap_xml() -> Response:
187 + urls = "".join(
188 + f"<url><loc>{BASE_URL}{p}</loc></url>"
189 + for p in ("/", "/contact", "/stats"))
190 + return Response(
191 + '<?xml version="1.0" encoding="UTF-8"?>\n'
192 + '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
193 + + urls + "</urlset>",
194 + media_type="application/xml",
195 + headers={"Cache-Control": "public, max-age=3600"})
196 +
197 +
169 198 # Assets de marque Groupe KA servis à la racine du domaine (voir src/api/web/) :
170 199 # favicon SVG, icône iOS et image Open Graph 1200x630 referencée par les meta og:image.
171 200 @app.get("/favicon.svg", include_in_schema=False)
modified src/api/web/contact.html +6 −0
@@ -67,6 +67,12 @@ section{padding:64px 0}
67 67 .account p{margin:0;max-width:56ch;color:var(--ink-2);font-size:14.5px}
68 68 .account b{color:var(--ink)}
69 69 </style>
70 +<link rel="canonical" href="https://www.api-ka.com/contact">
71 +<link rel="alternate" hreflang="fr-ca" href="https://www.api-ka.com/contact">
72 +<link rel="alternate" hreflang="x-default" href="https://www.api-ka.com/contact">
73 +<meta property="og:site_name" content="API-Ka">
74 +<meta property="og:locale" content="fr_CA">
75 +<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Accueil", "item": "https://www.api-ka.com/"}, {"@type": "ListItem", "position": 2, "name": "Contact", "item": "https://www.api-ka.com/contact"}]}</script>
70 76 </head>
71 77 <body>
72 78
modified src/api/web/index.html +8 −0
@@ -165,6 +165,14 @@ pre{margin:0;background:var(--ink);color:var(--paper);padding:16px 18px;overflow
165 165 .reveal.in{opacity:1;transform:none}
166 166 @media(prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none;transition:none}.hero-tile{transform:none}.pulse.ok{animation:none}}
167 167 </style>
168 +<link rel="canonical" href="https://www.api-ka.com/">
169 +<link rel="alternate" hreflang="fr-ca" href="https://www.api-ka.com/">
170 +<link rel="alternate" hreflang="x-default" href="https://www.api-ka.com/">
171 +<meta property="og:site_name" content="API-Ka">
172 +<meta property="og:locale" content="fr_CA">
173 +<script type="application/ld+json">{"@context": "https://schema.org", "@type": "WebSite", "name": "API-Ka", "url": "https://www.api-ka.com/", "description": "API publique des données quotidiennes de l'écosystème Groupe KA (Québec)", "inLanguage": "fr-CA"}</script>
174 +<script type="application/ld+json">{"@context": "https://schema.org", "@type": "Organization", "name": "API-Ka (Groupe KA)", "url": "https://www.api-ka.com/", "logo": "https://www.api-ka.com/og.png"}</script>
175 +<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Accueil", "item": "https://www.api-ka.com/"}]}</script>
168 176 </head>
169 177 <body>
170 178
modified src/api/web/stats.html +6 −0
@@ -176,6 +176,12 @@ table.dt tbody tr:nth-child(even){background:var(--surface-2)}
176 176 @media(max-width:767px){section{padding:32px 0}.hero-s{padding:40px 0 32px}}
177 177 @media(prefers-reduced-motion:reduce){*{transition:none!important}}
178 178 </style>
179 +<link rel="canonical" href="https://www.api-ka.com/stats">
180 +<link rel="alternate" hreflang="fr-ca" href="https://www.api-ka.com/stats">
181 +<link rel="alternate" hreflang="x-default" href="https://www.api-ka.com/stats">
182 +<meta property="og:site_name" content="API-Ka">
183 +<meta property="og:locale" content="fr_CA">
184 +<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Accueil", "item": "https://www.api-ka.com/"}, {"@type": "ListItem", "position": 2, "name": "Statistiques", "item": "https://www.api-ka.com/stats"}]}</script>
179 185 </head>
180 186 <body>
181 187
182 188