@klok-integration/cli 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,6 +43,7 @@ Credentials are written to `~/.config/klok/credentials.json` with mode 0600.
43
43
  | `klok agents init` | Write the Klok agent instructions and skills into a repository. |
44
44
  | `klok bead list\|show\|report` | Progress beads in the current repository. |
45
45
  | `klok docs publish` | Build this repository's znai documentation and upload it to the docs portal. |
46
+ | `klok docs build` | Build this repository's `klok-docs/` with znai the way its documentation project will, uploading nothing. |
46
47
  | `klok solutions validate` | Check the descriptors of an integration solution registry against the descriptor contract. |
47
48
  | `klok ci env` | Show what klok-cli detected about the CI job it runs in. |
48
49
  | `klok manifest update` | Set a container's image in a deploy manifest of your GitOps repository, then commit and push. |
@@ -19,7 +19,11 @@ https://docs.klok.dev/klok-environment-build-ci-templates/llm.txt for the pipeli
19
19
  documentation.
20
20
  * Consumers reference the artifact only through the catalog alias (`klokLibs.<key>`), never by literal version.
21
21
  * Datamodel documentation lives in `klok-docs/` (purpose, fields that need explanation, producers and consumers,
22
- design decisions). Datamodel projects publish no documentation payload yet, because the datamodel template runs
23
- no Klok Gradle task, so these pages do not reach docs.klok.dev until it does; write them anyway.
22
+ design decisions). The datamodel pipeline's `klok_docs_publish` job sends it with the XSD to docs.klok.dev, where
23
+ the model is documented from the XSD (a structure page, then AI sections from the complex types up) under
24
+ `<tenant>/documentation/datamodel/<same path>`. Put `xs:documentation` on types and fields; that is what the
25
+ generated text is written from.
26
+ * The repository's path is its class: `public` (A), `common` (B), `domain/<d>` (C) or `system/<s>` (X). The wider
27
+ the scope, the stricter a breaking change; see the `klok-datamodel` skill.
24
28
  * On `main` the pipeline publishes and updates the catalog; check it, then refresh consumers with
25
29
  `./gradlew updateKlokLibsToml`.
@@ -27,6 +27,14 @@ needs. Read https://docs.klok.dev/klok-framework-klok-quarkus-extension/llm.txt
27
27
  (`KlokTaskInitiation`, `KlokAsyncTaskWorkerRoute`).
28
28
  * Tests: `@QuarkusTest` with the recording broker client factory; assert routes started and published messages,
29
29
  never talk to a real broker or OpenSearch in unit tests.
30
+ * A route that serves several tenants (a shared platform service) consumes each tenant's own request topic,
31
+ `<tenant>[_<env>]/common/<Model>`, from the subscription list klok.dev keeps in the klok ODL; it takes the tenant
32
+ from the namespace it received on and rejects a message whose payload or properties name another tenant. It never
33
+ picks an index, repository or account from a field in the message, and what it writes back for a tenant goes to
34
+ klok's namespace, one topic per tenant.
35
+ * The service connects to the broker with a client of its own (`KLOK_BROKER_AUTH_CLIENT_ID`), granted `publish` and
36
+ `consume` on its own tenant's namespaces only; a topic of another tenant is a `consume` grant on that one topic,
37
+ reached with `<RouteId>.topic.tenant-override`. Never reuse another service's credentials.
30
38
  * `application.properties` keeps every `klok.*` key explicit; secrets come from environment variables that the
31
39
  Vault env secret provides in Kubernetes (`KLOK_BROKER_AUTH_CLIENT_ID`, ...).
32
40
  * Update `klok-docs/` (overview, design decisions, routes, operations) in the same merge request as the change.
@@ -152,6 +152,37 @@ step by step procedure; the contract every agent follows is:
152
152
  header, Pulsar property and CloudEvents extension, `klok.`-prefixed as MDC key.
153
153
  * Repositories: `<tenant>/integration/domain/<d>/<repo>`, `<tenant>/datamodel/...`, mirrored documentation under
154
154
  `<tenant>/documentation/...`; documentation ids are `slug(<tenant>-<group>-...-<repo>)`.
