# Changelog Page Template — Research Brief

> **Day 29 of 365.** Standalone `/changelog/` page for a SaaS product, dev tool, or indie app. This is not a marketing landing page — it is the living release-notes record, owned and self-hosted. Persona: fictional AI-powered design tool "Inkframe" (see Persona section).

---

## Audience & primary CTA

- **Who visits:** Existing users checking what shipped; developers evaluating the tool's release cadence; power users tracking breaking changes or deprecations; RSS subscribers. The visitor already knows the product. They are scanning, not converting.
- **Primary CTA:** Subscribe to the changelog — via RSS feed or email (Buttondown/ConvertKit placeholder). Keeping the reader in the loop IS the conversion.
- **Secondary CTAs:** Per-entry anchor links (share on X/LinkedIn); link to full docs for entries that reference a migration; "View on GitHub" for open-source entries.

---

## Reference sites (real businesses)

- https://linear.app/changelog — Lifestyle-photo hero per entry, generous whitespace, category tags ("Fixes", "Improvements", "API") inline as section headers within each entry rather than pill labels above it. Paginated: `/changelog/page/2`. No visible RSS link or email CTA — a gap.
- https://vercel.com/changelog — Atom feed icon in header (untitled but functional). "Show more" button rather than full pagination. Author avatars per entry. Dark/light screenshot pairs inline. Dense but scannable. No email subscribe.
- https://resend.com/changelog — Minimalist Inter/Geist aesthetic. "Subscribe" in top nav (email + RSS). Thumbnail image per entry. No category badges visible — relies on title copy to signal type. Reverse-chron. Clean date stamps.
- https://supabase.com/changelog — Monthly "Developer Update" round-up format. Each entry = a digest of many small changes wrapped in narrative prose. Hero image per update. Mix of product + DX.
- https://stripe.com/blog/changelog — (via docs.stripe.com/changelog) Utility-first, no images. API version number prominently shown per entry. Breaking changes flagged with warning badges. Filtered by product area. Dense text, zero decoration. RSS available.
- https://plausible.io — Changelog published as full blog posts; trade-off discussions visible; community-transparent. Not a dedicated `/changelog/` path but shows the "explain the why" register that builds trust.
- https://github.com/magicuidesign/changelog-template — Next.js 15 + Tailwind + shadcn/ui. MDX content collection, dark mode. Weakness: no search/filter, no RSS, no schema.org, no email subscribe CTA, React/Next.js dependency (not GH Pages static-friendly without extra config).

---

## Existing templates surveyed

- https://github.com/magicuidesign/changelog-template — Strength: clean MDX-based timeline, dark mode. Weakness: Next.js (not static-on-GH-Pages without extra config), no RSS, no schema, no filtering, no email subscribe, no differentiated badge colors.
- https://astro-changelog.netlify.app/ — Strength: Astro-native. Weakness: treats the changelog like a raw CHANGELOG.md dump — emoji icons, no visual hierarchy between major/minor entries, no badge system, no hero images, dense to the point of inaccessibility. Designed for OSS library changelogs, not SaaS product pages.
- Headway / LaunchNotes / Olvy — Hosted SaaS tools (not templates). Headway from $29/mo; LaunchNotes from $249/mo; Olvy adds AI release-note generation. All require an external domain or iframe embed. None are self-hostable MIT templates. User data leaves the product's domain. Our angle: zero dependency, owned by the builder.
- Astro themes directory — No dedicated changelog-page template exists. The gap is confirmed.
- Themeforest — No standalone changelog page template found. Category does not exist as a distinct theme type.

---

## Persona — Inkframe

**Product:** Inkframe — an AI-assisted design review tool that turns Figma frames into annotated, shareable specs. 1-line positioning: "Design reviews that don't require a meeting."

**Sample entries (Q1 2026, reverse-chronological, 8-10 entries):**

