Skip to content
Registry StackDocsDevelopment (unreleased)

Derive a registry from PublicSchema

For the data publisher

View as Markdown

If you are a data publisher who finished Create and query your first registry, you already have bregctl installed. This tutorial derives a registry project from PublicSchema, an external reference model embedded in the tooling, instead of writing the domain-neutral example project. You pick a starter selection of concepts and properties, read what init wrote, check and start the project, then edit the selection and derive it again.

Outcome
A project derived from PublicSchema with a starter selection, checked and started, then derived again from an edited selection.
Time
About 20 minutes
Level
Local authoring with synthetic data
Prerequisites
The binaries from Create and query your first registryRunning DockerAn editor

Open a terminal where you want to create the project, and confirm the binary is on your PATH:

Terminal window
bregctl --version

Nothing here needs the tutorial-work directory from Create and query your first registry; this tutorial derives a project of its own. Docker is needed only later, to start the registry.

bregctl init writes the domain-neutral example project by default. With --from publicschema, it derives a project from the PublicSchema 0.3.0 snapshot embedded in the binary instead, guided by a selection of concepts and properties. --starter household supplies a selection shipped with the model: the concepts Person, Household, and GroupMembership, with a subset of their properties.

Derive a project from the household starter:

Terminal window
bregctl init household-registry --from publicschema --starter household
Initialized a registry project. 6 artifacts written.
revision sha256:<digest>
README.md
dev-clients.yaml
model/selection.yaml
registry.yaml
runtime.example.yaml
tests/journeys.yaml
finding access.profile.higher_classification 2 paths
entities[id=person].accessProfiles[id=operator].readableFields[field=marital-status]
finding access.profile.unrestricted_collection 6 paths
entities[id=person].accessProfiles[id=operator].rowBoundaries
0 errors, 8 findings.
Next:
1. read household-registry/README.md, then run 'bregctl check household-registry'
2. leave the findings above as they are; the `operator` and `reader` profiles list
whole collections on purpose, and the `operator` profile reads 2 fields the model
marks sensitive, and household-registry/README.md says where to narrow them
3. run 'bregctl dev household-registry' to start the registry locally and replay
household-registry/tests/journeys.yaml
4. replace canonicalBaseIri in household-registry/registry.yaml before you build a
production package; the derived value is a reserved .invalid name that never
resolves
5. keep household-registry/model/selection.yaml beside the project: edit it and pass
it back with --selection to derive a fresh project

Each finding prints a sentence of its own and one path per place it fires; one path per finding is kept, the rest omitted. init compiled the project before printing its revision, the digest of the compiled model, and check and dev repeat that revision and every finding until you change something. Unlike the domain-neutral example, a derived project has no modules/ directory: every entity lives in registry.yaml. The rest of this tutorial follows the numbered steps in order.

Open household-registry/README.md. It carries the attribution PublicSchema’s license requires:

The README lists one section per entity, each naming the PublicSchema concept it came from and a field table. The person entity, from PublicSchema’s Person:

FieldPropertyTypeClassification
person-codeidentifierstring, 1 to 64 charactersinternal
given-namegiven_namestring, up to 255 charactersinternal
family-namefamily_namestring, up to 255 charactersinternal
date-of-birthdate_of_birthdateinternal
sexsexvocabulary-code from sexinternal
preferred-languagepreferred_languagestring, up to 64 charactersinternal
phone-numberphone_numberstring, up to 255 charactersinternal
marital-statusmarital_statusvocabulary-code from marital-statusrestricted

household and group-membership get the same shape lower in the file. The README’s “How the project was derived” section states the rules that chose these fields and their types; How a registry is derived from a model explains them and names what the derivation refuses outright.

household-registry/model/selection.yaml is the input init derived the project from, written back into the project. Keep it beside the project and edit it to derive again.

Run bregctl check the way the first next step says:

Terminal window
bregctl check household-registry

The report repeats the same revision and the same eight findings, without the artifact list and the next steps that only init writes. Both codes are expected: the household starter has no tenancy field to bind a row restriction to, so every operator and reader profile can list a whole collection, and the operator profile reads the two fields PublicSchema marks sensitive. The README’s “Access profiles” section names those two fields and says how to narrow either finding before you build a production package.