155
+ * Permission words, one meaning each: *ingress/egress* says what a service is and is never a permission; broker
156
+ rights are `publish` and `consume` (Pulsar's own `produce`/`consume` only inside a grant command); `read` and
157
+ `ingest` belong to klok.dev's integration context graph and never to the broker.
158
+
159
+ ## Broker access and tenant isolation
160
+
161
+ Read the *Broker Access And Tenant Isolation* page of
162
+ https://docs.klok.dev/klok-framework-development-guide/llm.txt before designing anything that touches broker
163
+ access, Keycloak broker clients or a service that serves several tenants.
164
+
165
+ * **The topic decides the tenant, never the message.** Pulsar does not tell a consumer who published; a `tenant`
166
+ field or property can be forged by any client allowed on the topic. A service takes the tenant from the topic
167
+ name and rejects a payload that claims another one.
168
+ * **Write narrow, consume wide.** A tenant publishes only in its own namespace, `<tenant>[_<env>]/<domain>`; nobody
169
+ holds `publish` in another tenant's namespace, not even on one topic. Reading elsewhere is a `consume` grant on a
170
+ named topic, approved by the owner and recorded in Git in the owning tenant. A topic read across tenants carries
171
+ its reader as the last purpose segment (`persistent://konvoj/hr/PersonnelScheduleExportV1_degerfors`).
172
+ * **Platform services** (logs, the ODL, AI, mail, SMS, documentation) are shared klok workers that follow the same
173
+ rule: a tenant's requests live in the tenant's namespace (`persistent://<tenant>[_<env>]/common/KlokLogEventV5`)
174
+ and the worker is granted `consume` on exactly those topics, taking the tenant from the namespace; what the
175
+ platform writes back lives in klok's namespace, one topic per tenant (`klok[_<env>]/<domain>/<Model>_<tenant>`).
176
+ The worker subscribes to a list of topics kept in the klok ODL, never to a pattern. The ODL runs as one instance
177
+ per tenant.
178
+ * **Identities:** one Keycloak client per running deployment, never shared, never used by a person; its Pulsar role
179
+ is `service-account-<client id>`; one CI broker client per tenant; every broker client attaches the client scope
180
+ `pulsar` (audience and the `nbf` claim Pulsar requires) instead of copying mappers.
181
+ * **Grants:** `publish` and `consume` on the service's own domain and its tenant's `common`, as namespace grants;
182
+ anything in another domain or tenant is `consume` on one topic, never `publish`, approved by its owner and
183
+ recorded in Git in the owning tenant. Pulsar's `produce`/`consume` appear only inside a grant command.
184
+ * **Who applies it:** Ansible (`klok/environment/klok-environment-setup`) for the platform and tenant klok's
185
+ services, klok.dev for tenant projects. A grant made only in the broker's admin API is drift.
155
186
 
156
187
  ## Documentation is part of every change
157
188
 
@@ -159,7 +190,7 @@ Klok documentation has three levels, and a change is finished only when all thre
159
190
 
160
191
  * **The repository's own `klok-docs/`** (znai markdown, `toc-manifest.json`). On every `main` pipeline
161
192
  `./gradlew publishKlokDocs` publishes it, together with the scan of the code, as `KlokProjectDocumentationV1` on
162
- `persistent://klok[_<env>]/common/KlokProjectDocumentationV1_prepared`. KlokDocumentationEgress
193
+ `persistent://<tenant>[_<env>]/common/KlokProjectDocumentationV1_prepared`. KlokDocumentationEgress
163
194
  (`klok/integration/klok-documentation-egress`, KLK007) builds the repository's documentation project from it. That
164
195
  documentation project is output, and nobody edits it. There are two places to change a project's documentation:
165
196
  `klok-docs/` in the source repository (including the `KLOK:GENERATED` markers that place AI sections in a page),
@@ -197,13 +228,17 @@ Klok documentation has three levels, and a change is finished only when all thre
197
228
  1. Update the repository's `klok-docs/` in the same merge request as the change — ideally in the same commit as
198
229
  the code it describes. Documentation that is promised for a later merge request is documentation that never
199
230
  arrives, and a final "docs" commit at the end of a branch is the same promise wearing a hat.
200
- 2. Ask what a reader of the platform documentation would now find wrong: a renamed command, a new rule, a changed
231
+ 2. Run `klok docs build` where a znai CLI is at hand (the Klok build image has one; `--znai <path>` points at
232
+ another). It builds `klok-docs/` with znai the way the repository's documentation project will, so a page znai
233
+ cannot parse fails now instead of stopping the documentation project from publishing after the merge, where
234
+ nobody in this repository sees it.
235
+ 3. Ask what a reader of the platform documentation would now find wrong: a renamed command, a new rule, a changed
201
236
  default, a workflow with one more step. Read the affected pages (`https://docs.klok.dev/<doc-id>/llm.txt`)
202
237
  instead of guessing what they say.
203
- 3. Correct what you can judge yourself. A central page that is now plainly wrong is fixed in its own small merge
238
+ 4. Correct what you can judge yourself. A central page that is now plainly wrong is fixed in its own small merge
204
239
  request against that documentation project, linked from the change. What you cannot judge is written down
205
240
  rather than dropped.
206
- 4. Write the merge request description for the reviewer: state what changed, why, and which documentation it
241
+ 5. Write the merge request description for the reviewer: state what changed, why, and which documentation it
207
242
  affects or might affect. A description that
208
243
  says only "fixes the build" produces no documentation update.
209
244
 
@@ -8,6 +8,24 @@ description: Create or change a Klok datamodel (XSD first, generated Java, publi
8
8
  Read https://docs.klok.dev/klok-framework-klok-common/llm.txt (naming) and
9
9
  https://docs.klok.dev/klok-environment-build-ci-templates/llm.txt (datamodel pipeline).
10
10
 
11
+ ## Choosing the class
12
+
13
+ Every datamodel is one of four classes (decided 2026-09-29; the reasoning is in
14
+ https://docs.klok.dev/klok-integration-strategy-and-tactics/platform-2-0/datamodel-classes/). All four may be sent
15
+ over the broker; the class sets how widely the model is shared and how strict its stability is.
16
+
17
+ | Class | Repository | Schema | A breaking change |
18
+ |---|---|---|---|
19
+ | A, public | `<tenant>/datamodel/public/<name>-v<n>` | XSD | the strictest: every reader notified; the old version runs at least 12 months after the notice |
20
+ | B, common | `<tenant>/datamodel/common/<name>-v<n>` | XSD | coordinated across the tenant's domains; the old version runs at least 3 months |
21
+ | C, domain | `<tenant>/datamodel/domain/<d>/<name>-v<n>` | XSD | decided within the domain; no fixed minimum |
22
+ | X, system | `<tenant>/datamodel/system/<s>/<name>-v<n>`, **or** plain Java classes in the integration's own source | XSD not required | follows the external system; no fixed minimum |
23
+
24
+ A class X model mirrors one external system's format. It does not need an XSD: simple Java classes in the
25
+ integration, explained in the source, are enough, and the steps below do not apply to them. Give it a repository
26
+ with an XSD when more than one integration or a service in another language needs it. Data that other systems or
27
+ domains read should still travel as class B or C (transform at the edge).
28
+
11
29
  ## Creating or changing a model
12
30
 
13
31
  1. The model lives in its own repository `<tenant>/datamodel/<common|public|domain/<d>|system/<s>>/<name>-v<n>`,
@@ -37,11 +55,14 @@ https://docs.klok.dev/klok-environment-build-ci-templates/llm.txt (datamodel pip
37
55
  3. `meta.json` in the flat form with `targetNamespace`, and `klok-docs/` with the purpose, the important fields and
38
56
  the producers and consumers.
39
57
  4. A breaking change is a new major version (`Customer_v2`), which is a new class, a new topic and a new catalog
40
- key; a compatible change (optional field) stays in the same version.
58
+ key; a compatible change (optional field) stays in the same version. The old and the new version run in
59
+ parallel while readers move, at least the class's minimum (table above) and until every known reader
60
+ has moved.
41
61
  5. Work in the task worktree (`klok-worktree` skill), push its `agent/<task-id>` branch, open a merge request;
42
62
  the pipeline validates the XSD and generates the Java project. On `main` it
43
- publishes `dev.klok.<tenant>.datamodel:<name>-v<n>:1.0.0-build.<ts>` and writes `<nameVn>` (for example
44
- `klokOdlV1`) into the dependency catalog.
63
+ publishes `dev.klok.<tenant>.datamodel:<name>-v<n>:1.0.0-build.<ts>` with its Python and TypeScript packages,
64
+ writes `<nameVn>` (for example `klokOdlV1`) into the dependency catalog, and publishes the documentation payload
65
+ that becomes `<tenant>/documentation/datamodel/<same path>` on docs.klok.dev.
45
66
 
46
67
  ## Using a model in a project
47
68
 
@@ -35,5 +35,9 @@ Read https://docs.klok.dev/klok-framework-klok-quarkus-extension/llm.txt first (
35
35
 
36
36
  * A route id that does not start with the solution id, or two routes with the same id.
37
37
  * Publishing to a hand written topic string; use the resolver and the datamodel.
38
+ * Choosing a tenant, index, repository or account from a field in the message; the topic decides the tenant.
39
+ * Sharing broker credentials between services, or granting a whole namespace of another domain or tenant.
40
+ * Publishing into another tenant's namespace, with `<RouteId>.topic.tenant-override` or otherwise; a route consumes
41
+ another tenant's topic with the override and a `consume` grant, and publishes only in its own tenant.
38
42
  * Catching exceptions to return HTTP 200 with an error text.
39
43
  * Pinning a framework or datamodel version in `gradle/klok-libs.versions.toml` by hand.