From 94ff2dbd7575571a790a357fa3f6380c35af558f Mon Sep 17 00:00:00 2001 From: Milan Milanovic Date: Mon, 17 Jun 2024 20:06:08 +0200 Subject: [PATCH] Initial version --- .github/workflows/deploy-docs.yml | 38 + README.md | 60 ++ .../structurizr-Component-001.png.cache | 1 + .../structurizr-Container-001.png.cache | 1 + .../structurizr-Deployment-001.png.cache | 1 + .../structurizr-SystemContext-001.png.cache | 1 + build/docs/index.html | 707 ++++++++++++++++++ build/docs/structurizr-Component-001.png | Bin 0 -> 16347 bytes build/docs/structurizr-Container-001.png | Bin 0 -> 17668 bytes build/docs/structurizr-Deployment-001.png | Bin 0 -> 14772 bytes build/docs/structurizr-SystemContext-001.png | Bin 0 -> 10665 bytes docker-compose.yml | 23 + src/docs/asciidoc/index.adoc | 17 + .../sections/01_introduction_and_goals.adoc | 2 + .../asciidoc/sections/02_constraints.adoc | 3 + .../sections/03_context_and_scope.adoc | 9 + .../sections/04_solution_strategy.adoc | 10 + .../sections/05_building_block_view.adoc | 17 + .../asciidoc/sections/06_runtime_view.adoc | 6 + .../asciidoc/sections/07_deployment_view.adoc | 11 + .../sections/08_crosscutting_concepts.adoc | 12 + .../asciidoc/sections/09_decision_log.adoc | 4 + .../sections/10_quality_scenarios.adoc | 30 + .../sections/11_risks_and_technical_debt.adoc | 10 + src/docs/asciidoc/sections/12_glossary.adoc | 21 + .../sections/adrs/0001-login-decision.adoc | 15 + .../structurizr-Component-001-key.puml | 28 + .../structurizr-Component-001.puml | 41 + .../structurizr-Container-001-key.puml | 38 + .../structurizr-Container-001.puml | 51 ++ .../structurizr-Deployment-001-key.puml | 39 + .../structurizr-Deployment-001.puml | 54 ++ .../structurizr-SystemContext-001-key.puml | 38 + .../structurizr-SystemContext-001.puml | 34 + src/docs/structurizr/structurizr.dsl | 95 +++ src/docs/structurizr/structurizr.properties | 3 + 36 files changed, 1420 insertions(+) create mode 100644 .github/workflows/deploy-docs.yml create mode 100644 README.md create mode 100644 build/docs/.asciidoctor/diagram/structurizr-Component-001.png.cache create mode 100644 build/docs/.asciidoctor/diagram/structurizr-Container-001.png.cache create mode 100644 build/docs/.asciidoctor/diagram/structurizr-Deployment-001.png.cache create mode 100644 build/docs/.asciidoctor/diagram/structurizr-SystemContext-001.png.cache create mode 100644 build/docs/index.html create mode 100644 build/docs/structurizr-Component-001.png create mode 100644 build/docs/structurizr-Container-001.png create mode 100644 build/docs/structurizr-Deployment-001.png create mode 100644 build/docs/structurizr-SystemContext-001.png create mode 100644 docker-compose.yml create mode 100644 src/docs/asciidoc/index.adoc create mode 100644 src/docs/asciidoc/sections/01_introduction_and_goals.adoc create mode 100644 src/docs/asciidoc/sections/02_constraints.adoc create mode 100644 src/docs/asciidoc/sections/03_context_and_scope.adoc create mode 100644 src/docs/asciidoc/sections/04_solution_strategy.adoc create mode 100644 src/docs/asciidoc/sections/05_building_block_view.adoc create mode 100644 src/docs/asciidoc/sections/06_runtime_view.adoc create mode 100644 src/docs/asciidoc/sections/07_deployment_view.adoc create mode 100644 src/docs/asciidoc/sections/08_crosscutting_concepts.adoc create mode 100644 src/docs/asciidoc/sections/09_decision_log.adoc create mode 100644 src/docs/asciidoc/sections/10_quality_scenarios.adoc create mode 100644 src/docs/asciidoc/sections/11_risks_and_technical_debt.adoc create mode 100644 src/docs/asciidoc/sections/12_glossary.adoc create mode 100644 src/docs/asciidoc/sections/adrs/0001-login-decision.adoc create mode 100644 src/docs/structurizr/structurizr-Component-001-key.puml create mode 100644 src/docs/structurizr/structurizr-Component-001.puml create mode 100644 src/docs/structurizr/structurizr-Container-001-key.puml create mode 100644 src/docs/structurizr/structurizr-Container-001.puml create mode 100644 src/docs/structurizr/structurizr-Deployment-001-key.puml create mode 100644 src/docs/structurizr/structurizr-Deployment-001.puml create mode 100644 src/docs/structurizr/structurizr-SystemContext-001-key.puml create mode 100644 src/docs/structurizr/structurizr-SystemContext-001.puml create mode 100644 src/docs/structurizr/structurizr.dsl create mode 100644 src/docs/structurizr/structurizr.properties diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..c816c8b --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,38 @@ +name: Deploy Documentation to GitHub Pages + +on: + push: + branches: + - main # Trigger the workflow on push to the main branch + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Generate PlantUML diagrams + run: docker-compose run --rm generate-diagrams + + - name: Generate HTML documentation + run: docker-compose run --rm generate-docs + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/docs + diff --git a/README.md b/README.md new file mode 100644 index 0000000..97dec4c --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# Software Architecture Documentation with arc42 and C4 Model + +This repository provides an example of generating architecture documentation using the arc42 template and the C4 model, with the help of Structurizr CLI and Asciidoctor. The documentation includes various architectural views and diagrams, generated automatically using Docker and Docker Compose. + +## Overview + +The repository demonstrates how to: +1. Define architecture using Structurizr DSL. +2. Generate PlantUML diagrams using Structurizr CLI. +3. Generate HTML documentation using Asciidoctor. +4. Serve the documentation using Nginx or GitHub Pages. + +## Prerequisites + +- Docker +- Docker Compose + +## Usage + +Follow these steps to generate and serve the architecture documentation. + +### 1. Generate PlantUML diagrams + +Run the following command to generate PlantUML diagrams from the Structurizr DSL: + +```sh +docker-compose run --rm generate-diagrams +``` +### 2. Generate HTML documentation +Run the following command to generate the HTML documentation: + +````sh +docker-compose run --rm generate-docs +```` +### 3. Serve the documentation +Run the following command to serve the documentation using Nginx: + +````sh +docker-compose up serve-docs +```` + +### 4. View the documentation +Open your browser and go to http://localhost:8080 to view the generated documentation. + +## GitHub Pages Demo +You can view the demo of this documentation on GitHub Pages at the following [URL](https://.github.io//). + +## Explanation of Key Files +- src/docs/structurizr/structurizr.dsl: Defines the architecture using Structurizr DSL. +- src/docs/asciidoc/index.adoc: Main AsciiDoc file that includes other sections. +- src/docs/asciidoc/sections/: Directory containing individual AsciiDoc section files. +- docker-compose.yml: Docker Compose configuration to orchestrate the generation and serving of documentation. + +## Customization +You can customize the Structurizr DSL file (structurizr.dsl) to reflect your own system's architecture. Similarly, you can edit the AsciiDoc files in the sections directory to include more detailed information about your system. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. + diff --git a/build/docs/.asciidoctor/diagram/structurizr-Component-001.png.cache b/build/docs/.asciidoctor/diagram/structurizr-Component-001.png.cache new file mode 100644 index 0000000..0f183a3 --- /dev/null +++ b/build/docs/.asciidoctor/diagram/structurizr-Component-001.png.cache @@ -0,0 +1 @@ +{"checksum":"plantuml-md5-be4964e4a52214fa7c6a3f1c7982c5ff","options":{"size_limit":"4096"},"width":344,"height":345} \ No newline at end of file diff --git a/build/docs/.asciidoctor/diagram/structurizr-Container-001.png.cache b/build/docs/.asciidoctor/diagram/structurizr-Container-001.png.cache new file mode 100644 index 0000000..4aa4b33 --- /dev/null +++ b/build/docs/.asciidoctor/diagram/structurizr-Container-001.png.cache @@ -0,0 +1 @@ +{"checksum":"plantuml-md5-472c1c2cff83c3fd62b54c68a4637fa9","options":{"size_limit":"4096"},"width":726,"height":202} \ No newline at end of file diff --git a/build/docs/.asciidoctor/diagram/structurizr-Deployment-001.png.cache b/build/docs/.asciidoctor/diagram/structurizr-Deployment-001.png.cache new file mode 100644 index 0000000..c815d13 --- /dev/null +++ b/build/docs/.asciidoctor/diagram/structurizr-Deployment-001.png.cache @@ -0,0 +1 @@ +{"checksum":"plantuml-md5-1222f37eb53c06b1a65b3c7ac23fabc7","options":{"size_limit":"4096"},"width":517,"height":193} \ No newline at end of file diff --git a/build/docs/.asciidoctor/diagram/structurizr-SystemContext-001.png.cache b/build/docs/.asciidoctor/diagram/structurizr-SystemContext-001.png.cache new file mode 100644 index 0000000..e09b8e6 --- /dev/null +++ b/build/docs/.asciidoctor/diagram/structurizr-SystemContext-001.png.cache @@ -0,0 +1 @@ +{"checksum":"plantuml-md5-ad6f96440bf1d5d50a427c16ed0d32a2","options":{"size_limit":"4096"},"width":378,"height":180} \ No newline at end of file diff --git a/build/docs/index.html b/build/docs/index.html new file mode 100644 index 0000000..3185d41 --- /dev/null +++ b/build/docs/index.html @@ -0,0 +1,707 @@ + + + + + + + + +Software Architecture Documentation Template + + + + + +
+
+

