> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hr-easy.nlead.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# The docs site

> Running this documentation locally, how it deploys, and the docs.hr-easy.nlead.ch custom domain.

This documentation is a [Mintlify](https://mintlify.com) site living in the product
repository at `docs/site/`, published at **docs.hr-easy.nlead.ch**.

## Layout

```
docs/site/
  docs.json              # navigation, theme, domain
  favicon.svg
  logo/light.svg
  logo/dark.svg
  index.mdx              # landing page
  quickstart.mdx
  concepts/              # architecture, roles, surfaces, philosophy
  guides/                # the product guide, by module
  swiss/                 # Swiss compliance
  api-reference/
    introduction.mdx
    authentication.mdx
    conventions.mdx
    portal.v1.json       # generated — do not hand-edit
  development/           # contributor documentation
  operations/            # this section
```

## Running it locally

```bash theme={null}
npm install -g mint
cd docs/site
mint dev
```

Serves on `http://localhost:3000` with hot reload. Note that the app's dev server uses
the same port — stop one before starting the other, or pass `mint dev --port 3333`.

Check links before pushing:

```bash theme={null}
cd docs/site
mint broken-links
```

## The generated API reference

`docs/site/api-reference/portal.v1.json` is **generated**, not written. It is one of the
committed artifacts produced by:

```bash theme={null}
npm run gen:openapi
```

which writes both `openapi/portal.v1.json` (the canonical cross-repo artifact the mobile
app generates its client from) and the docs-site copy. Mintlify resolves `openapi` paths
relative to its own `docs.json` directory, which is why a copy lives inside `docs/site/`
rather than being referenced across the repository.

`npm run check:openapi-drift` verifies **both** byte-for-byte against the Zod schemas and
runs in `npm run check:all`, so the two can never diverge. The artifact list itself is a
single shared constant pinned by a test.

<Warning>
  Never hand-edit `portal.v1.json` in either location, and do not let Prettier reformat it — both
  paths are in `.prettierignore` because a reformat would fight the drift gate. Change the Zod
  schema and regenerate.
</Warning>

## Deployment

The Mintlify GitHub App watches the repository and deploys on every push to the default
branch (`develop`), with the docs directory configured as `docs/site`. Both settings
live in the dashboard under **Settings → Deployment → Git settings**
(`app.mintlify.com/settings/deployment/git-settings`): install the app on
`RaiNotter/swiss-hr-easy` only, set the branch to `develop` and the docs path to
`docs/site`. Until the custom domain below is live, the site answers at the
`*.mintlify.site` address shown on the dashboard's Overview page.

Because documentation-only PRs take the [CI fast path](/development/quality-gate#ci-is-change-aware),
a docs change goes through a \~3-minute static leg rather than the full \~15-minute gate.

## The custom domain

<Steps>
  <Step title="Add the domain in Mintlify">
    In the Mintlify dashboard, open **Settings → Deployment → Custom domain**
    (`app.mintlify.com/settings/deployment/custom-domain`), enter
    `docs.hr-easy.nlead.ch` and leave the **Host at** toggle off (that toggle is
    for hosting under a path of an existing site). The dashboard then lists the
    DNS records to create.
  </Step>

  <Step title="Create the DNS records">
    In the DNS zone for `nlead.ch`, add the two verification `TXT` records first,
    wait until the dashboard shows both as verified, and only then add the `CNAME`:

    | Type    | Name                               | Value                            | TTL  |
    | ------- | ---------------------------------- | -------------------------------- | ---- |
    | `TXT`   | `_acme-challenge.docs.hr-easy`     | *(value shown in the dashboard)* | 3600 |
    | `TXT`   | `_cf-custom-hostname.docs.hr-easy` | *(value shown in the dashboard)* | 3600 |
    | `CNAME` | `docs.hr-easy`                     | `cname.mintlify.builders`        | 3600 |

    <Note>
      Use the values the dashboard shows rather than the ones written here. Mintlify
      has changed its CNAME target before, and the dashboard is authoritative. If
      `nlead.ch` is proxied through Cloudflare, add the CNAME right after the TXT
      records instead of waiting for verification.
    </Note>
  </Step>

  <Step title="Wait for propagation and the certificate">
    A TLS certificate is issued automatically once the CNAME resolves. Verify:

    ```bash theme={null}
    dig +short docs.hr-easy.nlead.ch CNAME
    curl -sI https://docs.hr-easy.nlead.ch | head -1
    ```
  </Step>

  <Step title="Confirm the site answers">
    Load `https://docs.hr-easy.nlead.ch`, check that the navigation renders all six tabs,
    and that the API-reference tab lists the portal endpoints.
  </Step>
</Steps>

### Verification

* [ ] `docs.hr-easy.nlead.ch` resolves to the Mintlify CNAME target.
* [ ] HTTPS serves a valid certificate; HTTP redirects to it.
* [ ] All six navigation tabs render.
* [ ] The API-reference tab shows generated endpoint pages.
* [ ] Search returns results.
* [ ] The site renders correctly in both light and dark appearance.

<Warning>
  `docs.hr-easy.nlead.ch` is a **public** site. It documents the product, not any
  customer's installation. Never put a customer's resource names, contacts, hostnames or
  configuration here — those belong in the customer overlay under
  `docs/customers/<customer>/` in the repository.
</Warning>

## Editing conventions

* Page files are `.mdx` with `title` and `description` frontmatter.
* Navigation is `docs.json` — a new page must be added there or it is unreachable.
* Internal links are absolute from the docs root: `/guides/payroll/overview`, with no
  file extension.
* Prettier formats the MDX, so run `npm run format` before committing.
* Keep the page slug stable once published; a rename breaks external links.

## When product behaviour changes

Update the page in the **same PR** as the code. The documentation is not a separate
deliverable — a docs page that describes last quarter's behaviour is trusted and wrong,
which is the worst combination.
