Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/chronicle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ site:
title: Chronicle
description: Config-driven documentation framework

url: https://chronicle.raystack.org

logo:
light: /logo.svg
dark: /logo-dark.svg

content:
- dir: docs
label: Docs
Expand All @@ -18,6 +24,30 @@ search:
enabled: true
placeholder: Search docs...

# The docs were reorganised into groups. These keep every old link working.
redirects:
- from: /docs/features
to: /docs
permanent: true
- from: /docs/cli
to: /docs/reference/cli
permanent: true
- from: /docs/configuration
to: /docs/reference/config
permanent: true
- from: /docs/frontmatter
to: /docs/reference/frontmatter
permanent: true
- from: /docs/components
to: /docs/writing/components
permanent: true
- from: /docs/image-optimization
to: /docs/writing/images
permanent: true
- from: /docs/docker
to: /docs/deploy/docker
permanent: true

telemetry:
enabled: true

Expand Down
107 changes: 107 additions & 0 deletions docs/content/docs/deploy/build.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: Build and serve
description: What a production build produces, and how presets change it.
order: 1
---

```bash
chronicle build
chronicle start
```

`build` writes the production site. `start` serves what `build` produced — it
does not build for you, so the order matters. `chronicle serve` runs both, which
is handy locally and wrong in a deployment, where you want the build to happen
once and the server to start many times.

## Two kinds of output

The `preset` decides which you get, and it is the only decision that really
matters here.

**A server build** produces a small server. Pages are rendered per request,
which is what makes search, image resizing and the API request tester work.
This is the default.

**A static build** produces a single-page app: one `index.html`, a JavaScript
bundle, and a small JSON file per page that the app fetches as the reader
navigates. There is no process to run and nothing to keep alive.

```yaml
preset: static
```

Or per build:

```bash
chronicle build --preset static
```

## What you give up going static

There is no server, so the parts that needed one change:

| | Server build | Static build |
|---|---|---|
| Page HTML | Rendered per request, works with JavaScript off | One shell; pages filled in by JavaScript |
| Search | Queried per request | Whole index downloaded, searched in the browser |
| Images | Resized on demand, then cached | Resized once, during the build |
| API request tester | Proxies through your server | Not available |
| Health and readiness | `/api/health`, `/api/ready` | Not available |
| Redirects | Served by Chronicle | Your host has to do them |

Everything else is generated either way: navigation, versions, the API
reference, markdown URLs, `llms.txt`, the sitemap and social cards.

The first row matters most. A server build sends finished HTML, so a crawler or
a reader with JavaScript off gets the page. A static build sends a shell, so
they get very little. If search ranking matters to you, that is the argument for
a server build.

Pick static for a small or medium site you want on a CDN with nothing to
operate. Pick a server build for a large site, when search needs to stay fast,
or when the request tester matters.

## Where the output goes

| Preset | Output directory |
|---|---|
| unset, `node-server`, `cloudflare` | `.output/` |
| `static`, `cloudflare-pages`, `github-pages` | `.output/public/` |
| `vercel`, `vercel-static` | `.vercel/output/` |

A static host has to send unknown paths to `index.html`, because every page
shares that one file. Getting this wrong is the usual reason a deep link 404s
while the home page works — see [Deploy](/docs/deploy/hosting).

Gitignore whichever applies. `chronicle init` adds `.output` for you.

## Build failures

The build stops on a page it cannot parse, and names the file and the line. This
is deliberate — a docs site that silently drops a broken page is worse than one
that refuses to build.

The usual cause is MDX being stricter than markdown about `<` and `{`, which it
reads as the start of a component or an expression. Wrap the character in
backticks.

## In CI

```bash
bun install
bun run chronicle build --preset static
```

Then publish the output directory. The build needs no network access beyond
installing packages, and no services.

If your build machine is not the machine that serves the site, remember `start`
needs the `.output/` directory that `build` wrote — copy it, or build on the
host.

## Next

- [Deploy](/docs/deploy/hosting) — putting the output on a host
- [Docker](/docs/deploy/docker) — running from the container image
- [Monitoring](/docs/deploy/monitoring) — health checks and metrics
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
---
title: Docker
description: Run Chronicle with Docker.
order: 8
description: Run Chronicle from the official container image.
order: 3
---