1. Introduction and Goals

+
+
+

This section provides an overview of the system’s goals and stakeholders.

+
+
+
+
+

2. Architecture Constraints

+
+
+

List of technical, organizational, and other constraints.

+
+
+
+
+

3. System Context and Scope

+
+
+

3.1. System Context

+
+
+structurizr SystemContext 001 +
+
+
+
+
+
+

4. Solution Strategy

+
+
+

4.1. Technology

+
+

Which techonologies are used in the solution?

+
+
+
+

4.2. Methods for high-level design

+
+

Which methods are used for high-level design?

+
+
+
+
+
+

5. Building Block View

+
+
+

5.1: System Context

+
+
+structurizr Container 001 +
+
+
+
+

5.2: Container

+
+
+structurizr Component 001 +
+
+
+
+
+
+

6. Runtime View

+
+
+

It shows the behavior of one of several building blocks in the form of essential use cases.

+
+
+

6.1. Login use case

+ +
+
+
+
+

7. Deployment View

+
+
+

This section describes how the software system is deployed, including the hardware, software, and networking components.

+
+
+

7.1. Deployment Diagram

+
+
+structurizr Deployment 001 +
+
+
+
+
+
+

8. Cross-cutting Concepts

+
+
+

Description of cross-cutting concerns such as security, performance, and logging.

+
+
+

8.1. Security

+
+

8.1.1. Authentication

+ +
+
+
+

8.2. Performance

+ +
+
+

8.3. Logging

+ +
+
+
+
+

9. Architecture Decisions Records

+
+
+

9.1. Login decision

+
+

9.1.1. Context and Problem Statement

+
+

We want to enable user login.

+
+
+
+

9.1.2. Considered Options

+
+
    +
  • +

    Option 1

    +
  • +
  • +

    Option 2

    +
  • +
+
+
+
+

9.1.3. Decision Outcome

+
+

We selected option 1, because X.

+
+
+
+
+
+
+

10. Quality Scenarios

+
+
+

10.1. Performance

+
+

TODO: Describe performance-related quality scenarios.

+
+
+
+

10.2. Scalability

+
+

TODO: Describe scalability-related quality scenarios.

+
+
+
+

10.3. Reliability

+
+

TODO: Describe reliability-related quality scenarios.

+
+
+
+

10.4. Availability

+
+

TODO: Describe availability-related quality scenarios.

+
+
+
+

10.5. Security

+
+

TODO: Describe security-related quality scenarios.

+
+
+
+

10.6. Maintainability

+
+

TODO: Describe maintainability-related quality scenarios.

+
+
+
+

10.7. Portability

+
+

TODO: Describe portability-related quality scenarios.

+
+
+
+
+
+

11. Risks and Technical Debt

+
+
+

11.1. Risks

+
+

Identify and describe potential risks.

+
+
+
+

11.2. Technical Debt

+
+

Identify and describe technical debt in the system.

+
+
+
+
+
+

12. Glossary

+
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TermDefinition

Term 1

Definition of term 1

Term 2

Definition of term 2

Term 3

Definition of term 3

Term 4

Definition of term 4

Term 5

Definition of term 5

