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:
jay
2026-06-05 19:37:05 +00:00
parent 427210ac3e
commit ea58039fb9
5 changed files with 176 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def client(tmp_path, monkeypatch):
db = tmp_path / "t.sqlite3"
monkeypatch.setenv("GOODNEWS_DB", str(db))
monkeypatch.setenv("GOODNEWS_PUBLIC_BASE_URL", "https://upbeatbytes.com")
import importlib
import goodnews.api as api
importlib.reload(api)
from goodnews.db import connect, init_db
c = connect(str(db)); init_db(c)
c.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (1,'BBC','http://s/f',5)")
c.execute("INSERT INTO articles (id,source_id,canonical_url,title,url_hash,published_at) "
"VALUES (1,1,'https://bbc.com/x','Bees are back','h1','2026-06-05T08:00:00')")
c.execute("INSERT INTO article_scores (article_id,accepted,reason_text) VALUES (1,1,'Hopeful.')")
c.execute("INSERT INTO article_summaries (article_id,summary) VALUES (1,'Bee numbers recovered after a restoration effort.')")
c.execute("INSERT INTO daily_briefs (id,brief_date,title) VALUES (1,'2026-06-05','B')")
c.execute("INSERT INTO daily_brief_items (brief_id,article_id,rank) VALUES (1,1,1)")
c.commit(); c.close()
return api.create_app()
def test_today_digest(client):
r = TestClient(client).get("/today")
assert r.status_code == 200
html = r.text
assert "Bees are back" in html
assert "Bee numbers recovered" in html # our summary
assert 'href="/a/1"' in html and "bbc.com/x" in html # summary + source links
assert 'rel="canonical" href="https://upbeatbytes.com/today"' in html
assert 'property="og:title"' in html
def test_sitemap(client):
r = TestClient(client).get("/sitemap.xml")
assert r.status_code == 200
assert "application/xml" in r.headers["content-type"]
xml = r.text
assert "<urlset" in xml
assert "https://upbeatbytes.com/a/1" in xml
assert "https://upbeatbytes.com/today" in xml
assert "<lastmod>2026-06-05</lastmod>" in xml