← back to Govarbitrage
SEO plumbing: sitemap.xml (static pages + every archive date), robots.txt (public routes allowed, app/private disallowed), canonicals from NEWSLETTER_BASE_URL
519132ec7f0b3dd7b43f78cac87046d1709d74c0 · 2026-07-13 01:38:44 -0700 · Steve Abrams
Files touched
A src/app/robots.tsA src/app/sitemap.ts
Diff
commit 519132ec7f0b3dd7b43f78cac87046d1709d74c0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jul 13 01:38:44 2026 -0700
SEO plumbing: sitemap.xml (static pages + every archive date), robots.txt (public routes allowed, app/private disallowed), canonicals from NEWSLETTER_BASE_URL
---
src/app/robots.ts | 27 +++++++++++++++++++++++++++
src/app/sitemap.ts | 27 +++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/src/app/robots.ts b/src/app/robots.ts
new file mode 100644
index 0000000..8458058
--- /dev/null
+++ b/src/app/robots.ts
@@ -0,0 +1,27 @@
+import type { MetadataRoute } from "next";
+import { publicBaseUrl } from "@/lib/site";
+
+export default function robots(): MetadataRoute.Robots {
+ const base = publicBaseUrl();
+ return {
+ rules: [
+ {
+ userAgent: "*",
+ allow: ["/newsletter", "/pricing", "/deals"],
+ // App/private surfaces: auth-walled anyway, but keep crawlers out of
+ // redirects and per-listing buyer pages entirely.
+ disallow: [
+ "/api/",
+ "/listings",
+ "/reports",
+ "/selling-avenues",
+ "/billing",
+ "/credentials",
+ "/login",
+ "/b/",
+ ],
+ },
+ ],
+ sitemap: `${base}/sitemap.xml`,
+ };
+}
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
new file mode 100644
index 0000000..d44fe7f
--- /dev/null
+++ b/src/app/sitemap.ts
@@ -0,0 +1,27 @@
+import type { MetadataRoute } from "next";
+import { listDigestDates } from "@/lib/digest-snapshot";
+import { publicBaseUrl } from "@/lib/site";
+
+export const dynamic = "force-dynamic";
+
+export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
+ const base = publicBaseUrl();
+ const dates = await listDigestDates();
+
+ const staticPages: MetadataRoute.Sitemap = [
+ { url: `${base}/`, changeFrequency: "daily", priority: 0.8 },
+ { url: `${base}/newsletter`, changeFrequency: "weekly", priority: 1 },
+ { url: `${base}/pricing`, changeFrequency: "weekly", priority: 0.7 },
+ { url: `${base}/deals`, changeFrequency: "daily", priority: 0.9 },
+ ];
+
+ return [
+ ...staticPages,
+ ...dates.map(({ date, lastModified }) => ({
+ url: `${base}/deals/${date}`,
+ lastModified,
+ changeFrequency: "monthly" as const, // frozen snapshots — they don't change
+ priority: 0.6,
+ })),
+ ];
+}
← 5e22c50 Public SEO deal archive: /deals index + /deals/[date] teaser
·
back to Govarbitrage
·
auto-save: 2026-07-13T01:52:00 (8 files) — prisma/schema.pri dba59ea →