+
+
+
+ + + \ No newline at end of file diff --git a/build/docs/structurizr-Component-001.png b/build/docs/structurizr-Component-001.png new file mode 100644 index 0000000000000000000000000000000000000000..584744f671afb425180bc94af033e230c621f77a GIT binary patch literal 16347 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 literal 0 HcmV?d00001 diff --git a/build/docs/structurizr-Deployment-001.png b/build/docs/structurizr-Deployment-001.png new file mode 100644 index 0000000000000000000000000000000000000000..29ab7d18705570d80714824a6b5423ed63bde048 GIT binary patch literal 14772 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 G`~LwU>6zF7 literal 0 HcmV?d00001 diff --git a/build/docs/structurizr-SystemContext-001.png b/build/docs/structurizr-SystemContext-001.png new file mode 100644 index 0000000000000000000000000000000000000000..0e262236672adc81d51504a96cf7818a067db472 GIT binary patch literal 10665 zcmb7qWmsHIuqF#u?710>?)z< zYU<$VX=iTX3L|9>Gr6I;<>^Cd9bco9* zTw*d=0yL^SE3yf&kUG5>HjxgpvwsItVs(XRm68M^YI8K|Z$GH9h#z?dI<+rlQ}fZd zvw7#}svfo5qIT{|bZpotx=ea_BHJ}T`83t>tilt?5ubvBXT-n@R@!9nKuVVeWiJeN zZEiE`b5RYeoEay6kkwler4^v}_|V_lDs0*A#jS8zG3Z;#Z%cXC6AyJ|0qNXu@VM;r z4AqFZ;x$u>9=ruo;}-rIms&-)OtI@0m6OiT5(vxRY;I2WRcUXI;fIi!y!H|)qkUh- zkUW^CKhekCd6!Mu05_9q%G#;p|s|GWavx zM)%sYh{l@-ZoXhlk^;P^_t_6#bN&lat9UdP3=AEbjJSxJhrwwMvKHRb>QKj~JRGQw zT3o(;!$aQLG^Uj(77<$_7XL&aH&$P`>{C$0a;z2>zVgX8#$_}v1Uw0mqB0HA+l=H7V;>xN?CkGr?pwo@waaAY3eTH>CCI&4geQn1LdB|EUKk5O`MnhYC5ZlA zBQb(V3c@OS5XCpRQzQ{Anm|x6MMRP?SOiO4<_ClVrGR=G2qnk)ALIoFYw|KOBi}h~ zdEL({i;9Y>s;Vj~p2k?Z9MRO1k#K&MxdkGf3w z-61F!bY4f}(NHHZU6L9d97LK-74W{rBOvJXyxKqSdOMpd!E90DRL;3lgxpPzkH262 z&Tgrorl#iPD^3<`BLG1;lqZdh$`z{EwqAI{-*E6>X_^c)x&>b5&RKXDV$29MCjzP+cKpaOV z@I9+%=kexP34VUA*0`_J_enHm*fft6&4nDJqEQ~@Adrc6_YDI zK3-8;Isiue;}9kK%k`Y1VlICmX}AQ9xN+BVtDO2?yEiN{tR7*(+1VKuq{;R}S!-#j zw2e9n=FOvY&yaT(m;LZZ`0ky+t-)Ah8*UNZ+pW78nd`@-D zrVYM~24NY(2dK(Myzq!;5U^B%ksMa&2u5U57#Y8ZaDk_%CpxuMK#puL!fQvs0*Rcb zP74qnHscGY!v=|7hS`idCI9>#mAa0O*YCkt>$&0{#_!p@R8n!&+G%NNSdb2HKuB;< z5Cy;0G({3(2`9t*p9Q)tKnn{C85tSsXu-GP;q8kl|JP)FvOzLF)D9CVnGE=m9R{W9 zNpH;}NH-iRYCwDfy__)xY9#eH8)gOuO63cAkghBE*;|?U5-1H@6S%}~ImvohNR2CT z-$Qjnmak-GVggs9kW4Et{mssf(dRh{Q;v_1Z#c*tam4H8k(2RoWB?oPk4tLEyInN} zSy@v$HpkH`sg(rATsXUV;JMfB$x49x*MT}>HvhoM1bTgTzR=0NO*EsiG$y4V_G``P zpVP7t+CGOM^Q({tq#|bXvRYcGgrO57nf_g<(9~~p4ZOc>4pm_6!x5a z02p-#ASI2Zoroh%K8%uAp&vE5s~ddYXDp_e4p<^sVOW4f55<%B6)0+Iejv!&)qRkP zCrf06iV64fEo=jwqUNblQc|*7Pfbm^ySas`A}?ad1x9~h;Y#rNfK~&w)?^kMjHi2h zi17Hu$C}l8fqG(MVo4H$FjQ1jnY|a-=ybM2airw@9!g3|7taqa?(TPF0$vGvx2&aX zI!yDv=W_D$GIs?91wZJf^BOFt*uDrlml4X*QBuMdn_~T7!S^pc{+(iTia4Id>vn{& zheL|L?UxCC?{JSm4Fah$1S6q;%6s15-~WEMU9;jHUP}8va`^ve%Kv{LkMyz! zM3!Y{Vd!VI`?zmz=J;ox&D;O|jD_&{+6hWI)M$v6Vtz#WfQRn_5W^~zoRyn0(m> zjSKc}4?*e$XUBaviU!O2S*v?mn7 zvbL&(#I&rhC~YR)qCAw>ZI2p91M+`UL@-(vL!OP#s}X7_ZS1UsyhaH0)G4J?t$si% zA@2E+BKBQ@zP=vl)0AMLu+`{Rt4f+VBNG(coC3YpO4;@)+PVxr{CrP7o)Pw>s4{DIG%L%Q(mzF*h z;#I_yvUA$X&bM8f7E6>M>1h)1L!YsOxqq`-?)wv3?QH~Pk;0#pAXPQJ)fMSiA=2tV zzl_??UukmIgb+kH27#cQ_8FzkD6;2KO|js;IABTZix`%;>50X~bL{nS%@=g-+Q@%M z`+x|d+x{`-?r%h)M{9K;4@_Z%{22uBC8pnoS%8Yal8h^W7Fi=zw(DPZfeyd;i$s^M{7T7BXAR=%}W zDR6`=^)4>8w%ofGD&?71b?*eJt^bs!K(M>ksf)y9*F#}*+k!3{%!>xh_qZmP6*5gv z*b67uKJRckcvK~ugPL17yMGq!cJI3VF$lD_%Nq3fR!)7klm*MyF19PoFhjMFyMU1dB}(K=&A0@uNN^jGP;_C{f5ceJ|uNh9y0%vJH}k! z1kQe-#i}=S!dCR7gpvYJ30pxo!K{3G3V(IaCT+2d;GMSN zHTad-u$uW`Qwj0d^ekVnd?)al%D^NLJ%L=~=p9xHKS4`gfc(BZZB`2m+sSE=Z?BZz za&yeFN<NfLBLDf% znj4|<4ev*CmZHJo8Q?y7#MUBnAhS06NDEi!x4u&(lxP{7;uh&OVb4vKCbmXi$I0|H zO!2COpAdfkEKK~>yvQ>vzm}X#hb~S``?ok$?_{a;%1r6-Ls$Hi{WWyQ6`@L}&Co^` zdeI5wmE~XAySFgPfL$v8>oD?^;pv-V6YX)9ryNL>F zl&l2eK<`CAKjvn?2r*e=QZ_KX!RL>z?c0kxuAwDfD(cwm)we0+l3Qn=?%kwbT>U)3 zh>=NVynr9wilDpVa}4yzsnBL4v2@!@L&ny=Gc6`{mJ=jyA0DL>Zq(f0jjWBCzYiwu ziIv5m8ucp~bbMI{32Y40ge3DR*3SpAo%HKse@w6fUGs!ENJaH=6jB44KD~Hn1+-|d zmt^gIKr;rauY?Ip`Z3U%zYK6IgxmgnGy!y{dSlm?tE{_aFN)cZbCK;gN0rh!H)g#~ zVye1)%lK|c`=^GV^d)EFX=L(Gv_pwmw98HQCNV5`sFGTmCbgZzeue5+9->Q4$76|> zuDT22UxHQ>t;@rOKE-}2OeHf^urdk1`siS38K)8KtlV~J3hzUT8d`$h;We%;&bzm! zbEoIj@2KI4o2sC3b1q5V3BNCNgUYI_T!>I z9%%FlD|G@wKB*>)!(;#M^P4Y&_m|tE%u$tpWK9B5FsXLHF)edP9ly9VU5xY>-3t0f za}40}?@vTH-bpN@|IE|e2&Xkl?JvysNqEmdE0v46agPE=dASqaZ`Xs0wy4@5&})pN z#@ve2ZF|&9Z*2g+DCwXXRU3icWd%D*EyDmx z3~{mmvTswPdm2$z2+)Z>NC`SkitevP3Bn%*5cpwO7K~{(5Mwdgj1Dj-!`srMWRPJS zQq!XPCL^PL75Ecg`zd&Wt~DwTV5s-m1T~=*M=nT*`FZ+4#Q(C1Sj)d>=Rh`@FQ@96 za?9tnPlCKYOV0D7s!bUbu!QWouedCEymHJKSO%1(ZK#~WrmoXVZSG&?kAdZN%*~o_ zws1rIMvpZOBI7PG#5XXRPvfUg)P1CKA7x)+Y=RiBbC zCs3aW3}0V3uY%f0oG*RN&A)hazksMfhRf(4*RuX~)~sSXNd9w$$Q9s~f2H#`3Yxyy z92a~#Ymn7bzHAp~^C71xXG%Um4ZCMMH28fu5ypMoPtD-o0$IdgqZO1;7lk5IDIm~x zd1U2f8h*x0?K#dFju`>xIz=UJuEHRHuKtL7ScC4|b%kU>6G|fr^?{ysiDK`PtPua1 z&HQ4*a$|3Olr5*+V;9r2kp_OM9*piD9%?V{6=>57(zWx%qF@a55W~Y7y3dJsZilH^ z+l{{}iCg$e`MenRQ6iGoF-FU&;KI!ExcO3~ttTRRC$5N@NF0djXWQB)UD`~`PRZBr zbe^m7UK(dUB`^APyd0z<1V2S>EUeb-|CS4#-1T=VYQQ>Q`Ula`x@csn^YTpX!(oP)5m78 z^Hq_*OJK@R2)$%eeOBaRb?o(w?Yv4Xx+dYI?i&|V@>B6AobpCul^BIT=`WcF1uDwu zTxw1u9vn76Ko`?$!NO*cV7#&oRWSZz!;&Oj`(9^LgdM0aBvwx}mv%QOKBQwLtBx*( zd7PfJq%itaU~=C%{p7{CB27QZ{EBFGLfjU>Byde6KmDWiI7y{wb4S>TQNJyPt{hcu z45(5sOF$NLKf9|yUV{8=$P_uc@%B5hqjjCe+kd&-Jl$-iofc$z>?H}#`{=t99CA2>x#F!CJS{$bB(4-@80V9Rm7`7UiXBVlQBmNxVjWRS74eqcC!Q zW-O<<;+s%zvnJm?mr?wpwga0=?^(9T8s1uQ>%3_#p^^!?zrSBzSz$_rnQ3g~(A3nl zwLOj{2GCMdPa~F(9WT{{*1zO6>wvC=o}Qk3HUnDCKA`SWheJsNdw+xY8SvA- zZntO;T<@orc|oH!Y8Cx!`cf6KQu)s}1<>tvXP<8uzN9(G)YKH0kWfqK@s-LQTERlg zLAXE)Ha6$EVtLoVqonloKl}S2X#3&W=kg`kvosCD8l?SRPF?y}shYSX8#l(d6Sr<1 zVAJ(s0V6MDxl!~2+avTMcg=wUvU87?v6P@IgCen`PKdC|h~tfpQcNc2Aj8ZA^7pDl zrS|6#+Rfw8ajwW|ed;40h-9+vqq$^yTGlW45)Mhy@7^@IK8^YFK~_ihY;BAgNu92~5#r)OtxUjyx0ZgI0}*4NiV z>uEI`o6i7nkj=_OXhLJBE!olc^}sTO28^IOd%tHyMoXhlFu3TG8b*@i=r2$-!Gs;5 z;XNe0e5m(6WW-*~B^m*WID&NLH*R9=hJhSPY_P^Gn}jl_m{xC)e(f`3KNcam99L?8 zNxBMlQ2N2>io7g(1MU}9&J$W5ftJX6AS<(B;_FzhfzX1@{paY3aH00iD6`E@-;Irp zP#lV_?d_h)P#R1^dC!59;=&MbQ{H0X35qy)f@ZrFwgVZplzZk(l5%qZ`(0RX)X!gP z*U$EXSDUggO(IYe!?sgfztT6P9><3GjJ${I)wetE!7FZP@+kGUJ;mIn%pw!>fP^k* zi;8>$jd+cmzH-NcbUn!z4UJ?9`{ddbXkK95n*aKzYqoW>2Z@h_9eNhoP7WOTtV4qd zgsak*Ehw$dd14V13;ym$Eb++V?bWg1m~21#V5qL4L7+8``tIrOd}@+l(>q_Uz8vo4 zNFz00rbCpU(RiUg@}` zORHfUz{-Qfk#}guNzlpRjYgFeH?up>RADAL;N-+H96gXXKsCnR0^IaP&fR|AtzC9q9?*Y6rKar0{|% z4Ry9pB(b4_+JS-((1yl!SsC*u@1DF@MoFJ9J{h(AUa$M2!n>osOI=xQp$wVX%r687 zt%w6B+>0sI{b(kz&^ZuZ_1wVw2RtLO{>2`P3y!* zaP}PnY=mgR&;W(XzV@{)+LElmpR;*R=P;Sk4E!DPcKlQnX=c1&`pSk!rqwF;@ym+3 zV~SdvH}w4-3?3!dxueoNKX<29-=n^@8tvg@&4E%PX=)$y`Mie%H&Y zqTeJp0LffQZ0r2*(%}sg)@z2U{8JfU6x2>84vQC*jf%h90Gywv@XC>(GtxhmS*Y;s z2B$I!l;@3=m7=Wo8D@aGSPTy*6Ru;wwapW`*RJTtFFe$CpO?vjG4g#8xj>fK>^I)S zyHAwp&J9=5qNd5vHL&TD`(=a%ISQyriZ}<5ZzAS-r6T#q6?re^gPTD=Z786FDt|Z=?~+(S*35MSTEXE|%Q`JTIcfuW~-67GGajcicb*iC6i$SWJw} zG>h>48T^S1Q{t z8IX)$+2Osc;6Qc!5?0(|TP2o!2ozE+e=d>a%u%6J2?hRuEc*i7#ukuSTu`G%CTFu? z4p$H{$OKoD{GEe-catC+cu(SQmTK9&s1U1AL3LgN7XK1Ji<+2Zz$@HK^AM1G9qf%C z$vL`Zyp}hp6TUvu-(J0{8y90+IRg5>&CWHtdlo$mh?ZI=9na;)1&*u?w8@^any+R( z6#q$mUF(f!mV4|D>$0Xda(b39Q}I(SqyO~PVYqk*ji1Uy1&zW>h__;G^vM;|T&<%v z%XtsOZ?A>k{U1dP+9v?c?_j0wH)yxiltvGK;3eIx?GJ57dS0w9&VR7m0hu9r_L4{` z;yRxyNV#)#JuRqgZtDg)NSF!lG)=qHO7&x|QR_I<|CJV2F%OjiEW7>XK&R=^=$`q} zw^lu5`2qDz!Z$(`eBxD3GtokU#8_Dx z!z&~yn$#hT3OmDHK|hnwbeMg}(IZBWSUfdK=6iY7hCIH9B^fbOzi%Fh40@_PE=&7& zVL+K$H(mUs!BIs@6B1SaD6NJRu@=f|>5?$kuYZ|@PcE4VT8QuKNa~&0`|m8{tvuDmu|?KI8vrH*{JRMY zEgzpxR<@L}5{g(*zgWq}FYm%T{(pY=b%P)&)3EKpXct#z)C%lb~ zM^-EHX+Jgru9~=C;TDzT2;>ZQW>J^)BdY2zD%?Y%P|`Tf?H`u7MeebNRsebiQLu6x zTXh9#u1t}E)*rp&>wuD0PO++5i_ z)bb2H)?bqzFS2It0x)sNs+h9D>G!X5iU&bI&7cVDWH;E1SDzEQtp6kLG}UIE+rxcI z{#)dCTJ`aOAnAk+GK&*^V0e`AzMt zAb*7NAy}P&7ONJ?7}KWEcH&Ft1KYy_COniKVRe6a~~m#=)Rq9JJH0?Fj#%$&{C0<>i^KAN0r?R&~pl{`1S_cDc!=7Vx^=Y#>2b z-hji9`RsF+W96%*m-AH_g%|ojz`rc^7r>$w!SRpUd8hTuXahexH7p0KI(&F3qK2$c zW>1Tqx(2R4mKA?D^5^)E+06Ns)9BFP~Dy&i2w2~e!Av_o}L_DB~|5K>79oU*viU<^Pk6R@Njx$q>x+K zbzosVFnh3k#K)}Tvf(K*_9riY(wRrT6mR45As4`iNEV|Um zd@O>aY-fHP%UTHu)X&IKsNZtShF~Aafc%toG+r->6<3LB%ttjBX_^lN9uM#A9p+rJ zF!cvgtOZQmpja?na?;hftYgQT2sH!9M^2WmqNPVfkY3Pbc7AeGQh+;0Nrd%y1TND( zAk!#LOnbt}#^2n85y6Xc1!taZl@(bkn6L#X79>?d zst<^GT0S0f4BO=?D&ffhSluvV<-?ZJ`bdoBHazg;b1h_=Z+vl{@U-0x$mo|2#)Z53#}{ zG|MK!xP=J^$Fmwwij!ES_U4r=Rh-eHx-uIRH+D4~f!(9gSN&63dlGV!~kM{&Vi&O-kdZ zrdqCrFS*6})EQ{+`gFVh$+p`|@4*n(FJ>FQ2+CNqr$_{Ns~r!WXyKRbml-U$p^-4& zjqIOG!g!PGAMW+FG)};T9F~2D{_@M+cmd-1(g;cXKC;gpL?M~>kv%h`qf8-R2gNDh zGmQVMRIFfUe;?i!)Mcrs%FvBp3(HzIR~`cw3z}sOE;-PRZ#fxwN2|l7V$o0So5}FI zj!_DX3fIstP6_#-XLpY$)NLN;JSESe0n%++4?}bUF_s`yId!``13qs6NoCLIDVq%A zXYAT=az%T)8BnseFSx7{Mlqc`sZEM~(F2k!*R)91DKK$J?Qg6A@c6!eF4V!7D&z2q zp?JP_zA1sAOr5$qQA`DBe9V}(q$_<{c4K|9W}l6edGIO3Eo>yd+Ft#PT`6Ux-Yf2( z(^a9j${G;wd+GBHCrlzCa?G4coFH zC5>&sh(W2;5vK*nSfK{0foq1)=+8)v>eh!)@(m9JWx~`|d7y|>!#BSZWb%O_2mWp9 z-1di*S6B?jdJ0m(JSb2SnD_BF^Re+9VEy&PF}Zw;#jSRXT_N9+6ONB8LvG;-LreP~ zsB6)K>Hho7U$IU_6B&XA=n?dKhr$F={W!c$uqKM8XBqdI{UCi-@Hku)^I+kHYh=~v zt+cLlzezHihWAEgJ!^^P|K4n7{!nSIwUL-^xFRUir>>&2jx6fSDvn}0<_=Kzv2Iag zwD1eR!5|}ze9fafum8I}_hj5}TN~iKNZ5%_lB}wfovZIS$rAK3aJpqq##;I}`kPUz z)0NY;1HqFFZ$p(@4m@yRT34gG(X|PUllv1|CiX6Cq0aLXB{rLrs6HdGs~4nv0!6BVX$KPqK^emb z1kbqYs8_Mc_9!PYQXPlO6*5#L{jv%Ma?YCB>J;B^nxPbsl-CkxEVPi@^jzWNM;SW4 zHzw_WooI|Y7_vUb$OS{YHQ3^bYQ_LzBP~64fy1R3Wt;NFKFtZk(@EbFZ1Em7dqBVo z@I35g{GfrLD9(ms8rV2O@cfrpS&(f7opk{eKkrbcWK+_E#zkFZ;kapppv+$nbt$yP z3-Wg*;ne601i}BQj#ls(^R>kmXHe?{23R)(W3MajOSr#rE|}Fq9MAym@?*Q5Whe!V z<(7bMox7_xF~-A&k42+LM(s9fIm8AvB1dU9Yv@>5fB*iG`9h3dTdZiCQeL**jo)Ee zy>jdp{KWhzVzw+20t1&nZ8A1U7}}Eky4*a}xZpwxxqMTK_@?{?Oo^ACLdNUweo}8QP{QX%*rB4k8Ab*} zA8H%mhD`Njz@9yr>9F~GFIiKm-!~7dusSgq!ipkMFtl9xpx>1j|f zI7u$_>8cS!C4LJCW2;N%LhqQN^g=iL|90!_-XAmcX8Ga8A{2UO5=KTsLA+YjDCmCy D>z2ie literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..929ad70 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + generate-diagrams: + image: structurizr/cli:latest + volumes: + - .:/workspace + working_dir: /workspace + command: ["export", "-workspace", "src/docs/structurizr/structurizr.dsl", "-format", "plantuml"] + + generate-docs: + image: asciidoctor/docker-asciidoctor:latest + volumes: + - .:/workspace + working_dir: /workspace + environment: + - PLANTUML_LIMIT_SIZE=8192 + command: ["asciidoctor", "-r", "asciidoctor-diagram", "-D", "build/docs", "src/docs/asciidoc/index.adoc"] + + serve-docs: + image: nginx:alpine + ports: + - "8080:80" + volumes: + - ./build/docs:/usr/share/nginx/html \ No newline at end of file diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 0000000..28a11a3 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,17 @@ += Software Architecture Documentation Template +Version 1.0, June 2024. +:toc: +:toc-placement: preamble + +include::sections/01_introduction_and_goals.adoc[] +include::sections/02_constraints.adoc[] +include::sections/03_context_and_scope.adoc[] +include::sections/04_solution_strategy.adoc[] +include::sections/05_building_block_view.adoc[] +include::sections/06_runtime_view.adoc[] +include::sections/07_deployment_view.adoc[] +include::sections/08_crosscutting_concepts.adoc[] +include::sections/09_decision_log.adoc[] +include::sections/10_quality_scenarios.adoc[] +include::sections/11_risks_and_technical_debt.adoc[] +include::sections/12_glossary.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/sections/01_introduction_and_goals.adoc b/src/docs/asciidoc/sections/01_introduction_and_goals.adoc new file mode 100644 index 0000000..958a80e --- /dev/null +++ b/src/docs/asciidoc/sections/01_introduction_and_goals.adoc @@ -0,0 +1,2 @@ +== 1. Introduction and Goals +This section provides an overview of the system's goals and stakeholders. diff --git a/src/docs/asciidoc/sections/02_constraints.adoc b/src/docs/asciidoc/sections/02_constraints.adoc new file mode 100644 index 0000000..71b29ad --- /dev/null +++ b/src/docs/asciidoc/sections/02_constraints.adoc @@ -0,0 +1,3 @@ + +== 2. Architecture Constraints +List of technical, organizational, and other constraints. diff --git a/src/docs/asciidoc/sections/03_context_and_scope.adoc b/src/docs/asciidoc/sections/03_context_and_scope.adoc new file mode 100644 index 0000000..cae6f73 --- /dev/null +++ b/src/docs/asciidoc/sections/03_context_and_scope.adoc @@ -0,0 +1,9 @@ + +== 3. System Context and Scope + +=== 3.1. System Context + +[plantuml, structurizr-SystemContext-001, png] +.... +include::../../structurizr/structurizr-SystemContext-001.puml[] +.... diff --git a/src/docs/asciidoc/sections/04_solution_strategy.adoc b/src/docs/asciidoc/sections/04_solution_strategy.adoc new file mode 100644 index 0000000..22f0377 --- /dev/null +++ b/src/docs/asciidoc/sections/04_solution_strategy.adoc @@ -0,0 +1,10 @@ + +== 4. Solution Strategy + +=== 4.1. Technology + +Which techonologies are used in the solution? + +=== 4.2. Methods for high-level design + +Which methods are used for high-level design? \ No newline at end of file diff --git a/src/docs/asciidoc/sections/05_building_block_view.adoc b/src/docs/asciidoc/sections/05_building_block_view.adoc new file mode 100644 index 0000000..a2e06f4 --- /dev/null +++ b/src/docs/asciidoc/sections/05_building_block_view.adoc @@ -0,0 +1,17 @@ + +== 5. Building Block View + +=== 5.1: System Context + +[plantuml, structurizr-Container-001, png] +.... +include::../../structurizr/structurizr-Container-001.puml[] +.... + +=== 5.2: Container + +[plantuml, structurizr-Component-001, png] +.... +include::../../structurizr/structurizr-Component-001.puml[] +.... + diff --git a/src/docs/asciidoc/sections/06_runtime_view.adoc b/src/docs/asciidoc/sections/06_runtime_view.adoc new file mode 100644 index 0000000..ac2850f --- /dev/null +++ b/src/docs/asciidoc/sections/06_runtime_view.adoc @@ -0,0 +1,6 @@ + +== 6. Runtime View + +It shows the behavior of one of several building blocks in the form of essential use cases. + +=== 6.1. Login use case \ No newline at end of file diff --git a/src/docs/asciidoc/sections/07_deployment_view.adoc b/src/docs/asciidoc/sections/07_deployment_view.adoc new file mode 100644 index 0000000..0f13995 --- /dev/null +++ b/src/docs/asciidoc/sections/07_deployment_view.adoc @@ -0,0 +1,11 @@ + +== 7. Deployment View + +This section describes how the software system is deployed, including the hardware, software, and networking components. + +=== 7.1. Deployment Diagram + +[plantuml, structurizr-Deployment-001, png] +.... +include::../../structurizr/structurizr-Deployment-001.puml[] +.... diff --git a/src/docs/asciidoc/sections/08_crosscutting_concepts.adoc b/src/docs/asciidoc/sections/08_crosscutting_concepts.adoc new file mode 100644 index 0000000..caf575e --- /dev/null +++ b/src/docs/asciidoc/sections/08_crosscutting_concepts.adoc @@ -0,0 +1,12 @@ + +== 8. Cross-cutting Concepts + +Description of cross-cutting concerns such as security, performance, and logging. + +=== 8.1. Security + +==== 8.1.1. Authentication + +=== 8.2. Performance + +=== 8.3. Logging \ No newline at end of file diff --git a/src/docs/asciidoc/sections/09_decision_log.adoc b/src/docs/asciidoc/sections/09_decision_log.adoc new file mode 100644 index 0000000..09d3a9f --- /dev/null +++ b/src/docs/asciidoc/sections/09_decision_log.adoc @@ -0,0 +1,4 @@ + +== 9. Architecture Decisions Records + +include::adrs/0001-login-decision.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/sections/10_quality_scenarios.adoc b/src/docs/asciidoc/sections/10_quality_scenarios.adoc new file mode 100644 index 0000000..ed3ce8b --- /dev/null +++ b/src/docs/asciidoc/sections/10_quality_scenarios.adoc @@ -0,0 +1,30 @@ + +== 10. Quality Scenarios + +=== 10.1. Performance + +TODO: Describe performance-related quality scenarios. + +=== 10.2. Scalability + +TODO: Describe scalability-related quality scenarios. + +=== 10.3. Reliability + +TODO: Describe reliability-related quality scenarios. + +=== 10.4. Availability + +TODO: Describe availability-related quality scenarios. + +=== 10.5. Security + +TODO: Describe security-related quality scenarios. + +=== 10.6. Maintainability + +TODO: Describe maintainability-related quality scenarios. + +=== 10.7. Portability + +TODO: Describe portability-related quality scenarios. diff --git a/src/docs/asciidoc/sections/11_risks_and_technical_debt.adoc b/src/docs/asciidoc/sections/11_risks_and_technical_debt.adoc new file mode 100644 index 0000000..d6e5b8b --- /dev/null +++ b/src/docs/asciidoc/sections/11_risks_and_technical_debt.adoc @@ -0,0 +1,10 @@ + +== 11. Risks and Technical Debt + +=== 11.1. Risks + +Identify and describe potential risks. + +=== 11.2. Technical Debt + +Identify and describe technical debt in the system. diff --git a/src/docs/asciidoc/sections/12_glossary.adoc b/src/docs/asciidoc/sections/12_glossary.adoc new file mode 100644 index 0000000..5a1b210 --- /dev/null +++ b/src/docs/asciidoc/sections/12_glossary.adoc @@ -0,0 +1,21 @@ + +== 12. Glossary + +|=== +| Term | Definition + +| Term 1 +| Definition of term 1 + +| Term 2 +| Definition of term 2 + +| Term 3 +| Definition of term 3 + +| Term 4 +| Definition of term 4 + +| Term 5 +| Definition of term 5 +|=== diff --git a/src/docs/asciidoc/sections/adrs/0001-login-decision.adoc b/src/docs/asciidoc/sections/adrs/0001-login-decision.adoc new file mode 100644 index 0000000..524c69c --- /dev/null +++ b/src/docs/asciidoc/sections/adrs/0001-login-decision.adoc @@ -0,0 +1,15 @@ + +=== 9.1. Login decision + +==== 9.1.1. Context and Problem Statement + +We want to enable user login. + +==== 9.1.2. Considered Options + +* Option 1 +* Option 2 + +==== 9.1.3. Decision Outcome + +We selected option 1, because X. \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Component-001-key.puml b/src/docs/structurizr/structurizr-Component-001-key.puml new file mode 100644 index 0000000..1912e93 --- /dev/null +++ b/src/docs/structurizr/structurizr-Component-001-key.puml @@ -0,0 +1,28 @@ +@startuml +set separator none + +skinparam { + shadowing false + arrowFontSize 15 + defaultTextAlignment center + wrapWidth 100 + maxMessageSize 100 +} +hide stereotype + +skinparam rectangle<<_transparent>> { + BorderColor transparent + BackgroundColor transparent + FontColor transparent +} + +skinparam rectangle<<1>> { + BackgroundColor #85bbf0 + FontColor #000000 + BorderColor #5d82a8 + roundCorner 20 +} +rectangle "==Component" <<1>> + + +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Component-001.puml b/src/docs/structurizr/structurizr-Component-001.puml new file mode 100644 index 0000000..2f69330 --- /dev/null +++ b/src/docs/structurizr/structurizr-Component-001.puml @@ -0,0 +1,41 @@ +@startuml +set separator none +title System - Web Application - Components + +left to right direction + +skinparam { + arrowFontSize 10 + defaultTextAlignment center + wrapWidth 200 + maxMessageSize 100 +} + +hide stereotype + +skinparam rectangle<> { + BackgroundColor #85bbf0 + FontColor #000000 + BorderColor #5d82a8 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #85bbf0 + FontColor #000000 + BorderColor #5d82a8 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BorderColor #2e6295 + FontColor #2e6295 + shadowing false +} + +rectangle "Web Application\n[Container: Java and Spring MVC]" <> { + rectangle "==Component A\n[Component: Spring Bean]\n\nA component within the web application." <> as System.WebApplication.ComponentA + rectangle "==Component B\n[Component: Spring Bean]\n\nAnother component within the web application." <> as System.WebApplication.ComponentB +} + +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Container-001-key.puml b/src/docs/structurizr/structurizr-Container-001-key.puml new file mode 100644 index 0000000..90f9aa4 --- /dev/null +++ b/src/docs/structurizr/structurizr-Container-001-key.puml @@ -0,0 +1,38 @@ +@startuml +set separator none + +skinparam { + shadowing false + arrowFontSize 15 + defaultTextAlignment center + wrapWidth 100 + maxMessageSize 100 +} +hide stereotype + +skinparam rectangle<<_transparent>> { + BorderColor transparent + BackgroundColor transparent + FontColor transparent +} + +skinparam rectangle<<1>> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 +} +rectangle "==Container" <<1>> + +skinparam person<<2>> { + BackgroundColor #08427b + FontColor #ffffff + BorderColor #052e56 +} +person "==Person" <<2>> + +rectangle "." <<_transparent>> as 3 +3 .[#707070,thickness=2].> 3 : "Relationship" + + +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Container-001.puml b/src/docs/structurizr/structurizr-Container-001.puml new file mode 100644 index 0000000..16356c0 --- /dev/null +++ b/src/docs/structurizr/structurizr-Container-001.puml @@ -0,0 +1,51 @@ +@startuml +set separator none +title System - Containers + +left to right direction + +skinparam { + arrowFontSize 10 + defaultTextAlignment center + wrapWidth 200 + maxMessageSize 100 +} + +hide stereotype + +skinparam rectangle<> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 + shadowing false +} +skinparam person<> { + BackgroundColor #08427b + FontColor #ffffff + BorderColor #052e56 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BorderColor #0b4884 + FontColor #0b4884 + shadowing false +} + +person "==User\n[Person]\n\nA user of the system." <> as User + +rectangle "System\n[Software System]" <> { + rectangle "==Web Application\n[Container: Java and Spring MVC]\n\nThe web application." <> as System.WebApplication + rectangle "==Database\n[Container: MySQL]\n\nThe database." <> as System.Database +} + +User .[#707070,thickness=2].> System.WebApplication : "Uses" +System.WebApplication .[#707070,thickness=2].> System.Database : "Reads from and writes to" +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Deployment-001-key.puml b/src/docs/structurizr/structurizr-Deployment-001-key.puml new file mode 100644 index 0000000..eca4a03 --- /dev/null +++ b/src/docs/structurizr/structurizr-Deployment-001-key.puml @@ -0,0 +1,39 @@ +@startuml +set separator none + +skinparam { + shadowing false + arrowFontSize 15 + defaultTextAlignment center + wrapWidth 100 + maxMessageSize 100 +} +hide stereotype + +skinparam rectangle<<_transparent>> { + BorderColor transparent + BackgroundColor transparent + FontColor transparent +} + +skinparam rectangle<<1>> { + BackgroundColor #ffffff + FontColor #000000 + BorderColor #888888 + roundCorner 20 +} +rectangle "==Element" <<1>> + +skinparam rectangle<<2>> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 +} +rectangle "==Container" <<2>> + +rectangle "." <<_transparent>> as 3 +3 .[#707070,thickness=2].> 3 : "Relationship" + + +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-Deployment-001.puml b/src/docs/structurizr/structurizr-Deployment-001.puml new file mode 100644 index 0000000..605492d --- /dev/null +++ b/src/docs/structurizr/structurizr-Deployment-001.puml @@ -0,0 +1,54 @@ +@startuml +set separator none +title System - Deployment - Live + +left to right direction + +skinparam { + arrowFontSize 10 + defaultTextAlignment center + wrapWidth 200 + maxMessageSize 100 +} + +hide stereotype + +skinparam rectangle<> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #ffffff + FontColor #000000 + BorderColor #888888 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #438dd5 + FontColor #ffffff + BorderColor #2e6295 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #ffffff + FontColor #000000 + BorderColor #888888 + roundCorner 20 + shadowing false +} + +rectangle "Web Server\n[Deployment Node: Apache Tomcat]" <> as Live.WebServer { + rectangle "==Web Application\n[Container: Java and Spring MVC]\n\nThe web application." <> as Live.WebServer.WebApplication_1 +} + +rectangle "Database Server\n[Deployment Node: MySQL]" <> as Live.DatabaseServer { + rectangle "==Database\n[Container: MySQL]\n\nThe database." <> as Live.DatabaseServer.Database_1 +} + +Live.WebServer.WebApplication_1 .[#707070,thickness=2].> Live.DatabaseServer.Database_1 : "Reads from and writes to" +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-SystemContext-001-key.puml b/src/docs/structurizr/structurizr-SystemContext-001-key.puml new file mode 100644 index 0000000..1d89467 --- /dev/null +++ b/src/docs/structurizr/structurizr-SystemContext-001-key.puml @@ -0,0 +1,38 @@ +@startuml +set separator none + +skinparam { + shadowing false + arrowFontSize 15 + defaultTextAlignment center + wrapWidth 100 + maxMessageSize 100 +} +hide stereotype + +skinparam rectangle<<_transparent>> { + BorderColor transparent + BackgroundColor transparent + FontColor transparent +} + +skinparam person<<1>> { + BackgroundColor #08427b + FontColor #ffffff + BorderColor #052e56 +} +person "==Person" <<1>> + +skinparam rectangle<<2>> { + BackgroundColor #1168bd + FontColor #ffffff + BorderColor #0b4884 + roundCorner 20 +} +rectangle "==Software System" <<2>> + +rectangle "." <<_transparent>> as 3 +3 .[#707070,thickness=2].> 3 : "Relationship" + + +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr-SystemContext-001.puml b/src/docs/structurizr/structurizr-SystemContext-001.puml new file mode 100644 index 0000000..cf9c751 --- /dev/null +++ b/src/docs/structurizr/structurizr-SystemContext-001.puml @@ -0,0 +1,34 @@ +@startuml +set separator none +title System - System Context + +left to right direction + +skinparam { + arrowFontSize 10 + defaultTextAlignment center + wrapWidth 200 + maxMessageSize 100 +} + +hide stereotype + +skinparam rectangle<> { + BackgroundColor #1168bd + FontColor #ffffff + BorderColor #0b4884 + roundCorner 20 + shadowing false +} +skinparam person<> { + BackgroundColor #08427b + FontColor #ffffff + BorderColor #052e56 + shadowing false +} + +person "==User\n[Person]\n\nA user of the system." <> as User +rectangle "==System\n[Software System]\n\nThe system." <> as System + +User .[#707070,thickness=2].> System : "Uses" +@enduml \ No newline at end of file diff --git a/src/docs/structurizr/structurizr.dsl b/src/docs/structurizr/structurizr.dsl new file mode 100644 index 0000000..4d73a9f --- /dev/null +++ b/src/docs/structurizr/structurizr.dsl @@ -0,0 +1,95 @@ +workspace { + + model { + user = person "User" { + description "A user of the system." + } + + system = softwareSystem "System" { + description "The system." + user -> this "Uses" + + webapp = container "Web Application" { + description "The web application." + technology "Java and Spring MVC" + user -> this "Uses" + + componentA = component "Component A" { + description "A component within the web application." + technology "Spring Bean" + } + + componentB = component "Component B" { + description "Another component within the web application." + technology "Spring Bean" + } + } + + database = container "Database" { + description "The database." + technology "MySQL" + webapp -> this "Reads from and writes to" + } + } + + deploymentEnvironment "Live" { + deploymentNode "Web Server" { + technology "Apache Tomcat" + webappInstance = containerInstance webapp + } + + deploymentNode "Database Server" { + technology "MySQL" + databaseInstance = containerInstance database + } + } + } + + views { + systemContext system { + include user + include system + autolayout lr + } + + container system { + include * + autolayout lr + } + + component webapp { + include * + autolayout lr + } + + deployment system "Live" { + include * + autolayout lr + } + + theme default + + styles { + element "Software System" { + background "#1168bd" + color "#ffffff" + } + + element "Person" { + background "#08427b" + color "#ffffff" + shape "person" + } + + element "Container" { + background "#438dd5" + color "#ffffff" + } + + element "Component" { + background "#85bbf0" + color "#000000" + } + } + } +} diff --git a/src/docs/structurizr/structurizr.properties b/src/docs/structurizr/structurizr.properties new file mode 100644 index 0000000..926c290 --- /dev/null +++ b/src/docs/structurizr/structurizr.properties @@ -0,0 +1,3 @@ +structurizr.cli.version=2.1.1 +structurizr.cli.workspace=structurizr.dsl +structurizr.output.dir=src/docs/asciidoc/diagrams