# Docker

Chronicle is available as a Docker image on [Docker Hub](https://hub.docker.com/r/raystack/chronicle).

## Pull the Image
Expand Down
186 changes: 186 additions & 0 deletions docs/content/docs/deploy/hosting.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
---
title: Deploy
description: Put a built site on Vercel, Cloudflare, a Node host, or any static host.
order: 2
---

Pick the preset that matches your host, build, and publish the output. The
preset is the only Chronicle-specific part — everything after it is your host's
normal workflow.

Set it in the config so every build agrees:

```yaml
preset: vercel
```

Or pass it per build, which is what you want if the same repository deploys to
more than one place:

```bash
chronicle build --preset static
```

## Vercel

```yaml
preset: vercel
```

```bash
chronicle build
```

The build writes `.vercel/output`, which is the directory Vercel deploys
directly. Set the build command to `chronicle build` and leave the output
directory at its default.

For a site that does not need per-request search or the API request tester, use
`vercel-static` instead. Same output location, built as a single-page app.

## Cloudflare

For Workers:

```yaml
preset: cloudflare
```

The build writes `.output/`. Deploy it with Wrangler.

For Pages, use the static preset built for it:

```yaml
preset: cloudflare-pages
```

That writes `.output/public/`. Point your Pages project at that directory.

## A Node host

Any host that runs a Node process — a VM, a container platform, a PaaS.

```yaml
preset: node-server
```

```bash
chronicle build
chronicle start --port 3000 --host 0.0.0.0
```

`--host 0.0.0.0` matters. The default binds to localhost, which works on your
machine and refuses connections from outside a container.

Point the platform's health check at `/api/health`, and its readiness check at
`/api/ready` if it has a separate one. See
[Monitoring](/docs/deploy/monitoring).

There is a container image if you would rather not build your own — see
[Docker](/docs/deploy/docker).

## GitHub Pages

```yaml
preset: github-pages
```

The build writes `.output/public/`. A workflow that builds and publishes it:

```yaml
name: docs
on:
push:
branches: [main]

permissions:
contents: read
pages: write
id-token: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run chronicle build --preset github-pages
# GitHub Pages cannot rewrite unknown paths, but it does serve 404.html
# for them — so a copy of the app shell makes deep links work.
- run: cp .output/public/index.html .output/public/404.html
- uses: actions/upload-pages-artifact@v3
with:
path: .output/public
deploy:
needs: build
runs-on: ubuntu-latest
environment: github-pages
steps:
- uses: actions/deploy-pages@v4
```

## Any other static host

```yaml
preset: static
```

`chronicle build` writes `.output/public/`. Upload it to S3, Netlify, a CDN, or
an nginx document root. There is nothing to run.

### Send unknown paths to index.html

This one step catches most people. A static build is a single-page app, so every
page is served by the same `index.html`. Without a rewrite rule the home page
works and `/docs/quick-start` returns a 404.

On nginx:

```nginx
location / {
try_files $uri $uri/ /index.html;
}
```

On Netlify, a `_redirects` file in the published directory:

```
/* /index.html 200
```

Most CDNs call this a "SPA fallback" or "rewrite to index". Whatever the name,
it is the same rule.

## Set `url` before you ship

```yaml
url: https://docs.example.com
```

Without it there are no absolute URLs for the sitemap, no canonical link tags,
and no social cards — a social network needs an absolute address to fetch a card
image from. It is the single easiest thing to forget and the one most visible
once the site is public.

## Redirects survive the move

If your docs used to live somewhere else, or you moved pages during the
migration, `redirects` in the config are served by Chronicle itself. They work
the same on every server preset.

Static presets have no server to run them, so on a static host use the host's
own redirect mechanism — the same place you configured the rewrite above. See
[Links and redirects](/docs/writing/links).

## A checklist

Before you call it done:

- `url` is set
- `/sitemap.xml` and `/robots.txt` return something sensible
- Search finds a page you know exists
- A shared link shows a social card
- Old URLs still resolve, if any moved
- Health check points at `/api/health`, on a server build
- A deep link like `/docs/quick-start` loads directly, on a static build
1 change: 1 addition & 0 deletions docs/content/docs/deploy/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "title": "Deploy and operate", "order": 8 }
Loading
Loading