SEO flywheel: /today digest, sitemap, robots, home OG tags
Make the summary pages discoverable so traffic compounds passively: - /today: a server-rendered, shareable + indexable digest of today's brief — each item's title (→ /a summary), our summary, and a source link. OG/Twitter meta + self-canonical. - /sitemap.xml: dynamic — home, /today, and every accepted non-duplicate /a page with lastmod. robots.txt allows all and points to it. - Home (SPA shell) gains canonical + OG/Twitter tags for cleaner unfurls. - Caddy routes /today + /sitemap.xml to the API. 133 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -800,6 +800,40 @@ def create_app() -> FastAPI:
|
||||
_kick_summary(article_id, background_tasks)
|
||||
return {"status": "pending", "summary": None}
|
||||
|
||||
@app.get("/today", response_class=HTMLResponse)
|
||||
def today_digest() -> HTMLResponse:
|
||||
with get_conn() as conn:
|
||||
b = queries.brief(conn)
|
||||
items = b.get("items") or []
|
||||
if not items:
|
||||
return HTMLResponse(share.render_not_found(PUBLIC_BASE_URL), status_code=404)
|
||||
return HTMLResponse(share.render_digest(items, PUBLIC_BASE_URL, b.get("brief_date")))
|
||||
|
||||
@app.get("/sitemap.xml")
|
||||
def sitemap() -> Response:
|
||||
with get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT a.id, COALESCE(a.published_at, a.discovered_at) AS lm "
|
||||
"FROM articles a JOIN article_scores s ON s.article_id = a.id "
|
||||
"WHERE s.accepted = 1 AND a.duplicate_of IS NULL "
|
||||
"ORDER BY lm DESC LIMIT 5000"
|
||||
).fetchall()
|
||||
base = PUBLIC_BASE_URL
|
||||
urls = [
|
||||
f"<url><loc>{base}/</loc><changefreq>hourly</changefreq><priority>1.0</priority></url>",
|
||||
f"<url><loc>{base}/today</loc><changefreq>daily</changefreq><priority>0.9</priority></url>",
|
||||
]
|
||||
for r in rows:
|
||||
lm = (r["lm"] or "")[:10]
|
||||
lastmod = f"<lastmod>{lm}</lastmod>" if lm else ""
|
||||
urls.append(f"<url><loc>{base}/a/{r['id']}</loc>{lastmod}</url>")
|
||||
xml = (
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
|
||||
+ "".join(urls) + "</urlset>"
|
||||
)
|
||||
return Response(content=xml, media_type="application/xml")
|
||||
|
||||
@app.post("/api/import")
|
||||
def import_local(body: ImportBody, request: Request) -> dict:
|
||||
"""Fold this device's anonymous history/saved into the account (one-time)."""
|
||||
|
||||
Reference in New Issue
Block a user