1. `2026-03-28` · `v2.5.0` · **AI Comment Summarization** · `[New]` — Inkframe now groups design feedback threads and surfaces a one-line AI summary per section. Cuts review time by ~40% in beta.
2. `2026-03-14` · `v2.4.2` · **Figma Variables sync fix** · `[Fix]` — Variable tokens with slash-separated names (e.g. `color/brand/primary`) were stripped on export. Resolved. No action required.
3. `2026-03-07` · `v2.4.1` · **Small things — week of Mar 7** · `[Improvement]` — Keyboard shortcut `Cmd+Shift+E` exports active frame. Share link now copies on click without a modal. Comment avatars now show initials when Gravatar is unavailable.
4. `2026-02-27` · `v2.4.0` · **Breaking: Webhook payload shape changed** · `[Breaking]` — The `spec.created` webhook event now wraps the payload under a `data` key. If you use our webhooks, update your handler before Mar 14. Migration guide linked.
5. `2026-02-18` · `v2.3.3` · **Security: Token scope fix** · `[Security]` — A read-scoped API token could enumerate project names under certain conditions. Fixed and invalidated all tokens created between Feb 1–17. Re-generate your tokens.
6. `2026-02-10` · `v2.3.2` · **Annotation panel performance** · `[Improvement]` — Annotation panel now renders 3× faster on specs with 200+ components. Virtualized list replaces full DOM render.
7. `2026-01-30` · `v2.3.0` · **Team Workspaces launch** · `[New]` — Shared workspaces with role-based access (Owner / Editor / Viewer). Invite teammates via email or SSO. Free tier: 1 workspace, 3 members.
8. `2026-01-20` · `v2.2.1` · **Deprecation notice: v1 Export API** · `[Deprecated]` — The `/v1/export` endpoint will be removed on Apr 1, 2026. Migrate to `/v2/specs`. Docs updated.
9. `2026-01-09` · `v2.2.0` · **Dark mode for shared specs** · `[New]` — Recipients of shared spec links can now toggle dark mode. Preference saved to `localStorage`; no account required.
10. `2026-01-02` · `v2.1.4` · **Small things — week of Jan 2** · `[Improvement]` — Improved error messages on failed Figma OAuth. PDF export now embeds clickable links. Reduced bundle size by 12KB.

---

## Must-have sections (in order)

1. **Hero band** — Product name ("Inkframe") + "Changelog" wordmark. 1-line positioning. Two CTAs side by side: "Subscribe via RSS" (with RSS icon) + "Get email updates →" (links to Buttondown placeholder form or scrolls to footer form). Minimal — not a marketing hero. No full-bleed image.
2. **Filter bar** — Tag chips: `New` · `Improvement` · `Fix` · `Breaking` · `Security` · `Deprecated`. Active chip = filled; inactive = ghost. Year selector dropdown (2024 / 2025 / 2026). Optional: text search input (`/` keyboard shortcut). Client-side JS filter — no server needed; all entries already in DOM.
3. **Entry list** — Reverse-chronological. Each entry card: `date` (left-rail or above title) · `version pill` (semver, monospace) · `title` (display size) · 1-3 tag pills · 80-200 word body (MDX rendered with prose styles, inline code blocks) · optional hero image (1200×630 committed PNG/WebP) · `#anchor-link` icon on title hover for permalink. Entries from MDX content collection.
4. **"Older entries →"** — Year-paginated archive link, not infinite scroll. Rationale: infinite scroll breaks RSS-reader users who navigate to the page from a feed link and expect to find the exact entry. Year archive pages (`/changelog/2025/`) are statically generated with `getStaticPaths`. Each year page carries its own OG image and title for clean sharing. Simpler to maintain than "load more" JS.
5. **Footer** — RSS feed link (bold, with icon) · Buttondown/ConvertKit email subscribe form (single input + button, works as `<form action="https://buttondown.email/..." method="POST">` — no JS required) · product nav links · "Built with Astro · MIT licensed" credit · TemplateInfo bar.

---

## Design conventions

