From 3b076233462d3fb26c47b4ff7f6d5963c228e1eb Mon Sep 17 00:00:00 2001 From: Raj Nandan Sharma Date: Wed, 18 Mar 2026 12:20:42 +0530 Subject: [PATCH] Implement SEO enhancements across documentation and application pages, including Open Graph and Twitter meta tags, improve robots.txt for AI crawlers, and streamline code formatting for better readability. --- CLAUDE.md | 4 +- src/app.html | 1 + .../server/controllers/monitorsController.ts | 13 +-- src/routes/(account)/+layout.svelte | 1 + .../(with-sidebar)/[...slug]/+page.svelte | 31 ++++++ src/routes/(docs)/docs/+layout.svelte | 51 +++++++++- src/routes/(docs)/docs/+page.svelte | 94 ++++++++++++++++++- .../v4/guides/api-custom-eval-examples.md | 4 +- .../(docs)/docs/content/v4/monitors/grpc.md | 14 +-- src/routes/(embed)/+layout.svelte | 1 + src/routes/(kener)/+page.svelte | 2 + src/routes/(kener)/[page_path]/+page.svelte | 2 + .../events/[MMMM]-[YYYY]/+page.svelte | 5 + .../(kener)/events/[MMMM]-[YYYY]/+page.svelte | 5 + .../incidents/[incident_id]/+page.svelte | 5 +- .../[maintenance_id]/+page.svelte | 5 +- .../monitors/[monitor_tag]/+page.svelte | 5 +- src/routes/(manage)/+layout.svelte | 1 + .../(manage)/manage/app/badges/+page.svelte | 4 +- src/routes/llms.txt/+server.ts | 11 +++ src/routes/sitemap.xml/+server.ts | 53 +++++++++++ static/robots.txt | 39 +++++++- 22 files changed, 318 insertions(+), 33 deletions(-) create mode 100644 src/routes/llms.txt/+server.ts create mode 100644 src/routes/sitemap.xml/+server.ts diff --git a/CLAUDE.md b/CLAUDE.md index 8f524cf2..01580c68 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,11 +87,11 @@ Constants are exported as a **default export** from `src/lib/global-constants.ts ```typescript // In Svelte/client code or SvelteKit routes: -import GC from "$lib/global-constants"; +import GC from "$lib/global-constants" // Usage: GC.UP, GC.DOWN, GC.DEGRADED, GC.MAINTENANCE, GC.NO_DATA // In server code (use relative path): -import GC from "../../global-constants.js"; +import GC from "../../global-constants.js" // Usage: GC.UP, GC.DOWN, etc. ``` diff --git a/src/app.html b/src/app.html index adf8bd87..948ce949 100644 --- a/src/app.html +++ b/src/app.html @@ -3,6 +3,7 @@ + %sveltekit.head% diff --git a/src/lib/server/controllers/monitorsController.ts b/src/lib/server/controllers/monitorsController.ts index db665008..c7a553d7 100644 --- a/src/lib/server/controllers/monitorsController.ts +++ b/src/lib/server/controllers/monitorsController.ts @@ -399,9 +399,7 @@ async function removeTagFromGroupMonitors(tag: string): Promise { const weight = Math.round((1 / remaining.length) * 1000) / 1000; for (let i = 0; i < remaining.length; i++) { remaining[i].weight = - i === remaining.length - 1 - ? Math.round((1 - weight * (remaining.length - 1)) * 1000) / 1000 - : weight; + i === remaining.length - 1 ? Math.round((1 - weight * (remaining.length - 1)) * 1000) / 1000 : weight; } } @@ -573,13 +571,10 @@ export const GetBadge = async (badgeType: BadgeType, params: BadgeParams): Promi } } const defaultLocale = i18nConfig?.defaultLocale || "en"; - const activatedCodes = new Set( - i18nConfig?.locales?.filter((l) => l.selected).map((l) => l.code) ?? ["en"], - ); + const activatedCodes = new Set(i18nConfig?.locales?.filter((l) => l.selected).map((l) => l.code) ?? ["en"]); const requestedLocale = params.locale || defaultLocale; - const locale = activatedCodes.has(requestedLocale) && isLocaleAvailable(requestedLocale) - ? requestedLocale - : defaultLocale; + const locale = + activatedCodes.has(requestedLocale) && isLocaleAvailable(requestedLocale) ? requestedLocale : defaultLocale; const statusLocaleKey: Record = { [GC.UP]: "Operational", diff --git a/src/routes/(account)/+layout.svelte b/src/routes/(account)/+layout.svelte index 92d550fc..297d2b32 100644 --- a/src/routes/(account)/+layout.svelte +++ b/src/routes/(account)/+layout.svelte @@ -20,6 +20,7 @@ + {@html ``}
diff --git a/src/routes/(docs)/docs/(with-sidebar)/[...slug]/+page.svelte b/src/routes/(docs)/docs/(with-sidebar)/[...slug]/+page.svelte index 530b43e3..19091e80 100644 --- a/src/routes/(docs)/docs/(with-sidebar)/[...slug]/+page.svelte +++ b/src/routes/(docs)/docs/(with-sidebar)/[...slug]/+page.svelte @@ -152,6 +152,37 @@ + + + + + {@html ``}
diff --git a/src/routes/(docs)/docs/+layout.svelte b/src/routes/(docs)/docs/+layout.svelte index 110a846d..d0ab2000 100644 --- a/src/routes/(docs)/docs/+layout.svelte +++ b/src/routes/(docs)/docs/+layout.svelte @@ -11,19 +11,62 @@ Kener Documentation - + + - + + + + {@html ``} - Documentation - {data.config.name} - + {data.config.name} - Open Source Status Page System | Documentation + + + + + + + + + + + {@html ``}
diff --git a/src/routes/(docs)/docs/content/v4/guides/api-custom-eval-examples.md b/src/routes/(docs)/docs/content/v4/guides/api-custom-eval-examples.md index 0e81c731..7908434c 100644 --- a/src/routes/(docs)/docs/content/v4/guides/api-custom-eval-examples.md +++ b/src/routes/(docs)/docs/content/v4/guides/api-custom-eval-examples.md @@ -31,7 +31,7 @@ Response: Array of todo objects with `completed` boolean field. ### Eval function: ```javascript -(async function (statusCode, responseTime, responseRaw) { +;(async function (statusCode, responseTime, responseRaw) { if (statusCode !== 200) { return { status: "DOWN", latency: responseTime } } @@ -81,7 +81,7 @@ SECRET_PARAM=your_real_secret_value ## Cheerio HTML content check {#cheerio-html-check-eval} ```javascript -(async function (statusCode, responseTime, responseRaw, modules) { +;(async function (statusCode, responseTime, responseRaw, modules) { if (statusCode !== 200) { return { status: "DOWN", latency: responseTime } } diff --git a/src/routes/(docs)/docs/content/v4/monitors/grpc.md b/src/routes/(docs)/docs/content/v4/monitors/grpc.md index 60e6e017..157efd1e 100644 --- a/src/routes/(docs)/docs/content/v4/monitors/grpc.md +++ b/src/routes/(docs)/docs/content/v4/monitors/grpc.md @@ -26,13 +26,13 @@ Connection errors and timeouts return **DOWN**. ## Configuration fields {#configuration-fields} -| Field | Type | Default | Notes | -| :-------- | :-------- | :------ | :--------------------------------------------- | -| `host` | `string` | — | Required | -| `port` | `number` | `50051` | Required | -| `service` | `string` | `""` | Fully qualified service name; empty = overall | -| `tls` | `boolean` | `false` | Use TLS credentials | -| `timeout` | `number` | `10000` | Request deadline in ms | +| Field | Type | Default | Notes | +| :-------- | :-------- | :------ | :-------------------------------------------- | +| `host` | `string` | — | Required | +| `port` | `number` | `50051` | Required | +| `service` | `string` | `""` | Fully qualified service name; empty = overall | +| `tls` | `boolean` | `false` | Use TLS credentials | +| `timeout` | `number` | `10000` | Request deadline in ms | ## Example {#example} diff --git a/src/routes/(embed)/+layout.svelte b/src/routes/(embed)/+layout.svelte index 60b52ebe..1b5f180c 100644 --- a/src/routes/(embed)/+layout.svelte +++ b/src/routes/(embed)/+layout.svelte @@ -13,6 +13,7 @@ + Kener Status {#if data.font?.cssSrc} diff --git a/src/routes/(kener)/+page.svelte b/src/routes/(kener)/+page.svelte index 6f7537f1..46b04435 100644 --- a/src/routes/(kener)/+page.svelte +++ b/src/routes/(kener)/+page.svelte @@ -133,6 +133,8 @@ {/if} + + {#if data.socialPagePreviewImage} diff --git a/src/routes/(kener)/[page_path]/+page.svelte b/src/routes/(kener)/[page_path]/+page.svelte index 6f7537f1..46b04435 100644 --- a/src/routes/(kener)/[page_path]/+page.svelte +++ b/src/routes/(kener)/[page_path]/+page.svelte @@ -133,6 +133,8 @@ {/if} + + {#if data.socialPagePreviewImage} diff --git a/src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.svelte b/src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.svelte index 99670b00..6b7e44f9 100644 --- a/src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.svelte +++ b/src/routes/(kener)/[page_path]/events/[MMMM]-[YYYY]/+page.svelte @@ -159,6 +159,11 @@ {currentMonth} - Maintenances & Incidents - {data.siteName} + + + + + {#if data.socialPreviewImage} diff --git a/src/routes/(kener)/events/[MMMM]-[YYYY]/+page.svelte b/src/routes/(kener)/events/[MMMM]-[YYYY]/+page.svelte index a04f7151..833b0259 100644 --- a/src/routes/(kener)/events/[MMMM]-[YYYY]/+page.svelte +++ b/src/routes/(kener)/events/[MMMM]-[YYYY]/+page.svelte @@ -159,6 +159,11 @@ {currentMonth} - Maintenances & Incidents - {data.siteName} + + + + + {#if data.socialPreviewImage} diff --git a/src/routes/(kener)/incidents/[incident_id]/+page.svelte b/src/routes/(kener)/incidents/[incident_id]/+page.svelte index 67ec1fa4..18e3e96e 100644 --- a/src/routes/(kener)/incidents/[incident_id]/+page.svelte +++ b/src/routes/(kener)/incidents/[incident_id]/+page.svelte @@ -20,9 +20,12 @@ {data.incident.title + " - " + data.siteName} - + + + {#if data.comments.length > 0} + {/if} {#if data.socialPreviewImage} diff --git a/src/routes/(kener)/maintenances/[maintenance_id]/+page.svelte b/src/routes/(kener)/maintenances/[maintenance_id]/+page.svelte index 813f3686..ed512a05 100644 --- a/src/routes/(kener)/maintenances/[maintenance_id]/+page.svelte +++ b/src/routes/(kener)/maintenances/[maintenance_id]/+page.svelte @@ -65,9 +65,12 @@ {data.maintenance.title + " - " + data.siteName} - + + + {#if data.maintenance.description} + {/if} {#if data.socialPreviewImage} diff --git a/src/routes/(kener)/monitors/[monitor_tag]/+page.svelte b/src/routes/(kener)/monitors/[monitor_tag]/+page.svelte index cd1c61fc..6bafeaf4 100644 --- a/src/routes/(kener)/monitors/[monitor_tag]/+page.svelte +++ b/src/routes/(kener)/monitors/[monitor_tag]/+page.svelte @@ -29,9 +29,12 @@ {data.monitorName + " - " + data.siteName} - + + + {#if data.monitorDescription} + {/if} {#if data.socialPreviewImage} diff --git a/src/routes/(manage)/+layout.svelte b/src/routes/(manage)/+layout.svelte index 81b87001..d931e73f 100644 --- a/src/routes/(manage)/+layout.svelte +++ b/src/routes/(manage)/+layout.svelte @@ -62,6 +62,7 @@ + {pageTitle} | Kener {#if data.font?.cssSrc} diff --git a/src/routes/(manage)/manage/app/badges/+page.svelte b/src/routes/(manage)/manage/app/badges/+page.svelte index 6532efba..e9f10093 100644 --- a/src/routes/(manage)/manage/app/badges/+page.svelte +++ b/src/routes/(manage)/manage/app/badges/+page.svelte @@ -250,9 +250,7 @@ {/each} -

