099bf55711
Settled plan (user + Codex) for standing up /news as the feed's home and cutting /home3 → / without breaking the feed, deep links, or SEO. Drives the upcoming implementation; next build is the feed extraction (pure refactor). Includes the four Codex amendments: /news noindex during transition, explicit prototype 301s, explicit legacy-view mapping (shim before render + /news?view=today alias), and the footer coverage inventory (FeedbackModal stays in the global layout). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.4 KiB
6.4 KiB
News relaunch — link/redirect map + interim-routing plan
Scope: stand up /news (the feed's new home) and cut /home3 → / (hub) without breaking
the feed, deep links, or SEO. Verified against the codebase 2026-06-28. Settled with the
user + Codex; amendments folded in. Next build = the extraction (§A, pure refactor).
A. Interim routing — no broken window, no duplicated impl
The feed currently IS routes/+page.svelte (~1,065 lines: views, BottomNav, MoodNav,
LanePicker, SavedFlyout, search). Don't clone it. Extract once, mount twice.
- Extract the feed UI from
routes/+page.svelte→lib/components/NewsFeed.svelte(verbatim move; URL base becomes/news).parseView/urlForViewswitch base/→/news. - Mount at both during transition:
routes/news/+page.svelte→<NewsFeed/>routes/+page.svelte→<NewsFeed/>(interim; identical component) One implementation, both routes live, zero interim breakage./newsstays hidden during transition:X-Robots-Tag: noindex, follow(so we don't publish a duplicate indexable feed). Removed at cutover, when/newsis added to the sitemap.
- Parity test at
/news(every view, deep link, Back/Forward, account action) — see §F. - Restyle
NewsFeedonce (CD editorial + reusable card — replacesArticleCard). - Behavior fix (separate, deliberate, post-parity): Latest stays chronological; Highlights gets prefs + geo scope.
- Cutover:
routes/+page.svelte→ hub content (move fromhome3); add the legacy-query redirect shim (§C); drop/newsnoindex + add to sitemap;/newsstays the feed.
B. Link/redirect map
Rule of thumb: brand/logo/"home"/"back to UB" → / (hub); anything "more news /
browse / a feed view" → /news; feed-internal view URLs → /news?… base;
/home3 fallbacks → /.
B1. Brand / home / back → / (KEEP)
Header.svelte:9brand/;account:103brand/,:108back/;admin:678brand/,:28non-admin bounce/;auth/verify:24post-signin/(DECIDED: always hub; future optional start-screen setting),:38back/;zen:59brand/;share.py:197,327brand logo/,:354"Back to Upbeat Bytes"/;api.py:781unsubscribe back/.
B2. News CTAs → /news (CHANGE)
home3:198"Read more good news"/→/news(the loop bug)share.py:210"Explore Upbeat Bytes →" →/newsshare.py:332"Browse more on Upbeat Bytes →" →/news
B3. Feed-internal view URLs → /news?… base (CHANGE, via the extraction)
routes/+page.svelte(→ NewsFeed):urlForViewbuilds/?source=,/?tag=,/?view=(:39-41), searchgoto('/?q=')(:50), cleargoto('/')(:689),urlForView('today')returns/(:344,503) → all rebase to/news.account:196Following/?view=following→/news?view=followingshare.py:30source link/?source={id}→/news?source={id}
B4. /home3 fallbacks → / (CHANGE)
HubBar:18home nav/home3→/;:28brand/home3→/HubShell:17back fallbackgoto('/home3')→/art:41,play:213back fallbackgoto('/home3')→/
C. Redirects
- Legacy root-query shim on the new hub
/— runs before the hub fetches/renders (no hub flash),replaceState:/?view=today→/news?view=highlights/?view=latest→/news(Latest is the default)?tag=,?source=,?q=, other?view=→ carry across to/news?…/news?view=todayremains an accepted alias (old links never break)
/home2,/home2.html,/home3,/home3.html→/permanent (301) (Caddy). A bare route delete would just serve the SPA fallback — redirect explicitly.
D. Infra
- Caddy
@hidden(currently/home2 /home3 /word /word.html /quote /quote.html /onthisday /onthisday.html /admin /admin.html):- REMOVE
/word* /quote* /onthisday*(indexable at launch) /home3*,/home2*→ 301 redirects (out of @hidden)/newscarriesX-Robots-Tag: noindex, followuntil cutover, then removed- KEEP
/admin*;/a/*still routed to FastAPI
- REMOVE
- Sitemap (
api.py sitemap()): raiseLIMIT 5000→ ~50000; gate on having a real summary (skip ~31 incomplete; ~+1,000 URLs); add static/news(at cutover) +/art /play /word /quote /onthisday(keep/,/today). FixHEAD /sitemap.xml(currently 404). - Head patcher (
patch-static-heads.mjs): add/news(title/desc/canonical/OG). - PWA description (
manifest.webmanifest+app.htmldescription/og/twitter): currently news-only — broaden to the hub (news + daily art + games + small resets). - Footer: ONE shared
Footer.svelte— consistent core (motto + Send feedback) + a default slot for per-section extras.FeedbackModalstays in the global layout; only the layout's<footer.site>markup is removed (and HubShell's<footer.foot>). Coverage inventory — the shared footer must be explicitly added to every public surface: Hub, News, Play, Art, HubShell details, Account, Zen (if dev-visible). Admin/auth get a deliberate minimal treatment (explicit, not by omission).
E. Behavior (deliberate, post-parity)
- Latest = newest accepted after safety/boundary exclusions; stop passing
home(or add an explicit "Local first" lane) so Latest ≠ local-first. - Highlights = ranked around interests + geo scope dial (kept at launch).
trackVisit()stays global;markBriefSeen()only inside Highlights.
F. Cutover checklist (rehearsal first, hidden)
- GSC review (coverage / manual-actions / crawl) BEFORE rehearsal.
- Parity at
/news: each view (today/latest/following/tag/source/search/mood/topic), deep links, Back/Forward single-history, account actions (save/follow/hide/replace), PWA. - Legacy redirects:
/?view=today→/news?view=highlights,/?view=latest→/news,/?tag=…,/?source=…,/?q=…→/news?…;/home2*,/home3*→/. - SEO:
/200 + indexable + canonical;/a/*200 + self-canonical (unchanged);/today200 indexable;/newsnoindex dropped + in sitemap; joy/art/play noindex removed + in sitemap; sitemap GET + HEAD 200. - Caches: anon Latest/Brief edge-cacheable (45s) intact; personalized private/no-store. SW is a kill-switch (no bump) — just verify.
- Promote → live 200/301/canonical/cache checks; resubmit sitemap in GSC.