Metadata-Version: 2.4
Name: rekisteri
Version: 2026.6.24
Summary: Manage catalogs of documents organized per publication identifier stem, issue, and optionally revision.
Author-email: Stefan Hagen <stefan@hagen.link>
Maintainer-email: Stefan Hagen <stefan@hagen.link>
License-Expression: MIT
Project-URL: Documentation, https://codes.dilettant.life/docs/rekisteri
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: kaava>=2026.6.20
Requires-Dist: pyyaml>=6.0.3
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"

# rekisteri

Register / registry (Finnish: rekisteri) manages catalogs of documents organised
per publication identifier stem, issue, and optionally revision.

Requires Python 3.11 or later.

## Install

```
pip install rekisteri
```

## Manual

The [man page](docs/rekisteri.1) provides the CLI reference (`man rekisteri` after placing the file on your `MANPATH`)

To use `man rekisteri`, copy `docs/rekisteri.1` to a directory on your `MANPATH`, for example:

```
mkdir -p ~/.local/share/man/man1
cp docs/rekisteri.1 ~/.local/share/man/man1/
```

## Overview

`rekisteri` is for operators of document publication registries — typically teams
that publish structured document sets (specifications, guides, manuals) and need a
stable, browsable web tree alongside a machine-readable catalog.

Given a `rekisteri.yaml` configuration it:

1. **Scans** a `source/ref/` tree for documents organised by stem, issue, and
   (optionally) revision.
2. **Validates** the tree: checks metadata completeness, issue numbering consistency,
   slug uniqueness, and catalog cross-references.
3. **Publishes** a `web-parent/` tree:
   - `ref/` — anchor copies of all documents with `index` navigation symlinks at
     issue and stem level.
   - `pub/` — per-slug cross-reference symlinks into `ref/`, grouped by issue.
   - `reference → ref` and `publication → pub` alias symlinks at the root.
4. **Generates** catalog JSON files (`documents.json`, `cards.json`) at a separate
   `catalog-out` path for consumption by a side-loading web application.

## Source tree structure

### Two-level (default-depth: 2, default)

```
source/ref/
└── <STEM>/
    ├── publication.yaml     ← stem-level metadata (title, status, …)
    ├── <ISSUE>/
    │   ├── version.yaml     ← optional issue-level metadata overrides
    │   └── <stem>-<some_id>-<issue>.<ext>
    └── <ISSUE>/
        └── …
```

### Three-level (default-depth: 3)

```
source/ref/
└── <STEM>/
    ├── publication.yaml
    └── <ISSUE>/
        ├── issue.yaml
        └── <REVISION>/
            ├── revision.yaml    ← optional revision-level metadata overrides
            └── <stem>-<some_id>-<issue>-<revision>.<ext>
```

Issue directories contain only digits (`01`, `2`, …).
Revision directories are any non-numeric non-hidden name (`A`, `B`, `draft`, …).

## Quickstart

```
# Write rekisteri.yaml and publication.yaml templates into the current directory
rekisteri eject .

# Check the tree is well-formed
rekisteri validate --config rekisteri.yaml

# Show the discovered publication tree
rekisteri explain

# Publish the web-parent tree
rekisteri publish
```

For a dedicated feature walkthrough you can follow in minutes visit [quickstart](quickstart/README.md).
A step-by-step guided build of a running registry is provided in the [tutorial](tutorial/README.md).

## Configuration

`rekisteri.yaml` controls all paths and behaviour.
Run `rekisteri eject` to write a commented template.

```yaml
source-root: ./source/ref    # path to the source document tree
web-root: ./web-parent       # path where the published tree is written
catalog-out: ./catalog       # path where catalog JSON files are written
default-depth: 2             # 2 (stem/issue) or 3 (stem/issue/revision)
supported-depths: [2]        # depths allowed in this registry; use [2, 3] for mixed
# stem-pattern: null         # optional regex; only matching stems are scanned
# slug-pattern: null         # optional regex applied to some_id before slugifying
catalog:
  documents-file: documents.json
  cards-file: cards.json
  cards:
    - title: Guides          # display name for this card group
      identifiers: [INTRO]   # slugs of publications belonging to this group
```

