Skip to main content

Use cases

Knowledge base

Internal-only docs for engineers + operators at your own company. Runbooks, postmortems, onboarding, architecture docs. Different audience than public docs, same platform, different governance.

A knowledge base is docs for your own team — engineers, customer support, ops, new hires. Runbooks, postmortems, onboarding material, internal process docs, architecture deep-dives. Different readership than the public docs + help center, different maintenance model, usually different privacy requirements.

Many teams split internal KB from public docs (Notion / Confluence / GitHub wiki for internal; NookDocs for public). But there's a case for unifying — single tooling, same editor, consistent voice, shared components. This guide covers the unified pattern and the split pattern; pick the one that matches your scale.

Public docs vs internal KB

AxisPublic docs / help centerInternal knowledge base
AudienceCustomers, prospects, integratorsEmployees, contractors
VoiceOutward-facing, vettedTerse, opinionated, operational
MaintenanceScheduled (per release + quarterly)Continuous, often ad hoc
PrivacyPublic by defaultGated by default
Content typesTutorials, reference, explanationsRunbooks, postmortems, decision docs
Search intent"How do I X with Acme?""What's the current on-call runbook?"
Review cadencePR review per changeVaries — sometimes none, sometimes heavier

These differences push most teams toward separate tooling. But they can coexist — below.

Two architectures

Architecture 1: Separate tenant per audience

Run two NookDocs projects on separate subdomains:

docs.acme.com       — public docs (open, indexed)
internal.acme.com   — knowledge base (private, auth-gated)

Pros:

  • Clean privacy story — internal tenant sets seo.indexing: "noindex" + middleware-level auth.

  • Different themes / branding if your public docs are marketing-adjacent.

  • No leak risk — public readers literally can't reach internal content.

Cons:

  • Two repos, two build pipelines, two editor experiences.

  • Writers context-switch when a doc needs to live in both.

Best for: teams 20+ engineers where the KB has its own dedicated maintainers.

Architecture 2: Single tenant, internal pages gated

One NookDocs project. Public content surfaces normally; internal content lives under pages with hidden: true or authGroups: ["employees"] (when the auth layer ships — see personalization).

Pros:

  • Single source of truth — a page that's "mostly public but with an internal section" can use <Visibility for="agents">-style splits (needs to be built — this is a roadmap extension of the existing <Visibility> component).

  • One repo, one build, one editor.

  • Easier to move content from internal to public as features launch.

Cons:

  • Privacy-by-accident risk — a misconfigured page leaks internal content.

  • Public-facing search surfaces must exclude internal pages at multiple layers (sitemap + search + AI assistant RAG).

  • Auth layer needs to be real + battle-tested.

Best for: teams under 20 engineers, or teams where public docs and internal KB genuinely share content (integration partner docs, for example).

Today on NookDocs: Architecture 1 is the shipping pattern. Architecture 2 requires the auth layer + per-page viewer-based gating (both on the roadmap per personalization guide).

The four KB sections every team needs

1. Onboarding

Week-one + month-one reading for new engineers. Architecture overview, repo map, dev environment setup, deployment walkthrough, team norms.

2. Runbooks

Operational procedures. "How to deploy a hotfix", "Recovering from X incident", "Rotating the OAuth secret". Short, actionable, frequently used.

3. Decision records (ADRs)

Why we chose X over Y. Date, context, alternatives, decision, consequences. Lets future engineers understand legacy choices without polling Slack archeology.

4. Postmortems

After-incident writeups. Blameless. Actionable. Often the most-read KB pages because the lessons apply across teams.

Onboarding flow

A great onboarding KB sequence for a new engineer:

Day 0 — pre-start

Background reading sent before day 1: company-wide mission, product overview, primary customer persona. Non-technical if the hire hasn't started yet.

Day 1 — orientation

Team structure, who owns what, how to reach people. Access setup (GitHub, Slack, dashboards, VPN). Dev environment stand-up checklist.

Week 1 — first PR

Pointer to the repo, code style guide, small starter issue, pairing partner. Ship something to production by Friday.

Month 1 — core architecture

Deep-dive pages: request lifecycle, data model, deployment story, observability stack. 1 page per major system.

Month 1 — team norms

PR review expectations, on-call rotation, oncall handoff ritual, meeting culture, how we communicate (sync vs async).

Most onboarding KBs fail by treating month-1 content as day-1 reading. Staged disclosure matters.

Runbook pattern

Every runbook follows the same structure:

---
title: Rotate the OAuth client secret
description: Required monthly OR when exposure suspected. 15-minute process; requires deploy + coordinated user session invalidation.
---

## TL;DR

1. Generate new secret in IdP admin console.
2. Deploy code change referencing new env var.
3. Confirm new secret works + old still works (grace period).
4. Remove old secret from IdP after 24h.

## Prerequisites

- IdP admin access (Okta console)
- Deploy access to production
- On-call coordination for any downtime window

## Steps

<Steps>
  <Step title="Generate new secret">
    ...
  </Step>
  ...
</Steps>

## Verification

