Build a Documentation Site

Create a structured documentation site with sidebar navigation, full-text search, and a custom domain.

intermediate15 min read

What You'll Build

In this guide you will build a structured documentation site powered by Lifestream Vault — the same stack used for professional product docs, API references, and knowledge bases.

By the end you will have:

  • A docs vault with an organised folder hierarchy
  • Versioned documentation using path-based v1/, v2/ directories
  • A working table of contents generated automatically from headings
  • Full-text search across all documents
  • A publicly accessible docs site with sidebar navigation
  • An optional custom domain (e.g. docs.example.com)

You can manage everything through the Lifestream Vault web UI, the TypeScript SDK, or the lsvault CLI.

Prerequisites

  • A Lifestream Vault account
  • Pro tier or higher to enable vault publishing and full-text search
  • Business tier to attach a custom domain
  • Node.js 18+ (for SDK and CLI usage)

Create Your Docs Vault

A vault is an isolated document container that maps to a single published site. Give your docs vault a descriptive name and a clean slug — the slug becomes part of every public URL.

Via the UI: open Settings → Vaults → New Vault, enter a name (e.g. Product Docs) and a slug (e.g. product-docs), then click Create.

Or use the SDK or CLI:

typescript
import { LifestreamVaultClient } from '@lifestreamdynamics/vault-sdk';

const { client } = await LifestreamVaultClient.login(
  'https://vault.lifestreamdynamics.com',
  'you@example.com',
  'your-password',
);

// The slug is generated from the name — you do not pass it.
const vault = await client.vaults.create({
  name: 'Product Docs',
});

console.log('Vault ID:', vault.id);
console.log('Vault slug:', vault.slug);

Organise with a Folder Structure

Every document in a vault is identified by its path — a forward-slash-delimited string ending in .md. Organising documents into folders gives your site a clear hierarchy that is reflected in the sidebar navigation when the vault is published.

A recommended layout for a documentation site:

product-docs/
├── index.md                    # Site home / landing page
├── getting-started.md          # Quick-start for new users
├── installation.md             # Installation instructions
├── api-reference/
│   ├── index.md                # API overview
│   ├── authentication.md
│   ├── endpoints.md
│   └── errors.md
├── guides/
│   ├── index.md                # Guides overview
│   ├── advanced-config.md
│   └── integrations.md
└── changelog.md                # Version history

The published sidebar mirrors this tree structure exactly. Folders appear as collapsible groups; the index.md inside each folder becomes the group's landing page.

Naming conventions:

  • Use lowercase, hyphen-separated names (e.g. api-reference, getting-started)
  • Avoid spaces and special characters in paths
  • Keep paths short — they appear in public URLs
typescript
// Create the initial document scaffold via the SDK
const docPaths = [
  'index.md',
  'getting-started.md',
  'installation.md',
  'api-reference/index.md',
  'api-reference/authentication.md',
  'api-reference/endpoints.md',
  'guides/index.md',
  'guides/advanced-config.md',
  'changelog.md',
];

for (const docPath of docPaths) {
  await client.documents.put(
    vault.id,
    docPath,
    `# ${docPath.replace(/\.md$/, '').replace(/[-/]/g, ' ')}

Content coming soon.`,
  );
  console.log('Created:', docPath);
}

Table of Contents via Headings

Lifestream Vault automatically generates an in-page table of contents from the heading hierarchy in each document. The renderer scans #, ##, and ### headings and builds a nested, clickable ToC that appears beside the content.

To get a well-structured ToC, follow these conventions:

  • Use a single # (H1) as the document title — it does not appear in the ToC itself
  • Use ## (H2) for top-level sections
  • Use ### (H3) for subsections within an H2

Here is an example well-structured document:

---
title: Authentication
description: How to authenticate requests to the Product API.
---

# Authentication

All API requests must include a valid Bearer token in the `Authorization` header.

## Obtaining a Token

You can obtain tokens via the login endpoint or by creating an API key.

### Login Endpoint

POST your credentials to `/api/v1/auth/login` to receive a short-lived access token.

### API Keys

API keys are long-lived tokens scoped to specific operations. Create them in
**Settings → API Keys**.

## Token Expiry

Access tokens expire after **15 minutes**. Use the refresh endpoint to obtain a
new token without re-authenticating.

## Error Codes

| Code | Meaning |
|------|---------|
| 401  | Missing or invalid token |
| 403  | Token lacks required scope |

This document produces a ToC with three H2 entries (Obtaining a Token, Token Expiry, Error Codes) and two H3 sub-entries nested under Obtaining a Token.

The ToC is generated at render time — you never need to write or maintain it manually. Keep your heading hierarchy clean and the ToC stays accurate automatically.

Versioning with Document Paths

Documentation for different product versions lives in separate top-level folders. The pattern v1/, v2/, etc. keeps versions cleanly separated and maps naturally to sidebar groups.

product-docs/
├── v1/
│   ├── getting-started.md
│   ├── api-reference/
│   │   └── authentication.md
│   └── changelog.md
├── v2/
│   ├── getting-started.md
│   ├── api-reference/
│   │   └── authentication.md
│   └── changelog.md
└── index.md    # Points readers to the latest version