- Status text will be shown in the selected language -

+

Status text will be shown in the selected language

{/if} diff --git a/src/routes/llms.txt/+server.ts b/src/routes/llms.txt/+server.ts new file mode 100644 index 00000000..c418afeb --- /dev/null +++ b/src/routes/llms.txt/+server.ts @@ -0,0 +1,11 @@ +import { redirect } from "@sveltejs/kit"; +import type { RequestHandler } from "./$types"; +import { getDocsRootConfig } from "../(docs)/docs/docs-utils.server"; + +export const GET: RequestHandler = () => { + const rootConfig = getDocsRootConfig(); + const latestVersion = rootConfig.versions.find((v) => v.latest) ?? rootConfig.versions[0]; + const versionSlug = latestVersion?.slug ?? "v4"; + + throw redirect(301, `/docs/${versionSlug}/llms.txt`); +}; diff --git a/src/routes/sitemap.xml/+server.ts b/src/routes/sitemap.xml/+server.ts new file mode 100644 index 00000000..f5149304 --- /dev/null +++ b/src/routes/sitemap.xml/+server.ts @@ -0,0 +1,53 @@ +import type { RequestHandler } from "@sveltejs/kit"; +import { getDocsRootConfig, getVersionDocsUrls } from "../(docs)/docs/docs-utils.server"; + +const BASE_DOMAIN = "https://kener.ing"; + +export const GET: RequestHandler = () => { + const rootConfig = getDocsRootConfig(); + const latestVersion = rootConfig.versions.find((v) => v.latest) ?? rootConfig.versions[0]; + + const urls: { loc: string; priority: string; changefreq: string }[] = [ + { loc: `${BASE_DOMAIN}/docs`, priority: "1.0", changefreq: "weekly" }, + ]; + + if (latestVersion) { + const docsUrls = getVersionDocsUrls(latestVersion.slug, BASE_DOMAIN); + for (const url of docsUrls) { + // Skip raw markdown URLs and external URLs + if (url.includes("/docs/raw/") || !url.startsWith(BASE_DOMAIN)) continue; + urls.push({ loc: url, priority: "0.8", changefreq: "weekly" }); + } + + // Add llms.txt for AI discoverability + urls.push({ + loc: `${BASE_DOMAIN}/docs/${latestVersion.slug}/llms.txt`, + priority: "0.5", + changefreq: "weekly", + }); + } + + const xml = ` + +${urls + .map( + (u) => ` + ${escapeXml(u.loc)} + ${u.changefreq} + ${u.priority} + `, + ) + .join("\n")} +`; + + return new Response(xml, { + headers: { + "content-type": "application/xml; charset=utf-8", + "cache-control": "public, max-age=3600", + }, + }); +}; + +function escapeXml(str: string): string { + return str.replace(/&/g, "&").replace(//g, ">"); +} diff --git a/static/robots.txt b/static/robots.txt index 4f9540ba..3fcb7596 100644 --- a/static/robots.txt +++ b/static/robots.txt @@ -1 +1,38 @@ -User-agent: * \ No newline at end of file +User-agent: * +Allow: / +Disallow: /manage/ +Disallow: /account/ +Disallow: /api/ +Disallow: /embed/ + +# AI Search Engine Crawlers +User-agent: GPTBot +Allow: / + +User-agent: ChatGPT-User +Allow: / + +User-agent: ClaudeBot +Allow: / + +User-agent: anthropic-ai +Allow: / + +User-agent: PerplexityBot +Allow: / + +User-agent: Google-Extended +Allow: / + +User-agent: Googlebot +Allow: / + +User-agent: Bingbot +Allow: / + +Sitemap: https://kener.ing/sitemap.xml + +# AI Documentation Index +# See https://llmstxt.org for specification +# /llms.txt redirects to the latest version +