- [ ] Users can still log in (check analytics dashboard for active sessions)
- [ ] No error spike in observability (10 min after deploy)
- [ ] Old secret rejected after revoke (test with old creds)

## Escalation

If step 3 fails (new secret doesn't work), revert deploy immediately.
Old secret remains valid during grace period. Page on-call lead if
revert + retry needed.

## Change log

- 2026-04-15 — Added IdP console screenshot (ESM)
- 2025-11-02 — Updated to new Okta admin flow (KTA)

Every runbook: TL;DR, prereqs, steps, verification, escalation, change log. Same every time. Readers under pressure scan for the right section.

ADR (Architecture Decision Record) pattern

---
title: "ADR-042: Use Postgres FTS instead of Elasticsearch for docs search"
description: 2026-04 decision. Trade-off between operational complexity and feature depth; FTS chosen for MVP.
---

## Context

We needed full-text search for tenant docs pages. Options considered:
- Elasticsearch (industry standard, high operational cost)
- Algolia (SaaS, fast, but adds a vendor)
- Postgres FTS (already in stack, less feature-rich)

## Decision

Ship Postgres FTS with pg_trgm + GIN index. Defer Elasticsearch
or Algolia until scale warrants.

## Consequences

**Good:**
- Zero new infrastructure to operate
- Syncs atomically with page writes (no eventual consistency)
- Free at current scale

**Trade-offs:**
- No fuzzy match beyond trigram (typos 1-2 chars work; longer distance don't)
- No synonym expansion without manual tables
- 100ms query latency at 100k pages; needs watching at 1M+

## Related ADRs

- ADR-038: Multi-tenant query isolation via project_id
- ADR-057: (Future) Embedding-based hybrid search

ADRs are append-only. Never edit — supersede by writing a new ADR referencing the old one.

Postmortem pattern

---
title: "PM-2026-04-18: API 5xx spike during deploy #14592"
description: Root cause, user impact, fix, lessons. Blameless.
---

## Summary

2026-04-18, 14:02 UTC. Deploy #14592 introduced a null-pointer crash
in the rate-limiter. ~8% of requests returned 500 for 23 minutes
before rollback.

## Timeline (UTC)

- **14:02** — Deploy #14592 completes (canary 10% traffic)
- **14:04** — Sentry error rate breaches alert threshold
- **14:06** — On-call paged
- **14:09** — Root cause identified (nil check missing in new code path)
- **14:12** — Rollback started
- **14:25** — Rollback complete; error rate back to baseline
- **14:30** — Customer comms sent via status page

## User impact

- ~2,400 failed API requests across ~180 tenants
- Support tickets from 8 tenants
- No data loss (idempotency keys preserved; failures returned HTTP
  500 without partial writes)

## Root cause

The rate-limiter code path added in #14592 accessed `request.user.tier`
without checking whether `user` was set. Unauthenticated requests
(API key without user) produced nil access → crash.

## Fix

- Short-term: rolled back #14592 (deployed 14:12).
- Short-term: hotfix in #14599 with nil guard shipped 15:30.
- Long-term: add unit test coverage for unauthenticated code paths.

## Lessons (blameless)

- The deploy pipeline's canary at 10% DID detect the issue — this is
  working as designed. Time-to-detect was 2 minutes.
- Time-to-revert was 10 minutes; could be faster with better
  tooling. Opened infra ticket #8812 to investigate.
- Test coverage gap: unauthenticated rate-limiter paths. Added to
  test suite in #14600.

## Action items

- [ ] @alice — add pre-commit check for nil access in rate-limiter
- [ ] @bob — faster rollback tooling (target TTR <5min)
- [ ] @carol — document canary traffic split in the deploy runbook

Blameless > detailed blame. Action items with owners + accountability, not just "we should do better."

KB privacy + auth

For Architecture 1 (separate internal tenant):

  • seo.indexing: "noindex" site-wide in the internal tenant's nookdocs.config.json. Ensures search engines don't index internal content.

  • Middleware auth at the proxy / CDN layer. Cloudflare Zero Trust, Vercel auth, or your own OAuth-proxy in front of the internal domain.

  • No anonymous read — every request requires a valid session cookie or bearer token.

For Architecture 2 (unified tenant with internal pages):

  • Roadmap: per-page authGroups gating (not yet enforced at runtime).

  • Today: use hidden: true frontmatter for "obscure by URL" content. NOT true privacy — if a URL leaks, content is readable. Don't put secrets here.

When your KB grows past 100 pages

Scale challenges:

  • IA rot — what started as 5 sections is now 20. Revisit navigation IA.

  • Stale content explosion — 100 pages of runbooks, many from years ago. Apply maintenance quarterly audits more aggressively here than public docs.

  • Search quality — more pages = more noise. Consider per-team scope filters in search.

  • Ownership fragmentation — without clear per-page owners, no one updates. Add a owner: frontmatter field + quarterly review assignment.

At 500+ pages, consider splitting the KB further — per-team micro-KBs rolled up to a top-level index.

Common KB mistakes

Related

Was this page helpful?

Last updated August 7, 2026