When you create a new major version, create the v2/ folder and migrate or copy documents from v1/. The older version remains publicly accessible at its original paths — no redirects needed.

typescript
// Create the v2 getting-started document
const gettingStartedV2 = await client.documents.put(
  vault.id,
  'v2/getting-started.md',
  `---
title: Getting Started (v2)
description: Quick-start guide for Product v2.
---

# Getting Started

Welcome to Product v2! This version introduces a new authentication model
and an improved API surface.

## What Changed in v2

- Bearer tokens replaced by signed JWTs with shorter expiry
- Rate limits increased to 1000 req/min on Pro tier
- New \`/api/v2/batch\` endpoint for bulk operations
`,
);

// Copy the v1 authentication reference to v2 with updates
await client.documents.put(
  vault.id,
  'v2/api-reference/authentication.md',
  `---
title: Authentication (v2)
---

# Authentication

v2 uses signed JWTs issued by the \`/api/v2/auth/token\` endpoint.
`,
);

console.log('v2 docs created:', gettingStartedV2.id);

Publish Your Docs Site

Publishing turns your vault into a publicly browsable documentation site complete with:

  • A sidebar reflecting your folder hierarchy
  • In-page table of contents on each document
  • A search bar across all published content
  • An author profile page linking to all your vaults

Via the UI: open your vault and go to Settings → Publishing → Enable vault publishing.

typescript
// Publish the vault — publishVault.publish is positional: (vaultId, params).
// slug and title are required.
await client.publishVault.publish(vault.id, {
  slug: 'product-docs',
  title: 'Product Docs',
  description: 'Official documentation for Product.',
  showSidebar: true,
  enableSearch: true,
});

// Update published-site settings later with publishVault.update(vaultId, params)
await client.publishVault.update(vault.id, {
  description: 'Official documentation for Product (v2).',
  theme: 'docs',
});

console.log('Documentation site is live!');

After enabling, your docs site is immediately available at:

https://vault.lifestreamdynamics.com/{profileSlug}/{vaultSlug}

No build step, CDN configuration, or deployment pipeline required.

Add a Custom Domain

Plan Required

Custom domains require a Business plan. Upgrade in Settings → Subscription.

Serve your docs from docs.example.com (or any subdomain) by adding two DNS records:

Step 1 — TXT record for ownership verification:

TypeHostValue
TXT_lsv-verify.docs.example.comlsv-verify=<token>

The verification token is returned when you register the domain (see below).

Step 2 — CNAME to route traffic:

TypeHostValue
CNAMEdocs.example.comvaults.lifestreamdynamics.com

DNS propagation typically takes 1–60 minutes. Once the TXT record resolves, ownership verification runs automatically via the background domain-verification worker — no manual trigger is needed. Monitor status in Settings → Custom Domains or via the SDK/CLI below.

After verification, Lifestream Vault automatically provisions a TLS certificate for your domain via Let's Encrypt. Your docs site will be available over HTTPS within a few minutes.

typescript
// Step 1 — register the domain (returns verification token).
// create takes only { domain }.
const domainRecord = await client.customDomains.create({
  domain: 'docs.example.com',
});

console.log('Verification token:', domainRecord.verificationToken);
console.log('Add TXT record: _lsv-verify.docs.example.com =', domainRecord.verificationToken);

// Step 2 — verification runs automatically via the background worker once the
// TXT record resolves. Poll status with get(domainId) (positional).
const status = await client.customDomains.get(domainRecord.id);
console.log('Domain status:', status.status); // 'pending' → 'verified'

Tips & Best Practices

Writing Conventions

  • Keep documents focused. One concept per page is easier to search and link to than long all-in-one pages.
  • Use frontmatter consistently. At minimum, include title and description in every document — these power search results and page metadata.
  • Prefer relative paths for internal links. Use [Installation](./installation.md) rather than absolute URLs so links work in both the editor and the published site.

The sidebar reflects alphabetical path ordering by default. Prefix filenames with numbers to control order:

getting-started/
├── 01-introduction.md
├── 02-installation.md
├── 03-first-steps.md
└── 04-next-steps.md

Cross-Linking Documents

Use wikilinks ([[document-slug]]) for internal references. They resolve automatically and are tracked as backlinks, making it easy to see which pages reference a given document.

Keeping Docs Up to Date

  • Attach a webhook on the document.updated event to notify your team in Slack or email when a docs page changes
  • Use the due date frontmatter field (due: 2026-06-01) to flag docs that need review by a certain date — the calendar view highlights overdue documents

Drafts vs Published Pages

Any document in the vault is visible to authenticated team members but is not public until you explicitly publish it. Use this to draft new sections, have them reviewed, and publish when ready — without a separate staging environment.

Search Quality Tips

  • Avoid very short section headings like Overview or Details — they produce weak search signals
  • Include relevant keywords naturally in the first paragraph of each page
  • Add a description frontmatter field; it appears as the search result excerpt

What's Next

You now have a fully published, searchable documentation site on Lifestream Vault. Here are some places to go next: