<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://rubentalstra.github.io/librechat-prom-exporter/blog</id>
    <title>LibreChat Prometheus Exporter Blog</title>
    <updated>2026-05-20T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://rubentalstra.github.io/librechat-prom-exporter/blog"/>
    <subtitle>LibreChat Prometheus Exporter Blog</subtitle>
    <icon>https://rubentalstra.github.io/librechat-prom-exporter/img/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[v0.9.0 — Documentation site]]></title>
        <id>https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0</id>
        <link href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0"/>
        <updated>2026-05-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[v0.9.0 introduces a dedicated documentation site at rubentalstra.github.io/librechat-prom-exporter. No exporter code changes — this release is entirely about how the project is documented, contributed to, and released.]]></summary>
        <content type="html"><![CDATA[<p>v0.9.0 introduces a dedicated documentation site at <strong><a href="https://rubentalstra.github.io/librechat-prom-exporter/" target="_blank" rel="noopener noreferrer" class="">rubentalstra.github.io/librechat-prom-exporter</a></strong>. No exporter code changes — this release is entirely about how the project is documented, contributed to, and released.</p>
<!-- -->
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-new">What's new<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0#whats-new" class="hash-link" aria-label="Direct link to What's new" title="Direct link to What's new" translate="no">​</a></h3>
<ul>
<li class=""><strong>Docusaurus 3.10.1</strong> docs site served from GitHub Pages. Versioned per release (use the version dropdown in the navbar after future cuts), local search (no Algolia signup), MDX content with <code>.mdx</code> extension throughout. Built with v4 future flags on (<code>future.v4: true</code>, <code>future.faster: true</code>) so the eventual Docusaurus 4 upgrade is a no-op.</li>
<li class=""><strong>Reference docs migrated out of the README.</strong> Environment variables, auth methods, metrics catalog, Prometheus + Grafana setup, tuning, troubleshooting, dashboard import — all now live on the docs site with proper navigation, search, and per-page edit-on-GitHub links.</li>
<li class=""><strong>Contributor docs written from scratch</strong> rather than copying CONTRIBUTING.md:<!-- -->
<ul>
<li class=""><a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/docs/contributing/architecture">Architecture</a> — 1500-word deep-dive on the two-tier scrape, the eager-kickoff promise pattern, JS-side joins instead of <code>$lookup</code>, cardinality gates, ESM/NodeNext gotchas. Two Mermaid diagrams (scrape sequence + auth method decision flowchart).</li>
<li class=""><a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/docs/contributing/ways-to-contribute">Ways to contribute</a> — five concrete paths: high-signal bug reports, propose-a-metric, share-a-dashboard, improve-docs, sponsor.</li>
<li class=""><a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/docs/contributing/adding-a-metric">Adding a metric</a> — step-by-step playbook including the cardinality budget rules every new metric must follow.</li>
</ul>
</li>
<li class=""><strong>README slimmed</strong> from 343 lines to 53. <strong>CONTRIBUTING.md</strong> from 86 lines to 26 — both now point at the docs site for detail.</li>
<li class=""><strong>Blog as changelog.</strong> This post is the first of a "Changelog &amp; news" feed on the docs site, with RSS/Atom for feed readers (<code>&lt;link rel="alternate"&gt;</code> in every page's <code>&lt;head&gt;</code>).</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ci--cd-additions">CI / CD additions<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0#ci--cd-additions" class="hash-link" aria-label="Direct link to CI / CD additions" title="Direct link to CI / CD additions" translate="no">​</a></h3>
<ul>
<li class=""><strong>Lighthouse CI on PRs</strong> — every PR touching <code>website/**</code> triggers a Lighthouse run with thresholds: a11y ≥ 90 and SEO ≥ 90 as errors; performance ≥ 85 and best-practices ≥ 85 as warnings. Full report posted to a temporary public URL and linked in the PR.</li>
<li class=""><strong>Docs build verification on PRs</strong> — <code>docs-test-deploy.yml</code> runs the production Docusaurus build on every PR. <code>onBrokenLinks</code>, <code>onBrokenAnchors</code>, and <code>onBrokenMarkdownLinks</code> are all set to <code>"throw"</code> so dead refs and stale anchors fail review.</li>
<li class=""><strong>Path-filtered <code>docs-deploy.yml</code></strong> — push-to-main only triggers a Pages deploy when <code>website/**</code> or <code>CONTRIBUTING.md</code> actually changes.</li>
<li class=""><strong>GitHub-native attestations</strong> for SBOM + build provenance (<code>actions/attest-build-provenance@v4</code>, <code>actions/attest-sbom@v4</code>) — verifiable via <code>gh attestation verify oci://...</code>. No GHCR clutter because <code>push-to-registry: false</code>.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="release-automation">Release automation<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0#release-automation" class="hash-link" aria-label="Direct link to Release automation" title="Direct link to Release automation" translate="no">​</a></h3>
<p>The version number now lives in <strong>one place</strong> — root <code>package.json</code> — and the docs site reads it dynamically. The current-version label in the navbar dropdown updates automatically when <code>package.json</code> is bumped; no more hand-editing <code>docusaurus.config.ts</code> per release.</p>
<p>A new <strong>"Prepare release"</strong> workflow (<code>workflow_dispatch</code>-only) automates the rest:</p>
<ol>
<li class="">Trigger it from the Actions tab with <code>version: 0.10.0</code> (no leading <code>v</code>).</li>
<li class="">The workflow snapshots the docs site as <code>0.10</code> (so the new "0.10" version dropdown entry will work after deploy), bumps <code>package.json</code> + <code>package-lock.json</code>, and opens a "Release v0.10.0" PR.</li>
<li class="">Review + merge.</li>
<li class="">Tag the merge commit (<code>git tag v0.10.0 origin/main &amp;&amp; git push --tags</code>) — or use the GitHub UI's "Draft a new release → Generate release notes" flow.</li>
<li class="">CD takes over: multi-arch build, cosign sign, attest build-provenance + SBOM, Trivy scan, attach SBOM to the Release.</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="community-polish">Community polish<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0#community-polish" class="hash-link" aria-label="Direct link to Community polish" title="Direct link to Community polish" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>.github/ISSUE_TEMPLATE/config.yml</code></strong> — adds contact links above the existing Bug/Feature templates pointing to the docs site, GitHub Discussions, and the private security advisory flow.</li>
<li class=""><strong>GitHub Discussions</strong> referenced from the issue config + docs site footer — needs a one-time toggle under repo Settings → General → Features → Discussions to activate.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrading">Upgrading<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0#upgrading" class="hash-link" aria-label="Direct link to Upgrading" title="Direct link to Upgrading" translate="no">​</a></h3>
<p>Image-side: <code>docker pull ghcr.io/rubentalstra/librechat-prom-exporter:0.9.0</code>. No code changes; behavior identical to v0.8.0. The version number is bumped just to land a clean release tag for the docs site.</p>
<p>If you've bookmarked specific README sections, update those bookmarks to the docs site:</p>
<table><thead><tr><th>Old README anchor</th><th>New docs site URL</th></tr></thead><tbody><tr><td><code>#environment-variables</code></td><td><code>/docs/reference/environment-variables</code></td></tr><tr><td><code>#auth-on-metrics</code></td><td><code>/docs/reference/auth</code></td></tr><tr><td><code>#tuning</code></td><td><code>/docs/guides/tuning</code></td></tr><tr><td><code>#troubleshooting</code></td><td><code>/docs/guides/troubleshooting</code></td></tr><tr><td><code>#dashboard-example</code></td><td><code>/docs/dashboard</code></td></tr></tbody></table>]]></content>
        <author>
            <name>Ruben Talstra</name>
            <uri>https://github.com/rubentalstra</uri>
        </author>
        <category label="release" term="release"/>
        <category label="docs" term="docs"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[v0.8.0 — Hardening release]]></title>
        <id>https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0</id>
        <link href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0"/>
        <updated>2026-05-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[v0.8.0 is a major hardening release rolling up four merged integration PRs. Every layer of the project — metrics correctness, HTTP server, container, CI/CD, docs — got polish. No breaking changes for default-config deployments; auth and tenant scoping remain opt-in.]]></summary>
        <content type="html"><![CDATA[<p>v0.8.0 is a major hardening release rolling up four merged integration PRs. Every layer of the project — metrics correctness, HTTP server, container, CI/CD, docs — got polish. No breaking changes for default-config deployments; auth and tenant scoping remain opt-in.</p>
<!-- -->
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="metrics-correctness--performance">Metrics correctness &amp; performance<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0#metrics-correctness--performance" class="hash-link" aria-label="Direct link to Metrics correctness &amp; performance" title="Direct link to Metrics correctness &amp; performance" translate="no">​</a></h3>
<ul>
<li class=""><strong>Tenant-leak fix</strong>: <code>Conversation.estimatedDocumentCount()</code> (which is tenant-blind by design) was replaced with <code>countDocuments({})</code> so the tenant hook applies. Fixes inflated <code>librechat_cost_per_conversation_avg</code> for multi-tenant installs.</li>
<li class=""><strong>6× redundant <code>$lookup</code> against <code>users</code> eliminated</strong> — all six places now use the pre-loaded <code>userIdToEmail</code> map. Material advanced-scrape speedup on large installs.</li>
<li class=""><strong><code>allowDiskUse: true</code></strong> added to every <code>$facet</code> / <code>$group</code> that touches the full <code>messages</code> or <code>transactions</code> collection. Prevents Mongo's 100 MB in-memory aggregation limit from biting on real LibreChat installs.</li>
<li class=""><strong>Index assertions</strong> extended: now warns on missing recommended indexes for <code>messages.createdAt</code>, <code>messages.{isCreatedByUser,createdAt}</code>, <code>files.user</code>, <code>transactions.user</code>, <code>transactions.conversationId</code>.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="http-hardening--optional-auth">HTTP hardening + optional auth<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0#http-hardening--optional-auth" class="hash-link" aria-label="Direct link to HTTP hardening + optional auth" title="Direct link to HTTP hardening + optional auth" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>helmet</code></strong> applied with sensible defaults (no CSP since <code>/metrics</code> returns text, no CORP).</li>
<li class=""><strong><code>compression</code></strong> middleware — significant payload reduction on <code>/metrics</code>.</li>
<li class=""><strong><code>express-rate-limit</code></strong> with separate per-IP limiters for <code>/metrics</code> (default 120/min) and <code>/health</code> (600/min).</li>
<li class=""><strong><code>/metrics</code> auth</strong> — four optional methods, all off by default: static bearer (<code>METRICS_BEARER_TOKEN</code>), HTTP Basic (<code>METRICS_BASIC_AUTH_USER</code> + <code>METRICS_BASIC_AUTH_PASSWORD</code>), OAuth2/OIDC JWT (<code>METRICS_OAUTH2_*</code>), IP allowlist (<code>METRICS_ALLOWED_IPS</code>). Constant-time comparison; rate-limited reject logging. See <a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/docs/reference/auth">Auth</a>.</li>
<li class=""><strong><code>METRICS_PORT</code></strong> — optionally bind <code>/metrics</code> on a separate port so it can be internal-only while <code>/health</code> stays public-reachable.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tooling-foundation">Tooling foundation<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0#tooling-foundation" class="hash-link" aria-label="Direct link to Tooling foundation" title="Direct link to Tooling foundation" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>pino</code></strong> structured logging — every <code>console.*</code> call swapped for the singleton logger. Pretty in dev, JSON in prod.</li>
<li class=""><strong><code>zod</code></strong> env validation — every env var schema-checked at boot. Misconfig fails fast with a clear list of issues. Replaces ad-hoc <code>parseInt</code> and <code>envFlag</code>.</li>
<li class=""><strong><code>vitest</code></strong> + 46 tests across <code>config</code>, <code>util</code>, <code>tenantHooks</code>, <code>metricsAuth</code>. JWT signing + JWKS mocking via <code>nock</code> for the OAuth2 path.</li>
<li class=""><strong><code>prettier</code></strong> + <strong><code>husky</code></strong> + <strong><code>lint-staged</code></strong> for consistent style and pre-commit hooks.</li>
<li class=""><strong>tsconfig modernization</strong>: <code>target: ES2023</code>, <code>noUncheckedIndexedAccess: true</code>, <code>exactOptionalPropertyTypes: true</code>, <code>sourceMap: true</code>.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="container--cicd">Container + CI/CD<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0#container--cicd" class="hash-link" aria-label="Direct link to Container + CI/CD" title="Direct link to Container + CI/CD" translate="no">​</a></h3>
<ul>
<li class=""><strong>Base image</strong>: distroless → <strong>Chainguard <code>cgr.dev/chainguard/node:latest</code></strong>. Daily rebuilds against the latest CVE fixes; currently zero CRITICAL/HIGH CVEs at every severity.</li>
<li class=""><strong>OCI labels + annotations</strong> via <code>docker/metadata-action</code> — description, vendor, source, license, documentation all visible on the GHCR Packages page (no more "No description provided").</li>
<li class=""><strong>SLSA build provenance</strong> + <strong>SBOM attestation</strong> via GitHub's native framework (<code>actions/attest-build-provenance@v4</code> + <code>actions/attest-sbom@v4</code>). <code>push-to-registry: false</code> so they live in GitHub's attestation DB and don't clutter GHCR. Verifiable with <code>gh attestation verify oci://...</code>.</li>
<li class=""><strong><code>cosign</code> keyless signing</strong> of every published tag via Sigstore.</li>
<li class=""><strong>Multi-arch-safe cleanup workflow</strong> — <code>actions/delete-package-versions@v5</code> is not manifest-aware (known upstream bugs); replaced with <code>dataaxiom/ghcr-cleanup-action@v1</code> which understands manifest lists, cosign signatures, and attestation referrers.</li>
<li class=""><strong>Weekly Trivy scan</strong> of the published <code>:latest</code> — catches CVEs introduced after publish (base-image regression, new Debian advisories) and reports them to GitHub Code Scanning.</li>
<li class=""><strong>PR-time <code>docker build</code></strong> added to CI so Dockerfile regressions surface at review time, not after merge.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrading">Upgrading<a href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.8.0#upgrading" class="hash-link" aria-label="Direct link to Upgrading" title="Direct link to Upgrading" translate="no">​</a></h3>
<ul>
<li class=""><code>docker pull ghcr.io/rubentalstra/librechat-prom-exporter:0.8.0</code>. No env-var changes needed for existing deployments.</li>
<li class="">New env vars are all opt-in: see <a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/docs/reference/environment-variables">Environment variables</a>.</li>
</ul>
<p>Thanks to everyone who reported issues during the integration PRs.</p>
<p>(A separate documentation site landed in <a class="" href="https://rubentalstra.github.io/librechat-prom-exporter/blog/v0.9.0">v0.9.0</a> — that's the recommended way to read these docs going forward.)</p>]]></content>
        <author>
            <name>Ruben Talstra</name>
            <uri>https://github.com/rubentalstra</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
</feed>