Skip to content

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

6 watching

Forks

Repository files navigation

Nightingale website

The open-source website and documentation for Nightingale, served at https://n9e.github.io. Built with Docusaurus 3. English is the default locale at /; Chinese is at /zh/. Chinese copy is the source of truth for wording, and the English copy is written alongside it rather than machine-translated.

Development

npm install
npm start                       # dev server for the default locale (English)
npm start -- --locale zh-Hans   # dev server for the Chinese site
npm run build                   # both locales: build/ (English) and build/zh/ (Chinese)
npm run serve                   # serve the build output locally
npm run typecheck

npm run build first runs the data scripts (see Generated data). If a fetch fails, the build carries on with the data already in the repository. The build also writes robots.txt (with both locales' sitemaps), llms.txt / llms-full.txt per locale and a .md copy of every page next to its HTML (/docs/x → /docs/x.md) for AI crawlers. Links and images in those Markdown files are absolute; scripts/llms-txt-links.mjs fixes the doubled /zh/zh/ prefix the llms-txt plugin otherwise produces for the Chinese locale (its route table is keyed by prefixed paths, so the prefix cannot simply be stripped before it runs). After the build, scripts/link-markdown-alternates.mjs adds <link rel="alternate" type="text/markdown"> (the page's .md twin) and <link rel="describedby"> (the locale's llms.txt) to the head of every page that has a Markdown copy, following the llms.txt proposal; GitHub Pages cannot send the equivalent Link: header or negotiate Accept: text/markdown, so the tags are the only in-band discovery path.

Fonts are self-hosted: node scripts/sync-fonts.mjs copies the @fontsource files into static/fonts/ and writes src/css/fonts.css, which docusaurus.config.ts inlines into <head> (not customCss, so webpack does not rewrite the URLs) together with preloads for the weights used above the fold. The CSS also defines metric-matched local fallbacks (Archivo Fallback, JetBrains Mono Fallback, overrides computed with scripts/font-metrics.py), so the swap from the fallback to the web font does not reflow the page. Lab CLS is ~0 on every page type; keep it that way by giving every <img> a width and height or a fixed CSS box.

Every doc carries a last_reviewed: YYYY-MM-DD front matter field. It is rendered under the title, emitted as article:modified_time and as TechArticle.dateModified, and it is the only date signal the site gives (git timestamps are deliberately not used, see docusaurus.config.ts). Bump it only after checking the page against the product. Troubleshooting pages are titled as questions on purpose: that is how people and AI assistants phrase the query.

Deployment

Every push to main triggers .github/workflows/deploy.yml: it runs npm ci && npm run build and publishes build/ to the gh-pages branch, which GitHub Pages serves at https://n9e.github.io. Pushing to main is a production release. The workflow can also be run by hand from the Actions tab.

Layout

docusaurus.config.ts   Site config: navbar, footer, i18n, analytics, the embed-mode script
sidebars.ts            Generated by scripts/scaffold-docs.mjs — do not edit by hand
docs/                  English docs
i18n/zh-Hans/          Chinese docs and theme strings
i18n/en/               English theme strings (navbar, footer, sidebar group labels)
src/
  content/             All homepage and landing-page copy (zh.ts and en.ts share types.ts)
  components/home/     Homepage sections and the shared home.module.css
  components/docs/     Components used inside docs pages (Shot, StackLayers, ...)
  pages/               Homepage plus the comparisons, integrations, download and Categraf pages
  css/custom.css       Design tokens, Docusaurus theme overrides, embed-mode styles
  clientModules/       Client-side hooks (Baidu Analytics pageviews on route changes)
  data/stats.json        GitHub numbers, refreshed by scripts/fetch-stats.mjs
  data/releases.json     Download page versions, links and checksums, refreshed by scripts/fetch-releases.mjs
  data/integrations.json Integration template catalog, refreshed by scripts/fetch-integrations.mjs
scripts/
  docs-tree.mjs        The docs information architecture: every page's title and description
  scaffold-docs.mjs    Regenerates sidebars.ts and the English sidebar labels from docs-tree.mjs
  integration-categories.mjs  Categories, hidden list, display names and search aliases for templates
  docs-env/            The screenshot environment for docs (see its README)
static/img/            Product screenshots, data source and channel logos, the user logo wall;
                       img/integrations/ holds template icons synced from upstream

Comparison pages

/comparisons is a hub; each competitor has a full page under src/pages/comparisons/<slug>.tsx rendered by src/components/comparisons/DetailPage.tsx from comparisonsPage.details in src/content/{en,zh}.ts (the hub's verdicts supply the stance, visual and Q&A; details add the verdict, two-column table, migration summary and FAQ). The hub keeps the #prometheus, #zabbix and #grafana anchors so old links still land.

The two long-form guides (zabbix-alternatives, open-source-alerting-platforms) are MDX pages: English in src/pages/comparisons/, Chinese in i18n/zh-Hans/docusaurus-plugin-content-pages/comparisons/. Both languages exist for every page so the hreflang alternates never point at a 404. Claims about other projects are dated in the page footer; keep "where the other tool fits" honest when editing.

Editing copy

All visible homepage and landing-page text lives in src/content/zh.ts and en.ts. Both follow the structure in types.ts, so a missing field fails npm run typecheck. Navbar and footer strings for English are in i18n/en/docusaurus-theme-classic/*.json.

Writing or editing docs follows WRITING-DOCS.md. Adding a docs page means registering it in scripts/docs-tree.mjs and running npm run scaffold.

Historical documentation URLs

scripts/legacy-doc-urls.mjs records how each pre-redesign Hugo documentation URL is handled: redirect to equivalent content, keep, restore, explain (a noindex notice with a suggested page, for removed content that old links still point at), or retire (404). Its frozen inventory comes from the commit before 54cbdc54; the older /docs/install/server entry is recorded separately and redirects to the current installation overview rather than retaining an obsolete-architecture article. English and Chinese keep their language. Collector and monitoring-practice articles retain their original URLs and are registered in the current sidebar.

The old site's non-documentation routes (the blog and the Doks contributor pages) are listed separately in the same file as legacySiteUrls; they redirect to the locale home, the closest current page, or the GitHub contributor graph, which the official plugin cannot target, so postbuild writes those aliases itself.

The official @docusaurus/plugin-client-redirects plugin emits static HTML aliases. postbuild adds slashless aliases without overwriting current pages, copies the target canonical URL, uses location.replace while forwarding query and hash, and checks the completed output. These are zero-second meta-refresh redirects, not HTTP 301 responses. Retired and unknown URLs remain 404 on GitHub Pages.

The old Hugo site also served RSS at /index.xml, /docs/index.xml, per-section /docs/<section>/index.xml, /blog/index.xml and /contributors/index.xml (both locales). scripts/write-legacy-feeds.mjs writes a small valid RSS 2.0 feed at each of those paths, with the latest Nightingale and Categraf releases and a pointer to the new documentation, so feed readers and crawlers that still poll them get a 200 and the new site's address rather than a 404.

The same plugin's createRedirects adds a trailing-slash alias for every current page (/docs/x/ → /docs/x), because trailingSlash: false leaves only docs/x.html and GitHub Pages answers /docs/x/ with 404 otherwise. scripts/finalize-slash-aliases.mjs gives those pages the target's absolute canonical and location.replace, matching the legacy aliases. A client module also handles known old URLs reached by SPA navigation; it does not replace the static aliases.

npm run test:legacy-doc-urls
npm run build                     # includes alias finalization and validation
npm run check:legacy-doc-urls     # validate an already completed build

The result table is build/legacy-doc-url-report.json. Validation includes every inventoried URL, both slash forms, final canonical URLs, target content and sitemap exclusions for moved pages. Changes to a mapping must include its reason and a valid final target. Do not redirect unrelated deleted articles to the homepage. For a future domain migration, reuse the path mapping and update the site URL rather than inserting an intermediate redirect destination.

Generated data

The homepage numbers, the download page and the integrations catalog come from files in src/data/, refreshed by:

npm run stats          # GitHub stars / forks / latest release
npm run releases       # release packages and checksums for the download page
npm run integrations   # template catalog; icons are re-downloaded only when their blob sha changes

Set GITHUB_TOKEN to avoid anonymous rate limits. When upstream adds a template that scripts/integration-categories.mjs does not categorize yet, the script prints a warning and files it under "Other"; the build does not fail.

The figures quoted across the homepage, comparisons page, integrations page and introduction (integration count, data source types, notification channels, MCP tools) all come from src/data/figures.ts. The integration count is the catalog length, and the "N of them ship alert rules / dashboards / metric descriptions" counts in the docs are derived from the same catalog (four upstream templates are deliberately hidden, see HIDDEN in scripts/integration-categories.mjs, so the product's template center shows a few more); the MCP numbers are src/data/mcp.json, written by scripts/docs-env/gen-mcp-reference.mjs from the toolset library pinned in nightingale's go.mod (the standalone n9e-mcp-server is deprecated; the tools ship inside n9e). Do not type these numbers into copy.

Docs screenshots are lossless WebP under static/img/docs/, produced from the PNGs that scripts/docs-env/shoot-docs.mjs captures by node scripts/docs-env/webp-docs.mjs, which also records their dimensions in src/data/doc-shots.json for the <Shot> component.

Design conventions

  • Accent colors are only the product's own alert severity colors (S1 red / S2 orange / S3 blue), and they must carry real meaning, never decoration.
  • The vertical rail beside the homepage's four stages is the severity bar from each alert row in the product, enlarged; at the step where data becomes an event it switches to the three severity colors, so the color change itself states a fact.
  • Structural markers use object names that exist in the product (datasource → rule → event → agent), not 01/02/03.
  • Motion is limited to one choreographed first screen (cards entering, the severity bar drawing, delivery channels landing in turn) plus hover states; all of it is off under prefers-reduced-motion.
  • Product screenshots are the core visual asset. Light and dark versions switch on [data-theme], not in JavaScript.

Embedding in the product

The product's help drawer opens docs pages in an iframe with ?onlyContent&theme=dark|light. In that mode the navbar, sidebars, table of contents and footer are hidden, the theme follows the parameter without being saved, and a trailing-slash URL is redirected to the slashless one. The logic is EMBED_INLINE_SCRIPT in docusaurus.config.ts; the styles are at the end of src/css/custom.css.

About

No description, website, or topics provided.

Resources

Stars

5 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages