Rework tooling to use Docker and Structurizr

This commit is contained in:
Eric Förster 2025-05-08 12:50:14 +02:00
parent a6984fafd0
commit f82ac4755b
33 changed files with 1185 additions and 279 deletions

View file

@ -1,28 +0,0 @@
trigger:
branches:
include:
- "*"
paths:
include:
- .docs/.arc42/src
pool:
vmImage: ubuntu-latest
steps:
- script: |
chmod +x ./init.sh
./init.sh
chmod +x ./create-pdf.sh
./create-pdf.sh
workingDirectory: .docs/.arc42/
- script: |
# Get the full branch reference from Azure DevOps environment variables
FULL_BRANCH_REF=$(Build.SourceBranch)
# Remove the "refs/heads/" prefix to get just the branch name
BRANCH_NAME=${FULL_BRANCH_REF#refs/heads/}
# Publish the PDF file as an artifact with the filename as the name
echo "##vso[artifact.upload containerfolder=arc42;artifactname=arc42-$(date +'%Y%m%d%H%M%S')-$BRANCH_NAME;]$(System.DefaultWorkingDirectory)/.docs/.arc42/output/arc42.pdf"
displayName: "Publish PDF Artifacts"
workingDirectory: .docs/.arc42/

View file

@ -1,19 +0,0 @@
trigger:
branches:
include:
- main
paths:
include:
- .docs/.arc42/src
pool:
vmImage: ubuntu-latest
variables:
group:
steps:
- script: |
chmod +x ./scripts/export-to-confluence.sh
./scripts/export-to-confluence.sh
workingDirectory: .docs/.arc42/

View file

@ -0,0 +1,37 @@
name: Export to Confluence
on:
push:
branches:
- main
jobs:
confluence:
runs-on: lxc
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker
run: |
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
- name: Set up JDK
uses: https://github.com/actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: stackit-solutions.git.onstackit.cloud
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Deploy to Confluence
run: ./dtcw publishToConfluence -PconfluenceUser="$ARC42_EXPORT_CONFLUENCE_USER_EMAIL" -PconfluencePass="$ARC42_EXPORT_CONFLUENCE_USER_PAT"
env:
ARC42_EXPORT_CONFLUENCE_USER_EMAIL: ${{ secrets.ARC42_EXPORT_CONFLUENCE_USER_EMAIL }}
ARC42_EXPORT_CONFLUENCE_USER_PAT: ${{ secrets.ARC42_EXPORT_CONFLUENCE_USER_PAT }}

9
.gitignore vendored
View file

@ -1,7 +1,10 @@
# ARC42 tooling
.gradle
dtcw
build/
.DS_Store
output
src/diagrams/*.svg
.vscode/settings.json
# C4 tooling
.structurizr
src/diagrams/c4/images
src/diagrams/c4/workspace.json

6
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"asciidoc.extensions.enableKroki": true,
"asciidoc.preview.asciidoctorAttributes": {
"kroki-server-url": "http://localhost:8000"
}
}

View file

@ -1,62 +1,82 @@
# arc42.tooling
Contains everything needed to create a [arc42](https://www.arc42.de/overview/) documentation for your project as a template with tooling to create html and pdf documents.
This repository provides a pre-configured template and tooling to help you create comprehensive software documentation based on the [arc42](https://www.arc42.de/overview/) architectural framework. It simplifies the process of generating HTML and PDF documents from your arc42 documentation.
We are using [asciidoc](https://asciidoc.org/) as a markup language and [d2](https://d2lang.com/tour/intro/) to draw diagrams.
We use [asciidoctor docker image](https://github.com/asciidoctor/docker-asciidoctor) to generate the required artifacts out of asciidoc.
We leverage the following technologies:
- **[AsciiDoc](https://asciidoc.org/)**: A lightweight markup language for writing the arc42 documentation.
- **[doctoolchain](https://doctoolchain.org/)**: A powerful toolchain for generating documentation from AsciiDoc, including HTML and PDF formats.
- **[Structurizr](https://structurizr.com/)**: A tool for creating [C4 model](https://c4model.com/) diagrams to visualize your system architecture.
- **[D2](https://d2lang.com/tour/intro/)**: A modern diagram scripting language for creating general diagrams.
## Goals
Software needs to be documented well. To lower the entry barrier as much as possible, you get all the tools preconfigured and ready to use so you can just start writing the code.
## Non Goals
## Non-Goals
Nothing will be generated automatically, you have to update your documentation by hand.
## Use Cases
- Create html from arc42 asciidoc
- Create pdf from arc42 asciidoc
- Create d2 diagrams as svg to be used in the arc42 documentation
- Export arc42 to confluence
## Get started MacOs/Linux
- download required dependencies, only needed on the first time: `./init.sh`
- create the documentation: `./create-html.sh` or `./create-pdf.sh`
- Generate HTML documentation from arc42 AsciiDoc files.
- Generate PDF documentation from arc42 AsciiDoc files.
- Export arc42 documentation to Confluence.
## Get started (Linux, WSL, macOS)
1. **Start the Docker Compose environment:**
```bash
docker compose up -d
```
This command will:
- Serve the generated HTML documentation at http://localhost:8080/arc42/arc42.html.
- Start the [Structurizr Lite](https://docs.structurizr.com/lite) server at http://localhost:8081 for creating and viewing C4 model diagrams.
- Start a local [Kroki](https://kroki.io/) server, enabling diagram previews within VS Code.
2. **Generate Documentation:**
Use the following commands to generate the documentation:
- **HTML:** `./dtcw generateHTML`
- **PDF:** `./dtcw generatePDF`
3. **Preview Documentation in VS Code:**
Install the [AsciiDoc](https://marketplace.visualstudio.com/items?itemName=asciidoctor.asciidoctor-vscode) extension in VS Code. This allows you to preview the AsciiDoc files, including embedded diagrams, directly within the editor. The repository includes pre-configured VS Code settings for optimal previewing.
## Export to confluence
Extensive guide here: https://doctoolchain.org/docToolchain/v2.0.x/020_tutorial/070_publishToConfluence.html#_publish_your_docs_to_confluence
**Needed env vars**
`ARC42_EXPORT_CONFLUENCE_API` e.g. `https://mmmake.atlassian.net/wiki/rest/api/`
`ARC42_EXPORT_CONFLUENCE_SPACE_KEY` e.g. `ANT`
You can export your arc42 documentation to Confluence using the `.forgejo/workflows/confluence.yaml` pipeline action.
either `ARC42_EXPORT_CONFLUENCE_USER_EMAIL` and `ARC42_EXPORT_CONFLUENCE_USER_PAT`
1. **Create a Confluence Personal Access Token (PAT):** Follow the instructions at [https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html#UsingPersonalAccessTokens-CreatingPATsintheapplication](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html#UsingPersonalAccessTokens-CreatingPATsintheapplication).
or
2. **Add Secrets to Your Repository:** Configure the following secrets in your repository settings:
`ARC42_EXPORT_CONFLUENCE_USER_BEARER` see https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html#UsingPersonalAccessTokens-CreatingPATsintheapplication
- `ARC42_EXPORT_CONFLUENCE_USER_EMAIL`: The email address of the Confluence user.
- `ARC42_EXPORT_CONFLUENCE_USER_PAT`: The generated Confluence PAT.
Use the `export-to-confluence.yml` as pipeline in azure devops
It is important that this documentation is located in the `/.docs` folder inside the root of your repository. It is also recommended to put this alongside your code to make sure the documentation and code can be merged simultaneously.
3. **Configure `docToolchainConfig.groovy`:** Update the `confluence.api` and `confluence.spaceKey` properties in the `docToolchainConfig.groovy` file. Refer to the [doctoolchain documentation](https://doctoolchain.org/docToolchain/v2.0.x/020_tutorial/070_publishToConfluence.html#_publish_your_docs_to_confluence) for detailed instructions.
## Repository structure
- /azure
- note: contains pipeline examples to automatically generate the documentation and publish it to multiple targets.
- /src
- /arc42
- note: contains the arc42 ascii doc template.
- /diagrams
- note: contains the d2 markup files.
- /images
- note: contains the images that are used while generating the documentation. D2 diagrams are automatically converted and copied into the images folder while creating documentation and are deleted afterwards.
- /scripts
- note: contains the scripts to create diagrams, generate the documentation and so on.
```bash
├── .forgejo/workflows # Pipeline examples for automated documentation generation and publishing.
├── .vscode # Pre-configured VS Code settings for AsciiDoc preview.
├── output # Generated documentation (HTML and PDF)
└── src # Source files for the documentation.
├── arc42 # arc42 AsciiDoc template.
├── diagrams # D2 markup files for general diagrams.
│ └── c4 # Structurizr workspace for C4 model diagrams.
├── images # Images used in the documentation.
└── themes # STACKIT PDF theme
```
## Maintaining and further developing
[The software architecture channel](https://indecagmbh.sharepoint.com/sites/Intranet/SitePages/Channels---Software-Architecture.aspx?web=1) is responsible for this repository.
The [Software Architecture channel](https://indecagmbh.sharepoint.com/sites/Intranet/SitePages/Channels---Software-Architecture.aspx?web=1) is responsible for maintaining this repository.
Challenges and better ideas are always welcome.
Feel free to create a Pull Request or get in touch with us.
We welcome contributions and suggestions for improvement! Please feel free to create a Pull Request or get in touch with us.

View file

@ -1,10 +0,0 @@
#!/usr/bin/env bash
./scripts/prepare.sh
echo "==========================="
echo " generating HTML"
echo "==========================="
docker run -it -v "$(pwd)":"/documents/" asciidoctor/docker-asciidoctor asciidoctor -a data-uri src/arc42/arc42.adoc -o output/arc42.html
./scripts/cleanup.sh

View file

@ -1,12 +0,0 @@
#!/usr/bin/env bash
chmod +x ./scripts/prepare.sh
./scripts/prepare.sh
echo "==========================="
echo " generating PDF"
echo "==========================="
docker run --rm -v "$(pwd):/documents/" asciidoctor/docker-asciidoctor asciidoctor -r asciidoctor-pdf -b pdf -a data-uri src/arc42/arc42.adoc -o output/arc42.pdf
chmod +x ./scripts/cleanup.sh
./scripts/cleanup.sh

View file

@ -1,10 +1,10 @@
outputPath = 'build'
outputPath = 'output'
// Path where the docToolchain will search for the input files.
// This path is appended to the docDir property specified in gradle.properties
// or in the command line, and therefore must be relative to it.
inputPath = './../src/';
inputPath = 'src/';
// the pdfThemeDir config in this file is outdated.
// please check http://doctoolchain.org/docToolchain/v2.0.x/020_tutorial/030_generateHTML.html#_pdf_style for further details
@ -187,42 +187,39 @@ confluence = [:]
/**
//tag::input-config[]
*input*
is an array of files to upload to Confluence with the ability
to configure a different parent page for each file.
=== Attributes
- `file`: absolute or relative path to the asciidoc generated html file to be exported
- `url`: absolute URL to an asciidoc generated html file to be exported
- `ancestorName` (optional): the name of the parent page in Confluence as string;
this attribute has priority over ancestorId, but if page with given name doesn't exist,
ancestorId will be used as a fallback
- `ancestorId` (optional): the id of the parent page in Confluence as string; leave this empty
if a new parent shall be created in the space
- `preambleTitle` (optional): the title of the page containing the preamble (everything
before the first second level heading). Default is 'arc42'
The following four keys can also be used in the global section below
- `spaceKey` (optional): page specific variable for the key of the confluence space to write to
- 'allInOnePage' (optional): page specific variable to determine whether documentation is written to just one
Confluence page or separate ones per chapter (default)
- `createSubpages` (optional): page specific variable to determine whether ".sect2" sections shall be split from the current page into subpages
- `pagePrefix` (optional): page specific variable, the pagePrefix will be a prefix for the page title and it's sub-pages
use this if you only have access to one confluence space but need to store several
pages with the same title - a different pagePrefix will make them unique
- `pageSuffix` (optional): same usage as prefix but appended to the title and it's subpages
only 'file' or 'url' is allowed. If both are given, 'url' is ignored
// 'input' is an array of files to upload to Confluence with the ability
// to configure a different parent page for each file.
//
// Attributes
// - 'file': absolute or relative path to the asciidoc generated html file to be exported
// - 'url': absolute URL to an asciidoc generated html file to be exported
// - 'ancestorName' (optional): the name of the parent page in Confluence as string;
// this attribute has priority over ancestorId, but if page with given name doesn't exist,
// ancestorId will be used as a fallback
// - 'ancestorId' (optional): the id of the parent page in Confluence as string; leave this empty
// if a new parent shall be created in the space
// Set it for every file so the page scanning is done only for the given ancestor page trees.
//
// The following four keys can also be used in the global section below
// - 'spaceKey' (optional): page specific variable for the key of the confluence space to write to
// - 'subpagesForSections' (optional): The number of nested sub-pages to create. Default is '1'.
// '0' means creating all on one page.
// The following migration for removed configuration can be used.
// 'allInOnePage = true' is the same as 'subpagesForSections = 0'
// 'allInOnePage = false && createSubpages = false' is the same as 'subpagesForSections = 1'
// 'allInOnePage = false && createSubpages = true' is the same as 'subpagesForSections = 2'
// - 'pagePrefix' (optional): page specific variable, the pagePrefix will be a prefix for the page title and it's sub-pages
// use this if you only have access to one confluence space but need to store several
// pages with the same title - a different pagePrefix will make them unique
// - 'pageSuffix' (optional): same usage as prefix but appended to the title and it's subpages
// only 'file' or 'url' is allowed. If both are given, 'url' is ignored
//end::input-config[]
**/
confluence.with {
input = [
[ file: "build/html5/arc42/arc42.html" ],
[ file: "output/html5/arc42/arc42.html" ],
]
// endpoint of the confluenceAPI (REST) to be used
@ -230,22 +227,14 @@ confluence.with {
// e.g. https://mmmake.atlassian.net/wiki/rest/api/user/current
// you should get a valid json which describes your current user
// a working example is https://arc42-template.atlassian.net/wiki/rest/api/user/current
api = System.getenv("ARC42_EXPORT_CONFLUENCE_API")
api = "https://mmmake.atlassian.net/wiki/rest/api/"
// Additionally, spaceKey, createSubpages, pagePrefix and pageSuffix can be globally defined here. The assignment in the input array has precedence
// the key of the confluence space to write to
spaceKey = System.getenv("ARC42_EXPORT_CONFLUENCE_SPACE_KEY")
spaceKey = ""
// the title of the page containing the preamble (everything the first second level heading). Default is 'arc42'
preambleTitle = ''
// variable to determine whether the whole document should be uploaded as just one page or split into separate
// pages per chapter
allInOnePage = false
// variable to determine whether ".sect2" sections shall be split from the current page into subpages
createSubpages = false
subpagesForSections = 1
// the pagePrefix will be a prefix for each page title
// use this if you only have access to one confluence space but need to store several

21
docker-compose.yml Normal file
View file

@ -0,0 +1,21 @@
services:
serve-docs:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./output/html5:/usr/share/nginx/html
serve-c4:
image: structurizr/lite:latest
ports:
- "8081:8080"
volumes:
- .:/usr/local/structurizr
environment:
- STRUCTURIZR_WORKSPACE_PATH=src/diagrams/c4
serve-kroki:
image: yuzutech/kroki:latest
ports:
- "8000:8000"

687
dtcw Executable file
View file

@ -0,0 +1,687 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MIT
# Copyright 2022 - 2023, Ralf D. Müller and the docToolchain contributors
set -e
set -u
set -o pipefail
# The main purpose of the wrapper script is to make 'docToolchain' easy to use.
# - it helps to install 'docToolchain' if not installed
# - you may manage different 'docToolchain' environments
# See https://github.com/docToolchain/docToolchain/releases for available versions.
# Set DTC_VERSION to "latest" to get the latest, yet unreleased version.
: "${DTC_VERSION:=3.4.2}"
# if not set, public docker hub is used
: "${DTC_DOCKER_PREFIX:=stackit-solutions.git.onstackit.cloud/eric.foerster/}"
# The 'generateSite' and 'copyThemes' tasks support DTC_SITETHEME, an URL of a theme.
# export DTC_SITETHEME=https://....zip
# The 'downloadTemplate' tasks uses DTC_TEMPLATE1, DTC_TEMPLATE2, ...
# with which you can specify the location of additional templates
# export DTC_TEMPLATE1=https://....zip
# export DTC_TEMPLATE2=https://....zip
# docToolchain configuration file may be overruled by the user
: "${DTC_CONFIG_FILE:=docToolchainConfig.groovy}"
# Contains the current project git branch, "-" if not available
: "${DTC_PROJECT_BRANCH:=$(git branch --show-current 2> /dev/null || echo -)}"
export DTC_PROJECT_BRANCH
# DTC_HEADLESS is true if no STDIN is open (i.e. we have an non-interactive shell).
: "${DTC_HEADLESS:=$([ -t 0 ] && echo false || echo true)}"
export DTC_HEADLESS
# Options passed to docToolchain
DTC_OPTS="${DTC_OPTS:-} -PmainConfigFile=${DTC_CONFIG_FILE} --warning-mode=none --no-daemon -Dfile.encoding=UTF-8 "
# Here you find the project
GITHUB_PROJECT_URL=https://github.com/docToolchain/docToolchain
GITHUB_PROJECT_URL_SSH=git@github.com:docToolchain/docToolchain
# Bump this version up if something is changed in the wrapper script
DTCW_VERSION=0.51
# Template replaced by the GitHub value upon releasing dtcw
DTCW_GIT_HASH=##DTCW_GIT_HASH##
# Exit codes
ERR_DTCW=1
ERR_ARG=2
ERR_CODING=3
main() {
# For debugging purpose at the top of the script
arch=$(uname -m)
os=$(uname -s)
bash=bash
print_version_info
assert_argument_exists "$@"
[ "${1}" = "--version" ] && exit 0
available_environments=$(get_available_environments)
echo "Available docToolchain environments:${available_environments}"
dtc_installations=$(get_dtc_installations "${available_environments}" "${DTC_VERSION}")
echo "Environments with docToolchain [${DTC_VERSION}]:${dtc_installations}"
if is_supported_environment "${1}" && assert_environment_available "${1}" "${DTC_VERSION}"; then
# User enforced environment
environment=${1}
shift 1
assert_argument_exists "$@"
else
environment=$(get_environment "$@")
fi
echo "Using environment: ${environment}"
if [ "${1}" = "install" ]; then
install_component_and_exit "${environment}" "${2-}"
elif [ "${1}" = "getJava" ]; then
# TODO: remove getJava in the next major release
echo "Warning: 'getJava' is deprecated and will be removed. Use './dtcw install java' instead."
install_component_and_exit "${environment}" "java"
fi
# No install command, so forward call to docToolchain but first we check if
# everything is there.
docker_image_name=""
docker_extra_arguments=""
if [[ ${environment} != docker ]]; then
assert_doctoolchain_installed "${environment}" "${DTC_VERSION}"
assert_java_version_supported
# TODO: what if 'doctoolchain' found by $PATH does not match the one from the local environment?
# The version provided by $DTC_VERSION could be a different one.
else
docker_image_name="doctoolchain"
if [ "${1}" = "image" ]; then
docker_image_name="${2-}"
shift 2
assert_argument_exists "$@"
fi
echo "Using docker image: ${docker_image_name}"
if [ "${1}" = "extra_arguments" ]; then
docker_extra_arguments="${2-}"
shift 2
assert_argument_exists "$@"
echo "Extra arguments passed to 'docker run' ${docker_extra_arguments}"
fi
fi
command=$(build_command "${environment}" "${DTC_VERSION}" "${docker_image_name}" "${docker_extra_arguments}" "$@")
[[ "${DTC_HEADLESS}" = true ]] && echo "Using headless mode since there is no (terminal) interaction possible"
show_os_related_info
emu=""
if [ "${os}" = "Darwin" ] && [ "${arch}" = "arm64" ]; then
echo "Apple silicon detected, using x86_64 mode and os native bash"
emu="/usr/bin/arch -x86_64"
bash="/bin/bash"
fi
# echo "Command to invoke: ${command}"
# shellcheck disable=SC2086
# as we hope to know what we are doing here ;-)
exec ${emu} ${bash} ${DTC_SHELL_DEBUG:-} -c "${command}"
}
assert_argument_exists() {
if [[ $# -lt 1 ]]; then
error "argument missing"
usage
exit ${ERR_ARG}
fi
}
error() {
printf "\nError: %s\n\n" "${1}" >&2
}
usage() {
cat <<EOF
dtcw - Create awesome documentation the easy way with docToolchain.
Usage: ./dtcw [environment] [option...] [task...]
./dtcw [local] install {doctoolchain | java }
Use 'local', 'sdk' or 'docker' as first argument to force the use of a specific
docToolchain environment:
- local: installation in '$HOME/.doctoolchain'
- sdk: installation with SDKMAN! (https://sdkman.io/)
- docker: use docToolchain container image
Examples:
Download and install docToolchain in '${DTC_ROOT}':
./dtcw local install doctoolchain
Download and install project documentation template from https://arc42.org/ :
./dtcw downloadTemplate
Generate PDF:
./dtcw generatePDF
Generate HTML:
./dtcw generateHTML
Publish HTML to Confluence:
./dtcw publishToConfluence
Multiple tasks may be provided at once:
./dtcw generatePDF generateHTML
Detailed documentation how to use docToolchain may be found at https://doctoolchain.org/
Use './dtcw tasks --group doctoolchain' to see docToolchain related tasks.
Use './dtcw tasks' to see all tasks.
EOF
}
print_version_info() {
echo "dtcw ${DTCW_VERSION} - ${DTCW_GIT_HASH}"
if is_doctoolchain_development_version "${DTC_VERSION}"; then
local dtc_git_hash=unknown
dtc_git_hash=$(git -C "${DTC_HOME}" rev-parse --short=8 HEAD 2> /dev/null || echo "unknown")
echo "docToolchain ${DTC_VERSION} - ${dtc_git_hash}"
else
echo "docToolchain ${DTC_VERSION}"
fi
echo "OS/arch: ${os}/${arch}"
}
get_available_environments() {
# The local environment is alway available - even if docToolchain is not installed
local envs=" local"
# 'sdk' is provided a bash founction - thus command doesn't work
if [ -n "${SDKMAN_DIR:-}" ] && [ -s "${SDKMAN_DIR}/bin/sdkman-init.sh" ]; then
envs+=" sdk"
fi
if has docker; then
envs+=" docker"
fi
echo "${envs}"
}
has() {
command -v "$1" 1>/dev/null 2>&1
}
get_dtc_installations() {
local envs=${1}
local version=${2}
local installations=""
if [ -x "${DTC_HOME}/bin/doctoolchain" ]; then
installations+=" local"
else
# maybe it is just available in the path
if command -v doctoolchain >/dev/null 2>&1; then
installations+=" local"
fi
fi
if [[ "${envs}" =~ sdk ]] && sdk_home_doctoolchain "${version}" &> /dev/null ; then
installations+=" sdk"
fi
if [[ "${envs}" =~ docker ]]; then
# Having docker installed means docToolchain is available
installations+=" docker"
fi
[ -z "${installations}" ] && installations=" none"
echo "${installations}"
}
sdk_home_doctoolchain() {
local version=${1}
local sdk_doctoolchain="${SDKMAN_DIR}/candidates/doctoolchain/${version}"
# Don't use `sdk home doctoolchain ${version}` - see https://github.com/sdkman/sdkman-cli/issues/1196
if [[ -x "${sdk_doctoolchain}/bin/doctoolchain" ]]; then
printf "%s" "${sdk_doctoolchain}"
return 0
fi
printf "doctoolchain %s is not installed on your system" "${version}" 1>&2
return 1
}
is_supported_environment() {
local supported_environments=("local" "sdk" "docker")
[[ "${supported_environments[*]}" =~ ${1} ]]
}
assert_environment_available() {
local env=${1}
local version=${2}
# If environment not available, exit with error
if ! is_environment_available "${env}" ; then
error "argument error - environment '${env}' not available"
if [[ "${env}" == "sdk" ]]; then
printf "%s\n" \
"Install SDKMAN! (https://sdkman.io) with" \
"" \
" $ curl -s \"https://get.sdkman.io\" | bash" \
"" \
"Then open a new shell and install 'docToolchain' with" \
" $ sdk install doctoolchain ${version}"
else
echo "Install 'docker' on your host to execute docToolchain in a container."
fi
echo
exit ${ERR_ARG}
fi
if is_doctoolchain_development_version "${version}" && [ "${env}" != local ] ; then
error "argument error - invalid environment '${env}'."
echo "Development version '${version}' can only be used in a local environment."
echo
exit ${ERR_ARG}
fi
}
is_environment_available() {
[[ "${available_environments}" =~ ${1} ]]
}
is_doctoolchain_development_version() {
local version=${1}
# Is 'latest' a good name? It maybe interpreted as latest stable release.
# Alternatives: 'testing', 'dev' (used for development)
[ "${version}" == "latest" ] || [ "${version}" == "latestdev" ]
}
# No environment provided - try to pick the right one
get_environment() {
# 'install' works only with 'local' environment
if [[ "${1}" == install ]] || [[ "${dtc_installations}" =~ none ]]; then
echo local
return
fi
# Pick the first one which has an installed docToolchain.
# Note: the preference is defined by the order we searched for available environments.
for e in ${available_environments}; do
if is_doctoolchain_installed "${e}"; then
echo "${e}"
return
fi
done
}
is_doctoolchain_installed() {
[[ "${dtc_installations}" =~ ${1} ]]
}
install_component_and_exit() {
local env=${1}
local component=${2}
if [ -z "${component}" ] ; then
error_install_component_and_die "component missing"
fi
exit_code=1
case ${env} in
local)
case ${component} in
doctoolchain)
local_install_doctoolchain "${DTC_VERSION}"
assert_java_version_supported
;;
java)
local_install_java
;;
*)
error_install_component_and_die "unknown component '${component}'"
;;
esac
if ! is_doctoolchain_installed "${environment}"; then
how_to_install_doctoolchain "${DTC_VERSION}"
else
printf "%s\n" \
"" \
"Use './dtcw tasks --group doctoolchain' to see docToolchain related tasks." \
""
fi
exit_code=0
;;
sdk)
error "argument error - '${env} install' not supported."
printf "%s\n" \
"To install docToolchain with SDKMAN! execute" \
"" \
" $ sdk install doctoolchain ${DTC_VERSION}" \
""
exit_code=${ERR_ARG}
;;
docker)
error "argument error - '${env} install' not supported."
echo "Executing a task in the 'docker' environment will pull the docToolchain container image."
echo
exit_code=${ERR_ARG}
;;
*)
echo "Coding error - not reachable"
exit ${ERR_CODING}
;;
esac
exit ${exit_code}
}
error_install_component_and_die() {
error "${1} - available components are 'doctoolchain', or 'java'"
printf "%s\n" \
"Use './dtcw local install doctoolchain' to install docToolchain ${DTC_VERSION}." \
"Use './dtcw local install java' to install a Java version supported by docToolchain." \
""
exit ${ERR_ARG}
}
local_install_doctoolchain() {
local version=${1}
if is_doctoolchain_development_version "${version}"; then
# User decided to pick a floating version - which means a git clone into the local environment.
assert_git_installed "Please install 'git' for working with a 'doctToolchain' development version"
if [ -d "${DTC_HOME}/.git" ]; then
git -C "${DTC_HOME}" pull
echo "Updated docToolchain in local environment to latest version"
else
local project_url
if [ "${version}" == "latest" ]; then
project_url="${GITHUB_PROJECT_URL}"
else
project_url="${GITHUB_PROJECT_URL_SSH}"
fi
git clone "${project_url}.git" "${DTC_HOME}"
echo "Cloned docToolchain in local environment to latest version"
fi
else
if [ -x "${DTC_HOME}/bin/doctoolchain" ]; then
echo "Skipped installation of docToolchain: already installed in '${DTC_HOME}'"
return
fi
if ! has unzip; then
error "no unzip program installed, exiting…"
echo "Install 'unzip' and try to install docToolchain again."
return ${ERR_DTCW}
fi
mkdir -p "${DTC_ROOT}"
local distribution_url=${GITHUB_PROJECT_URL}/releases/download/v${version}/docToolchain-${version}.zip
download_file "${distribution_url}" "${DTC_ROOT}/source.zip"
unzip -q "${DTC_ROOT}/source.zip" -d "${DTC_ROOT}"
rm -f "${DTC_ROOT}/source.zip"
echo "Installed docToolchain successfully in '${DTC_HOME}'."
fi
# Add it to the existing installations so the output to guide the user can adjust accordingly.
dtc_installations+=" local"
}
assert_git_installed() {
has git && return
error "git - command not found"
echo "${1}"
echo
exit ${ERR_DTCW}
}
download_file() {
local url=${1}
local file=${2}
if has curl; then
cmd="curl --fail --location --output $file $url"
elif has wget; then
# '--show-progress' is not supported in all wget versions (busybox)
cmd="wget --quiet --show-progress --output-document=$file $url"
elif has fetch; then
cmd="fetch --quiet --output=$file $url"
else
error "no HTTP download program (curl, wget, fetch) found, exiting…"
echo "Install either 'curl', 'wget', or 'fetch' and try to install docToolchain again."
return ${ERR_DTCW}
fi
$cmd && return 0 || rc=$?
error "Command failed (exit code $rc): ${cmd}"
return "${rc}"
}
assert_java_version_supported() {
# Defines the order in which Java is searched.
if [ -d "${DTC_JAVA_HOME}" ]; then
echo "Caution: Your JAVA_HOME setting is overriden by DTCs own JDK install (for this execution)"
if [ -d "${DTC_JAVA_HOME}/Contents" ]; then
# JDK for MacOS have a different structure
JAVA_HOME="${DTC_JAVA_HOME}/Contents/Home"
else
JAVA_HOME="${DTC_JAVA_HOME}"
fi
export JAVA_HOME
DTC_OPTS="${DTC_OPTS} '-Dorg.gradle.java.home=${JAVA_HOME}'"
JAVA_CMD="${JAVA_HOME}/bin/java"
elif [ -n "${JAVA_HOME-}" ]; then
JAVA_CMD="${JAVA_HOME}/bin/java"
else
# Don't provide JAVA_HOME if java is used by PATH.
JAVA_CMD=$(command -v java 2>/dev/null) || true
fi
if [ -z "${JAVA_CMD-}" ] || ! java_version=$("${JAVA_CMD}" -version 2>&1) ; then
error "unable to locate a Java Runtime"
java_help_and_die
fi
# We got a Java version
java_version=$(echo "$java_version" | awk -F '"' '/version/ {print $0}' | head -1 | cut -d'"' -f2)
major_version=$(echo "$java_version" | sed '/^1\./s///' | cut -d'.' -f1)
if [ "${major_version}" -ge 11 ] && [ "${major_version}" -le 17 ]; then
echo "Using Java ${java_version} [${JAVA_CMD}]"
return
fi
error "unsupported Java version ${major_version} [${JAVA_CMD}]"
java_help_and_die
}
java_help_and_die() {
printf "%s\n" \
"docToolchain supports Java versions 11, 14, or 17 (preferred). In case one of those" \
"Java versions is installed make sure 'java' is found with your PATH environment" \
"variable. As alternative you may provide the location of your Java installation" \
"with JAVA_HOME." \
"" \
"Apart from installing Java with the package manager provided by your operating" \
"system, dtcw facilitates the Java installation into a local environment:" \
"" \
" # Install Java in '${DTC_JAVA_HOME}'" \
" $ ./dtcw local install java" \
"" \
"Alternatively you can use SDKMAN! (https://sdkman.io) to manage your Java installations" \
""
if ! is_environment_available sdk; then
how_to_install_sdkman "Java 17"
fi
# TODO: This will break when we change Java version
printf "%s\n" \
" $ sdk install java 17.0.7-tem" \
"" \
"If you prefer not to install Java on your host, you can run docToolchain in a" \
"docker container. For this case dtcw provides the 'docker' execution environment." \
"" \
"Example: ./dtcw docker generateSite"\
""
exit ${ERR_DTCW}
}
how_to_install_sdkman() {
printf "%s\n" \
" # First install SDKMAN!" \
" $ curl -s \"https://get.sdkman.io\" | bash" \
" # Then open a new shell and install ${1} with"
}
local_install_java() {
version=17
implementation=hotspot
heapsize=normal
imagetype=jdk
releasetype=ga
case "${arch}" in
x86_64) arch=x64 ;;
arm64) arch=aarch64 ;;
esac
if [[ ${os} == MINGW* ]]; then
error "MINGW64 is not supported"
echo "Please use powershell or WSL"
exit 1
fi
case "${os}" in
Linux) os=linux ;;
Darwin) os=mac
# Enforce usage of Intel Java as long as jbake does not work on Apple Silicon
arch=x64 ;;
Cygwin) os=linux ;;
esac
mkdir -p "${DTC_JAVA_HOME}"
echo "Downloading JDK Temurin ${version} [${os}/${arch}] from Adoptium to ${DTC_JAVA_HOME}/jdk.tar.gz"
local adoptium_java_url="https://api.adoptium.net/v3/binary/latest/${version}/${releasetype}/${os}/${arch}/${imagetype}/${implementation}/${heapsize}/eclipse?project=jdk"
download_file "${adoptium_java_url}" "${DTC_JAVA_HOME}/jdk.tar.gz"
echo "Extracting JDK from archive file."
# TODO: should we not delete a previsouly installed on?
# Otherwise we may get a mix of different Java versions.
tar -zxf "${DTC_JAVA_HOME}/jdk.tar.gz" --strip 1 -C "${DTC_JAVA_HOME}/."
rm -f "${DTC_JAVA_HOME}/jdk/jdk.tar.gz"
echo "Successfully installed Java in '${DTC_JAVA_HOME}'."
echo
}
assert_doctoolchain_installed() {
local env=${1}
local version=${2}
if ! is_doctoolchain_installed "${env}"; then
# We reach this point if the user executes a command in an
# environment where docToolchain is not installed.
# Note that 'docker' always has a command (no instalation required)
error "doctoolchain - command not found [environment '${env}']"
how_to_install_doctoolchain "${version}"
exit ${ERR_DTCW}
fi
}
how_to_install_doctoolchain() {
local version=${1}
printf "%s\n" \
"It seems docToolchain ${version} is not installed. dtcw supports the" \
"following docToolchain environments:" \
"" \
"1. 'local': to install docToolchain in [${DTC_ROOT}] use" \
"" \
" $ ./dtcw local install doctoolchain" \
"" \
"2. 'sdk': to install docToolchain with SDKMAN! (https://sdkman.io)" \
""
if ! is_environment_available sdk; then
how_to_install_sdkman docToolchain
fi
printf "%s\n" \
" \$ sdk install doctoolchain ${version}" \
"" \
"Note that running docToolchain in 'local' or 'sdk' environment needs a" \
"Java runtime (major version 11, 14, or 17) installed on your host." \
"" \
"3. 'docker': pull the docToolchain image and execute docToolchain in a container environment." \
"" \
" \$ ./dtcw docker tasks --group doctoolchain" \
""
}
build_command() {
local env=${1}
local version=${2}
local docker_image=${3}
local docker_extra_arguments=${4}
shift 4
local cmd
if [ "${env}" = docker ]; then
# TODO: DTC_PROJECT_BRANCH is not passed into the docker environment
# See https://github.com/docToolchain/docToolchain/issues/1087
local container_name=doctoolchain-${version}
container_name+="-$(date '+%Y%m%d_%H%M%S')"
pwd=$(has cygpath && cygpath -w "${PWD}" || echo "${PWD}")
docker_env_file=dtcw_docker.env
env_file_option=""
if [ -f "$docker_env_file" ]; then
env_file_option="--env-file ${docker_env_file}"
fi
docker_args="run --rm -i --platform linux/amd64 -u $(id -u):$(id -g) --name ${container_name} \
-e DTC_HEADLESS=true -e DTC_SITETHEME -e DTC_PROJECT_BRANCH=${DTC_PROJECT_BRANCH} \
${docker_extra_arguments} ${env_file_option} \
--entrypoint /bin/bash -v '${pwd}:/project' ${DTC_DOCKER_PREFIX}${docker_image}:v${version}"
cmd="docker ${docker_args} -c \"doctoolchain . ${*} ${DTC_OPTS} && exit\""
else
# TODO: What is this good for? Has probably to do with Docker image creation.
if [[ "${DTC_HEADLESS}" = false ]]; then
# important for the docker file to find dependencies
DTC_OPTS="${DTC_OPTS} '-Dgradle.user.home=${DTC_ROOT}/.gradle'"
fi
if [ "${env}" = local ]; then
if [ -x "${DTC_HOME}/bin/doctoolchain" ]; then
cmd="${DTC_HOME}/bin/doctoolchain"
# is doctoolchain available on the path?
elif command -v doctoolchain >/dev/null 2>&1; then
cmd="doctoolchain"
else
echo "Could not find doctoolchain executable, neither in '${DTC_HOME}' nor on PATH ('${PATH}')" >&2
exit 1
fi
cmd="${cmd} . ${*} ${DTC_OPTS}"
else
cmd="$(sdk_home_doctoolchain "${version}")/bin/doctoolchain . ${*} ${DTC_OPTS}"
fi
fi
echo "${cmd}"
}
show_os_related_info() {
# check if we are running on WSL
if grep -qsi 'microsoft' /proc/version &> /dev/null ; then
# TODO: bug - This URL leads to now-where!
printf "%s\n" \
"" \
"Bash is running on WSL which might cause problems with plantUML." \
"See https://doctoolchain.org/docToolchain/v2.0.x/010_manual/50_Frequently_asked_Questions.html#wsl for more details." \
""
fi
}
# Location where local installations are placed.
DTC_ROOT="${HOME}/.doctoolchain"
# More than one docToolchain version may be installed locally.
# This is the directory for the specific version.
DTC_HOME="${DTC_ROOT}/docToolchain-${DTC_VERSION}"
# Directory for local Java installation
DTC_JAVA_HOME="${DTC_ROOT}/jdk"
main "$@"

View file

@ -1,7 +0,0 @@
#!/usr/bin/env bash
echo "==========================="
echo " get d2"
echo "==========================="
curl -fsSL https://d2lang.com/install.sh | sh -s --

View file

@ -1,7 +0,0 @@
#!/usr/bin/env bash
echo "==========================="
echo " cleaning up"
echo "==========================="
chmod +x ./scripts/delete-created-diagrams.sh
./scripts/delete-created-diagrams.sh

View file

@ -1,22 +0,0 @@
#!/usr/bin/env bash
echo "==========================="
echo " creating diagrams"
echo "==========================="
diagrams_target_dir=./src/images
diagrams_dir=./src/diagrams
# Recursively find all d2 files in diagrams directory and its subdirectories
diagrams=$(find ${diagrams_dir} -type f -name '*.d2')
for entry in $diagrams
do
echo "$entry"
# Extract the relative path without the extension
relative_path=${entry#"$diagrams_dir/"}
filename="${relative_path%.*}"
# Generate the target SVG path by combining the target directory and relative path
svg_path="${diagrams_target_dir}/${filename}.svg"
d2 "$entry" "$svg_path"
done

View file

@ -1,25 +0,0 @@
#!/usr/bin/env bash
echo "==========================="
echo " deleting created diagrams"
echo "==========================="
diagrams_target_dir=./src/images
diagrams_dir=./src/diagrams
# Recursively find all *.d2 files in the diagrams directory and its subdirectories
diagrams=$(find ${diagrams_dir} -type f -name '*.d2')
for d2file in $diagrams
do
# Construct the corresponding SVG file path by replacing the .d2 extension with .svg
svgfile="${diagrams_target_dir}${d2file#${diagrams_dir}}"
svgfile="${svgfile%.d2}.svg"
# Check if the corresponding SVG file exists and then delete it
if [ -e "$svgfile" ]; then
echo "Deleting $svgfile"
rm "$svgfile"
else
echo "SVG file not found for $d2file"
fi
done

View file

@ -1,29 +0,0 @@
###
# PREPARE
###
chmod +x ./init.sh
./init.sh
chmod +x ./scripts/prepare.sh
./scripts/prepare.sh
curl -Lo dtcw doctoolchain.github.io/dtcw
chmod +x ./dtcw
./dtcw install doctoolchain
###
# EXPORT
###
echo "==========================="
echo " start publishToConfluence"
echo "==========================="
./dtcw publishToConfluence -PbearerToken="$ARC42_EXPORT_CONFLUENCE_USER_BEARER" -PconfluenceUser="$ARC42_EXPORT_CONFLUENCE_USER_EMAIL" -PconfluencePass="$ARC42_EXPORT_CONFLUENCE_USER_PAT" --info
###
# CLEAN
###
chmod +x ./scripts/cleanup.sh
./scripts/cleanup.sh

View file

@ -1,7 +0,0 @@
#!/usr/bin/env bash
echo "==========================="
echo " preparing"
echo "==========================="
chmod +x ./scripts/create-diagrams.sh
./scripts/create-diagrams.sh

View file

@ -1,2 +0,0 @@
:imagesdir: ../images

View file

@ -1,8 +1,11 @@
:imagesdir: ../images
:jbake-menu: -
:pdf-themesdir: /documents/src/themes/
:pdf-fontsdir: /documents/src/themes/fonts
:pdf-themesdir: ../themes/
:pdf-fontsdir: ../themes/fonts
:pdf-theme: stackit
:diagram-format: svg
:plantuml-format: svg
:structurizr-renderer: plantuml
// header file for arc42-template,
// including all help texts
//
@ -20,11 +23,6 @@ include::chapters/config.adoc[]
include::chapters/about-arc42.adoc[]
image::example.svg["Example usage of d2 diagram"]
//additional style for arc42 help callouts
ifdef::backend-html5[]
++++

View file

@ -1,2 +0,0 @@
:imagesdir: ../../images

View file

@ -4,12 +4,12 @@ ifndef::imagesdir[:imagesdir: ../images]
== System Scope and Context
=== Business Context
[structurizr, view="SystemContext", view-key="SystemContext"]
....
include::../../diagrams/c4/workspace.dsl[][]
....
**<Diagram or Table>**
@ -17,8 +17,6 @@ ifndef::imagesdir[:imagesdir: ../images]
=== Technical Context
**<Diagram or Table>**
**<optionally: Explanation of technical interfaces>**

View file

@ -11,7 +11,10 @@ ifndef::imagesdir[:imagesdir: ../images]
_**<Overview Diagram>**_
[structurizr, view="Containers", view-key="Containers"]
....
include::../../diagrams/c4/workspace.dsl[][]
....
Motivation::
@ -67,9 +70,12 @@ _<black box template>_
==== White Box _<building block 1>_
==== White Box API Application
[structurizr, view="Components", view-key="Components"]
....
include::../../diagrams/c4/workspace.dsl[][]
....
_<white box template>_

View file

@ -4,10 +4,12 @@ ifndef::imagesdir[:imagesdir: ../images]
== Runtime View
=== Sign In
=== <Runtime Scenario 1>
[structurizr, view="SignIn", view-key="SignIn"]
....
include::../../diagrams/c4/workspace.dsl[][]
....
* _<insert runtime diagram or textual description of the scenario>_
* _<insert description of the notable aspects of the interactions between the

View file

@ -9,9 +9,10 @@ ifndef::imagesdir[:imagesdir: ../images]
=== Infrastructure Level 1
_**<Overview Diagram>**_
[structurizr, view="LiveDeployment", view-key="LiveDeployment"]
....
include::../../diagrams/c4/workspace.dsl[][]
....
Motivation::

View file

@ -7,3 +7,5 @@ ifndef::imagesdir[:imagesdir: ../images]
include::adr/0001-use-d2-as-diagram-modelling-tool.adoc[]
include::adr/0002-use-asciidoc-for-writing-documentation-with-arc42.adoc[]
include::adr/0003-use-structurizr-for-c4-diagrams.adoc[]

View file

@ -8,7 +8,10 @@ ifndef::imagesdir[:imagesdir: ../images]
=== Quality Tree
[d2, theme=1, pad=0, svg]
....
include::../../diagrams/10_quality_tree.d2[][]
....
=== Quality Scenarios

View file

@ -1,4 +1,4 @@
=== 1. Use D2 as diagram modelling tool
=== Use D2 as diagram modelling tool
Date: 2023-06-12

View file

@ -1,4 +1,4 @@
=== 2. Use AsciiDoc for writing documentation in arc42
=== Use AsciiDoc for writing documentation in arc42
Date: 2023-06-12

View file

@ -0,0 +1,44 @@
=== Use Structurizr for C4 diagrams
Date: 2025-05-08
==== Status
Proposed
==== Decision makers
* Eric Förster
* Stephan Weißenberger
* Ralf Hägele
* Marius Kort
* Andre Harms
==== Context
We currently use D2 (https://d2lang.com/) to generate C4 architecture diagrams. While D2 provides a concise DSL for general diagrams, it lacks built-in C4 abstractions (e.g. Software system, Container, Component, etc.). We need a tool that:
* Directly supports the C4 model
* Allows reuse of the same architecture definitions across views
==== Decision
We have decided to adopt the open-source version of Structurizr (using the DSL and Structurizr Lite) for authoring and maintaining C4 architecture diagrams. This decision was based on the following factors:
* **Native C4 Support:** Structurizr is specifically designed for the C4 model, providing built-in abstractions and validation.
* **Model-Driven Approach:** Structurizr uses a model-driven approach, allowing us to define the architecture once and generate multiple views from the same model.
* **Extensibility:** Structurizr is extensible, allowing us to customize the diagrams and integrate with other tools.
* **Community Support:** Structurizr has an active community and comprehensive documentation.
==== Consequences
* **Positive:**
** **Improved Diagram Accuracy:** C4 model validation will help ensure the diagrams accurately represent the architecture.
** **Reduced Maintenance Overhead:** The model-driven approach and code-as-configuration will simplify diagram maintenance.
** **Increased Consistency:** Reusing architectural definitions across views will ensure consistency.
* **Negative:**
** **Learning Curve:** Team members will need to learn the Structurizr DSL.
** **Migration Effort:** We will need to migrate existing D2 diagrams to Structurizr.
** **Potential Lock-in:** Adopting Structurizr may create a dependency on the tool.

View file

@ -0,0 +1,259 @@
/*
* This is a combined version of the following workspaces, with automatic layout enabled:
*
* - "Big Bank plc - System Landscape" (https://structurizr.com/share/28201/)
* - "Big Bank plc - Internet Banking System" (https://structurizr.com/share/36141/)
*/
workspace "Big Bank plc" "This is an example workspace to illustrate the key features of Structurizr, via the DSL, based around a fictional online banking system." {
model {
customer = person "Personal Banking Customer" "A customer of the bank, with personal bank accounts." "Customer"
group "Big Bank plc" {
supportStaff = person "Customer Service Staff" "Customer service staff within the bank." "Bank Staff"
backoffice = person "Back Office Staff" "Administration and support staff within the bank." "Bank Staff"
mainframe = softwaresystem "Mainframe Banking System" "Stores all of the core banking information about customers, accounts, transactions, etc." "Existing System"
email = softwaresystem "E-mail System" "The internal Microsoft Exchange e-mail system." "Existing System"
atm = softwaresystem "ATM" "Allows customers to withdraw cash." "Existing System"
internetBankingSystem = softwaresystem "Internet Banking System" "Allows customers to view information about their bank accounts, and make payments." {
singlePageApplication = container "Single-Page Application" "Provides all of the Internet banking functionality to customers via their web browser." "JavaScript and Angular" "Web Browser"
mobileApp = container "Mobile App" "Provides a limited subset of the Internet banking functionality to customers via their mobile device." "Xamarin" "Mobile App"
webApplication = container "Web Application" "Delivers the static content and the Internet banking single page application." "Java and Spring MVC"
apiApplication = container "API Application" "Provides Internet banking functionality via a JSON/HTTPS API." "Java and Spring MVC" {
signinController = component "Sign In Controller" "Allows users to sign in to the Internet Banking System." "Spring MVC Rest Controller"
accountsSummaryController = component "Accounts Summary Controller" "Provides customers with a summary of their bank accounts." "Spring MVC Rest Controller"
resetPasswordController = component "Reset Password Controller" "Allows users to reset their passwords with a single use URL." "Spring MVC Rest Controller"
securityComponent = component "Security Component" "Provides functionality related to signing in, changing passwords, etc." "Spring Bean"
mainframeBankingSystemFacade = component "Mainframe Banking System Facade" "A facade onto the mainframe banking system." "Spring Bean"
emailComponent = component "E-mail Component" "Sends e-mails to users." "Spring Bean"
}
database = container "Database" "Stores user registration information, hashed authentication credentials, access logs, etc." "Oracle Database Schema" "Database"
}
}
# relationships between people and software systems
customer -> internetBankingSystem "Views account balances, and makes payments using"
internetBankingSystem -> mainframe "Gets account information from, and makes payments using"
internetBankingSystem -> email "Sends e-mail using"
email -> customer "Sends e-mails to"
customer -> supportStaff "Asks questions to" "Telephone"
supportStaff -> mainframe "Uses"
customer -> atm "Withdraws cash using"
atm -> mainframe "Uses"
backoffice -> mainframe "Uses"
# relationships to/from containers
customer -> webApplication "Visits bigbank.com/ib using" "HTTPS"
customer -> singlePageApplication "Views account balances, and makes payments using"
customer -> mobileApp "Views account balances, and makes payments using"
webApplication -> singlePageApplication "Delivers to the customer's web browser"
# relationships to/from components
singlePageApplication -> signinController "Makes API calls to" "JSON/HTTPS"
singlePageApplication -> accountsSummaryController "Makes API calls to" "JSON/HTTPS"
singlePageApplication -> resetPasswordController "Makes API calls to" "JSON/HTTPS"
mobileApp -> signinController "Makes API calls to" "JSON/HTTPS"
mobileApp -> accountsSummaryController "Makes API calls to" "JSON/HTTPS"
mobileApp -> resetPasswordController "Makes API calls to" "JSON/HTTPS"
signinController -> securityComponent "Uses"
accountsSummaryController -> mainframeBankingSystemFacade "Uses"
resetPasswordController -> securityComponent "Uses"
resetPasswordController -> emailComponent "Uses"
securityComponent -> database "Reads from and writes to" "SQL/TCP"
mainframeBankingSystemFacade -> mainframe "Makes API calls to" "XML/HTTPS"
emailComponent -> email "Sends e-mail using"
deploymentEnvironment "Development" {
deploymentNode "Developer Laptop" "" "Microsoft Windows 10 or Apple macOS" {
deploymentNode "Web Browser" "" "Chrome, Firefox, Safari, or Edge" {
developerSinglePageApplicationInstance = containerInstance singlePageApplication
}
deploymentNode "Docker Container - Web Server" "" "Docker" {
deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
developerWebApplicationInstance = containerInstance webApplication
developerApiApplicationInstance = containerInstance apiApplication
}
}
deploymentNode "Docker Container - Database Server" "" "Docker" {
deploymentNode "Database Server" "" "Oracle 12c" {
developerDatabaseInstance = containerInstance database
}
}
}
deploymentNode "Big Bank plc" "" "Big Bank plc data center" "" {
deploymentNode "bigbank-dev001" "" "" "" {
softwareSystemInstance mainframe
}
}
}
deploymentEnvironment "Live" {
deploymentNode "Customer's mobile device" "" "Apple iOS or Android" {
liveMobileAppInstance = containerInstance mobileApp
}
deploymentNode "Customer's computer" "" "Microsoft Windows or Apple macOS" {
deploymentNode "Web Browser" "" "Chrome, Firefox, Safari, or Edge" {
liveSinglePageApplicationInstance = containerInstance singlePageApplication
}
}
deploymentNode "Big Bank plc" "" "Big Bank plc data center" {
deploymentNode "bigbank-web***" "" "Ubuntu 16.04 LTS" "" 4 {
deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
liveWebApplicationInstance = containerInstance webApplication
}
}
deploymentNode "bigbank-api***" "" "Ubuntu 16.04 LTS" "" 8 {
deploymentNode "Apache Tomcat" "" "Apache Tomcat 8.x" {
liveApiApplicationInstance = containerInstance apiApplication
}
}
deploymentNode "bigbank-db01" "" "Ubuntu 16.04 LTS" {
primaryDatabaseServer = deploymentNode "Oracle - Primary" "" "Oracle 12c" {
livePrimaryDatabaseInstance = containerInstance database
}
}
deploymentNode "bigbank-db02" "" "Ubuntu 16.04 LTS" "Failover" {
secondaryDatabaseServer = deploymentNode "Oracle - Secondary" "" "Oracle 12c" "Failover" {
liveSecondaryDatabaseInstance = containerInstance database {
tag "Failover"
}
}
}
deploymentNode "bigbank-prod001" "" "" "" {
softwareSystemInstance mainframe
}
}
primaryDatabaseServer -> secondaryDatabaseServer "Replicates data to"
}
}
views {
systemlandscape "SystemLandscape" {
include *
autoLayout
}
systemcontext internetBankingSystem "SystemContext" {
include *
animation {
internetBankingSystem
customer
mainframe
email
}
autoLayout
description "The system context diagram for the Internet Banking System."
properties {
structurizr.groups false
}
}
container internetBankingSystem "Containers" {
include *
animation {
customer mainframe email
webApplication
singlePageApplication
mobileApp
apiApplication
database
}
autoLayout
description "The container diagram for the Internet Banking System."
}
component apiApplication "Components" {
include *
animation {
singlePageApplication mobileApp database email mainframe
signinController securityComponent
accountsSummaryController mainframeBankingSystemFacade
resetPasswordController emailComponent
}
autoLayout
description "The component diagram for the API Application."
}
image mainframeBankingSystemFacade "MainframeBankingSystemFacade" {
image https://raw.githubusercontent.com/structurizr/examples/main/dsl/big-bank-plc/internet-banking-system/mainframe-banking-system-facade.png
title "[Code] Mainframe Banking System Facade"
}
dynamic apiApplication "SignIn" "Summarises how the sign in feature works in the single-page application." {
singlePageApplication -> signinController "Submits credentials to"
signinController -> securityComponent "Validates credentials using"
securityComponent -> database "select * from users where username = ?"
database -> securityComponent "Returns user data to"
securityComponent -> signinController "Returns true if the hashed password matches"
signinController -> singlePageApplication "Sends back an authentication token to"
autoLayout
description "Summarises how the sign in feature works in the single-page application."
}
deployment internetBankingSystem "Development" "DevelopmentDeployment" {
include *
animation {
developerSinglePageApplicationInstance
developerWebApplicationInstance developerApiApplicationInstance
developerDatabaseInstance
}
autoLayout
description "An example development deployment scenario for the Internet Banking System."
}
deployment internetBankingSystem "Live" "LiveDeployment" {
include *
animation {
liveSinglePageApplicationInstance
liveMobileAppInstance
liveWebApplicationInstance liveApiApplicationInstance
livePrimaryDatabaseInstance
liveSecondaryDatabaseInstance
}
autoLayout
description "An example live deployment scenario for the Internet Banking System."
}
styles {
element "Element" {
background #045462
color #ffffff
}
element "Group" {
color #424242
}
element "Deployment Node" {
color #424242
}
element "Person" {
color #424242
background #f8ec17
shape person
}
element "Software System" {
background #6a8f98
}
element "Database" {
shape cylinder
}
element "Queue" {
shape pipe
}
element "Web" {
shape WebBrowser
}
element "Mobile" {
shape MobileDeviceLandscape
}
relationship "Relationship" {
color #424242
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB