9 Commits

Author SHA1 Message Date
thejayman77 27022108b4 caddy: block vuln-scanner probe paths (no-PHP/WP stack) → 403, not the SPA shell
Path-only @junk matcher on upbeatbytes.com (*.php, /wp-*, /.env, /.git, /phpmyadmin,
/vendor, etc.) returns 403 instead of falling through try_files to a 200 SPA shell.
Never matches by User-Agent, so real users + Googlebot/Bing are untouched. Applied to
the live Caddyfile (validated + reloaded) and mirrored into the repo snapshot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:11:57 -04:00
thejayman77 1bd86e30e5 caddy: fix /home2,/home3 redirect (redir destination, not a path matcher)
`redir / permanent` mis-parsed — Caddy read the leading `/` as a path matcher and
`permanent` as the destination, so it only matched `/` and emitted a broken 302 to
"permanent". Use an explicit destination URL (matching the www→apex idiom):
`redir https://upbeatbytes.com/ permanent`. Live Caddy reloaded; snapshot mirrored.
Verified: /home2,/home3,/home3.html → 301 → /.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:21:44 -04:00
thejayman77 2cfffdfd6a NEWS RELAUNCH CUTOVER: promote the hub to /, feed to /news, go public
The big flip. /home3 (hub) becomes /; the feed lives at /news; both indexable.
- PROMOTE: routes/+page.svelte is now the hub (was the interim NewsFeed wrapper);
  noindex removed; "Read more good news" → /news. routes/home3 + home2 deleted.
- routes/+page.js: redirects legacy root-query links (/?view=latest, /?tag, /?source,
  /?q, /?view=today→highlights) to /news before the hub renders (no flash).
- /news: noindex dropped (route meta + Caddy @newsHidden removed); now public.
- LINKS: HubBar brand/Home → /, News default → /news; HubShell/art/play back → /;
  account Following + share.py Explore/Browse/source → /news.
- FOOTER: one shared Footer.svelte (motto + Send feedback + slot) across Hub/News/
  Play/Art/HubShell/Account/Zen; global layout footer removed (FeedbackModal stays).
- SITEMAP: + /news /art /play /word /quote /onthisday; cap 5k→50k; gated on
  has-summary; paywalled excluded; HEAD now 200 (api_route GET+HEAD).
- Head-patcher: /news entry. PWA + shell description broadened to the hub.
- Caddy: @newsHidden dropped; @hidden now admin-only (word/quote/onthisday public);
  /home2,/home3 → / 301. Mirrored to deploy/caddy snapshot.

425 backend + 36 frontend tests green; build clean; Caddy valid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:16:43 -04:00
thejayman77 2fd28fa719 news: track @newsHidden in Caddy snapshot + extract testable feed routing helpers
Housekeeping per Codex:
- Mirror the live @newsHidden rule into deploy/caddy/Caddyfile.snapshot so the
  /news noindex protection is reproducibly recorded.
- Extract the feed's routing helpers (feedBase/parseView/viewUrl) into pure
  $lib/feednav.js and unit-test them (the base-aware URL generation wasn't
  exercised by the prior suite). NewsFeed imports them; behavior unchanged.

(Note: the step-1 commit also swept in data/wotd_audio/renewal.mp3 — a legit
cached pronunciation, not extraction-related; left as-is per Codex.)

32 frontend tests green; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 15:19:36 -04:00
thejayman77 84b1fb514f Small joys: Codex audit #2 fixes (route resolution, noindex, sense/tone, exclude-current re-pick)
- Admin joy item route moved to /api/admin/joys/{kind}/items/{item_id} so the
  /add and /repick verbs resolve to their own routes instead of 422-ing as a
  non-int item id (the launch blocker). Frontend mutate URL updated to match.
- Re-pick now excludes the currently-shown item: the endpoint reads today's
  daily pool_id and passes it as `avoid`, so "Re-pick today" yields a different
  item. Added `avoid` to pick_daily/_candidates across wotd/quote/onthisday.
- WOTD sense selection: the LLM now proposes word + intended part of speech, and
  _lookup prefers that sense (fixes "serene" returning the archaic noun).
- On This Day tone prompt tightened to favor genuinely uplifting events and
  exclude merely procedural/political-administrative ones.
- Caddy @hidden now also noindexes /word /quote /onthisday /admin (+ .html).
- Regression tests: add/repick resolve (401 not 422), add/feature/block/delete,
  re-pick excludes current; WOTD pos-preference + proposal parsing units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:19:02 -04:00
thejayman77 4739d87f4b caddy: X-Robots-Tag noindex,nofollow on /home2 + /home3 (HTTP-level, for non-JS crawlers)
Per Codex audit — the JS <meta robots> isn't seen by bots that don't run JS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 15:59:30 -04:00
thejayman77 b172c5eefd home2 round 2: Manrope nav, bigger logo, photo-top news / photo-left art, tinted static cards
- Self-hosted Manrope (OFL) as the hub sans; nav lighter (weight 500, soft slate, not all
  "on"). Logo up to 58px.
- News card: photo on top + headline below, and it now respects the reader's saved
  Closer-to-Home filter (goodnews:home/homeScope) so the headline matches their Brief.
- Art card: rectangular cover-cropped thumbnail on the LEFT (crops ragged scan edges),
  text on the right — variety against the photo-top news card.
- Play/Daily Moment: tinted backgrounds, bigger centered icon+title, blurb left-aligned.
- /fonts/* + /textures/* served immutable (Caddy live + snapshot).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 19:46:51 -04:00
thejayman77 dd8706e2fc Art post-audit polish (Codex): image HEAD, texture immutable cache, lightbox a11y, spacing
- /api/art/image/{id} now answers HEAD as well as GET (was 404 on HEAD) — mirrors the
  /a/{id} fix. Added tests/test_art_api.py (GET+HEAD+size=full fallback + today payload).
- /textures/* served immutable (long cache) instead of no-cache; excluded from the
  revalidate matcher. Live Caddyfile + repo snapshot both updated.
- Lightbox: Escape closes it, and focus moves to it on open (keyboard-friendly).
- Trimmed the gallery's top padding so "Daily Art" sits closer to the bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:17:30 -04:00
thejayman77 59ff48ae90 Game share-loop: instrument funnel, deep-link shares, /play metadata
Sharpen the existing daily-game share loop into something measurable (per Codex's
"instrument what you have, then feed people into it" plan), ahead of a Show HN launch.

Analytics:
- Per-game funnel events <game>_{arrival,started,completed,shared} (article_id=0).
  arrival = landed via a shared link (utm_source=game_share); started = first move
  (guess/find/flip); completed = solved/cleared/Full Bloom; shared = on share success.
- trackVisit() moved into the global layout so direct /play landings count; the
  server-rendered /a/ share page now creates a visitor token + sends a daily visit
  beacon (first-time /a/-only visitors were previously dropped).
- Admin "Games funnel" panel: arrivals / engaged / completed / shared, per game.

Sharing:
- Memory Match gains a Share button (it was the only game without one).
- All shares deep-link to the exact game+variant with a full https:// URL +
  utm_source=game_share (gameShareUrl helper), instead of a bare /play.
- "shared" is counted only after navigator.share()/clipboard.writeText() succeeds.

/play social metadata:
- /play served homepage canonical/OG (static SPA, ssr=false). postbuild script
  patches build/play.html's head to /play canonical/title/description/OG; fails the
  build if the homepage tags drift. Caddy try_files now serves {path}.html so /play
  is served from the patched file (snapshot in deploy/caddy/).

Tests: backend 352, frontend 27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:22:06 -04:00