← Back to the site changelog
Site Changelog
Original commit record
configure SKYTICAL custom domain (#102)
Publish SKYTICAL from https://skytical.tech at the custom-domain root and update SEO URLs, public paths, provider attribution, documentation, and regression coverage.
SHA
962442d141a19498678a7ff152a3b1ebd2ea3e4e
Commit date
2026-08-13T16:32:04Z
Author
nnneeeooo-nnneeeooo
Committer
web-flow
Changed files (9)
README.md
modified · +2 / −1
pipeline/CONTRACTS.md
modified · +2 / −1
pipeline/common.py
modified · +4 / −4
pipeline/providers.py
modified · +1 / −1
tests/test_changelog.py
modified · +2 / −2
tests/test_providers_payloads.py
modified · +1 / −1
tests/test_radar.py
modified · +1 / −1
tests/test_search.py
modified · +10 / −10
tests/test_seo.py
modified · +5 / −3
Full diff
@@ -107,7 +107,8 @@ python -m http.server -d site 8000\n | `AVWIRE_NVIDIA_MODEL` | `z-ai/glm-5.2` | NVIDIA NIM 模型 |\n | `NEWS_MAX_AGE_HOURS` | `120` | 新聞新鮮度窗口(小時),驗證範圍 24–336,非法值回退預設並警告 |\n | `AEROAPI_KEY` | — | FlightAware AeroAPI(選用統計) |\n-| `AVWIRE_BASE_PATH` | `/avwire` | 站台子路徑(Pages 專案站台) |\n+| `AVWIRE_BASE_PATH` | 空字串 | 站台子路徑;正式自訂網域使用根路徑 |\n+| `AVWIRE_SITE_ORIGIN` | `https://skytical.tech` | canonical、hreflang、sitemap 與 JSON-LD 的公開站台來源 |\n \n ## 稀有民航機偵測(預設關閉)\n \n@@ -284,7 +284,8 @@ site/\n └─ .nojekyll\n ```\n \n-All internal links are prefixed with `common.BASE_PATH` (default `/avwire`).\n+All internal links are prefixed with `common.BASE_PATH` (empty by default for\n+the `https://skytical.tech` custom-domain root).\n Every page rendered through `base.html` includes a language-correct footer\n button linking to its changelog page.\n \n@@ -22,14 +22,14 @@\n TEMPLATES_DIR = ROOT / "templates"\n STATIC_DIR = ROOT / "static"\n \n-# GitHub Pages project sites live under /<repo>/ — override with env for\n-# user/organization pages or local preview (set AVWIRE_BASE_PATH="").\n-BASE_PATH = os.environ.get("AVWIRE_BASE_PATH", "/avwire").rstrip("/")\n+# The production site is served from the root of the SKYTICAL custom domain.\n+# Override this for a project-site preview that needs a repository subpath.\n+BASE_PATH = os.environ.get("AVWIRE_BASE_PATH", "").rstrip("/")\n \n # Absolute origin for hreflang/canonical links (search engines require\n # fully-qualified URLs there).\n SITE_ORIGIN = (os.environ.get("AVWIRE_SITE_ORIGIN")\n- or "https://nnneeeooo-nnneeeooo.github.io").rstrip("/")\n+ or "https://skytical.tech").rstrip("/")\n \n USER_AGENT = (\n "AVWIREBot/1.0 (automated aviation news aggregator; "\n@@ -925,7 +925,7 @@ def _post(self, messages: list, repair: bool):\n "Accept": "application/json",\n "Content-Type": "application/json",\n "HTTP-Referer":\n- "https://nnneeeooo-nnneeeooo.github.io/avwire/",\n+ "https://skytical.tech/",\n "X-Title": "AVWIRE",\n },\n )\n@@ -107,8 +107,8 @@ def main() -> None:\n description=t["changeSub"], ticker=[], build=fake_build)\n ctx["changelog"] = view\n html = env.get_template("changelog.html").render(**ctx)\n- expected_path = ("/avwire/changelog/" if lang == "zh"\n- else "/avwire/en/changelog/")\n+ expected_path = ("/changelog/" if lang == "zh"\n+ else "/en/changelog/")\n assert f'href="{expected_path}"' in html\n assert t["footerChangelog"] in html\n assert t["changeNotice"] in html\n@@ -224,7 +224,7 @@ def fake_post(url, json=None, timeout=None, headers=None):\n check((payload.get("reasoning") or {}).get("exclude") is True,\n f"{model}: reasoning trace excluded")\n check(headers.get("X-Title") == "AVWIRE"\n- and headers.get("HTTP-Referer", "").endswith("/avwire/"),\n+ and headers.get("HTTP-Referer") == "https://skytical.tech/",\n f"{model}: optional attribution headers")\n check(provider.usage["inputTokens"] == 11\n and provider.usage["outputTokens"] == 7\n@@ -153,7 +153,7 @@ def main() -> None:\n assert "Callsign format" not in en\n assert "台灣民航雷達" in zh\n assert "Taiwan civil flight radar" in en\n- assert 'href="/avwire/radar/"' in home\n+ assert 'href="/radar/"' in home\n \n assert "flags & (1 | 4 | 8)" in js\n assert '["7500", "7600", "7700"]' in js\n@@ -96,21 +96,21 @@ def main() -> None:\n assert 'class="header-search-form"' in home\n assert 'class="header-search-form"' in article\n assert 'data-article-body' in article\n- assert 'data-search-aliases-url="/avwire/search-aliases.json"' in article\n- assert re.search(r'/avwire/assets/highlight\.js\?v=[0-9a-f]{10}', article)\n- assert 'action="/avwire/search/"' in home\n- assert 'action="/avwire/en/search/"' in en\n- assert re.search(r'/avwire/assets/site\.css\?v=[0-9a-f]{10}', zh)\n- assert re.search(r'/avwire/assets/app\.js\?v=[0-9a-f]{10}', zh)\n- assert re.search(r'/avwire/assets/search\.js\?v=[0-9a-f]{10}', zh)\n+ assert 'data-search-aliases-url="/search-aliases.json"' in article\n+ assert re.search(r'/assets/highlight\.js\?v=[0-9a-f]{10}', article)\n+ assert 'action="/search/"' in home\n+ assert 'action="/en/search/"' in en\n+ assert re.search(r'/assets/site\.css\?v=[0-9a-f]{10}', zh)\n+ assert re.search(r'/assets/app\.js\?v=[0-9a-f]{10}', zh)\n+ assert re.search(r'/assets/search\.js\?v=[0-9a-f]{10}', zh)\n assert home.index('class="header-search-row"') < home.index('id="clock-utc"')\n assert home.index('class="header-search-row"') < home.index('class="brand-row"')\n main_markup = re.search(r'<main class="search-page">(.*?)</main>', zh,\n re.DOTALL).group(1)\n assert "<form" not in main_markup\n- assert 'data-index-url="/avwire/search-index.json"' in zh\n- assert 'data-index-url="/avwire/search-index.json"' in en\n- assert 'href="/avwire/en/search/"' in en\n+ assert 'data-index-url="/search-index.json"' in zh\n+ assert 'data-index-url="/search-index.json"' in en\n+ assert 'href="/en/search/"' in en\n assert "border-radius: 999px" in css\n assert ".header-search-form:focus-within" in css\n assert ".header-search-input:not(:placeholder-shown) + .header-search-clear" in css\n@@ -21,6 +21,8 @@ def _json_ld(html: str) -> list[dict]:\n \n \n def main() -> None:\n+ assert build.SITE_ORIGIN == "https://skytical.tech"\n+ assert build.BASE_PATH == ""\n assert build.main() == 0\n \n verification = ROOT / "site" / "google83f7fe8f9aeba973.html"\n@@ -107,15 +109,15 @@ def main() -> None:\n taiwan_hub = (ROOT / "site" / "topics" / "taiwan-aviation" /\n "index.html").read_text(encoding="utf-8")\n assert "<h1>臺灣航空新聞</h1>" in taiwan_hub\n- assert 'href="/avwire/news/' in taiwan_hub\n+ assert 'href="/news/' in taiwan_hub\n for slug in build.TOPICS:\n- assert f'href="/avwire/topics/{slug}/"' in article\n+ assert f'href="/topics/{slug}/"' in article\n \n policy = (ROOT / "site" / "editorial-policy" / "index.html").read_text(\n encoding="utf-8")\n assert "編輯、更正與聯絡政策" in policy\n assert "avwire/issues/new" in policy\n- assert 'href="/avwire/editorial-policy/"' in article\n+ assert 'href="/editorial-policy/"' in article\n \n print("test_seo: OK")\n