All multi-word keys are kebab-case.
`--config` / `-c` accepts either a file path or a directory (looks for
`rekisteri.yaml` inside it).

## Metadata files

Each stem, issue, and revision may carry a YAML metadata file.
Inner files override outer ones via `dict.update()`; keys the inner file does not mention are inherited unchanged.

```yaml
title: ""          # human-readable publication title (required; must not be empty)
abstract: ""       # short abstract
responsible: ""    # team or person responsible
tags: []           # free-form tags
status: active     # active | superseded | archived
supersedes: []     # list of STEM/ISSUE entries this publication supersedes
mapping: []        # list of mapping slugs from mapping.yaml (used by rekisteri map)
```

## Filename conventions

Documents are named `<stem>-<some_id>-<issue>.<ext>` (two-level) or
`<stem>-<some_id>-<issue>-<revision>.<ext>` (three-level), all lowercase.
The `some_id` part is extracted by stripping the stem prefix and the issue (and
revision) suffix from the filename stem.  It is then uppercased (after optional
`slug-pattern` filtering) to form the **slug** used in `pub/` and catalog.

Example: `x-guide-intro-01.pdf` in stem `X-GUIDE`, issue `01`
→ `some_id = intro` → `slug = INTRO`.

The slug is stable as long as `some_id` is preserved across stem renames and
issue increments.

## Web-parent tree topology

After `rekisteri publish`:

```
web-parent/
├── ref/
│   └── <STEM>/
│       ├── index.<ext>              → latest issue's document
│       └── <ISSUE>/
│           ├── <doc-name>.<ext>     ← anchor copy
│           └── index.<ext>          → <doc-name>
├── pub/
│   └── <SLUG>/
│       ├── index.<ext>              → latest issue's document
│       └── <ISSUE>/
│           ├── <doc-name>.<ext>     → ../../../ref/STEM/ISSUE/doc
│           └── index.<ext>          → <doc-name>
├── reference                        → ref
└── publication                      → pub
```

With `--copy`, `pub/` entries are real file copies instead of symlinks
(useful for Windows or archival scenarios).

## Commands

### `rekisteri doctor`

Check the environment and configuration: Python version, config file presence,
source-root existence, and web-root parent.

```
rekisteri doctor [-c PATH]
```

### `rekisteri eject`

Write `rekisteri.yaml` and `publication.yaml` templates to a target directory.
Skips existing files unless `--overwrite` is given.

```
rekisteri eject [TARGET] [--overwrite]
```

### `rekisteri explain`

Print the discovered publication tree: stems, issues (and revisions for
three-level trees), documents, and slugs.

```
rekisteri explain [-c PATH]
```

### `rekisteri publish`

Build the `web-parent/` tree from the source tree.
Creates anchor copies in `ref/`, cross-reference symlinks in `pub/`,
and the `reference` / `publication` alias symlinks.

```
rekisteri publish [-c PATH] [--copy]
```

`--copy` replaces `pub/` cross-reference symlinks with real file copies.

### `rekisteri validate`

Validate the source tree and metadata.
Prints findings tagged `[error]` or `[warning]`.
Exits 1 on any error; with `--strict`, also exits 1 on warnings.

```
rekisteri validate [-c PATH] [--strict]
```

### `rekisteri map`

Harvest the latest active issue per stem, group documents by mapping slug, and write
`mapping.json` to `catalog-out`.
Requires `mapping-source` to be set in `rekisteri.yaml` pointing to a `mapping.yaml` file.
`publish` runs this automatically when `mapping-source` is configured.

```
rekisteri map [-c PATH]
```

## Changes

See `docs/changes.md` for the release history.

## Coverage

The test suite maintains 99% branch coverage.
The HTML report (if generated) is in `site/coverage/`.

## SBOM

Runtime dependency information is published in `docs/sbom/` in SPDX 3.0 (JSON-LD) and CycloneDX 1.6 (JSON) formats.
See `docs/sbom/README.md` for the component inventory and validation guide.
