Files
unique/CHANGELOG.md
T
rzen 86ea4c8873 site: feeds everywhere + programmatic surface
Feeds: JSON Feed 1.1 at /feed.json, per-category and per-tag RSS at
/categories/<name>/rss.xml and /tags/<name>/rss.xml alongside the main
/rss.xml — all from a shared src/lib/feed.ts item source. Category/tag
pages advertise their scoped feed via autodiscovery; new /feeds/
directory page (footer-linked) lists every feed with counts; RSS feeds
gain an atom:link self reference and a feed.xsl stylesheet so they
render readably in browsers.

Programmatic readers: build-generated /llms.txt (site map with every
review/bundle/post), SearchAction on the WebSite JSON-LD wired to
/search/?q=, and a "For robots" section on /feeds/ documenting
search.json, llms.txt, the sitemap, and JSON-LD coverage.

Claude-Session: https://claude.ai/code/session_01WZaczDJjL3xZ3u5spsN5AL
2026-07-12 17:56:55 -04:00

76 lines
14 KiB
Markdown

# Changelog
## July 2026
- Feeds for everything: alongside the existing `/rss.xml`, add a JSON Feed 1.1 at `/feed.json`, per-category RSS at `/categories/<name>/rss.xml`, and per-tag RSS at `/tags/<name>/rss.xml` — all derived from a shared `src/lib/feed.ts` item source (reviews + posts + bundles, same visibility rules as the site). Category/tag pages advertise their scoped feed via `<link rel="alternate">` autodiscovery; a new `/feeds/` directory page (linked from the footer) lists every feed with entry counts; every RSS feed carries an `atom:link` self reference and renders as a readable page in browsers via `public/feed.xsl`
- Programmatic-reader pass: build-generated `/llms.txt` (llmstxt.org format — site description, feed/endpoint map, and every review, bundle, and post with one-line descriptions), `SearchAction` on the home-page `WebSite` JSON-LD wired to `/search/?q=`, and a "For robots" section on `/feeds/` documenting `search.json`, `llms.txt`, the sitemap, and JSON-LD coverage
- Autonomous pipeline overhaul: new `/daily-pipeline` skill chains capture → bundle → review graduation → pick-of-the-day → build → commit → push and ends with a digest; `daily-finds` gains a score-and-shortlist stage (up to 12 `shortlist: true` finds per run, top 1-3 flagged as review candidates), feed-first fetching (`fetch: "feed"` + `feedUrl` in sources.json), cadence-aware scanning, and authority to apply mechanical source maintenance itself; `build-bundle`/`cluster-bundles`/`build-review` gain unattended `auto` modes (publish + log instead of pausing for confirmation), and `build-bundle weekly` writes a date-based "week's catch" so shortlisted finds never sit unbundled for weeks
- Review heroes are now auto-discovered: `src/lib/hero.ts` globs `reviews/*/hero.<ext>` (images and `hero.mp4`), so a new review needs no registration — only legacy non-`hero`-named assets remain as explicit overrides; both hero globs also accept `.avif`
- Pick of the day moves from a hardcoded constant in `src/pages/index.astro` to `src/data/pick.json` (falls back to the latest review); the dev-mode "Make today's pick" button writes the JSON file
- Optional `amazonLink` frontmatter on finds and reviews renders an "Also on Amazon" link with the existing affiliate tagging, badge, and disclosure; the capture pipeline looks up exact Amazon matches for shortlisted physical products
- Fact-checking against the product's own site is now a mandatory step when a find graduates to a review unattended
## May 2026
- Bucket `find/` folders by capture date: every find moves from `src/content/find/<slug>/index.mdx` to `src/content/find/<year>/<month>/<slug>/index.mdx` (all 289 existing finds migrated to `2026/05/`). The `find` content-collection loader uses a new `leafSlug` `generateId` so the id (and therefore the URL at `/find/<slug>/`) stays flat, and `src/lib/find-hero.ts` switched to a recursive `**/hero.{...}` glob. No URL changes; bundle `items[]`, `promotedTo`/`fromFind` cross-references, and category/tag pages all keep working unchanged. Rationale: the flat folder was getting hard to scan and slow `git status` at ~290 finds and growing 20+/day
- Rename the "finds" superpost concept to **bundle**. The `finds` collection becomes `bundles` (`src/content/bundles/`), URLs move from `/finds/<slug>/` to `/bundles/<slug>/`, and the home/footer/search labels switch from "List" to "Bundle". Internal renames: `findListMosaic``bundleMosaic`, `FindsPost``Bundle`, `findsReferencing``bundlesReferencing`, `Entry.type 'finds'``'bundle'`, `OgFallback 'finds'``'bundles'`. Build script and generated mosaic dir follow (`scripts/build-bundle-mosaics.mjs`, `src/generated/bundle-mosaics/`). Skills `build-finds` and `cluster-finds` renamed to `build-bundle` and `cluster-bundles`. The `find` collection (individual items) is unchanged
- Add Cloudflare Web Analytics: privacy-preserving, cookieless beacon injected into `BaseLayout.astro` so per-page traffic, referrers, and Core Web Vitals show up in the Cloudflare dashboard scoped to `unique.rzen.dev`. Privacy statement on `/legal/` updated to disclose the beacon
- Strengthen the "Use of the site" section on `/legal/`: explicit "inclusion isn't endorsement" + no warranty on safety/quality/durability/fit/continued-existence + no responsibility for what happens after click-through. Tone kept plain, not legalese
- Colocate every collection's articles with their media: each entry is now a folder `<slug>/index.mdx` with sibling media files. Applied to `reviews/`, `find/` (104 articles + 89 heroes auto-resolved by `src/lib/find-hero.ts` via `import.meta.glob('../content/find/*/hero.{...}')`), `finds/`, and `posts/`. Slug derivation handled by a shared `stripIndex` helper on each glob loader; URLs unchanged across the entire site. MDX paths shortened from `../../assets/reviews/<slug>/<file>` to `./<file>`. `src/assets/` removed entirely
- Media optimization pass: re-encode the 13 heaviest assets (h264 CRF 28, scale ≤1280px, audio stripped) and convert the two animated GIFs (cotypist, flux-markdown) to MP4 — `dist/` drops from 53 MB to 31 MB (~42% smaller); biggest single wins are `homerow/search.mp4` (6.7 MB → 1.6 MB), `antinote/links.mp4` (2.9 MB → 193 KB), `flux-markdown/demo.gif` (3.9 MB → 1.3 MB MP4). Originals preserved at `src/assets/reviews/<slug>/source/` and never bundled
- Tile videos on `/` and `/grid/` switched from `preload="metadata"` to `preload="none"` so below-the-fold demos don't fetch on page load
- `src/lib/hero.ts` and the cotypist/flux-markdown review MDX updated to render the new MP4 heroes as inline autoplay-loop muted `<video>` instead of `<img>`
- Comprehensive SEO pass: new `<SEO>` component centralising every head-level tag (canonical, Open Graph, Twitter Card, theme-color, RSS alternate, JSON-LD); page-aware structured data — `Review` + `BreadcrumbList` on review pages, `BlogPosting` on posts, `Product` + `BreadcrumbList` on finds, `Article` + `ItemList` on finds superposts, `CollectionPage` + `ItemList` on category/tag/sources/blog pages, `WebSite` + `Organization` + `ItemList` on the home page, `AboutPage` on /about
- Add `@astrojs/sitemap` (auto sitemap-index.xml excluding `/grid/`, `/index3/`, `/404/`) and `@astrojs/rss` (feed at `/rss.xml` covering reviews + posts + finds superposts); add `public/robots.txt` pointing at the sitemap
- Add custom 404 page with recent reviews + nav fallback (noindex)
- Wire promoted finds to canonical to their review (via `promotedTo`); other finds self-canonical
- Noindex `/grid/` and `/index3/` (kept linked but absent from sitemap and search)
- Per-page descriptions + OG image alt text for every page; count-bearing titles and descriptions on category/tag pages (`{category} ({n})`); hero image upgraded with real alt text, `fetchpriority="high"`, `loading="eager"`, `decoding="sync"`; static OG fallback tiers in `/public/og/` (default/reviews/finds/posts — PNGs to be supplied)
- Set `trailingSlash: 'always'` and `build.format: 'directory'` explicitly to keep canonical URLs stable
- Memoize `getSiteStats()` so per-page SEO additions don't multiply build cost
- Site-wide UI/UX refresh: newspaper-style masthead on every page (entry-count + last-updated on the left, large serif "Unique" wordmark centered between thin rules, About · Blog nav on the right), per-page italic subheader with last-updated date on listing pages, and an SEO-friendly footer with Browse / Collections / About link columns
- Home page swapped to a Pinterest-style hero + masonry grid; the plain chronological list view moves to `/index3/`
- New `/about` stub and `/blog` index (Astro page over the `posts` collection with an empty-state when no posts exist)
- Single 76rem page width across the entire site (replaces the 42rem default + `wide` prop split); article prose is constrained to a 42rem reading measure inside the wider layout so reviews/finds stay readable
- New `getSiteStats()` helper in `src/lib/entries.ts` powers the masthead counts and footer Collections column live
- Amazon affiliate handling: outbound links to `amazon.com`, `amzn.to`, `a.co`, and `smile.amazon.com` get the configured tracking ID appended at render time, are marked with `rel="sponsored noopener noreferrer"`, and display a clearly-signposted "Affiliate" badge plus a one-line FTC-style disclosure on review and find pages. Tracking IDs live in `src/lib/affiliate.ts` keyed by marketplace; non-US Amazon hostnames are recognized but left untagged until a marketplace-specific ID is added
- Restructure into a four-collection content pipeline: `find` (captured items, hidden from indexes), `finds` (editorial superposts that reference find slugs in a Pinterest-style grid), `reviews` (existing — gains optional `source` and `fromFind` fields for graduations), and `posts` (existing, generic essays)
- New routes `/find/<slug>/` (direct URL only — finds don't appear on home, tag, or category pages) and `/finds/<slug>/` (superpost detail with intro + grid)
- New components: `FindCard`, `FindsGrid`, `Backlinks`, `SourceBadge`
- `/sources` cards gain a "Recent finds" sub-list per source — the one cross-cutting surface where individual finds are visible
- Find pages show "Featured in:" backlinks computed at build time from any superpost referencing them; review pages show "← First surfaced…" when promoted from a find
- New project-local skills under `.claude/skills/`: `daily-finds` (capture-only — no theme detection, no candidate post, no winner pick), `build-finds` (editorial superpost author), `build-review` (find → review graduation)
- `sources.json` gains per-source `fetch` strategy (`webfetch` / `curl` / `skip`) with optional `fetchUrl` override; 11 sources switch to curl with a Safari User-Agent (Cool Material, MoMA Design Store, StyleForum, Atlas Obscura, etc.); 9 marked `skip` after Cloudflare JS challenges and active anti-bot defeats both WebFetch and curl
- New `/sources` page (3-column card stream listing every source with its type, cadence, topics, and notes)
- Migrate the seed daily-finds post: extract 5 candidates into individual find files, slim the superpost to just the intro paragraph, move from `posts/` to `finds/`
- Initial `sources.json` curated across macOS apps, useful tools, gifts, clothing, travel, and general-delight feeds (47 sources)
- Daily-finds capture log at `daily-finds.log.md`; new-source nominations queued at `candidate-sources.md`
- Initial blog scaffold with Astro 5 (content collections, no client JS)
- Base layout with light/dark theme via `prefers-color-scheme`
- Index page listing posts by date (newest first)
- Per-post page with title, date, category, optional external link, tags
- Auto-generated category and tag listing pages
- Seed content: 12 posts on delightful Mac apps (Cotypist, Folder Peek, DockDoor, TypeWhisper, Hyperkey, AntiNote, FluxMarkdown, Monocle, Alcove, Shottr, MiddleDrag, LinearMouse)
- Switch to MDX (`@astrojs/mdx`) for post bodies
- Restructure into two content types: `reviews` (name + subtitle + body) and `posts` (title + body, empty for now)
- Unified entry helper (`src/lib/entries.ts`) and shared `EntryList` component so the home, category, and tag pages render a mixed chronological feed across collections
- Reviews route moved to `/reviews/<slug>/`; review detail pages show name as `<h1>` with subtitle as a tagline beneath
- Index entries now show two lines for reviews (bold name + muted subtitle), single line for posts
- Migrate the 12 seed entries from `src/content/posts/*.md` to `src/content/reviews/*.mdx` with the new schema
- Add 5 new reviews: Ice (interface), AltTab (interface), Mac Mouse Fix (input), Homerow (input), Tot (writing)
- Establish media convention at `src/assets/reviews/<slug>/` for real screenshots/clips downloaded from each app's site
- Add visuals to 15 of 17 reviews (mp4 demos, animated gifs, or App Store screenshots), with one-line italic captions naming what's shown
- Style images and videos in review pages: max-width 100%, centered, soft border-radius; italic-only paragraphs auto-render as captions
- Use `import …?url` for animated GIFs (cotypist, flux-markdown) to bypass Sharp and preserve animation
- linearmouse and middledrag intentionally have no visual: linearmouse.app is JS-only with no scrapeable demo and the repo carries no screenshots; the `artginzburg/MiddleDrag` repo cited in the review no longer exists
- Rewrite all 17 reviews — informative, concise, no sales tone; longer reviews lead with a pre-review blockquote summary
- Style `.body blockquote` as a confident lead (accent left-border, no italics, foreground color) on review and post detail pages
- Add optional `linkText` field to reviews: overrides the external-link label (e.g. "Visit in App Store" or "Visit on GitHub"); defaults to the link's hostname with `www.` stripped
- Sample a Pinterest-like 3-column tile stream at `/grid/` (CSS `column-count` masonry, no JS); responsive to 2 cols / 1 col on narrow viewports
- `src/lib/hero.ts` maps slug → hero asset (image or video) so the grid can render visuals; reviews without media (linearmouse, middledrag) become text-only tiles with an accent gradient
- Add `wide` prop to `BaseLayout` for pages that need a wider max-width than the default reading column
- Floating "grid view →" link from the home page; the main index keeps its plain list layout
- Add a CSS-only scroll-snap carousel for reviews with multiple visuals: each `<figure>` slide carries its own `<figcaption>`; pure CSS, no client JS; thin scrollbar visible on desktop, swipe on touch
- Expand 8 reviews into multi-slide carousels with downloaded media — antinote (5), typewhisper (6), dockdoor (3), shottr (3), folder-peek (3), homerow (3), ice (3), tot (2); 28 slides total across the site
- Limit the home page index to the 12 most recent entries across all collections; older entries remain reachable via `/grid/`, categories, and tags