DATA MODEL · data-model.md
Data Model: First npm Release, Safe Release Automation, and Documentation Site
Raw markdown
# Data Model: First npm Release, Safe Release Automation, and Documentation Site
**Feature**: [spec.md](./spec.md) | **Plan**: [plan.md](./plan.md)
No runtime data is stored. The entities below are files and workflow values; the rules are
enforced by `scripts/release/release.js` (see [contracts/release-cli.md](./contracts/release-cli.md)).
## Version
| Field | Rule |
|---|---|
| `value` | SemVer 2.0 `MAJOR.MINOR.PATCH` with optional pre-release `-<id>.<n>` (id: `rc` by default). No build metadata. Defined only in `package.json` `version` (§III). |
| `tag` | `v` + `value`, e.g. `v1.0.0`. Annotated, points at the release commit. |
| `prerelease` | `true` when `value` contains `-`. |
| `distTag` | `next` when `prerelease`, otherwise `latest` (FR-016). |
**Next version** (`bump`):
| Kind | From `1.2.3` | From `1.3.0-rc.1` |
|---|---|---|
| `patch` | `1.2.4` | `1.3.0` (finishes the pre-release) |
| `minor` | `1.3.0` | `1.3.0` |
| `major` | `2.0.0` | `2.0.0` |
| `prepatch` | `1.2.4-rc.0` | `1.3.1-rc.0` |
| `preminor` | `1.3.0-rc.0` | `1.4.0-rc.0` |
| `premajor` | `2.0.0-rc.0` | `2.0.0-rc.0` |
| `prerelease` | `1.2.4-rc.0` | `1.3.0-rc.2` |
| `--version X` | `X` (must be valid; may equal the current version only if there is no `## [X]` section — the first-release case, `1.0.0`; an existing tag `vX` is caught by the Release run's checks, not by the script) | same |
Uniqueness: a value is released at most once — no existing git tag, no changelog section, not on
npm (npm refuses reuse even after unpublish).
## Changelog section
`CHANGELOG.md` keeps the Keep a Changelog 1.1.0 shape:
```text
# Changelog
<intro>
## [Unreleased]
### Added | Changed | Deprecated | Removed | Fixed | Security
- entries…
## [X.Y.Z] - YYYY-MM-DD
…
[Unreleased]: https://github.com/SerafAC/speckit-eye/compare/vX.Y.Z...HEAD
[X.Y.Z]: https://github.com/SerafAC/speckit-eye/compare/vW...vX.Y.Z (first release: /releases/tag/vX.Y.Z)
```
| Rule | Where enforced |
|---|---|
| Unreleased must have at least one `- ` entry to bump | `bump` (FR-008) |
| After bump: Unreleased is empty (heading only); the entries sit under `## [X.Y.Z] - <UTC date>` directly below it, sub-headings kept | `bump` (FR-006) |
| The newest released section's version equals `package.json` version and the tag, and is non-empty | `verify` (FR-010) |
| Link definitions: exactly one `[Unreleased]` line comparing the newest tag to `HEAD`, one line per released version | `bump` rewrites them; repository URL from `package.json` `repository` (§III) |
| Release notes = body of the version's section (without its heading) | `notes` (FR-015) |
## Release run
One run of `release.yml` for one version.
```text
┌── not a release commit ──► done (nothing happens)
prepare ────┤
└── release ──► ci ─┐
verify ─┴─► awaiting approval ──rejected──► stopped (no tag, nothing published)
│ approved
▼
tag created (if missing) ──► published to npm ──► GitHub release created
any failing check ─────────────────────────────────────────► failed (names the check; nothing published)
```
| Field | Source |
|---|---|
| `trigger` | `push-main` / `push-tag` / `dispatch` (on a tag, to re-run a release) |
| `commit` | head commit (push) or tag target |
| `version`, `tag`, `distTag` | `package.json` (push-main) or the tag name |
| `tarball` | artifact `speckit-eye-<version>.tgz` from `verify`, the only file published |
| `notes` | artifact `notes.md` from `verify` |
| `provenance` | attached by npm from the OIDC identity of the `publish` job |
## Documentation site
| Path on the site | Content | Source |
|---|---|---|
| `/` (e.g. `https://serafac.github.io/speckit-eye/`) | docmd home page | `docs/index.md` |
| `/usage/`, `/hosting/`, `/architecture/`, `/releasing/` | guides | `docs/<name>.md` |
| `/assets/…` | docmd assets + screenshots | docmd + `docs/assets/` |
| `/status/…` | speckit-eye static build of this repository | `specs/`, `.specify/` via `bin/speckit-eye.js --build` |
The site URL has one definition: `package.json` `homepage`. The docmd `url`, the dashboard
`--base` (`<path of homepage>status/`) and `--home` (`homepage`) are derived from it.
Feature: spec.md | Plan: plan.md
No runtime data is stored. The entities below are files and workflow values; the rules are
enforced by scripts/release/release.js (see contracts/release-cli.md).
01 Version
| Field | Rule |
|---|---|
value |
SemVer 2.0 MAJOR.MINOR.PATCH with optional pre-release -<id>.<n> (id: rc by default). No build metadata. Defined only in package.json version (§III). |
tag |
v + value, e.g. v1.0.0. Annotated, points at the release commit. |
prerelease |
true when value contains -. |
distTag |
next when prerelease, otherwise latest (FR-016). |
Next version (bump):
| Kind | From 1.2.3 |
From 1.3.0-rc.1 |
|---|---|---|
patch |
1.2.4 |
1.3.0 (finishes the pre-release) |
minor |
1.3.0 |
1.3.0 |
major |
2.0.0 |
2.0.0 |
prepatch |
1.2.4-rc.0 |
1.3.1-rc.0 |
preminor |
1.3.0-rc.0 |
1.4.0-rc.0 |
premajor |
2.0.0-rc.0 |
2.0.0-rc.0 |
prerelease |
1.2.4-rc.0 |
1.3.0-rc.2 |
--version X |
X (must be valid; may equal the current version only if there is no ## [X] section — the first-release case, 1.0.0; an existing tag vX is caught by the Release run's checks, not by the script) |
same |
Uniqueness: a value is released at most once — no existing git tag, no changelog section, not on npm (npm refuses reuse even after unpublish).
02 Changelog section
CHANGELOG.md keeps the Keep a Changelog 1.1.0 shape:
# Changelog
<intro>
## [Unreleased]
### Added | Changed | Deprecated | Removed | Fixed | Security
- entries…
## [X.Y.Z] - YYYY-MM-DD
…
[Unreleased]: https://github.com/SerafAC/speckit-eye/compare/vX.Y.Z...HEAD
[X.Y.Z]: https://github.com/SerafAC/speckit-eye/compare/vW...vX.Y.Z (first release: /releases/tag/vX.Y.Z)
| Rule | Where enforced |
|---|---|
Unreleased must have at least one - entry to bump |
bump (FR-008) |
After bump: Unreleased is empty (heading only); the entries sit under ## [X.Y.Z] - <UTC date> directly below it, sub-headings kept |
bump (FR-006) |
The newest released section's version equals package.json version and the tag, and is non-empty |
verify (FR-010) |
Link definitions: exactly one [Unreleased] line comparing the newest tag to HEAD, one line per released version |
bump rewrites them; repository URL from package.json repository (§III) |
| Release notes = body of the version's section (without its heading) | notes (FR-015) |
03 Release run
One run of release.yml for one version.
┌── not a release commit ──► done (nothing happens)
prepare ────┤
└── release ──► ci ─┐
verify ─┴─► awaiting approval ──rejected──► stopped (no tag, nothing published)
│ approved
▼
tag created (if missing) ──► published to npm ──► GitHub release created
any failing check ─────────────────────────────────────────► failed (names the check; nothing published)
| Field | Source |
|---|---|
trigger |
push-main / push-tag / dispatch (on a tag, to re-run a release) |
commit |
head commit (push) or tag target |
version, tag, distTag |
package.json (push-main) or the tag name |
tarball |
artifact speckit-eye-<version>.tgz from verify, the only file published |
notes |
artifact notes.md from verify |
provenance |
attached by npm from the OIDC identity of the publish job |
04 Documentation site
| Path on the site | Content | Source |
|---|---|---|
/ (e.g. https://serafac.github.io/speckit-eye/) |
docmd home page | docs/index.md |
/usage/, /hosting/, /architecture/, /releasing/ |
guides | docs/<name>.md |
/assets/… |
docmd assets + screenshots | docmd + docs/assets/ |
/status/… |
speckit-eye static build of this repository | specs/, .specify/ via bin/speckit-eye.js --build |
The site URL has one definition: package.json homepage. The docmd url, the dashboard
--base (<path of homepage>status/) and --home (homepage) are derived from it.