buildmymcpserver/apps/web/app/(marketing)/changelog/page.tsx
Marco Sadjadi b843394d0f
Some checks failed
Deploy to Production / deploy (push) Failing after 46s
feat(web): full SEO stack — metadata, JSON-LD, sitemap, robots, OG image
Ported and adapted from the BuildMyDiscord SEO setup:

- lib/seo.ts — single source for site constants, the FAQ data (shared by
  the rendered FAQ and the FAQPage schema so they never drift) and JSON-LD
  builders.
- Rich root metadata: title template, keywords, Open Graph, Twitter card,
  robots directives, canonical.
- JSON-LD: Organization + WebSite + SoftwareApplication sitewide, FAQPage
  on the landing page. No AggregateRating — there are no real reviews yet.
- app/robots.ts — allow all, explicit allow-list for AI answer-engine
  crawlers (GPTBot, ClaudeBot, PerplexityBot, …), disallow private routes.
- app/sitemap.ts — every public marketing + docs route.
- app/opengraph-image.tsx — monochrome on-brand 1200x630 share card.
- app/manifest.ts + public/llms.txt.
- Per-page metadata for pricing, changelog, security, privacy, terms,
  docs, templates and status.
- opengraph-image + apple-icon pinned to the edge runtime — next/og
  crashes during a Node-runtime prerender.

Verified: next build passes; /robots.txt, /sitemap.xml,
/manifest.webmanifest and /opengraph-image all generate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:16:40 +02:00

109 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { CodeBlock } from '@/components/code-block';
import { pageMetadata } from '@/lib/seo';
export const metadata = pageMetadata({
title: 'Changelog',
description:
'Product updates and release notes for BuildMyMCPServer — new features, fixes and improvements to the MCP server platform.',
path: '/changelog',
});
interface Release {
version: string;
date: string;
tag: 'launch' | 'feature' | 'fix';
title: string;
items: string[];
}
const RELEASES: Release[] = [
{
version: '0.2.0',
date: '2026-05-19',
tag: 'feature',
title: '3-step wizard + filled-in pages',
items: [
'Real 3-step wizard: prompt → confirm parsed spec → build. Step 2 shows the tools Claude actually parsed and only asks for the credentials it identified.',
'Preview endpoint: POST /v1/servers/preview runs Claude once, caches the spec 5 min, build worker reuses it. Saves a second Claude round-trip (~30s).',
'Shared @bmm/llm package — system prompt + generateSpec live in one place, used by api and generator.',
'Audit log: writes for login, logout, server.create, server.iterate, server.delete. /v1/audit endpoint + /audit page.',
'Real /settings page (org info, plan & usage, members, encryption status).',
'Full /docs site: quickstart, MCP concepts, OAuth flow, authoring, self-hosting, API reference, FAQ.',
'Changelog, /security, /privacy, /terms, /pricing, /status pages — all marketing links work.',
],
},
{
version: '0.1.0',
date: '2026-05-18',
tag: 'launch',
title: 'Sprints 13 — initial public dev build',
items: [
'Monorepo: Next.js 15 + Fastify + BullMQ generator + runner-template.',
'Drizzle schema for orgs, servers, builds, secrets, oauth, metrics, audit.',
'Magic-link auth, 30-day sessions, AES-256-GCM secret encryption.',
'OAuth 2.1 Authorization Server: PKCE, RFC 7591 dynamic registration, RFC 8707 resource indicators, RS256 JWKS.',
'Runner template with Streamable HTTP + OAuth 2.1 Resource Server.',
'WebSocket build stream: queued → generating → building → deploying → live.',
'Install snippet generator for Claude Desktop, Cursor, ChatGPT.',
'docker-compose dev environment, pnpm dev bootstraps everything.',
],
},
];
const tagStyle: Record<Release['tag'], string> = {
launch: 'border-[--color-accent]/40 bg-[--color-accent]/10 text-[--color-accent]',
feature: 'border-emerald-400/40 bg-emerald-400/10 text-emerald-300',
fix: 'border-amber-400/40 bg-amber-400/10 text-amber-300',
};
export default function Changelog() {
return (
<div className="mx-auto max-w-3xl px-6 py-16">
<header className="mb-12">
<div className="text-[11px] uppercase tracking-[0.16em] text-[--color-fg-subtle]">
Release notes
</div>
<h1 className="mt-2 text-[32px] font-semibold tracking-tight">Changelog</h1>
<p className="mt-3 text-[14px] leading-relaxed text-[--color-fg-muted]">
What shipped, when, and why.
</p>
</header>
<div className="space-y-12">
{RELEASES.map((r) => (
<article key={r.version} className="relative pl-6">
<div className="absolute left-0 top-2 size-2 rounded-full border border-[--color-border-strong] bg-[--color-bg-elevated]" />
<div className="flex items-baseline gap-3">
<span className="mono text-[13px] text-[--color-fg]">v{r.version}</span>
<span className="text-[12px] text-[--color-fg-subtle]">{r.date}</span>
<span
className={`mono rounded-full border px-2 py-0.5 text-[10.5px] uppercase tracking-wider ${tagStyle[r.tag]}`}
>
{r.tag}
</span>
</div>
<h2 className="mt-2 text-[16px] font-semibold tracking-tight">{r.title}</h2>
<ul className="mt-3 space-y-1.5">
{r.items.map((item) => (
<li
key={item}
className="relative pl-4 text-[13px] leading-relaxed text-[--color-fg-muted] before:absolute before:left-0 before:top-2 before:size-1 before:rounded-full before:bg-[--color-fg-subtle]"
>
{item}
</li>
))}
</ul>
</article>
))}
</div>
<footer className="mt-16">
<CodeBlock
label="subscribe"
code={`Follow @buildmymcp on Mastodon — or watch the GitHub repo for tagged releases.`}
/>
</footer>
</div>
);
}