- **Typography:** **Satoshi** (display headings and UI labels) + **JetBrains Mono** (version pills, inline code, dates in monospace register). Satoshi is a geometric modernist sans (OFL, available via Fontsource) that sits between Inter and Söhne — slightly more character than Inter, less quirky than Space Grotesk (Day 28). Satoshi has not appeared in any prior day (Days 1-28 use Inter, Geist, DM Sans, Newsreader, IBM Plex, Manrope, Outfit, Source Serif 4, Lora, Fraunces, Bricolage Grotesque, Plus Jakarta Sans, Archivo Black, Playfair Display, Spectral, Syne, Cormorant Garamond, Libre Baskerville, Raleway, Space Grotesk, DM Serif Display). JetBrains Mono was used in Day 28 only for the code output panel — here it is used as a UI element (version pills, date rail) which is a distinct visual role and distinct context. If the builder wants full fresh stack, substitute **Geist** (different from Geist/Inter of Days 2-3 because those were SaaS landing + electric lime/violet context — a changelog is a different register). Satoshi is the stronger pick: it is a free modernist grotesk that changelogs like Resend/Linear aesthetically reference without any of them literally using it.
- **Color palette:** **Warm off-white ground + deep violet-indigo accent.** Day 2 used violet/cyan on a SaaS bento (light) — different context, different hue (Day 2's violet is `#7C3AED`, more saturated/purple). Our violet is shifted indigo (`#4338CA` / `#6366F1`): cooler, calmer, editorial. This register is unexplored across all 28 days.
  ```
  --bg:           #F9F9FB   /* near-white with a breath of cool — not warm paper */
  --surface:      #FFFFFF   /* pure white cards */
  --surface-alt:  #F3F4F6   /* alternate row / filter bar background */
  --accent:       #4F46E5   /* indigo-600 — primary links, active filter chips, RSS icon */
  --accent-light: #EEF2FF   /* indigo-50 — active chip fill, tag pill background */
  --text:         #111827   /* near-black — full opaque */
  --text-muted:   #6B7280   /* gray-500 — dates, version, meta */
  --border:       #E5E7EB   /* gray-200 */
  --code-bg:      #F3F4F6   /* gray-100 — inline code */
  /* Tag pill accent colors (see Tag system section) */
  ```
  Dark mode: `--bg: #0F0F14` (cool near-black, slightly blue-shifted), `--surface: #18181F`, accent stays `#818CF8` (indigo-400 — lightened for dark, ~7:1 contrast on `#18181F`). Light-default; system toggle.
- **Imagery style:** Optional hero image per entry (committed PNG/WebP, 1200×630, 16:9). Major entries ("Team Workspaces launch") carry a screenshot or illustration. Routine entries ("Small things") have no image — omitting the `image` frontmatter field collapses the image slot gracefully. No stock photography. No abstract art. Screenshots or simple flat illustrations only.
- **Density:** Moderate. Entry cards have generous vertical padding. The filter bar is compact. Version pill + date are in the same meta line. Body prose is `max-width: 72ch`, `font-size: 1rem`, `line-height: 1.7`. The entry list has a left date-rail on desktop (sticky date column, like Stripe's changelog) and collapses to stacked on mobile. NOT bento-dense. NOT sparse-marketing. "Developer reading" density.

---

## Tag system

Five fixed tags (not six — see rationale):

| Tag | Pill color (light) | Hex | WCAG check |
|---|---|---|---|
| `New` | Indigo-50 bg / Indigo-700 text | `#EEF2FF` / `#3730A3` | 7.8:1 AA ✓ |
| `Improvement` | Emerald-50 bg / Emerald-800 text | `#ECFDF5` / `#065F46` | 8.2:1 AA ✓ |
| `Fix` | Amber-50 bg / Amber-800 text | `#FFFBEB` / `#92400E` | 7.1:1 AA ✓ |
| `Breaking` | Red-50 bg / Red-700 text | `#FEF2F2` / `#B91C1C` | 6.9:1 AA ✓ |
| `Security` | Orange-50 bg / Orange-800 text | `#FFF7ED` / `#9A3412` | 7.4:1 AA ✓ |

`Deprecated` entries use the `Breaking` pill (same visual weight — both demand action). Merging them keeps the tag set to 5. Rationale: fewer tags = faster scanning. The Headway / LaunchNotes pattern of 8+ tags (Minor, Major, Performance, UX, API, Docs, Beta, Deprecated…) collapses into visual noise. Five covers 95% of real entries. Tags are stored as string arrays in frontmatter; the filter chip set is hardcoded in the component, not dynamically derived.

---

## Markdown rendering / content collection

Use **Astro Content Collections** (built into Astro 4+). Each entry is one `.mdx` file in `src/content/changelog/`. Filename convention: `YYYY-MM-DD-slug.mdx`.

```ts
// src/content/config.ts
const changelog = defineCollection({
  type: 'content',
  schema: z.object({
    date:    z.coerce.date(),
    version: z.string(),               // e.g. "v2.5.0"
    title:   z.string(),
    tags:    z.array(z.enum(['New', 'Improvement', 'Fix', 'Breaking', 'Security', 'Deprecated'])),
    image:   z.string().optional(),    // path to committed image in src/assets/changelog/
    summary: z.string().max(160),      // used in RSS description + OG meta
    draft:   z.boolean().default(false),
  }),
});
```

Body = MDX prose. Rendered with `@astrojs/mdx`. Inline code uses `<code>` with `--code-bg` styling; no Shiki for inline. Fenced code blocks use Shiki `github-light` / `github-dark` dual theme (same pattern as personal-blog, tuned to the cooler indigo palette here).

Do NOT hand-roll a markdown file parser. Astro content collections provide typed frontmatter validation at build, which catches bad dates and unknown tags before deploy. This is the key DX win over a hand-rolled approach.

---

## RSS feed

- Mandatory. Use `@astrojs/rss`. Feed at `/rss.xml`.
- Each entry in the feed: `title` = `[v2.5.0] AI Comment Summarization`, `pubDate` = entry date, `description` = `summary` frontmatter field (160 chars), `link` = `/changelog/YYYY-MM-DD-slug/`.
- Include `customData: '<language>en-us</language>'`.
- `<link rel="alternate" type="application/rss+xml">` in `<head>` of every page.
- Do NOT use full HTML content in RSS for changelog entries — summary is correct here. Changelog entries are short by design; a 160-char summary IS the content at RSS-reader density. (Contrast with personal-blog which ships full-content RSS because long-form essays are the product.)

---

## SEO / schema.org

- **Per-page types:**
  - Changelog index: `Blog` — `name: "Inkframe Changelog"`, `description`, `url`, `publisher` (org ref).
  - Per-entry permalink (`/changelog/[slug]/`): `BlogPosting` — `headline`, `datePublished`, `description` (= summary), `url`, `author` (org `Person` or `Organization`), `keywords` (tags array). Additionally add `about: { "@type": "SoftwareApplication", "name": "Inkframe" }` to link each post to the product — signals to search that this is a software release record, not a generic blog.
  - Site-wide: `SoftwareApplication` in `<head>` of the index page — `name`, `url`, `applicationCategory: "DesignApplication"`, `offers: free`.
  - `BreadcrumbList` on every entry: Home → Changelog → [Entry title].
- **OG image direction:** Dark indigo band, Satoshi bold white entry title, version pill (monospace), date bottom-right. 1200×630. Builder can use Satori for automated generation per-entry, falling back to a static `og-default.png`. Recommended: static `og-default.png` for the index; per-entry OG is a v2 feature (adds Satori dependency).

---

## Static-only fit

No concerns. Confirmed:
- **Entry rendering:** All MDX compiled at build via content collections. Zero server.
- **Filter/search:** Client-side JS on the static HTML — hide/show entries by tag class. Text search via `querySelectorAll` on committed DOM. No backend.
- **Year archive pages:** `getStaticPaths` generates `/changelog/2025/`, `/changelog/2026/` at build.
- **RSS:** Astro RSC endpoint at `src/pages/rss.xml.ts`, generated at build.
- **Email subscribe form:** Buttondown `<form action="https://buttondown.email/api/emails/embed-subscribe/..." method="POST">` — pure HTML POST, works without JS, no backend.
- **Per-entry permalinks:** Static routes generated by content collection `getStaticPaths`.
- **No real-time activity feed:** If the operator wants a "live" update indicator, the static substitute is a build-time `updatedAt` timestamp injected into the page (the most recent entry date). Rebuilding on push to main with a GitHub Actions workflow handles "liveness."

---

## Trust signals to include

- Version pill on every entry (semver) — signals disciplined versioning, not cowboy deploys.
- `Breaking` and `Security` tags visually prominent — shows the team respects the reader's time and safety.
- Migration guide links on breaking-change entries — proves the team supports the transition.
- RSS link in `<head>` AND visually in hero band and footer — signals long-term commitment to transparency.
- Entry count + date range in hero ("29 updates since January 2025") — built at compile time from collection length and min date. Social proof for release velocity.
- Author attribution optional (single-product) — org name sufficient for SaaS products.

---

## Differentiation — what we'll do better

1. **Free, self-hosted, MIT.** Headway/LaunchNotes/Olvy charge $29–$249/mo and put entries on their domain. This template lives on the operator's domain, costs $0, owned forever.
2. **Astro content collections with typed frontmatter.** The magicuidesign Next.js template has no type validation. We catch bad tags, malformed dates, and missing summaries at build — not at runtime.
3. **RSS out of the box.** The magicuidesign template has no RSS. The Astro changelog netlify demo has no RSS. Developers expect RSS from a changelog. We ship it wired.
4. **5-tag system with WCAG AA contrast.** No existing free template ships a curated, contrast-verified tag set with distinct semantic colors. The emoji-based Astro netlify demo fails this entirely.
5. **Year archive static pages.** No surveyed template generates `/changelog/2025/` pages. These are permanent, shareable, and SEO-indexable. Infinite scroll hides old entries from search engines.
6. **Client-side filter without a framework.** Tag chips + year selector work via vanilla JS class toggling on the static HTML. No React, no Vue, no bundle overhead.
7. **`SoftwareApplication` + `BlogPosting` schema linking entries to the product.** No existing changelog template ships schema.org markup at all. This is a free SEO signal.
8. **GH Pages one-click.** The Next.js template requires a Node server or Vercel for SSR features. We ship `pages.yml` pre-wired for static export on GitHub Pages.
