# Cross-references & the shape of the site

> The documentation is not a set of pages. It is one hypertext with six views over it — the docs, the glossary, the component catalog, the toolbelt, the API object model and the live showcase — and every one of those views is generated from the same files in docs/ and src/.

Source: https://lopifi.com/docs/architecture/03-cross-references
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

# Cross-references & the shape of the site

The documentation is not a set of pages. It is one hypertext with six views over it — the docs, the glossary, the component catalog, the toolbelt, the API object model and the live showcase — and every one of those views is generated from the same files in `docs/` and `src/`.

That is the whole advantage, and it is also the whole risk. Six generated views means six independent implementations of "what does this link to", and the failure mode is never a broken build. It is a link that lands on the right page at the wrong place, or a page that nothing points at.

---

## The one rule

**Every surface links outward the same way, through the same component.**

The alternative — each page inventing its own related-links block, in its own shape — is how a documentation site ends up with pages nothing points at. When there is one component, an orphan is a missing entry rather than a missing design, and it shows up in a diff.

---

## The components

### `SeeAlso`

The standard "where to go from here" block. It takes a list of typed cross-references and renders them as a ruled list with the kind stated on each row.

```tsx
<SeeAlso
  description="A component is specified in one place, defined in another, and running in a third."
  links={[
    { kind: "doc", href: component.docUrl, title: "Payables — the family spec" },
    { kind: "showcase", href: "/showcase/ap", title: "The family, running" },
    { kind: "term", href: "/glossary/three-way-match", title: "Three-way match" },
  ]}
/>
```

**The kind is not decoration.** The six surfaces are genuinely different kinds of answer:

| Kind | What the reader gets |
|---|---|
| `term` | A word, defined in one sentence |
| `doc` | An argument for why something is the way it is |
| `component` | Code you install and then own |
| `tool` | A number, computed |
| `api` | The shape of a payload |
| `showcase` | The thing running, with figures in it |

A reader who cannot tell which of those a link leads to has to click to find out, and mostly does not click.

### `TermRef` and automatic glossary linking

A reader who hits *three-way match* in the middle of a payables spec has no way to know it is defined elsewhere, and the block of terms at the foot of the page is only useful to someone who already finished reading. So the renderer links the **first mention** of each glossary term in a document's prose.

Restraint is the entire design:

- First mention only, and never a term the document is itself the definition of.
- Never inside a heading, a link, a code span or a code block.
- Never a term that is also ordinary English — *account*, *period*, *balance*, *statement*. Those concepts are still in the glossary; they are just not worth interrupting a sentence for.
- Never more than twelve on one page. Past that, the page is a glossary.

Term links are **dotted and in the text colour**, not the accent. An author's link is a destination they chose; an auto-linked term is a definition the build offered. The two should not look the same.

### `PageHeader aside`

The one place on a page where an illustration is allowed to sit — beside the header, dropped entirely on narrow viewports. See [imagery & isometric](../foundations/08-imagery-and-isometric.md).

---

## Anchors: one algorithm, two consumers

Every document in `docs/` is read in two places — on this site and on GitHub — and an author writing `#law-2--data-does-not-re-animate` is reading that anchor off the GitHub heading.

So `headingId` in `src/lib/markdown.ts` is **GitHub's slug algorithm**, deliberately, and `scripts/build-glossary.mjs` mirrors it when recording the anchor a term is defined at.

The subtle part: GitHub maps *each space* to a dash rather than collapsing runs of whitespace. A heading containing an em dash, a slash or an ampersand loses that character and leaves two spaces behind — so `Law 2 — Data does not re-animate` is `law-2--data-does-not-re-animate`, with two dashes. Collapse the whitespace instead and every such anchor silently lands at the top of the page rather than at the section.

The two implementations live in different languages in different directories. `tests/doc-links.test.ts` is the assertion that they agree.

---

## Section indexes

Seven of them, one per directory under `docs/`, at `/docs/<section>`.

They exist for three reasons at once:

1. The source markdown links to directories — ``[the domain layer](domain/)``, written just like that — because on GitHub a directory is exactly what that is. Those links have to land somewhere on the site.
2. A reader who arrives mid-sequence from a search result needs the shape of the section they landed in.
3. Before them, every section had exactly one inbound link: the sidebar. A sidebar is a list, not a structure.

`SECTIONS` in `src/lib/docs-sections.ts` is the table. It is data rather than markup so the link tests can import it without pulling JSX through the test transform — and it must stay in step with the directories on disk, because a document in a directory no section names falls back to "Start here" and sits next to the manifesto. That is not a graceful degradation; it is a filing error that nobody sees. The test asserts the two match.

---

## What the tests hold

`tests/doc-links.test.ts` is the only thing standing between this structure and slow rot:

- Every relative link resolves to a document or a section index.
- Every anchor resolves to a heading the site **actually renders** — checked against the rendered HTML, not against a re-implementation of the rule.
- Every glossary term points at a heading that exists.
- Every component points at a family document that exists.
- Every directory under `docs/` has a navigation section.
- No auto-linked term is ever nested inside another link, a heading or a code block.

None of these can be caught by `tsc`, and none of them break the build. They break the reader.
