From 018a2e26659bf0eb8e9a6c361abf94a1933e687d Mon Sep 17 00:00:00 2001 From: RAIF-KARANI Date: Thu, 1 Oct 2026 00:56:17 +0530 Subject: [PATCH] fix: exclude seed data from sitemap, regenerate favicon at Google-compliant sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deterministic seed/load-test rows (IDs prefixed 00000000-0000-4000-8000-) were leaking into sitemap.xml and getting crawled as if they were real companies/professionals. Filter them out. Also rebuilt favicon.ico from the vector mark at 16/32/48/96px — the old file was a single 32x32 frame, under Google's recommended 48px-multiple minimum for favicons shown in search results. Co-Authored-By: Claude Sonnet 5 --- apps/web/src/app/favicon.ico | Bin 4286 -> 3846 bytes apps/web/src/app/sitemap.ts | 34 ++++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apps/web/src/app/favicon.ico b/apps/web/src/app/favicon.ico index a360dc76fdf8486644aefed91f9bb58be1c6515a..cbd8c7865b30edf25669ecba862a3232d13e31ce 100644 GIT binary patch literal 3846 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 id.startsWith(SEED_ID_PREFIX); + // The API caps `limit` at 100 per page, so a flat single fetch silently // missed everything once there were more than 100 rows (it 400'd, and the // catch below swallowed it). Page through instead so the sitemap keeps @@ -29,12 +35,14 @@ async function fetchAllPages(path: string): Promise { async function companyEntries(): Promise { try { const companies = await fetchAllPages('/companies'); - return companies.map((company) => ({ - url: `${SITE_URL}/companies/${company.id}`, - lastModified: company.updatedAt, - changeFrequency: 'weekly', - priority: 0.7, - })); + return companies + .filter((company) => !isSeedId(company.id)) + .map((company) => ({ + url: `${SITE_URL}/companies/${company.id}`, + lastModified: company.updatedAt, + changeFrequency: 'weekly', + priority: 0.7, + })); } catch { // The API being unreachable shouldn't take the whole sitemap down — // crawlers still get the static routes below. @@ -45,12 +53,14 @@ async function companyEntries(): Promise { async function professionalEntries(): Promise { try { const profiles = await fetchAllPages('/professionals'); - return profiles.map((profile) => ({ - url: `${SITE_URL}/professionals/${profile.id}`, - lastModified: profile.updatedAt, - changeFrequency: 'weekly', - priority: 0.6, - })); + return profiles + .filter((profile) => !isSeedId(profile.id)) + .map((profile) => ({ + url: `${SITE_URL}/professionals/${profile.id}`, + lastModified: profile.updatedAt, + changeFrequency: 'weekly', + priority: 0.6, + })); } catch { return []; }