Start the project as a registry the same way as Create and query your first registry:

Terminal window
bregctl dev household-registry

The first start downloads the pinned PostgreSQL image. Once the registry answers, the report shows its address, a token endpoint, and one credential per client in dev-clients.yaml: an operator and a reader, matching this project’s two access profiles.

Before that report, dev replayed household-registry/tests/journeys.yaml against a throwaway database, then activated the package on an empty one, so the registry starts with no records. To make the journey’s first record by hand, get a token the way Create and query your first registry does, then send this body with the create request:

{
"data": {
"personCode": "person-1",
"givenName": "example",
"familyName": "example",
"dateOfBirth": "2024-01-01",
"sex": "not_known",
"preferredLanguage": "example",
"phoneNumber": "example",
"maritalStatus": "never_married"
}
}

The journey file writes those field identifiers in kebab case, person-code; the API takes them in camel case. This project routes them under persons rather than the records route of the domain-neutral example:

$registry_url/v1/records/persons?accessProfile=operator

The other routes are households and group-memberships. Stop the registry with bregctl dev stop household-registry.

model/selection.yaml is ordinary input, not a generated file: edit it and derive again to get a fresh project from the change. Open household-registry/model/selection.yaml and remove marital_status from Person’s properties:

- concept: Person
properties:
- name: given_name
- name: family_name
- name: date_of_birth
- name: sex
- name: preferred_language
- name: phone_number

Derive a second project from the edited file, into a new directory:

Terminal window
bregctl init household-registry-2 --from publicschema --selection household-registry/model/selection.yaml

The report has a new revision, the same six access.profile.unrestricted_collection findings, and one access.profile.higher_classification finding left, for group-membership.person; removing marital_status removed the other one. The person field table in household-registry-2/README.md no longer lists marital-status, and that README’s “Access profiles” section now reads in the singular. Any other edit, adding a property or removing one, follows the same cycle: change model/selection.yaml, derive into a new directory, and read the new README.

Without --starter or --selection, init --from publicschema asks its questions at a terminal instead of reading a file:

Terminal window
bregctl init household-registry-3 --from publicschema

Nine questions follow: what the registry is called, which concepts become entities, which unchosen concepts would connect them, which properties become fields, how the entities and routes are named, and which code lists the project writes out in full. The last one prints the selection your answers describe and asks whether to derive from it. Every prompt goes to standard error, so a script that captures standard output still gets a clean report. The PublicSchema wizard prompts records each question, what it lists, and what starts ticked.

Without a terminal at all, for example in a script or in CI, the wizard cannot run, and init --from publicschema alone refuses immediately:

bregctl init refused.
error init.selection.missing arguments
`init --from publicschema` asks its questions at a terminal; without one,
pass `--selection <FILE>` or `--starter <NAME>` (one of `household`)
1 error, 0 findings.

Pass --starter household or --selection <FILE> instead, the way the rest of this tutorial does.

You derived a project from PublicSchema with a shipped selection, read the attribution and the fields init chose, checked the project, started it and made its first record by hand, then edited the selection and derived a second project with one fewer sensitive field.

Create and query your first registry covers the problems common to every project: a binary that is not on PATH, a port already taken, and a dev start that never reaches ready because Docker is not running.

SymptomNext move
bregctl dev refuses with dev.failed over a reported versionThe installed breg or mint comes from another release than this bregctl. The refusal names the file that answered, the version it reported, and the version this bregctl reports. Install all three from the same release, or put the matching build first on PATH.
init --from publicschema refuses with init.selection.missingNo terminal is attached, so the wizard cannot ask its questions. Pass --starter household or --selection <FILE> instead.
init --from publicschema --selection <FILE> refuses over the file<FILE> is a symbolic link, or larger than 256 KiB. Point --selection at an ordinary file under that size.
bregctl init cannot parse the edited model/selection.yamlCompare the indentation of the lines you changed with the rest of the file; a selection is a plain YAML list of entities, each with a properties list under it.