← back to Trademarks Copyright
src/app/changelog/page.tsx
76 lines
import Link from "next/link";
export const metadata = {
title: "Changelog",
description: "What's shipped on Drops.",
};
type Entry = { date: string; items: string[] };
const CHANGELOG: Entry[] = [
{
date: "2026-04-24",
items: [
"Welcome drop — new trial subscribers now get the most recent drop immediately on signup instead of waiting until 9am tomorrow.",
"Daily drop composition fully parallelized (~3× faster).",
"Admin: inline drop-item editor (edit headlines/blurbs/PRO hints without recomposing).",
"Admin: subscribers list with tier/status/open-rate, edit inline.",
"Referral system — subscribers get a unique URL; 3 signups = 30 free days.",
"Email open-tracking pixel; open-rate visible in admin drops dashboard.",
"Public archive at /drops/archive with teased past issues for SEO + conversion.",
"Sample-drop preview embedded in the landing page for instant social proof.",
"Seed catalog expanded by 25 items — defunct retail (Linens 'n Things, Filene's Basement, Sharper Image, Montgomery Ward, Tower Records), defunct restaurants (HoJo, Chi-Chi's, Bennigan's), and the 1929 public-domain cohort (Sherlock Holmes final stories, Steamboat-contemporary animation, A Farewell to Arms).",
"Legal pages: Terms, Privacy, Refund — Stripe-ready, California-governed.",
"Marketing pages: About, Pricing, FAQ — each with its own metadata + SEO.",
"SEO: per-page metadata, Organization + WebApp JSON-LD, OpenGraph + Twitter Card, robots.txt + sitemap.xml, dynamic /opengraph-image route.",
"Health endpoint /api/health returns db + ollama + email-backend + stripe status (200/503).",
"Admin auth: cookie-gated /admin/* routes via ADMIN_TOKEN.",
"Rate limit + disposable-email filter on signup.",
"Custom 404/500 pages.",
"Test suite (23 tests) for scoring + lifecycle classification.",
],
},
{
date: "2026-04-23",
items: [
"Drops SaaS shipped — signup, Stripe checkout (optional), daily cron, multi-backend email (Resend / SMTP / file).",
"Qwen-powered drop composer reads items + brand_candidates tables.",
"Subscriber portal + unsubscribe flow.",
"Brand hunter — DDG HTML + DDG Lite + Brave Search fallback, Qwen classifies live USPTO registration status.",
"Brand-domain sanity gate (flags parked/registrar-redirect pages as 'parked').",
"Opportunity labels: domain_snipe / abandonment_watch / licensing_outreach / do_not_target.",
"Activity clock — scans homepage for © year, classifies active / stale / abandoned.",
"Domain lifecycle — HTTP liveness + WHOIS expiry.",
"Underlying 'Trademarks & Copyright' opportunity finder: 30-item seed, TanStack table with multi-select, 4-agent SWOT via Qwen (no paid APIs), composite scoring, React Flow canvas.",
],
},
];
export default function ChangelogPage() {
return (
<article className="mx-auto max-w-3xl space-y-4">
<div className="card p-6">
<div className="text-xs uppercase tracking-widest text-brass">Changelog</div>
<h1 className="mt-2 text-3xl font-semibold">What's shipped.</h1>
<p className="mt-2 text-sm text-ink/70">
We ship frequently. See <Link href="/drops" className="text-brass underline">drops</Link> for the daily product,
or the <Link href="/faq" className="text-brass underline">FAQ</Link> for common questions.
</p>
</div>
{CHANGELOG.map((entry) => (
<div key={entry.date} className="card p-5">
<div className="text-xs uppercase tracking-wide text-brass mb-2">
{new Date(entry.date).toLocaleDateString(undefined, { weekday: "long", month: "long", day: "numeric", year: "numeric" })}
</div>
<ul className="list-disc pl-5 space-y-1 text-sm">
{entry.items.map((it, i) => (
<li key={i} className="text-ink/80 leading-relaxed">{it}</li>
))}
</ul>
</div>
))}
</article>
);
}