tracking: training-doc pipeline - credentials JSON schema + Quarto renderer role
Umbrella: TBD
Wave: WAVE_04 (since TBD)
Cross-repo umbrellas: TBD
Cross-cutting WAVE_04 task : at the end of provisioning, the operator hands
each student a per-student PDF listing their credentials, service URLs, and
getting-started instructions. Generated automatically from data emitted by
each admin service (gitea, mattermost, nextcloud, rocketchat).
Shape
[admin services] --emit--> <service>-credentials.json --collect-->
[Ansible role] --aggregate per student--> [Quarto] --render--> [PDFs]
Storage
- Per-service JSON artifacts : named volume on the lab VM (path TBD ; e.g.
tokens/ already used by gitea-registry)
- Aggregated structure + rendered PDFs :
~/range42/_current-training/<session-id>/ on the operator host - outside any git repo, ephemeral, never committed
Schema sketch (v1, to be locked)
Shared base + per-service extension :
{
"service": "<short-name>",
"service_url": "<base-url>",
"service_version": "<version-tag>",
"provisioned_at": "<ISO-8601-UTC>",
"users": [
{
"username": "...",
"email": "...",
"password": "...",
"ssh_public_key": "...",
"groups": ["..."],
"tokens": [ { "name": "...", "value": "...", "scope": "..." } ],
"service_specific": { }
}
]
}
Per-service service_specific extensions :
- gitea :
{ repos: [...], orgs: [...] }
- mattermost :
{ teams: [...], channels: [...], bot_account: {...} }
- nextcloud :
{ shares: [...], app_passwords: [...] }
- rocketchat :
{ channels: [...], bot_account: {...} }
- misp :
{ org: "...", roles: [...], warning_lists_enabled: [...] }
Schema is not frozen - expected to evolve
The shape above is a starting point only. As soon as new features land
on the admin services, fields will appear in service_specific that the
schema sketch did not anticipate. The schema is deliberately versioned and
designed to evolve : shared base fields move slowly (versioned bumps for
breaking changes), service_specific is the free-form extension point that
absorbs most of the churn.
Concrete example already visible in WAVE_04 :
The Mattermost / Rocket.Chat tracking issues introduce a player-team layer
(suggested default blue/red/yellow/purple x 1-4 = 16 player teams) with a
dedicated channel per team and auto-join wiring. Implementing this surfaces
fields that do not yet exist in the sketch above :
"service_specific": {
"player_team": "blue_1",
"team_channel": "#team-blue-1",
"auto_joined_channels": ["#general", "#help", "#team-blue-1"]
}
The aggregator + Quarto template will need to render this new shape (e.g. a
"Your team" section in the per-student PDF). Expect every Suggestions item
picked up from the per-element tracking issues to trigger a small parallel
evolution here : add the field(s) to service_specific, update the renderer
template, bump the schema patch version if needed.
Lock (in the scope below) applies to v1 only ; v2+ are expected.
Scope to cover
Deferred (tracked here for context, not for this iteration)
- Schema versioning lifecycle (v2+ as services evolve)
- HTML / DOC output variants (Quarto-trivial once PDF works)
- Encrypted archive of the output dir for cross-operator handoff
- Per-student delivery automation outside Nextcloud (email / portal)
tracking: training-doc pipeline - credentials JSON schema + Quarto renderer role
Cross-cutting WAVE_04 task : at the end of provisioning, the operator hands
each student a per-student PDF listing their credentials, service URLs, and
getting-started instructions. Generated automatically from data emitted by
each admin service (gitea, mattermost, nextcloud, rocketchat).
Shape
Storage
tokens/already used bygitea-registry)~/range42/_current-training/<session-id>/on the operator host - outside any git repo, ephemeral, never committedSchema sketch (v1, to be locked)
Shared base + per-service extension :
{ "service": "<short-name>", "service_url": "<base-url>", "service_version": "<version-tag>", "provisioned_at": "<ISO-8601-UTC>", "users": [ { "username": "...", "email": "...", "password": "...", "ssh_public_key": "...", "groups": ["..."], "tokens": [ { "name": "...", "value": "...", "scope": "..." } ], "service_specific": { } } ] }Per-service
service_specificextensions :{ repos: [...], orgs: [...] }{ teams: [...], channels: [...], bot_account: {...} }{ shares: [...], app_passwords: [...] }{ channels: [...], bot_account: {...} }{ org: "...", roles: [...], warning_lists_enabled: [...] }Schema is not frozen - expected to evolve
The shape above is a starting point only. As soon as new features land
on the admin services, fields will appear in
service_specificthat theschema sketch did not anticipate. The schema is deliberately versioned and
designed to evolve : shared base fields move slowly (versioned bumps for
breaking changes),
service_specificis the free-form extension point thatabsorbs most of the churn.
Concrete example already visible in WAVE_04 :
The Mattermost / Rocket.Chat tracking issues introduce a player-team layer
(suggested default
blue/red/yellow/purplex 1-4 = 16 player teams) with adedicated channel per team and auto-join wiring. Implementing this surfaces
fields that do not yet exist in the sketch above :
The aggregator + Quarto template will need to render this new shape (e.g. a
"Your team" section in the per-student PDF). Expect every Suggestions item
picked up from the per-element tracking issues to trigger a small parallel
evolution here : add the field(s) to
service_specific, update the renderertemplate, bump the schema patch version if needed.
Lock (in the scope below) applies to v1 only ; v2+ are expected.
Scope to cover
roles/training_doc_gen/(path TBD) : SSH-collect from lab VMs, aggregate per-student, invoke Quarto~/range42/_current-training/<session-id>/<student>.{pdf,xlsx}(outside any git repo)<service>-credentials.jsonartifact at end of provisioning. Per-element implementation tracked separately :Deferred (tracked here for context, not for this iteration)