[[profile-dieterbaier-arc42]]Profile Dieter Baier arc42 Architecture
This architecture documentation describes profile-dieterbaier as a software project:
a personal profile, CV, thoughts, articles, and publishing pipeline based on
Docs-as-Code and the principle "write once, publish everywhere".
1. Introduction and Goals
profile-dieterbaier exists to maintain one authoritative personal profile source and publish it to multiple channels: personal website, CV, GitHub README, GitLab README, article exports, and architecture documentation.
1.1. Motivation
Maintaining the same professional profile across several platforms creates duplication, inconsistency, and avoidable manual work. The project applies Docs-as-Code to personal professional content: source text is versioned, reviewed, validated, generated, and deployed like software.
As a running example of the Docs-as-Code Toolkit, the project keeps structured source content, metadata, and relations above the publishing layer. Generated website, README, CV, article, and architecture outputs are derived artifacts rendered by the build pipeline.
1.2. Business Goals
| ID | Goal | Success indicator |
|---|---|---|
G-001 |
Single source of truth for profile, CV, articles, shorts, and architecture documentation. |
Public artifacts are generated from repository sources. |
G-002 |
Multi-target publishing without copy-paste maintenance. |
README, website, CV, and article Markdown are built by Gradle tasks. |
G-003 |
Treat the profile as a software product. |
Architecture documentation, decisions, risks, quality scenarios, metamodels, validators, and generators are part of the repository. |
1.3. Top Quality Goals
| ID | Priority | Quality goal | Meaning |
|---|---|---|---|
1 |
Reproducibility |
Same source and environment produce the same generated artifacts. |
|
2 |
Maintainability |
Content, presentation, metadata, and build logic have explicit responsibilities. |
|
3 |
Automation |
Normal publishing and validation run without manual transformation steps. |
|
4 |
Correctness |
Generated public artifacts reflect the intended source content and metadata. |
|
5 |
Sustainability |
The site and pipeline avoid unnecessary runtime logic, tracking, and waste. |
1.4. Stakeholders
| ID | Stakeholder | Concern |
|---|---|---|
ST-001 |
Dieter Baier |
Maintain professional profile information efficiently and correctly. |
ST-002 |
Potential employers and clients |
Read current CV, project history, articles, and contact information. |
ST-003 |
Technical community |
Access thoughts, articles, README content, and toolkit examples. |
ST-004 |
CI/CD runtime |
Build and deploy only the artifacts affected by a change. |
2. Profile Product Goals
2.1. Content Product Purpose
The project publishes the author’s professional identity as structured source content. The core value is not the build pipeline itself, but the reusable, versioned profile knowledge that the pipeline turns into channel-specific outputs.
2.2. Authoring Principle
The profile content follows the same discipline as architecture documentation:
-
stable artifact identity where content is independently meaningful;
-
explicit metadata for validation and generation;
-
source artifacts as the authority;
-
generated indexes and matrices as derived output;
-
AI-assisted work governed by contracts and skills.
2.3. Private-To-Public Article Lifecycle
The profile product has a private-to-public article lifecycle. New articles and private notes should start in a private source boundary, become reviewable through a preview status, and appear on dieterbaier.eu only after an explicit publication decision.
The implementation is tracked as GitHub issue #26. The epic links backlog work to the architecture roadmap and must not be implemented before the related ADRs are reviewed:
3. Architecture Constraints
| ID | Constraint | Consequence |
|---|---|---|
CON-001 |
AsciiDoc is the primary authoring format. |
Profile and architecture content can use includes, attributes, and multi-format rendering. |
CON-002 |
Gradle orchestrates local and CI builds. |
New generators and validators are exposed as Gradle tasks. |
CON-003 |
GitHub Actions and the docs-toolbox container are the deployment runtime. |
CI must remain compatible with containerized execution. |
CON-004 |
Private contact data is injected from environment variables. |
Secrets must not be committed to the repository. |
CON-005 |
Profile and architecture metadata must remain source-controlled and reviewable. |
Generated output is reproducible and excluded from source editing. |
4. System Scope and Context
4.1. Business Context
4.2. Technical Context
5. Solution Strategy
| Strategy | Supports | Description |
|---|---|---|
Single source profile knowledge |
Profile artifacts are authored once and reused across website, CV, README, and article exports. |
|
Metadata-backed content |
Standalone content artifacts receive front matter; include-heavy reusable fragments are covered by sidecar metadata. |
|
Toolkit-compatible architecture knowledge |
arc42 chapters, ADRs, quality scenarios, risks, schemas, validators, and generated fragments follow architecture-knowledge-toolkit conventions. |
|
Gradle task orchestration |
Build, validation, and generation are exposed as repeatable Gradle tasks. |
|
Containerized CI/CD |
GitHub Actions run the same toolchain in the docs-toolbox container and deploy changed outputs through target-specific deploy jobs. |
|
Scoped deployment credentials |
Deployment credentials are separated by target. GitHub profile README deployment uses a fine-grained token for |
5.1. Build Pipeline Strategy
The GitHub Actions workflow separates change detection, build execution, artifact upload, and target-specific deployment.
Only changed target categories trigger the matching Gradle tasks:
| Change category | Build output |
|---|---|
README |
|
Articles |
Markdown exports under |
Architecture |
|
Site |
|
Generated artifacts are uploaded once and consumed by separate deploy jobs. Each deploy job owns one deployment target so failed deployments can be re-run without repeating successful targets. The deploy jobs use target-specific credentials instead of one shared deployment token:
| Target | Credential | Reason |
|---|---|---|
GitHub profile README |
|
Cross-repository push to |
GitLab profile README |
|
GitLab push requires a GitLab credential independent of GitHub Actions. |
Personal website and architecture documentation |
|
Private webspace deployment is external to GitHub and uses SFTP. |
Personal contact data |
|
Private data is injected only during CI generation and is not stored in source files. |
PROFILE_REPO_TOKEN should be a fine-grained GitHub personal access token scoped to dieterbaier/dieterbaier with Contents: Read and write. A failure in the checkout github profile repo step with Bad credentials indicates that this token is invalid, expired, revoked, or missing the required target repository permission.
5.1.1. Consequences
Advantages:
-
Reduced pipeline runtime
-
Lower resource consumption
-
Deterministic builds
-
Clear separation of concerns
-
Smaller credential blast radius per deployment target
Trade-offs:
-
Increased pipeline complexity
-
Additional maintenance for path filters
-
Token expiry and rotation must be operated explicitly
6. Building Block View
6.1. C4 Level 1: System Context
The system publishes profile content from source repositories into static artifacts. The public repository owns the reusable publishing application, architecture documentation, validators, generators, and theme. The private repository is proposed as a separate source component for private articles, notes, and protocols.
6.2. Repository Collaboration
This component diagram is the proposed decision basis from ADR-009. It is included here to show the official building block view of the public/private repository collaboration without duplicating the model.
6.3. C4 Level 2: Containers
| Container | Responsibility | Storage |
|---|---|---|
Public Profile Repository |
Public profile source, public articles, previewable article source, reusable build logic, theme, profile metadata contracts, and architecture documentation. |
|
Article Comments Repository |
Public GitHub issues created through a structured form. A repository workflow validates the submitted article ID against the deployed public-article allowlist and assigns a stable per-article label. |
|
Private Profile Repository |
Private article, note, and protocol source. Proposed as a separate source component, not as a duplicated product. |
|
Architecture Knowledge |
arc42 chapters, ADRs, quality scenarios, risks, canvases, Q&A, and metadata. |
|
Theme Assets |
CSS, fonts, icons, JavaScript, and shared docinfo fragments used by generated static outputs. For feature #44, the local article-comments script progressively loads matching GitHub issues only after reader consent. |
|
Validators |
Check architecture and profile metadata before generation and deployment. |
|
Generators |
Create derived indexes, traceability fragments, article summaries, article-specific GitHub comment blocks for feature #44, and proposed publication target inputs. |
|
Gradle Tasks |
Orchestrate build, validation, generation, conversion, and asset copying. |
|
6.4. C4 Level 3: Build-Time Components
| Component | Responsibility | Current implementation |
|---|---|---|
Gradle Build Orchestrator |
Defines build tasks, task dependencies, source sets, output directories, and asset copying. |
|
Architecture Metamodel Validator |
Validates architecture artifact metadata, IDs, relations, and structural conventions. |
|
Architecture Artifact Generator |
Generates ADR, quality scenario, risk, chapter include, open-question, and traceability fragments. |
|
Profile Metamodel Validator |
Validates profile sidecar/frontmatter metadata, IDs, statuses, channels, and relations. |
|
Profile Artifact Generator |
Generates the profile artifact index from profile metadata. |
|
Article Summary Generator |
Generates LinkedIn/Substack-oriented HTML summary packs without publishing them into public site targets. |
|
Publication Target Generator |
Proposed component for deriving public, preview, and private article source sets and navigation from metadata. |
6.5. COMP-001: Publication Target Generator
6.5.1. Responsibility
The Publication Target Generator is a build-time component that reads article sidecar metadata and creates target-specific AsciiDoc inputs for public, preview, and private site builds.
It owns:
-
status-based article selection;
-
generated article matrix/navigation fragments;
-
publication-target source lists for Gradle/Asciidoctor;
-
target-specific HTML metadata decisions such as canonical URL eligibility and
noindexmode. -
verification inputs that prove
build/sitedoes not contain preview or private articles.
It does not own:
-
article prose;
-
reviewer authentication;
-
private repository access control;
-
deployment credentials.
6.5.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
|
Input |
publication target, for example |
Output |
metadata-derived article matrix for the target |
Output |
source include/build list for the target |
Output |
target attributes for canonical and robots metadata handling |
6.5.3. Target Rules
| Target | Article eligibility | HTML metadata |
|---|---|---|
Public |
|
canonical links allowed, search indexing allowed |
Preview |
|
no canonical links, |
Private |
private repository content plus preview and published context |
no canonical links, |
6.5.4. Implementation Guard
The public canonical-URL slice is authorized by accepted ADR-008 and may be implemented independently because it processes only already selected public output. Publication selection, preview/private targets, and promotion automation remain subject to ADR-009 and the still-missing first promotion check.
6.5.5. Integration Sketch
6.6. COMP-002: Architecture Metamodel Validator
6.6.1. Responsibility
The Architecture Metamodel Validator checks architecture source artifacts before generated architecture fragments or rendered architecture pages are produced.
It owns:
-
required architecture metadata fields;
-
unique artifact IDs;
-
filename and ID consistency warnings;
-
relation key, relation type, relation status, and target validation;
-
detection of unusual bidirectional relations;
-
validation reports for architecture documentation changes.
It does not own:
-
rendered HTML output;
-
profile artifact metadata;
-
human acceptance of proposed architecture decisions.
6.6.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
architecture AsciiDoc files with YAML front matter |
Input |
|
Input |
|
Output |
validation report with errors and warnings |
Output |
failed Gradle task when architecture metadata is invalid |
6.6.3. Implementation
| Field | Value |
|---|---|
Script |
|
Gradle task |
|
Primary scope |
|
6.7. COMP-003: Profile Metamodel Validator
6.7.1. Responsibility
The Profile Metamodel Validator checks profile content metadata before profile indexes, website artifacts, CV output, README output, or article exports are generated.
It owns:
-
profile artifact required fields;
-
supported profile artifact types;
-
supported lifecycle statuses, including proposed
previewandprivate; -
supported publication channels;
-
profile artifact ID uniqueness;
-
relation key, relation type, relation status, and target validation.
It does not own:
-
article prose quality;
-
publication target filtering;
-
deployment authorization.
6.7.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
|
Input |
profile AsciiDoc files with YAML front matter |
Input |
|
Output |
validation report with errors and warnings |
Output |
failed Gradle task when profile metadata is invalid |
6.7.3. Implementation
| Field | Value |
|---|---|
Script |
|
Gradle task |
|
Primary scope |
|
6.8. COMP-004: Architecture Artifact Generator
6.8.1. Responsibility
The Architecture Artifact Generator derives navigation and traceability fragments from validated architecture metadata.
It owns:
-
ADR, quality scenario, and risk indexes;
-
chapter include fragments for generated chapter assembly;
-
open-question index generation;
-
per-artifact traceability fragments;
-
the architecture-wide traceability matrix.
It does not own:
-
source architecture decisions;
-
acceptance of generated relations;
-
profile artifact indexes.
6.8.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
validated architecture artifacts |
Input |
|
Output |
ignored |
Output |
traceability matrix and per-artifact traceability fragments |
6.8.3. Implementation
| Field | Value |
|---|---|
Script |
|
Gradle task |
|
Generated storage |
|
6.9. COMP-005: Profile Artifact Generator
6.9.1. Responsibility
The Profile Artifact Generator derives a profile artifact index from validated profile metadata.
It owns:
-
collecting metadata-backed profile artifacts;
-
rendering a generated artifact index;
-
rendering per-article navigation includes (series and related articles);
-
rendering the article listings: a recent-articles fragment and the standalone overview pages for all articles, each tag, and each skill;
-
keeping generated profile documentation aligned with source metadata.
It does not own:
-
article lifecycle promotion;
-
architecture traceability generation.
6.9.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
validated profile artifacts under |
Output |
generated profile artifact index |
Output |
per-article navigation includes next to each article |
Output |
article listing fragment under the articles |
Output |
standalone article listing pages under the articles |
6.9.3. Implementation
| Field | Value |
|---|---|
Script |
|
Gradle task |
|
Generated file |
|
Generated listings |
recent fragment plus all/tag/skill overview pages, rendered into the site by the |
6.9.4. Affected Features
| Feature | Description | Status |
|---|---|---|
Per-article navigation includes (previous/next series links and related articles) added to this generator. |
implemented |
|
Article index replaced by generated listings (recent, all, per tag, per skill) plus skill metadata, adding the article listing outputs to this generator. |
implemented |
6.10. COMP-006: Article Summary Generator
6.10.1. Responsibility
The Article Summary Generator creates paste-ready publication summary packs from source articles.
It owns:
-
reading article source and article metadata;
-
deriving summary content from the source article;
-
applying LinkedIn and Substack HTML templates;
-
writing generated summary files to
build/summaries/; -
keeping summary outputs out of public website and article export targets.
It does not own:
-
publishing summaries to external platforms;
-
inventing publication URLs;
-
changing article metadata or article status.
6.10.2. Inputs And Outputs
| Kind | Description |
|---|---|
Input |
article AsciiDoc files under |
Input |
article |
Input |
HTML templates under |
Output |
LinkedIn and Substack HTML files under |
6.10.3. Implementation
| Field | Value |
|---|---|
Script |
|
Gradle task |
|
Guard |
|
7. Runtime View
7.1. Build And Publish Scenario
7.2. Failure Scenario
If metadata validation fails, Gradle stops before rendering or deployment. This keeps generated artifacts from drifting away from source truth.
7.3. DOC-06001: Private To Public Article Lifecycle Runtime
7.3.1. Status
In progress. The backlog epic is tracked as GitHub issue #26. The lifecycle is accepted in ADR-008. Public canonical metadata can proceed independently; private repository integration and promotion automation remain proposed in ADR-009, and no first promotion check has yet been performed.
7.3.2. Scenario 1: Draft Private Article
The private site is a reading and review surface for the author. It is not a substitute for source privacy; private content remains in the private repository.
7.3.3. Scenario 2: Promote Article To Preview
After promotion, preview content is public-source content. It is not official publication content, but it must no longer contain information that depends on private repository confidentiality.
7.3.4. Scenario 3: Publish Reviewed Article
Publishing is an explicit metadata transition. The public target must not include preview or private articles.
7.3.5. Scenario 4: Reject Or Continue Private Draft
If an article is not ready to become public-source preview material, it stays private. No generated preview or public artifact is expected.
8. Deployment View
| Target | Deployment mechanism | Output path |
|---|---|---|
Personal website |
SFTP from GitHub Actions |
|
Preview website |
SFTP from GitHub Actions or local deploy script to a Basic Auth protected and non-indexed preview target |
|
Private article notebook |
SFTP from private source build to a Basic Auth protected target |
|
Architecture documentation |
SFTP from GitHub Actions |
|
GitHub profile README |
Git commit from GitHub Actions |
|
GitLab profile README |
Git push from GitHub Actions |
|
Personal CV PDF |
Local build artifact, not deployed by default |
|
The deploy workflow uses one GitHub Actions job per deployed target. A failed target job can be re-run independently without deploying targets that already succeeded.
8.1. Publication Target Deployment
The publication targets are defined by accepted ADR-008. The diagram is included from the ADR so the decision basis and the official deployment view stay aligned.
8.2. Deployment Credentials
| Target | GitHub Actions configuration | Stored in | Required permission |
|---|---|---|---|
GitHub profile README |
|
Repository secret in |
Fine-grained GitHub token for |
GitLab profile README |
|
Repository secret in |
GitLab repository write access |
Personal website |
|
|
SFTP write access to the configured site directory |
Preview website |
|
Preview environment secrets and variables |
SFTP write access to the configured preview site directory and Basic Auth configuration |
Private article notebook |
Private repository deployment secrets and |
Private repository or local deployment environment |
SFTP write access to the configured private site directory |
Architecture documentation |
|
|
SFTP write access to the configured architecture directory |
Private contact data |
|
|
Value injection only; no repository or deployment permission |
The GitHub profile README is deployed to a different repository than the workflow source repository. The default GITHUB_TOKEN is intentionally not used for this cross-repository push; it is scoped to the workflow repository. PROFILE_REPO_TOKEN therefore has to be rotated when it expires or when GitHub reports Bad credentials during the checkout github profile repo step.
Preview and private deployments are intentionally separated from the public website deployment and require Basic Auth. The public target emits canonical links for published pages from the deployment-specific SITE_BASE_URL; preview and private targets must emit noindex metadata and omit canonical links.
9. Crosscutting Concepts
9.1. Security
Private contact data and deployment credentials are injected from environment variables or GitHub Secrets. .env is local-only.
Deployment credentials are scoped by target system. PROFILE_REPO_TOKEN grants write access only to the GitHub profile README target repository. GITLAB_TOKEN grants write access to the GitLab profile README target repository. SFTP credentials are used only for private webspace deployment. This avoids one shared credential for all deployment targets and makes token rotation diagnosable from the failing workflow step.
9.2. Testing And Validation
Metadata validation runs before documentation rendering. The architecture validator follows the architecture-knowledge-toolkit metamodel. The profile validator checks profile artifact metadata, relations, and generated indexes.
9.3. Metadata Contract Version
Every profile artifact declares the version of the metadata contract it was
written against, and the validator accepts only versions it knows. The accepted
versions are declared once, as the metadata_version enum in
metamodel/profile-artifact.schema.yaml; the validator reads them from there
instead of holding a second list, and any build can read the same file without
running the validator.
The set is read from the validator’s own checkout rather than from the tree it was pointed at. Content validated from elsewhere — the private repository reaching the shared tooling through a sibling checkout, as ADR-009 accepts — is judged by the contract of the tooling doing the validating, which is what makes a checkout older than the content beside it fail by name instead of passing.
An artifact that declares no version fails as a missing field. Treating absence as the initial version would let content say nothing about its contract and still pass, and the silent case is the one this field exists to remove.
The observable behaviour is specified in
features/metadata-contract-version.feature and bridged to
test/profile_metadata_version_test.rb.
9.4. Publication Selection
A publication target renders the article statuses that target allows, decided in
ADR-008. The public target allows published and nothing else. An article of any
other status is absent from build/site rather than merely absent from its
listings, so it has no URL to reach.
Selection is by article metadata, never by where a file sits, so an article is kept out of a target by what it says about itself. The build asks the profile validator which sources a target excludes while it configures itself, because a render task resolves its sources before any generator runs; a list produced during the build would be missing exactly when a clean build needs it.
The same selection applies to the markdown export, since CI uploads the whole build directory as a workflow artifact of a public repository.
The selection fails closed. An article that must be kept out of a target and whose source file cannot be named stops the build, because a list that silently omits such an article looks complete while leaving out exactly what must not be rendered.
Two checks stand behind the selection rather than beside it.
verifyPublicRenderTasksValidateMetadata asserts that every task rendering
article sources reaches metadata validation through its dependencies, so the
contract survives a refactoring instead of resting on a transitive edge.
verifyPublicTargetHasOnlyPublishedArticles inspects the rendered result: an
article that must not be public either has output there or it does not,
whatever the build did with the selection.
The observable behaviour is specified in
features/article-publication-status.feature and bridged to
test/profile_publication_status_test.rb.
9.5. Private Content Target
A second target renders the private repository’s content locally, so a draft can
be read as a finished page before anything is decided about it. It carries
private, preview, and published, which is a wider status set than the
public target and safe only because it is a wider set for a target that is
deployed nowhere.
Both targets ask the same question of the same validator; only the answer differs, because the status set belongs to the target rather than to the mechanism. The private target renders to HTML alone: the markdown export exists so public articles can be published elsewhere, and a private draft is published nowhere.
The private repository holds content only. Its build reaches this repository’s
tooling through a sibling checkout, resolved from PROFILE_PRIVATE_DIR or from
the sibling path, and the build stops when that checkout carries a schema,
validator, generator, or build of its own. The interface terms and theme come
from this repository too, which is why the validator takes the includes tree as
a parameter rather than assuming it sits inside the content root.
Every page of the target carries a robots noindex tag and no canonical link.
The two belong together: a page that says it must not be indexed while also
claiming to be the canonical location of its content states two opposite things,
and the build refuses to be asked for both. Neither is a confidentiality control.
A checkout without the sibling is an ordinary state of this repository. Nothing about the private target may fail while the build configures itself, because that would break every Gradle invocation instead of the one task that needs the sibling.
The observable behaviour is specified in
features/private-content-target.feature and bridged to
test/profile_private_target_test.rb and
test/private_checkout_contract_test.rb.
9.6. Observability
CI logs, Gradle task output, and validator reports are the operational feedback loop.
9.7. Error Handling
Failed validation or missing tooling stops the build. Missing publication URLs in AI-generated article summaries are represented as placeholders rather than invented values.
9.8. Optional Article Interaction
The GitHub-backed article-comments feature #44
keeps the website static.
Article metadata generates a prefilled issue-form link into the dedicated
dieterbaier/profile-artikelkommentare repository. Public-site deployment
synchronizes an allowlist derived from published website articles. The comments
workflow idempotently creates and assigns the fixed Artikelkommentar label,
validates the submitted ID against that allowlist, and assigns the article-ID label. A local,
framework-free script lists issues matching both labels, but contacts the GitHub
API only after the reader explicitly requests the list. Failure or rate limiting
affects only the optional list, never the article content. The observable behaviour is specified in
features/article-comments.feature and bridged to
test/profile_comments_test.rb.
9.9. Sustainability
Generated output is static. The public site avoids runtime backends, trackers, and unnecessary third-party scripts.
10. Architecture Decisions
10.1. ADR Index
| ADR | Title | Status | Notes |
|---|---|---|---|
AsciiDoc as Primary Source |
proposed |
Use AsciiDoc as the primary source format for profile and architecture content. |
|
Gradle Build Orchestration |
proposed |
Use Gradle tasks as the local and CI build orchestration layer. |
|
Containerized Build Runtime |
proposed |
Use the docs-toolbox container as the reproducible CI runtime. |
|
Pandoc Markdown Export |
proposed |
Use Pandoc via DocBook for README and article Markdown exports. |
|
Minimal Static Site |
proposed |
Keep the public website static and avoid unnecessary third-party runtime behavior. |
|
Profile Content Metamodel |
proposed |
Use a profile-specific metamodel, validator, and generator alongside the architecture metamodel. |
|
Build-Generated Article Summaries |
proposed |
Generate article summaries as HTML build artifacts under build/summaries. |
|
Private To Public Article Lifecycle |
accepted |
Use repository boundaries and metadata-driven publication targets for article drafting, preview, and public release. |
|
Private Repository Integration |
accepted |
Treat the private repository as a separate source component of the profile application and integrate it through explicit content and promotion contracts. |
|
Multilingual Content And Language Fallback |
accepted |
Resolve language variants and their fallback to the default language at build time in the generator instead of in AsciiDoc markup or at runtime. |
|
Preview Visibility Without Authentication |
accepted |
Serve the preview target without authentication, keep it unreachable from the public site, and replace the access boundary with a visible notice on every article that is not published. |
|
Reading Context of the Private Target |
accepted |
Render the private target from private source alone, with this repository’s theme and page chrome, and accept that links out of it do not resolve; collisions with public source are an error and the pipeline keeps non-public targets away from the public deployment. |
10.2. ADR-001: AsciiDoc as Primary Source
10.2.1. Status
Proposed (derived).
10.2.2. Decision
Use AsciiDoc as the primary source format for profile and architecture content.
10.2.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.2.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.2.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Negative: Contributors need to understand the chosen toolchain.
-
Follow-up: Human review should confirm the derived status and rationale.
10.3. ADR-002: Gradle Build Orchestration
10.3.1. Status
Proposed (derived).
10.3.2. Decision
Use Gradle tasks as the local and CI build orchestration layer.
10.3.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.3.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.3.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Negative: Contributors need to understand the chosen toolchain.
-
Follow-up: Human review should confirm the derived status and rationale.
10.4. ADR-003: Containerized Build Runtime
10.4.1. Status
Proposed (derived).
10.4.2. Decision
Use the docs-toolbox container as the reproducible CI runtime.
10.4.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.4.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.4.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Negative: Contributors need to understand the chosen toolchain.
-
Follow-up: Human review should confirm the derived status and rationale.
10.5. ADR-004: Pandoc Markdown Export
10.5.1. Status
Proposed (derived).
10.5.2. Decision
Use Pandoc via DocBook for README and article Markdown exports.
10.5.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.5.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.5.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Negative: Contributors need to understand the chosen toolchain.
-
Follow-up: Human review should confirm the derived status and rationale.
10.6. ADR-005: Minimal Static Site
10.6.1. Status
Proposed (derived).
10.6.2. Decision
Keep the public website static and avoid unnecessary third-party runtime behavior.
Optional integrations may use progressive enhancement when the core content and
navigation work without them and the reader explicitly triggers any third-party
request. The article-comments proof of concept follows this boundary: creating a
comment navigates to a structured issue form in the dedicated
dieterbaier/profile-artikelkommentare repository, while loading label-matched
comment issues requires an explicit button click. This applies ADR-005 to
feature #44.
10.6.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.6.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.6.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Positive: Reading an article does not automatically disclose the visit to the optional GitHub comments integration.
-
Negative: Contributors need to understand the chosen toolchain.
-
Negative: The optional comment list depends on GitHub availability and its unauthenticated API rate limit.
-
Follow-up: Human review should confirm the derived status and rationale.
10.7. ADR-006: Profile Content Metamodel
10.7.1. Status
Proposed (derived).
10.7.2. Decision
Use a profile-specific metamodel, validator, and generator alongside the architecture metamodel.
10.7.3. Context
This ADR was derived while bootstrapping the existing project to the architecture-knowledge-toolkit structure. The decision reflects existing repository practice and should be reviewed before being marked accepted.
10.7.4. Pugh Matrix
| Criterion | Keep existing practice | Replace with custom tooling | Manual process |
|---|---|---|---|
Fit to Docs-as-Code |
+1 |
0 |
-1 |
Build reproducibility |
+1 |
? |
-1 |
Maintainability |
+1 |
0 |
-1 |
Sum |
+3 |
? |
-3 |
10.7.5. Consequences
-
Positive: The project keeps a coherent source-based publishing workflow.
-
Negative: Contributors need to understand the chosen toolchain.
-
Follow-up: Human review should confirm the derived status and rationale.
10.8. ADR-007: Build-Generated Article Summaries
10.8.1. Status
Proposed.
This ADR is AI-assisted and must not be treated as accepted architecture truth until reviewed and accepted by the accountable owner.
10.8.2. Decision
We propose to generate file-based article summaries as HTML build artifacts
under build/summaries. Each summary filename uses the article filename stem
plus summary<target> and the .html extension.
These summaries are generated writing aids. They are excluded from generated site and article-export targets, and generated public content must not link to them.
For example:
src-content/profile/site/articles/documentation/doc-as-code.adoc
build/summaries/doc-as-code_summary_linkedin.html
build/summaries/doc-as-code_summary_substack.html
10.8.3. Context
The project already treats profile article sources under
src-content/profile/site/articles as product source. AI-assisted article
summaries are paste-ready publication aids for LinkedIn and Substack.
An earlier proposal placed written summaries next to the article source. The
current desired practice is different: summaries are generated whenever they are
requested and written to build/summaries.
This keeps authored article sources clean, makes the workflow reproducible through Gradle, and avoids treating publication drafts as primary source.
10.8.4. Decision Drivers
-
Summary drafts should be reproducible through a build task.
-
Article source directories should contain only primary article sources and metadata.
-
Summary drafts should not become public generated content by accident.
-
Generated build output should remain separate from authored source.
-
The convention should stay simple enough for agents and humans to apply.
-
Future relocation should remain possible through a later ADR and contract update.
10.8.5. Considered Options
Option 1: Build-generated summary files
Generate each platform summary under build/summaries with the naming pattern
<article-slug>_summary_<target>.html.
Option 2: Source-adjacent summary files
Store each platform summary next to the article with the naming pattern
<article-slug>_summary_<target>.md.
Option 3: Nested build summary files
Store generated HTML summaries in nested directories such as
build/summaries/<article-slug>/<target>.html.
Option 4: Central source summary directory
Store summaries under a source-controlled directory such as
src-content/profile/site/article-summaries/<article-slug>/<target>.md.
10.8.6. Pugh Matrix
| Criterion | Build-generated files | Source-adjacent files | Nested build-directory files | Central source directory |
|---|---|---|---|---|
Reproducible generation |
+1 |
-1 |
0 |
-1 |
Clean article source directories |
+1 |
-1 |
+1 |
+1 |
Separation from public generated output |
+1 |
+1 |
+1 |
+1 |
Directory simplicity |
0 |
+1 |
-1 |
-1 |
Future relocation flexibility |
0 |
0 |
0 |
0 |
Sum |
+3 |
0 |
+1 |
0 |
10.8.7. Consequences
Positive
-
Summary drafts can be regenerated with
./gradlew generateArticleSummaries. -
Article source directories stay focused on primary sources and metadata.
-
build/remains the place for reproducible generated outputs. -
The build verifies that generated site and article-export outputs do not contain summary files or
summary<target>references.
Negative
-
Generated summary files are not visible in ordinary Git diffs unless copied or reviewed separately.
-
The summary generator must be maintained when the article format or supported publication targets change.
-
The verification task must continue to distinguish public generated outputs from
build/summaries.
Neutral or Follow-Up
-
A future ADR may move summaries again if they become curated source artifacts.
-
Validators may later add checks for expected summary targets and naming.
10.8.8. Impact
| Artifact | Impact | Rationale |
|---|---|---|
addressed |
Generated summaries remain traceable to article metadata and source files. |
|
mitigated |
Regeneration reduces manual drift between source articles and publication aids. |
|
affected |
Pandoc exports remain generated Markdown outputs, while summaries become generated HTML outputs. |
10.8.9. Traceability
| Relation | Target | Rationale |
|---|---|---|
|
Supports consistency between generated publication aids and source articles. |
|
|
Reduces hidden drift by regenerating summary artifacts from article source. |
|
|
Clarifies that summary HTML is generated separately from Pandoc article Markdown exports. |
10.8.10. Assumptions
-
Summary files are deterministic build artifacts by default.
-
AI-assisted refinements may still be created through the article-summary skill, but generated files remain under
build/summaries.
10.8.11. Open Questions
-
Should future validation require one summary file for every supported target?
-
Should generated site or Markdown export tasks explicitly ignore all
summary<target>files regardless of extension?
10.8.12. Review Notes
Confirm that generated summaries should stay build artifacts before changing this ADR to accepted or reviewed.
10.9. ADR-008: Private To Public Article Lifecycle
10.9.1. Status
Accepted.
The Basic Auth requirement this record states for the preview target is replaced by ADR-011. Everything else here stands, including Basic Auth for the private target.
10.9.2. Decision
We separate article privacy from article publication quality by combining repository boundaries with metadata-driven build targets.
Private drafts, notes, and protocols start in the private repository dieterbaier/profile-private. Reviewable but not official article content is promoted to the public profile repository with status: preview. Public deployment uses only metadata-selected status: published article content and derives canonical links from a deployment-specific base URL plus each generated output path. Preview and private deployments render their own target-specific sites without canonical links, with noindex metadata, and behind Basic Auth.
10.9.3. Context
The profile repository is public. Deployment protection such as .htaccess can protect generated HTML on a webspace, but it cannot protect source files that are already public in Git. Therefore, the privacy boundary must exist at source level before generated deployment targets are considered.
At the same time, not every unfinished article is confidential. After an article is cleaned enough for feedback, public source visibility is acceptable, while public website visibility and search indexing are still not desired.
This decision supports the lifecycle tracked as GitHub issue #26.
10.9.4. Decision Basis Diagrams
The following diagrams document the decision basis for the lifecycle. While this ADR is proposed, they remain close to the options and consequences. Official architecture views include these diagrams by tag so that the accepted decision can be reused without duplicating the model.
Draft Private Article Runtime
Promote Article To Preview Runtime
Publish Reviewed Article Runtime
Reject Or Continue Private Draft Runtime
Publication Target Deployment
10.9.5. Options
| Criterion | Repository boundary plus metadata targets | Only .htaccess protected preview/private targets |
Branch-only review in public repository |
|---|---|---|---|
Protects truly private source content |
+1 |
-1 |
-1 |
Keeps public website deterministic |
+1 |
0 |
0 |
Supports rendered review before publication |
+1 |
+1 |
0 |
Operational simplicity |
0 |
+1 |
+1 |
Fits static hosting and Gradle pipeline |
+1 |
+1 |
0 |
Sum |
+4 |
+2 |
0 |
10.9.6. Consequences
Positive:
-
Private material is protected before it becomes source in a public repository.
-
Preview becomes a quality state, not a secrecy state.
-
Public website generation can be validated by metadata rules instead of source tree location alone.
-
preview.dieterbaier.euandprivate.dieterbaier.eucan share the static-site toolchain while enforcing different content sets.
Negative:
Neutral or follow-up:
-
Basic Auth is required for generated preview and private deployments, but it is not the source confidentiality mechanism.
-
A local promotion script should be preferred initially. A GitHub Action can be introduced once promotion checks are reviewed.
-
publishedis the canonical public lifecycle status. -
The public canonical-URL slice is independent of private-source promotion: it operates only on already selected public output. The first promotion check remains required before promotion automation is implemented or used.
10.9.7. Review Notes
Confirmed on 2026-07-18:
-
the private source repository is
dieterbaier/profile-private; -
preview and private deployments require Basic Auth;
-
publishedis the canonical public lifecycle status; -
the public canonical-URL slice may proceed independently of ADR-009 because it neither reads private source nor performs promotion.
Open follow-up:
-
No first promotion check has been performed. Promotion automation remains blocked until checks that prevent private-only content from entering the public repository are defined, implemented, and verified.
10.10. ADR-009: Private Repository Integration
10.10.1. Status
Accepted by the site owner.
10.10.2. Decision
We treat profile-private (dieterbaier/profile-private) as a separate source component of the same profile application, integrated through explicit content and promotion contracts instead of Git submodules or duplicated build logic.
The two repositories are checked out as siblings. The private build reaches the shared tooling through that sibling checkout and owns no copy of it. Private rendering and verification run locally; the private target needs no GitHub Actions deployment.
Promotion moves an article from the private repository to the public one rather than copying it, so that an article has exactly one authoritative source and no second place to edit it.
Move is the outcome, not a property of the operation. Two repositories cannot be written atomically: the promotion is a saga with an ordering, states it can stop in, and a recovery step. The Promotion Saga section below defines them.
The public repository remains the owner of shared build logic, validators, generators, theme assets, profile metadata contracts, and architecture documentation. The private repository owns private article, note, and protocol source content. Private content is rendered by reusing the public repository’s build tooling through a documented checkout or local path contract.
The private repository should not maintain separate architecture documentation unless it introduces architecture decisions that are not part of the overall profile application. It may contain local operational notes, but architecture truth stays in this repository.
10.10.3. Context
The private repository is not just backup storage. It is part of the profile publishing system because it contributes source content to the private site and can promote reviewable articles to the public repository. At the same time, its main architectural reason to exist is privacy: content that must not be public source cannot live in the public repository.
Git submodules could express a repository relationship directly, but they introduce extra workflow complexity, detached version management, and contributor friction. Treating the private repository as a completely independent product would keep boundaries simple, but it would likely duplicate generators, validation rules, theme assets, and deployment behavior.
This decision supports GitHub issue #26 and must be reviewed before implementation slices that create private repository automation.
10.10.4. Decision Basis Diagrams
The component model below documents the preferred repository integration option. The official building block view includes it by tag while the decision is still proposed, so later refinements can happen once at the decision source.
Public And Private Repository Components
10.10.5. Options
| Criterion | Separate source component with explicit contracts | Git submodule | Independent private product | Copy shared tooling manually |
|---|---|---|---|---|
Keeps private source out of public Git history |
+1 |
+1 |
+1 |
+1 |
Avoids duplicated generators and theme logic |
+1 |
+1 |
-1 |
-1 |
Keeps day-to-day authoring simple |
+1 |
-1 |
0 |
0 |
Makes coupling explicit and reviewable |
+1 |
0 |
0 |
-1 |
Supports independent private deployment |
+1 |
0 |
+1 |
0 |
Low operational surprise |
+1 |
-1 |
0 |
-1 |
Sum |
+6 |
0 |
+1 |
-2 |
10.10.6. Integration Contract
| Contract | Rule |
|---|---|
Source ownership |
Public source stays in |
Tooling ownership |
Shared Gradle tasks, generators, validators, schemas, and theme assets are owned by |
Private build input |
The private repository provides content roots that match the public profile article metadata contract. |
Tooling access |
The two repositories are checked out as siblings. The private build uses the public checkout’s tooling directly; no submodule, no packaged version, no vendored copy. |
No second implementation |
The private repository holds no schema, validator, or generator of its own. Its build stops when it finds one. |
Contract version |
Every artifact declares |
Promotion |
A reviewed script validates an article against the public contract, then transfers its source and sidecar metadata from private to public source and sets |
Private deployment |
Private rendering and verification run locally. No GitHub Actions deployment for the private target. |
Architecture documentation |
Architecture decisions stay in the public repository unless private-only implementation creates a separate architectural concern. |
10.10.7. Promotion Saga
Two Git repositories cannot be written in one transaction. Promotion therefore has a defined order, and every point it can stop at is a state someone has to be able to recognize and finish.
The public repository leads. From the moment the promoted article lands there, it is the authoritative copy. Everything after that point is cleanup of the private side, never a source of truth.
The order follows from which failure is survivable. Removing from private first would put the article nowhere if the public write then fails. Writing to public first can only ever produce a duplicate, and a duplicate is recoverable while a loss is not.
| Step | Stops here means | Recovery |
|---|---|---|
Validate the article against the public contract |
Nothing was written. The article is private and unchanged. |
None needed. Fix the article and start over. |
Write source and sidecar into public, |
The public working tree holds an uncommitted addition. |
Discard the working tree change and start over. |
Commit and push public |
The article is public and authoritative. The private copy still exists. |
Continue with the private removal. |
Remove the article from private |
The private working tree holds an uncommitted deletion. |
Discard or complete the deletion; either way the public copy stands. |
Commit and push private |
Promotion is complete. |
None. |
The incomplete state is duplication, and it is detectable. The same artifact id present in both repositories is the signal a resumed promotion looks for, which is why artifact IDs are stable and unique across the contract rather than per repository.
The signal is not conclusive on its own. A shared id can also mean a genuine collision — two different articles that ended up with the same identifier — and a resumption that trusted the id alone would overwrite public content with private content. Recognizing an interrupted promotion therefore means matching the public artifact against the private one being promoted, not matching identifiers. The three states a public id can represent, and their opposite responses, are specified in GitHub issue #85.
A promoted article is never rolled back by moving it home. If the article should not have been promoted, it is removed from the public repository like any other public content, and the public Git history keeps the record. Promotion is not reversible by re-running it backwards, because public history cannot be unpublished.
10.10.8. Preventing Contract Drift
Two rules carry the drift concern, and they divide the failure between them.
The no second implementation rule removes drift in the tooling rather than detecting it. A vendored copy keeps looking like the original after it has stopped being one, which is the property that made the divergence in metamodel/artifact.schema.yaml invisible; a repository that holds no copy cannot diverge in one.
The contract version rule covers what remains: a sibling checkout that is simply older than the content beside it. Enforcing metadata_version makes a stale contract fail with a name attached, and makes raising the version the deliberate act it should be when the contract changes.
The rule needs one place where the accepted versions are declared, and it is the metadata_version enum in metamodel/profile-artifact.schema.yaml. The validator reads it from there rather than carrying a second list, and reads it from its own checkout rather than from the tree it was pointed at, so a run against private content answers with the contract of the tooling doing the validating. A build that borrows this repository as its metamodel can read the same file to report what its checkout accepts.
Absence is not read as the initial version. An artifact that declares no metadata_version fails as a missing field, because a default would let content say nothing about its contract and still pass — and a checkout older than that content would then accept it silently, which is the mismatch this rule exists to catch.
Neither rule catches a contract change nobody versioned. That is a discipline gap rather than a mechanism gap, and no inexpensive check closes it.
10.10.9. Implementation Status
The decision holds; the rules it accepts are at different stages, and this section says which is which so the documentation does not claim protection that does not exist yet.
| Rule | State | Where |
|---|---|---|
Sibling checkout as the tooling access mechanism |
implemented |
|
No second implementation in the private repository |
implemented for the private build |
|
|
implemented |
Declared in |
Promotion saga: validate, then public, then private |
decided, not implemented |
|
Private deployment runs locally |
decided, not implemented |
metadata_version is required on every artifact, and the validator rejects a version outside the accepted set by name. Both drift rules are in force, and the private build applies them: buildSitePrivate validates the private content root with this repository’s validator before rendering it, and reads the accepted versions from this checkout rather than from the tree beside the content.
What the private build does not yet do is run the generators against the private tree, so a private page carries no tags, no article navigation, and no series links. The generators write link registries into the includes tree, which for the private target is this repository’s — a generator run would write into the public checkout while rendering private content. That is a real coupling and not a detail of wiring, so it is left to a slice of its own rather than solved in passing.
This was the gate on private-source work. No slice that reads private source or promotes an article was to run before the accepted-version check existed, because a promotion validated against an unenforced contract is the exact failure this decision claims to prevent. #83 closed that gate; the remaining private slices are ordered by their own dependencies.
10.10.10. Consequences
Positive:
-
The privacy boundary is solved at source level without making the generated deployment the only control.
-
Shared generators and validators remain in one owner repository.
-
The private repository can be developed and deployed independently while still obeying the same metadata contracts.
-
The project avoids Git submodule complexity until there is concrete evidence that it is needed.
Negative:
-
The private repository build must locate the sibling public checkout, and fails without it.
-
A sibling checkout can lag behind the content beside it. The contract version rule turns that into a named failure rather than a silent one.
-
Local development requires two checkouts for private builds.
-
Promotion crosses a repository boundary and cannot be atomic. Its incomplete state is a duplicated article, which someone or something has to notice and finish. The saga puts that state on the recoverable side rather than removing it.
-
A promotion cannot be undone by reversing it. Once the public push has happened, the article is in public history, and withdrawing it is a public change rather than a return.
Neutral or follow-up:
-
A later packaging step may turn shared tooling into a reusable toolkit artifact if local path coupling becomes painful.
-
A Git submodule can be reconsidered if reproducible pinning becomes more important than simple authoring.
10.10.11. Review Outcome
The site owner confirmed the four open points at acceptance:
-
the private repository is
dieterbaier/profile-private; -
tooling access is a sibling checkout, not a packaged version and not a submodule;
-
private deployment runs locally, not in GitHub Actions;
-
drift is prevented by the no-second-implementation rule together with an enforced
metadata_version.
The same review corrected promotion from a copy to a move.
A second review round sharpened two claims this record had overstated. A cross-repository move is not atomic, so the promotion is described as a saga with a leading repository, an order, its stop states, and their recovery. The metadata_version protection is decided but not yet built, so the Implementation Status section separates what holds from what runs.
10.11. ADR-010: Multilingual Content And Language Fallback
10.11.1. Status
Accepted.
The decision was drafted AI-assisted, then reviewed and accepted by the accountable owner with all open questions decided and all traceability relations confirmed.
10.11.2. Decision
The site becomes multilingual with de as the default language, and every language-dependent reference is resolved at build time in the profile artifact generator rather than in AsciiDoc markup or at page runtime.
Four resolution classes are distinguished, because they need different fallback semantics:
-
UI chrome (menu labels, table-of-contents title, comment section wording, footer): resolved through an attribute cascade, and required to be complete per language. A missing key fails the build.
-
Content fragments (reusable includes such as profile prose, CV blocks, contact data): resolved through per-language include trees and required to exist in the language of the including page. A fragment that is not available in the page language fails the build; fragments never fall back.
-
References to pages (menu links, footer links, article navigation, tag and skill listings): resolved through a generated per-language link registry. A missing translation falls back to the default-language page, the link is marked with the target language, and the generator warns.
-
Translation provenance (which variant is the original, and whether a translation still matches it): recorded in metadata, derived by the generator, overridable by the author, and rendered as a reader-facing note at the top of a translated page.
Fallback and hard failure are therefore deliberately split along the line of what a reader can make sense of. A link that leads to a German page is usable, so it falls back and says so. A German paragraph inside an English article is not, so it fails the build instead of producing a page in mixed languages.
Every language variant of an artifact is a profile artifact in its own right, with its own stable ID, its own sidecar metadata, and its own comment thread.
Default language and original language are deliberately separate concepts. de is the default language, which means it is the fallback target when a translation is missing. The original is the variant an artifact was authored in first, which may be any language. An article written in English and translated into German afterwards is therefore an English original with a German translation, while German remains the site’s fallback language.
10.11.3. Context
The site currently exists in German only. src-content/profile/includes/docheader.adoc already defaults :lang: to de, and article sources already use en for external links, so the language attribute exists but carries no structural meaning. All chrome is hard-coded German: menue.adoc contains German labels and hard-coded relative page paths, docheader.adoc sets :toc-title: Inhalt, includes/docinfo/docinfo-footer.html links to {basedir}/legal.html, and src-content/theme/article-comments.js carries German status strings.
The authoring concept relies on reusable includes. Writing an article in another language therefore does not only mean translating the article body; the surrounding generated chrome must switch language as well, and the references inside it must point at same-language pages where those exist.
The core constraint is that AsciiDoc has no file-existence conditional. ifdef and ifeval evaluate attributes only, and opts=optional expresses "include or skip", not "include A, otherwise B". A language-aware include or xref cannot be expressed in portable AsciiDoc markup. Only the build knows which language variants exist, and the profile artifact generator (scripts/validate-profile-metamodel.rb) already owns exactly that knowledge: it reads every .profile.yaml, and it already writes per-article navigation, tag, and comment includes plus the article listings.
The comment integration adds a second constraint. Comment threads are keyed by article ID, and generateProfileArtifacts synchronizes an allowlist of published article IDs to the comments repository. Any language model that does not produce a stable ID per language variant would break that contract.
10.11.4. Decision Drivers
-
Authoring must stay previewable in a plain AsciiDoc editor, without a custom build extension.
-
A page reference must never lead nowhere, whether the translation exists or not.
-
A published page must never mix languages in its body text.
-
The reader must be able to tell when a reference leads to another language.
-
Language selection must not require a backend, a redirect layer, or client-side negotiation.
-
Adding a translation must not require manual maintenance of link tables or duplicated chrome.
-
Missing translations must be detectable by validation, not by reading the rendered site.
-
A reader must be able to tell that a page is a translation, which variant it was translated from, and whether it still matches that original.
10.11.5. Considered Options
Option 1: Build-time resolution in the profile artifact generator
The generator resolves language and emits per-language artifacts: a link registry, per-language navigation, listings, comment blocks, and provenance notes. Markup contains only attribute references that always resolve. UI terms use a plain AsciiDoc attribute cascade, since later attribute assignments override earlier ones. Fragment availability is validated rather than filled in.
Option 2: Custom Asciidoctor include processor and inline macro
A Ruby extension registered in the Gradle build handles a custom scheme such as include::i18n:profile/profile.adoc[] and implements the fallback chain in code. No generated stub files are needed.
Option 3: Runtime language negotiation
The published site keeps a single page set and selects language in the browser or in the hosting layer, for example through JavaScript string swapping or server-side rewrites.
Option 4: Fully duplicated language trees without fallback
Each language maintains its own complete copy of chrome, fragments, and pages. No fallback exists; an untranslated page simply does not exist in that language.
10.11.6. Pugh Matrix
| Criterion | Build-time resolution in generator | Asciidoctor extension | Runtime negotiation | Duplicated trees |
|---|---|---|---|---|
Editor preview works without custom tooling |
+1 |
-1 |
0 |
+1 |
References always resolve |
+1 |
+1 |
0 |
-1 |
Fallback is visible and reviewable |
+1 |
0 |
-1 |
-1 |
Keeps the site static (QS-004) |
+1 |
+1 |
-1 |
+1 |
Low authoring effort per translation |
+1 |
+1 |
0 |
-1 |
Missing translations detectable by validation |
+1 |
0 |
-1 |
-1 |
Fits the existing generator responsibility |
+1 |
0 |
-1 |
0 |
Sum |
+7 |
+2 |
-4 |
-2 |
Option 2 loses mainly on tooling: a custom include processor is invisible to the IntelliJ AsciiDoc preview, which breaks the authoring loop for the person who writes the content. Option 3 contradicts ADR-005: Minimal Static Site. Option 4 pushes drift detection to the reader.
10.11.7. Language Contract
| Contract | Rule |
|---|---|
Default language |
|
Language declaration |
Each artifact declares |
Source and URL layout |
The default language stays at the site root permanently; it is not moved into a |
Artifact identity |
Each language variant is its own artifact with its own ID, for example |
Original and translation |
An artifact without |
Translation freshness |
A translation records the digest of the original’s full source content at translation time. The generator recompares it against the current original and marks the translation as outdated on mismatch. An outdated translation stays publishable; it is never a build failure. |
Author override |
The derived freshness state is a default, not a verdict. The author can re-accept the current original without changing the translation, which clears the outdated state and suppresses its note. This is the intended answer to a cosmetic change in the original, such as a typo fix. |
Intentional divergence |
Independently of freshness, a translation can declare that it deliberately differs from its original. The declaration is shown to the reader even when the translation is in sync. |
Reader-facing provenance |
The generator renders a note at the top of every translated page, in the page language: "Das ist eine Übersetzung vom Originalartikel …" / "This is a translation of the original …", linking to the original. Outdated state and declared divergence are shown as additional notes and may appear together. The note is emitted as a generated per-article include, like the existing tag and comment includes. |
Language switcher |
The switcher is present on a page as soon as the artifact exists in more than one language, and offers the languages in which the artifact really exists. |
CV outputs |
The CV follows the same language model as site pages, and the PDF build produces one PDF per CV language variant. |
UI chrome |
|
Content fragments |
Fragments live under |
Page references |
Chrome and content reference pages through generated attributes such as |
Build failures |
Missing UI key for a configured language; fragment not available in the page language; unresolvable link registry key; metadata violations such as an unknown |
Warnings |
Page references that fall back to the default language because no translation exists, reported per generated language page; untranslated fragments that no page includes yet, reported as translation coverage. |
Comments |
Each language variant gets its own comment thread, keyed by its own artifact ID. The published-ID allowlist synchronization is unchanged and simply covers more IDs. |
HTML metadata |
|
Client-side strings |
JavaScript in |
10.11.8. Consequences
Positive
-
A page reference never leads nowhere; the worst case is a default-language page, explicitly marked as such.
-
A published page is never a mix of languages, because the build refuses to produce one.
-
AsciiDoc sources stay standard: attribute references and ordinary includes, previewable in any editor.
-
The generator already owns per-article generated includes and listings, so the language dimension extends an existing responsibility instead of adding a new component.
-
Fragment resolution needs no generated stub files at all: a fragment either exists in the page language or the build stops, which keeps the include trees free of machine-written filler.
-
Language selection produces plain static files with no runtime negotiation, preserving QS-004: Minimal Static Site.
-
Existing default-language URLs remain unchanged, so canonical URLs and the comment allowlist keep working.
-
Translation provenance is explicit for the reader instead of implicit, and staleness is detected mechanically rather than remembered by the author.
-
Because the original is declared per artifact rather than fixed to the default language, articles can be authored in any language without inverting the site’s fallback rules.
Negative
-
The generator, the profile validator, and the profile metamodel all grow a language dimension, and the generated file count multiplies with the number of languages.
-
Language variants can drift apart in content while both remain publishable, which increases RISK-001: Metadata Drift.
-
Hard-coded paths in
menue.adocanddocinfo-footer.htmland the German literals indocheader.adocandarticle-comments.jsmust be migrated before the first non-default page is published. -
Discussion about one article is split across language threads.
-
Translation freshness depends on a recorded digest that must be re-accepted deliberately, which adds a step to the translation workflow.
-
Because the digest covers the full source, a cosmetic edit to an original marks its translations as outdated even when the meaning did not change. The author override exists precisely for this case, but it must be exercised.
-
A page cannot be published in a new language before every fragment it includes is translated. This is the intended trade-off against mixed-language pages, but it makes fragment-heavy artifacts such as the CV an all-or-nothing translation effort rather than an incremental one.
Neutral or Follow-Up
-
Translation drift is covered by RISK-001: Metadata Drift; no dedicated risk artifact is created for it.
-
The
language: mixedvalue, used by nine profile artifacts, is resolved to a concrete language when the metamodel gains the language dimension. The value disappears from the vocabulary: a page may only include fragments of its own language, so an artifact is always written in exactly one language. -
The placement of the language switcher in the chrome is a presentation detail left to implementation.
-
Fragment granularity becomes a design lever: the finer the fragments, the smaller the unit that blocks a translated page from being published.
10.11.9. Assumptions
-
The site is served from the domain root, so root-relative URLs in the generated link registry are valid for the site build while the existing
ifdef::buildsite[]branch keeps relative paths for PDF and local builds. -
Language-dependent attributes are not set through the Gradle
attributes(…)map, because API-set attributes are locked and could not be overridden by:lang:in a document. -
English is the first additional language; no right-to-left language is planned.
10.11.10. Open Questions
None. The questions raised while drafting this ADR were decided by the accountable owner and folded into the language contract above: outdated translations stay publishable with a visible note, the digest covers the full article source, freshness and divergence notes may appear together, the author can override the derived freshness state, and the language switcher appears whenever an artifact exists in more than one language.
10.11.11. Review Notes
Reviewed and accepted by the accountable owner. The following were confirmed during review:
-
the language subtree layout and the
-<lang>ID suffix convention for translated artifacts; -
translation drift stays covered by RISK-001 without a dedicated risk artifact;
-
the reader-facing wording for a translated page and the
(de)marker behind a link that falls back; -
the split between build failures and warnings recorded in the language contract.
Implementation is tracked in GitHub issue #47 and its slices.
10.12. ADR-011: Preview Visibility Without Authentication
10.12.1. Status
Accepted by the site owner.
10.12.2. Decision
The site owner decides that preview.dieterbaier.eu serves the preview target without authentication. Preview pages carry noindex metadata and no canonical link, and every article whose status is not published carries a visible notice saying that it is not finished.
The public site never links to the preview target. No page, listing, navigation entry, related-article suggestion, or link registry entry generated into dieterbaier.eu points at preview.dieterbaier.eu. A preview URL is something a reviewer is handed, not something a reader can arrive at.
Basic Auth stays on the private target, where it protects content whose source is not public.
10.12.3. What This Replaces In ADR-008
ADR-008 remains accepted. Three statements in it are replaced by this record:
-
its Decision section, where preview and private deployments are described as rendering "without canonical links, with
noindexmetadata, and behind Basic Auth" — for the preview target the last clause no longer holds; -
its consequence "Basic Auth is required for generated preview and private deployments";
-
its Review Notes entry confirming that "preview and private deployments require Basic Auth".
ADR-008’s own publication target deployment diagram already shows the preview target as noindex, no canonical with no Basic Auth, and names Basic Auth on the private target only. The diagram agrees with this record; the prose did not.
Everything else in ADR-008 stands, including the repository boundary, the metadata-driven targets, and Basic Auth for the private target.
10.12.4. Context
The preview target is built from the public repository. An article reaches it by being promoted into public source, which means its text is already readable in Git by anyone before any page is deployed. Authentication in front of the rendered pages therefore guards a copy of something already published in another form.
What the preview target does need is that its pages are not mistaken for finished work: not indexed, not canonical, and not read as a statement the author stands behind. The first two are technical and invisible to a reader. The third is what a password was standing in for, badly — a credential prompt says "you may not read this", which is not the message, and once a reviewer has the credential the prompt says nothing at all.
Reachability is a separate question from indexing. noindex keeps a preview page out of search results; a link from the public site would put it in front of readers who never searched for it, and would make an unfinished article part of the site’s navigable surface. The two rules cover the two ways a reader arrives.
The private target is a different case and keeps its access boundary. Its source is not public, so the deployment is the only place its content could leak.
10.12.5. Options
| Criterion | Open preview with noindex and a visible notice | Basic Auth in front of the preview target | Unguessable preview URLs |
|---|---|---|---|
Protects something not already public |
0 |
-1 |
-1 |
Tells a reader the article is unfinished |
+1 |
-1 |
-1 |
Keeps the page out of search results |
+1 |
+1 |
+1 |
Lets a reviewer read it without a credential handshake |
+1 |
-1 |
+1 |
Honest about what it protects |
+1 |
-1 |
-1 |
Low operational overhead |
+1 |
-1 |
0 |
Sum |
+5 |
-4 |
-1 |
Basic Auth ties the chosen option on exactly one criterion — keeping the page out of search results — and noindex achieves that without it. On the other five it loses. It costs credential handling, rotation, and a handshake with every reviewer, and it buys protection for content that is public in source. It also misleads: a reader who gets past it reasonably concludes the page was worth protecting.
Unguessable URLs lose for the same reason without the operational cost. Obscurity that is described as protection is the more dangerous of the two, because nothing about it fails visibly.
10.12.6. Consequences
Positive:
-
No credentials to issue, rotate, or revoke for review; a preview link is shareable as a link.
-
The signal a reader needs is on the page, where a reader can act on it, instead of in HTTP metadata that only a crawler reads.
-
The preview target’s access rule now matches ADR-008’s deployment diagram, so the two no longer disagree.
-
The no-link rule needs little new machinery. Public listings, navigation, and related-article suggestions are generated from metadata and already carry
publishedarticles only, so a preview article has no generated route into the public site.
Negative:
-
An unfinished article is readable by anyone holding its URL. This raises RISK-005 on the human-reader side;
noindexaddresses only crawlers. -
The notice becomes load-bearing. If it is missing, wrong, or unreadable in one language, nothing else tells the reader what they are looking at.
-
The no-link rule holds for generated links by construction, but a hand-written link in article prose is outside that guarantee and needs a check of its own.
Neutral or follow-up:
-
The notice is a signal, not a control. Nothing about preview visibility may be relied on for confidentiality; content that must not be readable does not belong in public source, which is ADR-008’s rule and is unchanged.
-
Wording, per-status text, and language parity for the notice are implementation work tracked as GitHub issue #88.
10.12.7. Review Outcome
The site owner raised the contradiction, confirmed that the deployment diagram and not the prose states the intent, and answered both open points at acceptance:
-
a preview page carrying
noindex, no canonical link, and a visible notice is sufficient for the review use case; -
the preview target must never be reachable from the public site, which is why the no-link rule is part of the decision rather than a follow-up.
10.12.8. Implementation Status
The decision holds; the mechanisms that carry it are at different stages.
| Rule | State | Where |
|---|---|---|
Preview served without authentication |
decided |
Nothing to implement; the preview deployment is #79 |
|
decided, not implemented |
|
No generated link from the public site to preview |
implemented |
Public listings, navigation, and related entries carry |
No hand-written link from the public site to preview |
decided, not implemented |
Checked as part of #79 |
Visible notice on every article that is not published |
decided, not implemented |
Until the notice exists, a preview page carries no reader-facing signal at all. The preview deployment therefore waits for #88: the decision removes an access boundary and puts the notice in its place, so deploying the one without the other would leave an unfinished article publicly readable with nothing saying so. This is a blocking dependency of #79, recorded there and in the epic rather than only here.
10.13. ADR-012: Reading Context of the Private Target
10.13.1. Status
Accepted by the site owner on 2026-08-04, after the first private render in GitHub issue #86 raised the question.
10.13.2. Decision
The private target is rendered from the private content root alone, with this repository’s theme, includes, and page chrome. A draft is read as a styled page, and links that leave it — start page, CV, legal notice, article listings — do not resolve, because their targets are not in this repository.
That is accepted rather than worked around. If it turns out to obstruct reading, this record is superseded rather than amended.
Two rules come with it:
-
A collision between private and public source is an error, reported as early as it can be seen rather than when an article is promoted.
-
The pipeline keeps non-public targets away from the public deployment. The safeguard is in CI, not in the shape of the rendered output.
10.13.3. Context
ADR-009 gives the private repository content and nothing else. The first private render therefore produced what the private repository contains: three article pages and the theme, with no site around them. Every link in the page chrome points at a file that is not in the target.
The target exists so a draft can be read as a finished page before anything is decided about it. The open question was whether "as a finished page" requires the finished site around it.
The preview target does not have this problem, and stating that here keeps it
from being solved twice. Promotion moves an article into the public repository
and sets status: preview there. build/site-preview is built from public
source only, as #78 specifies,
so it already contains the whole public site plus the preview articles. Only the
private target reads from a tree that holds articles alone.
10.13.4. Options
| Criterion | Private content only | Compose public site and private content | Generated minimal shell | Read only after promotion to preview |
|---|---|---|---|---|
A draft is read as the page it will become |
-1 |
+1 |
0 |
+1 |
Links in the site chrome resolve |
-1 |
+1 |
0 |
+1 |
An unfinished article is not published in order to read it |
+1 |
+1 |
+1 |
-1 |
A draft is read without leaving the private repository |
+1 |
+1 |
+1 |
-1 |
No invented structure that matches no real site |
+1 |
+1 |
-1 |
+1 |
Cost of one private render |
+1 |
-1 |
0 |
+1 |
Failure modes are easy to reason about |
+1 |
0 |
-1 |
+1 |
Sum |
+3 |
+4 |
0 |
+3 |
Private content only is what #86 built and what this record accepts. It is the cheapest and the most predictable, and its output is plainly not a site.
Compose public site and private content renders both trees into one target. It scores one point higher, and the point it wins is the reading context.
Generated minimal shell would produce just enough index and menu targets for the links to resolve. It invents a structure that matches no real site, so a draft would be read inside a fourth thing that exists only in this target.
Read only after promotion to preview removes the private reading target entirely. It scores well until the criterion that matters: the article would be publicly reachable — ADR-011 removed the access boundary in front of preview — before its author had read it as a page once.
10.13.5. Why The Matrix Did Not Decide It
The chosen option is not the highest-scoring one, and the difference is a single point on seven criteria. The owner weighed the two criteria that separate them — reading context against cost and predictability — and judged the broken chrome tolerable for a target read by the person who wrote its content and knows why the links fail.
The matrix is kept as it was scored rather than re-weighted to agree with the outcome. A matrix adjusted until it produces the decision already made records nothing.
10.13.6. Review Outcome
The site owner accepted the decision and answered all three open questions:
-
Collision rule: error, as early as possible. The alternative — discovering it when an article becomes reviewable or public — puts the collision at the moment the article is being written into the public repository, which is the worst time to find it. The owner is the only author, so a collision is a mistake rather than a coordination event; if several people ever draft here, the same check is what makes that safe. Implemented by #94.
-
Public articles in the private listings: accepted. The private status set includes
published, so they appear. Nothing about that needs a rule. -
Protection against deployment: in the pipeline. The owner does not regard the merged-looking output as the danger. What must hold is that CI never publishes the private or the preview target to the public destination, which is #95.
10.13.7. Consequences
Positive:
-
The private build stays cheap: three drafts render without rendering the whole public site.
-
The output is obviously not a site, which is itself a safeguard against mistaking it for one.
-
No structure is invented for this target, so nothing in it can drift from a site that exists.
-
The collision rule moves a class of promotion failure to the point where the draft is written instead of the point where it is published.
Negative:
-
Links out of a draft do not resolve, and the reader has to separate the draft’s defects from the target’s.
-
The private reading and the later preview reading have different shapes, so what the private read shows about page context carries over only partly.
-
The safeguard against publishing a non-public target now lives in CI, away from the target it protects. A pipeline change is what would break it, and that is the thing #95 has to make visible.
10.13.8. Implementation Status
The decision holds; the rules it accepts are at different stages.
| Rule | State | Where |
|---|---|---|
Private target rendered from private source alone |
implemented |
|
Theme, includes, and page chrome come from this repository |
implemented |
|
Collision between private and public source is an error |
decided, not implemented |
|
The pipeline keeps non-public targets out of the public deployment |
decided, not implemented |
11. Quality Requirements
11.1. Quality Tree
11.2. Quality Goals
11.2.1. Quality Goal Index
| ID | Priority | Quality goal | Meaning |
|---|---|---|---|
1 |
Reproducibility |
Same source and environment produce the same generated artifacts. |
|
2 |
Maintainability |
Content, presentation, metadata, and build logic have explicit responsibilities. |
|
3 |
Automation |
Normal publishing and validation run without manual transformation steps. |
|
4 |
Correctness |
Generated public artifacts reflect the intended source content and metadata. |
|
5 |
Sustainability |
The site and pipeline avoid unnecessary runtime logic, tracking, and waste. |
11.2.2. QG-001: Reproducibility
Meaning
Same source and environment produce the same generated artifacts.
Priority
1
Quality Scenarios
| ID | Scenario | Response measure |
|---|---|---|
Reproducible Build |
The same task succeeds twice without source changes |
11.2.3. QG-002: Maintainability
Meaning
Content, presentation, metadata, and build logic have explicit responsibilities.
Priority
2
Quality Scenarios
No quality scenarios currently refine this quality goal.
11.2.4. QG-003: Automation
Meaning
Normal publishing and validation run without manual transformation steps.
Priority
3
Quality Scenarios
No quality scenarios currently refine this quality goal.
11.2.5. QG-004: Correctness
Meaning
Generated public artifacts reflect the intended source content and metadata.
Priority
4
Quality Scenarios
| ID | Scenario | Response measure |
|---|---|---|
Profile Metadata Validity |
Validator exits non-zero on missing required fields or broken relations |
|
Public Artifact Consistency |
Generated indexes list every metadata-backed article and project |
|
Publication Visibility Boundary |
|
11.2.6. QG-005: Sustainability
Meaning
The site and pipeline avoid unnecessary runtime logic, tracking, and waste.
Priority
5
Quality Scenarios
| ID | Scenario | Response measure |
|---|---|---|
Minimal Static Site |
No backend call is required for core content display |
11.3. Quality Scenarios
11.3.1. Quality Scenario Index
| ID | Quality goal | Source | Stimulus | Artifact | Environment | Response | Response measure |
|---|---|---|---|---|---|---|---|
Developer or CI runner |
runs a build from unchanged sources |
Gradle build pipeline |
normal build environment |
generates equivalent output artifacts |
The same task succeeds twice without source changes |
||
Contributor |
changes profile metadata |
profile artifact metadata |
pre-render validation |
invalid metadata stops the build |
Validator exits non-zero on missing required fields or broken relations |
||
Reader |
opens generated website, CV, README, or article export |
generated artifact |
after CI deployment |
content reflects the source artifact |
Generated indexes list every metadata-backed article and project |
||
Website visitor |
loads a public page |
website output |
normal browsing |
page works without application backend or trackers |
No backend call is required for core content display |
||
Site owner |
changes an article status or promotes an article between repositories |
generated public, preview, and private site targets |
during local build or CI build before deployment |
each publication target contains only the statuses allowed for that target; preview and private targets emit |
|
11.3.2. QS-001: Reproducible Build
Quality Goal
Scenario
| Element | Description |
|---|---|
Source |
Developer or CI runner |
Stimulus |
runs a build from unchanged sources |
Artifact |
Gradle build pipeline |
Environment |
normal build environment |
Response |
generates equivalent output artifacts |
Response Measure |
The same task succeeds twice without source changes. |
11.3.3. QS-002: Profile Metadata Validity
Quality Goal
Scenario
| Element | Description |
|---|---|
Source |
Contributor |
Stimulus |
changes profile metadata |
Artifact |
profile artifact metadata |
Environment |
pre-render validation |
Response |
invalid metadata stops the build |
Response Measure |
Validator exits non-zero on missing required fields or broken relations. |
11.3.4. QS-003: Public Artifact Consistency
Quality Goal
Scenario
| Element | Description |
|---|---|
Source |
Reader |
Stimulus |
opens generated website, CV, README, or article export |
Artifact |
generated artifact |
Environment |
after CI deployment |
Response |
content reflects the source artifact |
Response Measure |
Generated indexes list every metadata-backed article and project. |
11.3.5. QS-004: Minimal Static Site
Quality Goal
Scenario
| Element | Description |
|---|---|
Source |
Website visitor |
Stimulus |
loads a public page |
Artifact |
website output |
Environment |
normal browsing |
Response |
page works without application backend or trackers |
Response Measure |
No backend call is required for core content display. |
11.3.6. QS-005: Publication Visibility Boundary
Quality Goal
Scenario
| Element | Description |
|---|---|
Source |
Site owner |
Stimulus |
changes an article status or promotes an article between repositories |
Artifact |
generated public, preview, and private site targets |
Environment |
during local build or CI build before deployment |
Response |
each publication target contains only the statuses allowed for that target; preview and private targets emit |
Response Measure |
|
Assumptions
The public half of the response measure is verified: build/site is rendered
from a metadata-derived source set that carries published only, specified in
features/article-publication-status.feature and bridged to
test/profile_publication_status_test.rb.
The preview and private half is not. Those targets do not exist yet, so the
noindex and canonical-link part of the measure has nothing to verify against.
The mechanism for it is still open and may become a Gradle verification task
that inspects generated HTML.
12. Risks and Technical Debt
12.1. Risks
| ID | Risk | Probability | Impact | Priority | Mitigation/action |
|---|---|---|---|---|---|
Metadata Drift |
Medium |
Medium |
Medium |
- |
|
Build Toolchain Drift |
Medium |
High |
High |
- |
|
Private Data Exposure |
Low |
High |
Medium |
- |
|
Source Boundary Leakage |
Medium |
High |
High |
||
Preview Mispublication |
Medium |
Medium |
Medium |
12.2. RISK-001: Metadata Drift
12.2.1. Risk Statement
Because content and metadata evolve separately, generated indexes may become incomplete, leading to misleading public artifacts.
12.2.2. Assessment
| Field | Value |
|---|---|
Likelihood |
Medium |
Impact |
Medium |
Priority |
Medium |
Timeframe |
medium-term |
Confidence |
medium |
12.2.3. Mitigation Options
-
Validate metadata before build and generate indexes from source metadata.
12.3. RISK-002: Build Toolchain Drift
12.3.1. Risk Statement
Because local and CI tool versions may diverge, builds may become non-reproducible, leading to deployment failures.
12.3.2. Assessment
| Field | Value |
|---|---|
Likelihood |
Medium |
Impact |
High |
Priority |
High |
Timeframe |
medium-term |
Confidence |
medium |
12.3.3. Mitigation Options
-
Use containerized builds and expose environment checks as Gradle tasks.
12.4. RISK-003: Private Data Exposure
12.4.1. Risk Statement
Because CV builds can inject private contact data, secrets may be exposed if environment handling is wrong.
12.4.2. Assessment
| Field | Value |
|---|---|
Likelihood |
Low |
Impact |
High |
Priority |
Medium |
Timeframe |
medium-term |
Confidence |
medium |
12.4.3. Mitigation Options
-
Keep private data in environment variables and exclude local
.envfiles from version control.
12.5. RISK-004: Source Boundary Leakage
12.5.1. Risk Statement
Because private drafts and public preview content are promoted across repository boundaries, private-only source material may be copied into the public repository, leading to irreversible disclosure through public Git history.
12.5.2. Assessment
| Field | Value |
|---|---|
Likelihood |
Medium |
Impact |
High |
Priority |
High |
Timeframe |
near-term |
Confidence |
medium |
12.5.3. Mitigation Options
-
Keep truly private content in a private repository until it is intentionally promoted.
-
Start with a local promotion script so the owner reviews the diff before push.
-
Add promotion checks for private-only markers, disallowed paths, and status transitions.
-
Treat
previewas reviewable public-source content, not as confidential content. -
If private material enters public Git history, rotate affected secrets and rewrite history only after an explicit incident decision.
12.6. RISK-005: Preview Mispublication
12.6.1. Risk Statement
Because public, preview, and private builds share article sources and build tooling, preview articles may be included in the public website or indexed by search engines, leading to premature or misleading publication.
12.6.2. Assessment
| Field | Value |
|---|---|
Likelihood |
Medium |
Impact |
Medium |
Priority |
Medium |
Timeframe |
near-term |
Confidence |
medium |
12.6.3. Mitigation Options
-
Generate article matrices and source lists from metadata instead of maintaining public links manually.
-
Add a verification task that fails if
build/sitecontains non-publishedarticles. -
Add a verification task that fails if preview/private HTML contains canonical links or lacks
noindex. -
Keep deployment jobs target-specific so preview artifacts cannot be uploaded to the public webspace by a reused deploy step.
13. Glossary
| Term | Definition |
|---|---|
Profile artifact |
A content source that contributes independently meaningful personal profile knowledge. |
Sidecar metadata |
YAML metadata stored next to include-heavy AsciiDoc fragments to avoid rendering metadata as content. |
Generated fragment |
Derived AsciiDoc output produced by a generator and not edited manually. |
14. Appendix
14.1. Questions and Answers
14.1.1. Q-001 Is the profile metamodel accepted?
Status: open.
The bootstrap derives a profile metamodel from the existing content and the architecture-knowledge-toolkit pattern. A human review should confirm artifact types, required fields, and whether further profile fragments need first-class metadata.
14.1.2. Q-002 Which canonical publication URLs should generated summaries use?
Status: open.
AI-generated article publication packs must not invent URLs. Missing canonical URLs remain placeholders until supplied.
14.1.3. Q-003 How should this project demonstrate the Docs-as-Code Toolkit layers?
Status: open.
Current assumption: The profile project should remain a concrete running
example, not a second copy of the organization positioning. It should show that
profile content and architecture metadata are authoritative source knowledge,
while generated website, README, CV, article, and architecture outputs are
derived publication artifacts. docs-toolbox is the reproducible rendering
runtime; docToolchain or similar tools could be combined with the same source
model in other projects.
14.2. Traceability Matrix
| Artifact ID | Type | Title | Status | Outgoing relations | Incoming relations |
|---|---|---|---|---|---|
ADR |
AsciiDoc as Primary Source |
proposed |
addresses → QS-003-public-artifact-consistency |
- |
|
ADR |
Gradle Build Orchestration |
proposed |
addresses → QS-001-reproducible-build |
- |
|
ADR |
Containerized Build Runtime |
proposed |
addresses → QS-001-reproducible-build |
- |
|
ADR |
Pandoc Markdown Export |
proposed |
addresses → QS-003-public-artifact-consistency |
||
ADR |
Minimal Static Site |
proposed |
addresses → QS-004-minimal-static-site |
- |
|
ADR |
Profile Content Metamodel |
proposed |
addresses → QS-002-profile-metadata-validity |
ADR-010-multilingual-content-fallback → refines |
|
ADR |
Build-Generated Article Summaries |
proposed |
addresses → QS-003-public-artifact-consistency |
COMP-006-article-summary-generator → depends_on |
|
ADR |
Private To Public Article Lifecycle |
accepted |
addresses → QS-005-publication-visibility-boundary |
DOC-06001-private-to-public-article-lifecycle-runtime → depends_on |
|
ADR |
Private Repository Integration |
accepted |
addresses → QS-005-publication-visibility-boundary |
ADR-008-private-to-public-article-lifecycle → depends_on |
|
ADR |
Multilingual Content And Language Fallback |
accepted |
addresses → QS-003-public-artifact-consistency |
- |
|
ADR |
Preview Visibility Without Authentication |
accepted |
addresses → QS-005-publication-visibility-boundary |
- |
|
ADR |
Reading Context of the Private Target |
accepted |
depends_on → ADR-009-private-repository-integration |
- |
|
Component |
Publication Target Generator |
proposed |
addresses → QS-005-publication-visibility-boundary |
ADR-010-multilingual-content-fallback → affects |
|
Component |
Architecture Metamodel Validator |
proposed |
refines → DOC-05000-building-block-view |
- |
|
Component |
Profile Metamodel Validator |
proposed |
addresses → QS-002-profile-metadata-validity |
- |
|
Component |
Architecture Artifact Generator |
proposed |
refines → DOC-05000-building-block-view |
- |
|
Component |
Profile Artifact Generator |
proposed |
addresses → QS-003-public-artifact-consistency |
ADR-010-multilingual-content-fallback → constrains |
|
Component |
Article Summary Generator |
proposed |
depends_on → ADR-007-build-generated-article-summaries |
- |
|
CANVAS-001-business-model |
Document |
Business Model Canvas |
draft |
- |
- |
CANVAS-002-value-proposition |
Document |
Value Proposition Canvas |
draft |
- |
- |
CANVAS-003-architecture-inception |
Document |
Architecture Inception Canvas |
draft |
- |
- |
CANVAS-004-architecture-communication |
Document |
Architecture Communication Canvas |
draft |
- |
- |
CANVAS-005-techstack |
Document |
Techstack Canvas |
draft |
- |
- |
DOC-001-profile-dieterbaier-arc42 |
Document |
Profile Dieter Baier arc42 Architecture |
draft |
documents → DOC-01000-introduction-and-goals |
- |
DOC-002-vision-mission |
Document |
Vision and Mission |
draft |
- |
- |
DOC-004-roadmap |
Document |
Roadmap |
draft |
- |
- |
Document |
Introduction and Goals |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Profile Product Goals |
draft |
documents → ADR-008-private-to-public-article-lifecycle |
- |
|
Document |
Architecture Constraints |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
System Scope and Context |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Solution Strategy |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Building Block View |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Runtime View |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Private To Public Article Lifecycle Runtime |
proposed |
depends_on → ADR-008-private-to-public-article-lifecycle |
- |
|
Document |
Deployment View |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Crosscutting Concepts |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Architecture Decisions |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Quality Requirements |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Risks and Technical Debt |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Glossary |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
Document |
Appendix |
draft |
- |
DOC-001-profile-dieterbaier-arc42 → documents |
|
QG-001-reproducibility |
QualityGoal |
Reproducibility |
proposed |
refines → DOC-10000-quality-requirements |
QS-001-reproducible-build → refines |
QG-002-maintainability |
QualityGoal |
Maintainability |
proposed |
refines → DOC-10000-quality-requirements |
- |
QG-003-automation |
QualityGoal |
Automation |
proposed |
refines → DOC-10000-quality-requirements |
- |
QG-004-correctness |
QualityGoal |
Correctness |
proposed |
refines → DOC-10000-quality-requirements |
QS-002-profile-metadata-validity → refines |
QG-005-sustainability |
QualityGoal |
Sustainability |
proposed |
refines → DOC-10000-quality-requirements |
QS-004-minimal-static-site → refines |
QS-001-reproducible-build |
QualityScenario |
Reproducible Build |
proposed |
refines → QG-001-reproducibility |
ADR-002-gradle-build-orchestration → addresses |
QS-002-profile-metadata-validity |
QualityScenario |
Profile Metadata Validity |
proposed |
refines → QG-004-correctness |
ADR-006-profile-content-metamodel → addresses |
QS-003-public-artifact-consistency |
QualityScenario |
Public Artifact Consistency |
proposed |
refines → QG-004-correctness |
ADR-001-asciidoc-primary-source → addresses |
QS-004-minimal-static-site |
QualityScenario |
Minimal Static Site |
proposed |
refines → QG-005-sustainability |
ADR-005-minimal-static-site → addresses |
QS-005-publication-visibility-boundary |
QualityScenario |
Publication Visibility Boundary |
proposed |
refines → DOC-01000-introduction-and-goals |
ADR-008-private-to-public-article-lifecycle → addresses |
Risk |
Metadata Drift |
proposed |
- |
ADR-010-multilingual-content-fallback → introduces_risk |
|
Risk |
Build Toolchain Drift |
proposed |
- |
- |
|
Risk |
Private Data Exposure |
proposed |
- |
- |
|
Risk |
Source Boundary Leakage |
proposed |
affects → QS-005-publication-visibility-boundary |
ADR-008-private-to-public-article-lifecycle → mitigates |
|
Risk |
Preview Mispublication |
proposed |
affects → QS-005-publication-visibility-boundary |
ADR-011-preview-visibility-without-authentication → introduces_risk |