diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..9560d5b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,24 @@
+# Changelog
+
+All notable changes to Epicure are documented here. This file is mirrored in-app at `/changelog` (and in the admin dashboard) via `apps/web/lib/changelog.ts` — update both together.
+
+## 0.2.0 — 2026-07-12
+
+### Added
+- **Batch cooking**: generate a single "mega recipe" covering several meals at once — merged shopping list, steps tagged per dish (including steps that advance several dishes at once), and per-dish storage/reheat guidance. Available from the recipe list's Generate dialog and from the meal planner.
+- **Leftover expiry reminders**: mark a batch-cook dish as cooked, track its fridge life, see it surfaced on the Pantry page, and get a daily reminder before it goes bad.
+- **"Cooked it" photo reviews**: attach a photo and written review when rating a recipe.
+- **Pantry-expiry recipe suggestions**: the Pantry page now surfaces recipes that use up ingredients about to expire.
+- **Trending collections**: star public collections; browse trending and recently-added ones under Collections → Discover.
+- **Add to collection from the recipe list**: select recipes and add them to a new or existing collection without leaving the page.
+- List and compact view modes for the recipe list, alongside the existing grid view.
+
+### Fixed
+- Recipe version-comparison diff was unreadable and partially untranslated.
+- Print/export pages always render light, regardless of the app's dark/light setting.
+- Presigned photo-upload URLs were signed against an internal-only address in production, breaking uploads.
+- Several recipe-list and recipe-form UI issues: filter menu closing on every click, tag filter not accepting keystrokes, inconsistent card badge styling, missing tooltips, a floating save button on long recipe forms.
+
+## 0.1.0 — earlier
+
+Initial feature set: recipes (create, edit, AI-generate, import from URL/photo), meal planning, shopping lists, pantry tracking, collections, social features (follow, comment, rate, notifications), nutrition tracking, admin dashboard, and account/billing basics.
diff --git a/apps/web/app/(app)/changelog/page.tsx b/apps/web/app/(app)/changelog/page.tsx
new file mode 100644
index 0000000..87f76e2
--- /dev/null
+++ b/apps/web/app/(app)/changelog/page.tsx
@@ -0,0 +1,19 @@
+import type { Metadata } from "next";
+import { ChangelogList } from "@/components/shared/changelog-list";
+import { APP_VERSION } from "@/lib/changelog";
+
+export const metadata: Metadata = {};
+
+export default function ChangelogPage() {
+ return (
+
+
+
Changelog
+
Currently running v{APP_VERSION}.
+
+
+
+
+
+ );
+}
diff --git a/apps/web/app/admin/changelog/page.tsx b/apps/web/app/admin/changelog/page.tsx
new file mode 100644
index 0000000..65e248c
--- /dev/null
+++ b/apps/web/app/admin/changelog/page.tsx
@@ -0,0 +1,17 @@
+import type { Metadata } from "next";
+import { ChangelogList } from "@/components/shared/changelog-list";
+import { APP_VERSION } from "@/lib/changelog";
+
+export const metadata: Metadata = {};
+
+export default function AdminChangelogPage() {
+ return (
+
+
+
Changelog
+
Currently running v{APP_VERSION}. Edit apps/web/lib/changelog.ts to update.
+
+
+
+ );
+}
diff --git a/apps/web/app/admin/layout.tsx b/apps/web/app/admin/layout.tsx
index 3176231..319a3f0 100644
--- a/apps/web/app/admin/layout.tsx
+++ b/apps/web/app/admin/layout.tsx
@@ -3,7 +3,7 @@ import { headers } from "next/headers";
import { auth } from "@/lib/auth/server";
import { db, users, eq } from "@epicure/db";
import Link from "next/link";
-import { Shield, Users, BookOpen, Settings, BarChart3, ClipboardList, HardDrive, Bot, ArrowLeft, Gauge, Mail, Flag } from "lucide-react";
+import { Shield, Users, BookOpen, Settings, BarChart3, ClipboardList, HardDrive, Bot, ArrowLeft, Gauge, Mail, Flag, History } from "lucide-react";
import { cn } from "@/lib/utils";
const adminNav = [
@@ -17,6 +17,7 @@ const adminNav = [
{ href: "/admin/storage", label: "Storage", icon: HardDrive },
{ href: "/admin/ai-config", label: "AI Config", icon: Bot },
{ href: "/admin/settings", label: "Settings", icon: Settings },
+ { href: "/admin/changelog", label: "Changelog", icon: History },
];
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
diff --git a/apps/web/app/admin/page.tsx b/apps/web/app/admin/page.tsx
index 0dc3147..1939c08 100644
--- a/apps/web/app/admin/page.tsx
+++ b/apps/web/app/admin/page.tsx
@@ -1,9 +1,11 @@
import type { Metadata } from "next";
+import Link from "next/link";
import { db } from "@epicure/db";
import { users, recipes, userUsage, recipePhotos } from "@epicure/db";
import { count, eq, sql } from "@epicure/db";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Users, BookOpen, Sparkles, Image } from "lucide-react";
+import { Users, BookOpen, Sparkles, Image, History } from "lucide-react";
+import { APP_VERSION, CHANGELOG } from "@/lib/changelog";
export const metadata: Metadata = {};
@@ -46,6 +48,22 @@ export default async function AdminPage() {
))}
+
+
+
+ Version
+
+
+
+