archsight 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/docs/archimate.md +21 -1
- data/docs/configuration.md +1 -0
- data/docs/diagram.md +15 -3
- data/docs/docker.md +4 -1
- data/docs/icons.md +8 -2
- data/docs/import.md +178 -55
- data/docs/index.md.erb +24 -18
- data/docs/modeling.md +645 -34
- data/docs/pages.md +46 -15
- data/docs/search.md +21 -1
- data/docs/togaf.md +2 -1
- data/lib/archsight/analysis/result.rb +8 -2
- data/lib/archsight/analysis/sandbox.rb +8 -0
- data/lib/archsight/analysis/typst_renderer.rb +245 -0
- data/lib/archsight/analysis.rb +1 -0
- data/lib/archsight/annotations/annotation.rb +30 -3
- data/lib/archsight/annotations/architecture_annotations.rb +47 -0
- data/lib/archsight/annotations/link_annotations.rb +15 -0
- data/lib/archsight/annotations/resource_reference.rb +12 -0
- data/lib/archsight/cli.rb +124 -23
- data/lib/archsight/database.rb +40 -0
- data/lib/archsight/diagram/cli.rb +50 -2
- data/lib/archsight/diagram/formatter.rb +112 -0
- data/lib/archsight/diagram/routing/edge_router/orthogonal_path.rb +38 -10
- data/lib/archsight/diagram/routing/edge_router.rb +29 -4
- data/lib/archsight/diagram/routing/edge_routing.rb +61 -5
- data/lib/archsight/diagram/style/theme.rb +7 -2
- data/lib/archsight/documentation.rb +4 -4
- data/lib/archsight/editor/page_source.rb +13 -1
- data/lib/archsight/export/confluence/analysis_output.rb +100 -0
- data/lib/archsight/export/confluence/client.rb +13 -0
- data/lib/archsight/export/confluence/diagram_links.rb +1 -1
- data/lib/archsight/export/confluence/exporter.rb +43 -14
- data/lib/archsight/export/confluence/labels.rb +25 -0
- data/lib/archsight/export/confluence/page_properties.rb +6 -9
- data/lib/archsight/export/confluence/storage.rb +63 -14
- data/lib/archsight/export/confluence/tables.rb +2 -3
- data/lib/archsight/git_source.rb +81 -0
- data/lib/archsight/helpers/asset_images.rb +3 -4
- data/lib/archsight/helpers/embeds.rb +18 -7
- data/lib/archsight/helpers/resource_resolver.rb +25 -0
- data/lib/archsight/import/executor.rb +140 -16
- data/lib/archsight/import/handler.rb +55 -6
- data/lib/archsight/import/handler_loader.rb +64 -0
- data/lib/archsight/import/handlers/cache_pruner.rb +30 -7
- data/lib/archsight/import/handlers/command.rb +120 -0
- data/lib/archsight/import/handlers/github.rb +4 -1
- data/lib/archsight/import/handlers/gitlab.rb +4 -1
- data/lib/archsight/import/handlers/go_dep_resolver.rb +10 -2
- data/lib/archsight/import/handlers/go_grapher.rb +102 -5
- data/lib/archsight/import/handlers/go_module_parser.rb +88 -0
- data/lib/archsight/import/handlers/grapher.rb +40 -1
- data/lib/archsight/import/handlers/repository.rb +3 -0
- data/lib/archsight/import/handlers/rest_api_index.rb +3 -0
- data/lib/archsight/import/registry.rb +22 -1
- data/lib/archsight/import.rb +89 -1
- data/lib/archsight/linter/structure.rb +239 -0
- data/lib/archsight/linter.rb +123 -16
- data/lib/archsight/markdown.rb +48 -0
- data/lib/archsight/openapi.rb +169 -0
- data/lib/archsight/page_loader.rb +12 -1
- data/lib/archsight/page_tree.rb +2 -3
- data/lib/archsight/query/evaluator.rb +13 -6
- data/lib/archsight/query/parser.rb +73 -6
- data/lib/archsight/query.rb +1 -1
- data/lib/archsight/references.rb +3 -3
- data/lib/archsight/renderer.rb +80 -23
- data/lib/archsight/resources/analysis.rb +3 -2
- data/lib/archsight/resources/application_component.rb +75 -7
- data/lib/archsight/resources/application_interface.rb +12 -0
- data/lib/archsight/resources/application_service.rb +12 -1
- data/lib/archsight/resources/base.rb +58 -5
- data/lib/archsight/resources/business_actor.rb +5 -0
- data/lib/archsight/resources/business_contract.rb +72 -0
- data/lib/archsight/resources/business_product.rb +12 -0
- data/lib/archsight/resources/business_role.rb +1 -0
- data/lib/archsight/resources/implementation_deliverable.rb +1 -0
- data/lib/archsight/resources/implementation_plateau.rb +8 -2
- data/lib/archsight/resources/implementation_work_package.rb +2 -1
- data/lib/archsight/resources/import.rb +37 -11
- data/lib/archsight/resources/location.rb +56 -0
- data/lib/archsight/resources/motivation_requirement.rb +6 -0
- data/lib/archsight/resources/motivation_stakeholder.rb +14 -0
- data/lib/archsight/resources/page.rb +4 -7
- data/lib/archsight/resources/strategy_capability.rb +9 -0
- data/lib/archsight/resources/technology_artifact.rb +11 -4
- data/lib/archsight/resources/technology_communication_network.rb +91 -0
- data/lib/archsight/resources/technology_device.rb +88 -0
- data/lib/archsight/resources/technology_equipment.rb +75 -0
- data/lib/archsight/resources/technology_facility.rb +70 -0
- data/lib/archsight/resources/technology_node.rb +50 -0
- data/lib/archsight/resources/technology_service.rb +33 -0
- data/lib/archsight/resources/technology_system_software.rb +28 -0
- data/lib/archsight/resources.rb +12 -0
- data/lib/archsight/version.rb +1 -1
- data/lib/archsight/web/api/analysis_helpers.rb +55 -0
- data/lib/archsight/web/api/docs.rb +2 -1
- data/lib/archsight/web/api/json_helpers.rb +3 -37
- data/lib/archsight/web/api/openapi/spec.yaml +146 -35
- data/lib/archsight/web/api/page_helpers.rb +1 -8
- data/lib/archsight/web/api/routes.rb +9 -4
- data/lib/archsight/web/application.rb +40 -4
- data/lib/archsight/web/editor/routes.rb +2 -1
- data/lib/archsight/web/public/vendor/redoc/LICENSE +22 -0
- data/lib/archsight/web/public/vendor/redoc/VERSION +1 -0
- data/lib/archsight/web/public/vendor/redoc/api.html +27 -0
- data/lib/archsight/web/public/vendor/redoc/api.js +19 -0
- data/lib/archsight/web/public/vendor/redoc/redoc.standalone.js +1851 -0
- data/lib/archsight/web/public/vendor/redoc/redoc.standalone.js.LICENSE.txt +102 -0
- data/lib/archsight/web/public/vue/DocPage-C2ubTXH7.js +1 -0
- data/lib/archsight/web/public/vue/EditorPage-Dso6PLMn.js +35 -0
- data/lib/archsight/web/public/vue/ErrorPage-DnZ6YJLi.js +2 -0
- data/lib/archsight/web/public/vue/GraphView-CTl03Yre.js +1 -0
- data/lib/archsight/web/public/vue/HomePage-C339nihQ.js +2 -0
- data/lib/archsight/web/public/vue/InstanceRouter-DFW7tOrD.js +1 -0
- data/lib/archsight/web/public/vue/InstanceRouter-ZaCcjlIX.css +1 -0
- data/lib/archsight/web/public/vue/KindList-C0oaM3CF.js +1 -0
- data/lib/archsight/web/public/vue/KindList-yYcRT2BV.css +1 -0
- data/lib/archsight/web/public/vue/PageView-B93woeN3.css +1 -0
- data/lib/archsight/web/public/vue/PageView-OZB6G9Wu.js +1 -0
- data/lib/archsight/web/public/vue/QueryError-C2xLkCEm.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-D75O87zG.css +1 -0
- data/lib/archsight/web/public/vue/ResourceList-DooWFwQP.js +2 -0
- data/lib/archsight/web/public/vue/SearchResults-BK-HjFnv.js +1 -0
- data/lib/archsight/web/public/vue/{SearchResults-BewvsfOc.css → SearchResults-BV6UHriJ.css} +1 -1
- data/lib/archsight/web/public/vue/WikiPage-B2FYmeHL.js +3 -0
- data/lib/archsight/web/public/vue/WikiPage-TpmM1VAF.css +1 -0
- data/lib/archsight/web/public/vue/architecture-WOLXFQ4H-BGN-TV5r.js +1 -0
- data/lib/archsight/web/public/vue/cynefin-EF2NZ3EQ-CZd6g_tq.js +1 -0
- data/lib/archsight/web/public/vue/eventmodeling-K75KTNOO-CYnbEx8O.js +1 -0
- data/lib/archsight/web/public/vue/gitGraph-VSP46ZUC-DialfQSk.js +1 -0
- data/lib/archsight/web/public/vue/graphviz-1lWBhpEX.js +3 -0
- data/lib/archsight/web/public/vue/index-BLSE5DSv.css +1 -0
- data/lib/archsight/web/public/vue/index-CLuLTE5I.js +3 -0
- data/lib/archsight/web/public/vue/info-OHQRW6UA-BuhOW7ss.js +1 -0
- data/lib/archsight/web/public/vue/katex-B_JcIwqj.js +257 -0
- data/lib/archsight/web/public/vue/mermaid-C3bOamfn.js +3999 -0
- data/lib/archsight/web/public/vue/packet-JDAUHWVQ-CUeRz7w4.js +1 -0
- data/lib/archsight/web/public/vue/pie-XZMESJXO-DnuewJI6.js +1 -0
- data/lib/archsight/web/public/vue/radar-ABXABTNO-Bi9l8bcv.js +1 -0
- data/lib/archsight/web/public/vue/railroad-I3PHUGI6-DSlxFbxk.js +1 -0
- data/lib/archsight/web/public/vue/railroad-abnf-LNEFI6M7-D6Kqu8wu.js +1 -0
- data/lib/archsight/web/public/vue/railroad-ebnf-DWYD2UWJ-MR7uCYT0.js +1 -0
- data/lib/archsight/web/public/vue/railroad-peg-JR7BVNR7-BL7aKIc-.js +1 -0
- data/lib/archsight/web/public/vue/rolldown-runtime-COiEfhsA.js +1 -0
- data/lib/archsight/web/public/vue/treeView-D4JQ5SDB-CamtB04D.js +1 -0
- data/lib/archsight/web/public/vue/treemap-SAJKECNS-DeQxu_HM.js +1 -0
- data/lib/archsight/web/public/vue/{useGraphviz-DlSnFeCL.js → useGraphviz-Dnm2pkon.js} +2 -2
- data/lib/archsight/web/public/vue/useHighlight-BH32C7yt.js +10 -0
- data/lib/archsight/web/public/vue/usePanZoom-HxgEsqq2.js +12 -0
- data/lib/archsight/web/public/vue/wardley-7MLQ67FV-BvKIB6Tv.js +1 -0
- data/lib/archsight/web/public/vue.html +5 -5
- metadata +68 -41
- data/lib/archsight/web/public/vue/ApiDocsPage-BgqnQgwa.js +0 -1
- data/lib/archsight/web/public/vue/ApiDocsPage-DZ0fa5-h.css +0 -1
- data/lib/archsight/web/public/vue/DocPage-CNO71nBH.js +0 -1
- data/lib/archsight/web/public/vue/EditorPage-DR0FCNTz.js +0 -35
- data/lib/archsight/web/public/vue/ErrorPage-BfYArv6s.js +0 -2
- data/lib/archsight/web/public/vue/GraphView-BVTW30Ak.js +0 -1
- data/lib/archsight/web/public/vue/HomePage-Wk9P4Pma.js +0 -2
- data/lib/archsight/web/public/vue/InstanceRouter-BV8ycydz.js +0 -1
- data/lib/archsight/web/public/vue/InstanceRouter-jeavM6PW.css +0 -1
- data/lib/archsight/web/public/vue/KindList-C8yMsN5J.js +0 -1
- data/lib/archsight/web/public/vue/PageView-BaN6TyJB.js +0 -1
- data/lib/archsight/web/public/vue/QueryError-D790wH-a.js +0 -1
- data/lib/archsight/web/public/vue/ResourceList-B0FLaFR3.css +0 -1
- data/lib/archsight/web/public/vue/ResourceList-D-66nas2.js +0 -2
- data/lib/archsight/web/public/vue/SearchResults-CHyqIerQ.js +0 -1
- data/lib/archsight/web/public/vue/WikiPage-D2svpk6B.js +0 -13
- data/lib/archsight/web/public/vue/WikiPage-DoFJ0dbW.css +0 -1
- data/lib/archsight/web/public/vue/architecture-7GRP2DOG-BfA1TPxQ.js +0 -1
- data/lib/archsight/web/public/vue/cynefin-OW5HDTMX-BmgdUKVD.js +0 -1
- data/lib/archsight/web/public/vue/eventmodeling-NTZA5JFV-DbXDvAWF.js +0 -1
- data/lib/archsight/web/public/vue/gitGraph-4MIJSDKK-BkVhrKS1.js +0 -1
- data/lib/archsight/web/public/vue/graphviz-SXWTgZH5.js +0 -3
- data/lib/archsight/web/public/vue/index-BXXkUK1V.js +0 -3
- data/lib/archsight/web/public/vue/index-Cov1SnzY.css +0 -1
- data/lib/archsight/web/public/vue/info-A6RAGUB7-BIlCVuUY.js +0 -1
- data/lib/archsight/web/public/vue/katex-CXMH3UgJ.js +0 -257
- data/lib/archsight/web/public/vue/mermaid-BjEi5URd.js +0 -3334
- data/lib/archsight/web/public/vue/packet-AYTQ26CC-eoQTjY3j.js +0 -1
- data/lib/archsight/web/public/vue/pie-WAS4IAKB-DEOotGhh.js +0 -1
- data/lib/archsight/web/public/vue/radar-RG4KPBEZ-C2yucuUN.js +0 -1
- data/lib/archsight/web/public/vue/railroad-74A4TZTK-CzONK5VY.js +0 -1
- data/lib/archsight/web/public/vue/railroad-abnf-HS5TGJTU-9zRPsDsx.js +0 -1
- data/lib/archsight/web/public/vue/railroad-ebnf-LZEXJU2U-BJ4dkz9l.js +0 -1
- data/lib/archsight/web/public/vue/railroad-peg-WCYAUIDC-DFy_rqAj.js +0 -1
- data/lib/archsight/web/public/vue/treeView-Q6P3EWNA-2cq5CyD2.js +0 -1
- data/lib/archsight/web/public/vue/treemap-WGGIJYW6-DK-e9Ez4.js +0 -1
- data/lib/archsight/web/public/vue/useHighlight-D5Gf8DLl.js +0 -10
- data/lib/archsight/web/public/vue/wardley-WFR3VGLG-BQwqUqfB.js +0 -1
data/lib/archsight/renderer.rb
CHANGED
|
@@ -40,9 +40,11 @@ module Archsight
|
|
|
40
40
|
def gnode(graph, inst, opts = {})
|
|
41
41
|
label = "<TABLE><TR><TD><B>#{inst.name}</B></TD></TR><TR><TD>#{inst.klass}</TD></TR></TABLE>"
|
|
42
42
|
label = inst.name if opts[:simple_label]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
attrs = { class: css_class(inst), shape: :box, style: "rounded,filled", fontname: FONT, label: label,
|
|
44
|
+
href: "/kinds/#{inst.klass}/instances/#{inst.name}" }
|
|
45
|
+
# A resource at the depth limit with more dependencies: dashed, its own page shows them
|
|
46
|
+
attrs.merge!(style: "rounded,filled,dashed", tooltip: "More dependencies: open it to explore them") if opts[:truncated]
|
|
47
|
+
graph.node gname(inst), attrs
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
def gedge(graph, a_inst, b_inst, label)
|
|
@@ -104,29 +106,84 @@ module Archsight
|
|
|
104
106
|
end
|
|
105
107
|
end
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
# The layer an instance graph also follows by default, below the instance's own layer (technology is the bottom
|
|
110
|
+
# of the stack; implementation points at what it changes)
|
|
111
|
+
NEXT_LAYER = { "motivation" => "strategy", "strategy" => "business", "business" => "application",
|
|
112
|
+
"application" => "technology", "implementation" => "application" }.freeze
|
|
113
|
+
|
|
114
|
+
# The layers the graph of a resource of this layer follows when its page opens: its own and the next one below,
|
|
115
|
+
# every layer for `other` (pages, views, locations, ... refer to anything)
|
|
116
|
+
def self.default_graph_layers(layer)
|
|
117
|
+
return Archsight::Resources::LAYERS.dup unless Archsight::Resources::LAYERS.include?(layer) && layer != "other"
|
|
118
|
+
|
|
119
|
+
[layer, NEXT_LAYER[layer]].compact
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# The dependency graph of one instance: the resources its relations lead to, breadth first, so a resource gets
|
|
123
|
+
# the depth of its shortest path.
|
|
124
|
+
# @param max_depth [Integer, nil] follow relations this many steps from the instance (nil: all the way). A
|
|
125
|
+
# resource at the limit that has more relations is drawn dashed.
|
|
126
|
+
# @param layers [Array<String>, nil] follow only relations to resources of these layers (nil: every layer); the
|
|
127
|
+
# instance itself is always shown
|
|
128
|
+
def create_graph_one(db, klass_pat, name_pat, max_depth: nil, layers: nil)
|
|
129
|
+
klass = Archsight::Resources[klass_pat] || raise("kind #{klass_pat} unknown")
|
|
130
|
+
root = db.instances[klass]&.[](name_pat) || raise("name #{name_pat} for kind #{klass_pat} not found")
|
|
131
|
+
|
|
132
|
+
Archsight::Graphvis.new("#{klass_pat}:#{name_pat}").draw_dot do |g|
|
|
133
|
+
nodes = {}
|
|
134
|
+
edges = {}
|
|
135
|
+
queue = [[root, 0]]
|
|
136
|
+
while queue.any?
|
|
137
|
+
inst, depth = queue.shift
|
|
138
|
+
next if nodes[inst]
|
|
139
|
+
|
|
140
|
+
nodes[inst] = true
|
|
141
|
+
targets = graph_targets(inst, layers)
|
|
142
|
+
if max_depth && depth >= max_depth
|
|
143
|
+
gnode(g, inst, truncated: targets.any?)
|
|
144
|
+
next
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
gnode(g, inst)
|
|
148
|
+
targets.each do |verb, rel|
|
|
149
|
+
edge_name = "#{gname(inst)}|#{verb}|#{gname(rel)}"
|
|
150
|
+
gedge(g, inst, rel, verb) unless edges[edge_name]
|
|
151
|
+
edges[edge_name] = true
|
|
152
|
+
queue << [rel, depth + 1] unless nodes[rel]
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# The relations of a kind to its own kind (a team's sub-teams, a service's dependencies on other services) as
|
|
159
|
+
# [verb, key] pairs
|
|
160
|
+
def self.self_relations(klass)
|
|
161
|
+
kind = klass.name.to_s.split("::").last
|
|
162
|
+
klass.declared_relations.filter_map { |verb, key, target| [verb, key] if target.to_s == kind }
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# The graph of a kind: its resources that are related to each other by its relations to its own kind (an org
|
|
166
|
+
# chart for BusinessActor). Resources without such a relation are left out, the kind's list shows them.
|
|
167
|
+
def create_graph_kind(db, klass_pat)
|
|
168
|
+
klass = Archsight::Resources[klass_pat] || raise("kind #{klass_pat} unknown")
|
|
169
|
+
relations = Archsight::GraphvisRenderer.self_relations(klass)
|
|
170
|
+
sources = (db.instances[klass] || {}).values.reject(&:abandoned?)
|
|
171
|
+
edges = sources.flat_map do |inst|
|
|
172
|
+
relations.flat_map { |verb, key| inst.relations(verb, key).reject(&:abandoned?).map { |rel| [inst, verb, rel] } }
|
|
173
|
+
end
|
|
174
|
+
edges.uniq! { |inst, verb, rel| "#{gname(inst)}|#{verb}|#{gname(rel)}" }
|
|
175
|
+
|
|
176
|
+
Archsight::Graphvis.new(klass_pat).draw_dot do |g|
|
|
177
|
+
edges.flat_map { |inst, _, rel| [inst, rel] }.uniq.each { |inst| gnode(g, inst, simple_label: true) }
|
|
178
|
+
edges.each { |inst, verb, rel| gedge(g, inst, rel, verb) }
|
|
116
179
|
end
|
|
117
180
|
end
|
|
118
181
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
inst.class.relations.each do |verb, kind|
|
|
125
|
-
inst.relations(verb, kind).each do |rel|
|
|
126
|
-
edge_name = "#{inst}|#{verb}|#{rel}"
|
|
127
|
-
gedge(graph, inst, rel, verb) unless edges[edge_name]
|
|
128
|
-
edges[edge_name] = true
|
|
129
|
-
create_graph_one_inst(db, graph, rel, nodes, edges)
|
|
182
|
+
# The [verb, target] pairs of an instance's relations the graph follows: those to resources of the layers
|
|
183
|
+
def graph_targets(inst, layers)
|
|
184
|
+
inst.class.relations.flat_map do |verb, kind|
|
|
185
|
+
inst.relations(verb, kind).filter_map do |rel|
|
|
186
|
+
[verb, rel] if layers.nil? || layers.include?(rel.class.layer)
|
|
130
187
|
end
|
|
131
188
|
end
|
|
132
189
|
end
|
|
@@ -57,8 +57,9 @@ class Archsight::Resources::Analysis < Archsight::Resources::Base
|
|
|
57
57
|
|
|
58
58
|
# Description
|
|
59
59
|
annotation "analysis/description",
|
|
60
|
-
description: "Human-readable description of what this analysis validates",
|
|
61
|
-
title: "Description"
|
|
60
|
+
description: "Human-readable description of what this analysis validates (markdown)",
|
|
61
|
+
title: "Description",
|
|
62
|
+
format: :markdown
|
|
62
63
|
|
|
63
64
|
# Execution configuration
|
|
64
65
|
annotation "analysis/timeout",
|
|
@@ -25,6 +25,46 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
25
25
|
- Frontend applications
|
|
26
26
|
- Background workers
|
|
27
27
|
|
|
28
|
+
## Choosing this kind
|
|
29
|
+
|
|
30
|
+
**Question:** What is built, deployed and versioned?
|
|
31
|
+
**Test:** It has artifacts and a `component/type`, and can be deployed or linked.
|
|
32
|
+
**Name:** The part, by runtime role (API, Operator, Worker) as in "Payments:API", not by repository category
|
|
33
|
+
("Testing", "Tools", "Infrastructure"). Test, tooling and infrastructure-as-code repositories belong to the
|
|
34
|
+
component they build, test or deploy.
|
|
35
|
+
|
|
36
|
+
A component belongs to exactly one service. See the modeling guide, "Choosing the Kind".
|
|
37
|
+
|
|
38
|
+
## Component types
|
|
39
|
+
|
|
40
|
+
Set `component/type` to say what the component is built as; importers set it from the manifests:
|
|
41
|
+
|
|
42
|
+
- `executable`: has an entry point and is run or deployed (services, workers, operators, command-line tools)
|
|
43
|
+
- `library`: imported by other components and not run on its own (shared libraries, SDKs)
|
|
44
|
+
- `module`: a unit of versioning or dependency that bundles executables and importable libraries (a Go module
|
|
45
|
+
with `cmd/` and shared packages, a Maven parent, an npm workspace root)
|
|
46
|
+
- `plugin`: loaded by a host program (kubectl, Terraform, Grafana)
|
|
47
|
+
- `frontend`: runs in the browser
|
|
48
|
+
- `other`
|
|
49
|
+
|
|
50
|
+
`component/role` refines an executable or plugin (`service`, `cli`, `job`, `operator`, `agent`); importers cannot
|
|
51
|
+
tell these apart, so it is set by hand and never overwritten. Importers also add machine tags
|
|
52
|
+
(`namespace:value`) to the regular `architecture/tags`: `ecosystem:go`, `packaging:go-module`,
|
|
53
|
+
`linkage:shared`; the tags a person set stay, and a re-import only replaces the machine tags of these
|
|
54
|
+
namespaces. The entry points (main packages such as `cmd/api`) go to `component/entrypoints`, a list that
|
|
55
|
+
works in queries like a tag but is not a sidebar filter, as there are too many distinct values. Deployable forms (container image, chart, package) are `TechnologyArtifact`s, not
|
|
56
|
+
component types.
|
|
57
|
+
|
|
58
|
+
## Where it runs
|
|
59
|
+
|
|
60
|
+
A component is `servedBy` the `TechnologyService` it is deployed on (a product's cluster, a managed platform) and
|
|
61
|
+
`servedBy` the `TechnologySystemSoftware` it runs on (the runtime, such as a Kubernetes distribution). Deployment
|
|
62
|
+
importers write the service per component, so a sidecar or agent deployed into many clusters shows where it runs
|
|
63
|
+
without making its own service look like it runs in all of them.
|
|
64
|
+
|
|
65
|
+
The computed `component/dependents` counts the components that depend on this one, which tells shared libraries
|
|
66
|
+
and modules from components nobody consumes.
|
|
67
|
+
|
|
28
68
|
## Security and risk modelling
|
|
29
69
|
|
|
30
70
|
- **Asset at risk:** set `asset/value` and the protection needs; `assesses` from a vulnerability or risk.
|
|
@@ -46,6 +86,18 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
46
86
|
title: "Architecture Size",
|
|
47
87
|
enum: %w[microservice monolith]
|
|
48
88
|
|
|
89
|
+
# Classification
|
|
90
|
+
annotation "component/type",
|
|
91
|
+
description: "What the component is built as (executable, library, module, ...)",
|
|
92
|
+
title: "Component Type",
|
|
93
|
+
enum: %w[executable library module plugin frontend other],
|
|
94
|
+
filter: :word
|
|
95
|
+
annotation "component/role",
|
|
96
|
+
description: "What an executable or plugin does; set by hand",
|
|
97
|
+
title: "Component Role",
|
|
98
|
+
enum: %w[service cli job operator agent],
|
|
99
|
+
filter: :word
|
|
100
|
+
|
|
49
101
|
# Availability
|
|
50
102
|
annotation "availability/quality",
|
|
51
103
|
description: "Service availability quality target per year",
|
|
@@ -129,6 +181,12 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
129
181
|
enum: ["no support", "support by dev", "support by ops", "support by api",
|
|
130
182
|
"self service support via a frontend"]
|
|
131
183
|
|
|
184
|
+
annotation "component/entrypoints",
|
|
185
|
+
description: "Comma-separated entry points (main packages or commands such as cmd/api), set by importers",
|
|
186
|
+
title: "Entry points",
|
|
187
|
+
sidebar: false,
|
|
188
|
+
filter: :list
|
|
189
|
+
|
|
132
190
|
# Deployment (from ArgoCD/cluster)
|
|
133
191
|
annotation "deployment/images",
|
|
134
192
|
description: "Deployed container images",
|
|
@@ -136,20 +194,21 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
136
194
|
sidebar: false,
|
|
137
195
|
filter: :list
|
|
138
196
|
annotation "deployment/chart",
|
|
139
|
-
description: "Deployed Helm
|
|
197
|
+
description: "Deployed Helm charts, comma separated",
|
|
140
198
|
title: "Helm Chart",
|
|
141
199
|
sidebar: false,
|
|
142
|
-
filter: :
|
|
200
|
+
filter: :list
|
|
143
201
|
annotation "deployment/namespace",
|
|
144
|
-
description: "Kubernetes
|
|
202
|
+
description: "Kubernetes namespaces, comma separated",
|
|
145
203
|
title: "Namespace",
|
|
146
204
|
sidebar: false,
|
|
147
|
-
filter: :
|
|
205
|
+
filter: :list
|
|
148
206
|
annotation "deployment/cluster",
|
|
149
|
-
description: "Target
|
|
207
|
+
description: "Target clusters, comma separated",
|
|
150
208
|
title: "Cluster",
|
|
151
|
-
filter: :
|
|
152
|
-
summary: true
|
|
209
|
+
filter: :list,
|
|
210
|
+
summary: true,
|
|
211
|
+
deprecated: "list the clusters as spec.servedBy.technologyServices"
|
|
153
212
|
|
|
154
213
|
# Computed Annotations
|
|
155
214
|
computed_annotation "repository/artifacts/total",
|
|
@@ -197,6 +256,14 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
197
256
|
end
|
|
198
257
|
end
|
|
199
258
|
|
|
259
|
+
computed_annotation "component/dependents",
|
|
260
|
+
title: "Dependents",
|
|
261
|
+
description: "Number of components that depend directly on this one",
|
|
262
|
+
type: Integer,
|
|
263
|
+
sidebar: true do
|
|
264
|
+
count(incoming(:ApplicationComponent))
|
|
265
|
+
end
|
|
266
|
+
|
|
200
267
|
computed_annotation "scc/language",
|
|
201
268
|
title: "Primary Language",
|
|
202
269
|
summary: true,
|
|
@@ -350,6 +417,7 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
350
417
|
relation :realizedThrough, :technologyArtifacts, :TechnologyArtifact
|
|
351
418
|
relation :realizedBy, :technologyComponents, :TechnologyNode
|
|
352
419
|
relation :servedBy, :technologyComponents, :TechnologySystemSoftware
|
|
420
|
+
relation :servedBy, :technologyServices, :TechnologyService
|
|
353
421
|
relation :exposes, :applicationInterfaces, :ApplicationInterface
|
|
354
422
|
relation :dependsOn, :applicationInterfaces, :ApplicationInterface
|
|
355
423
|
relation :dependsOn, :applicationComponents, :ApplicationComponent
|
|
@@ -25,6 +25,17 @@ class Archsight::Resources::ApplicationInterface < Archsight::Resources::Base
|
|
|
25
25
|
- gRPC services
|
|
26
26
|
- Message queues (producer/consumer interfaces)
|
|
27
27
|
- WebSocket endpoints
|
|
28
|
+
|
|
29
|
+
## Reachability
|
|
30
|
+
|
|
31
|
+
An interface is `servedBy` the `TechnologyInterface` that carries it (a protocol, an authentication method) and
|
|
32
|
+
by the `TechnologyCommunicationNetwork`s on which it can be reached, just as a `TechnologyNode` attaches to the
|
|
33
|
+
networks it is on. Together with `api/authenticationMethod` this decides the exposure of the interface: an
|
|
34
|
+
interface without authentication on an internal network is a different risk than on a network that
|
|
35
|
+
internet-facing components attach to. The network page lists the interfaces as incoming "served by".
|
|
36
|
+
|
|
37
|
+
Write the networks only when they are known. An interface without a network makes no claim about where it can
|
|
38
|
+
be reached.
|
|
28
39
|
MD
|
|
29
40
|
|
|
30
41
|
icon "usb"
|
|
@@ -47,6 +58,7 @@ class Archsight::Resources::ApplicationInterface < Archsight::Resources::Base
|
|
|
47
58
|
enum: ["none", "hard coded", "pbac", "abac", "rbac"]
|
|
48
59
|
|
|
49
60
|
relation :servedBy, :technologyComponents, :TechnologyInterface
|
|
61
|
+
relation :servedBy, :technologyCommunicationNetworks, :TechnologyCommunicationNetwork
|
|
50
62
|
relation :realizes, :motivationConstraints, :MotivationConstraint
|
|
51
63
|
relation :serves, :dataObjects, :DataObject
|
|
52
64
|
end
|
|
@@ -20,11 +20,21 @@ class Archsight::Resources::ApplicationService < Archsight::Resources::Base
|
|
|
20
20
|
|
|
21
21
|
Use ApplicationService to represent:
|
|
22
22
|
|
|
23
|
-
-
|
|
23
|
+
- Behaviour software offers to a user or another system ("Payment Authorization", "Document Search")
|
|
24
24
|
- Logical groupings of application components
|
|
25
25
|
- Services exposed to business processes
|
|
26
26
|
- APIs and their implementations as a cohesive unit
|
|
27
27
|
|
|
28
|
+
## Choosing this kind
|
|
29
|
+
|
|
30
|
+
**Question:** What behaviour does software offer a consumer?
|
|
31
|
+
**Test:** It can be described without naming repositories, deployments or runtime objects, and has one owning actor.
|
|
32
|
+
**Name:** The function, not the technology or a deployment object ("Payment Authorization").
|
|
33
|
+
|
|
34
|
+
A component belongs to exactly one service. One service using another is `dependsOn` between the two services, not
|
|
35
|
+
the other service's components listed again; a service that many others use is modeled once. A service whose only component has the same name is a smell. See
|
|
36
|
+
the modeling guide, "Choosing the Kind".
|
|
37
|
+
|
|
28
38
|
## Security and risk modelling
|
|
29
39
|
|
|
30
40
|
A service is an asset at risk (`asset/*` profile, protection needs) that loss events `affects`, a trigger target
|
|
@@ -217,6 +227,7 @@ class Archsight::Resources::ApplicationService < Archsight::Resources::Base
|
|
|
217
227
|
end
|
|
218
228
|
|
|
219
229
|
relation :realizedThrough, :applicationComponents, :ApplicationComponent
|
|
230
|
+
relation :dependsOn, :applicationServices, :ApplicationService
|
|
220
231
|
relation :servedBy, :businessActors, :BusinessActor
|
|
221
232
|
relation :servedBy, :technologyServices, :TechnologyService
|
|
222
233
|
relation :realizes, :motivationConstraints, :MotivationConstraint
|
|
@@ -35,12 +35,20 @@ module Archsight
|
|
|
35
35
|
# A kind may mark at most this many annotations as summary (see Base.annotation)
|
|
36
36
|
MAX_SUMMARY_ANNOTATIONS = 3
|
|
37
37
|
|
|
38
|
+
# The options `annotation` accepts (see Archsight::Annotations::Annotation)
|
|
39
|
+
ANNOTATION_OPTIONS = %i[description filter title format enum sidebar type summary editor validator unique
|
|
40
|
+
deprecated default].freeze
|
|
41
|
+
|
|
38
42
|
# Define an annotation using the Annotation class
|
|
39
43
|
# `summary: true` marks it as a summary attribute: it is returned with every search hit of this kind.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
# `unique: true` makes it an identifier: its values (each element of a list) are unique among the resources
|
|
45
|
+
# of the kind, which `archsight lint` checks, and its values are shown as chips without links (not tags).
|
|
46
|
+
# `deprecated: "what to use instead"` keeps it working while `archsight lint` lists every use.
|
|
47
|
+
# `default: "value"` is the value of a resource that does not set it (see #apply_annotation_defaults!).
|
|
48
|
+
def self.annotation(key, **options)
|
|
49
|
+
unknown = options.keys - ANNOTATION_OPTIONS
|
|
50
|
+
raise ArgumentError, "unknown annotation option(s) #{unknown.join(", ")} for #{key}" if unknown.any?
|
|
51
|
+
|
|
44
52
|
register_annotation(Archsight::Annotations::Annotation.new(key, options))
|
|
45
53
|
end
|
|
46
54
|
|
|
@@ -143,8 +151,11 @@ module Archsight
|
|
|
143
151
|
end
|
|
144
152
|
end
|
|
145
153
|
|
|
154
|
+
# The layer of the kind, one of Archsight::Resources::LAYERS (default `other`)
|
|
146
155
|
def self.layer(layer_name = nil)
|
|
147
156
|
if layer_name
|
|
157
|
+
raise ArgumentError, "unknown layer #{layer_name.inspect} for #{name}" unless Archsight::Resources::LAYERS.include?(layer_name)
|
|
158
|
+
|
|
148
159
|
@layer = layer_name
|
|
149
160
|
else
|
|
150
161
|
@layer || "other" # default layer
|
|
@@ -223,6 +234,26 @@ module Archsight
|
|
|
223
234
|
@raw["metadata"]["annotations"][key] = value
|
|
224
235
|
end
|
|
225
236
|
|
|
237
|
+
# Gives every annotation with a `default:` that the file does not set its default, in the annotations hash like
|
|
238
|
+
# a written value, so queries, filters and the page see it. The editor leaves these out (#defaulted?), so a
|
|
239
|
+
# save does not write them into the file.
|
|
240
|
+
def apply_annotation_defaults!
|
|
241
|
+
self.class.annotations.each do |annotation|
|
|
242
|
+
next if annotation.default.nil? || annotation.pattern? || annotations.key?(annotation.key)
|
|
243
|
+
|
|
244
|
+
defaulted = (@defaulted ||= []) #: Array[String]
|
|
245
|
+
defaulted << annotation.key
|
|
246
|
+
@raw["metadata"] ||= {}
|
|
247
|
+
@raw["metadata"]["annotations"] = @raw["metadata"]["annotations"] || {} #: Hash[String, untyped]
|
|
248
|
+
@raw["metadata"]["annotations"][annotation.key] = annotation.default
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Whether the value of the annotation is its default, not written in the file
|
|
253
|
+
def defaulted?(key)
|
|
254
|
+
@defaulted&.include?(key) || false
|
|
255
|
+
end
|
|
256
|
+
|
|
226
257
|
# Get a computed annotation value from the cache
|
|
227
258
|
# @param key [String] The annotation key
|
|
228
259
|
# @return [Object, nil] The computed value or nil
|
|
@@ -338,7 +369,29 @@ module Archsight
|
|
|
338
369
|
|
|
339
370
|
def merge!(inst)
|
|
340
371
|
# NOTE: path reference is preserved from the original instance
|
|
341
|
-
|
|
372
|
+
merged = Archsight::Helpers.deep_merge(@raw, inst.raw)
|
|
373
|
+
union_list_annotations!(merged, inst.raw)
|
|
374
|
+
@raw = merged
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Annotations hold strings, which replace each other on merge. The values of a list annotation (tags, aliases)
|
|
378
|
+
# are joined instead, so two documents of one resource can each add to it.
|
|
379
|
+
def union_list_annotations!(merged, other_raw)
|
|
380
|
+
mine = @raw.dig("metadata", "annotations")
|
|
381
|
+
theirs = other_raw.dig("metadata", "annotations")
|
|
382
|
+
return unless mine.is_a?(Hash) && theirs.is_a?(Hash)
|
|
383
|
+
|
|
384
|
+
theirs.each do |key, value|
|
|
385
|
+
next unless mine[key].is_a?(String) && value.is_a?(String)
|
|
386
|
+
next unless self.class.annotation_matching(key)&.list?
|
|
387
|
+
|
|
388
|
+
values = (split_list(mine[key]) + split_list(value)).uniq
|
|
389
|
+
merged["metadata"]["annotations"][key] = values.join(",")
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def split_list(text)
|
|
394
|
+
text.split(/,|\n/).map(&:strip).reject(&:empty?)
|
|
342
395
|
end
|
|
343
396
|
|
|
344
397
|
# raise provides a helper for better error messages including current path and line no
|
|
@@ -25,6 +25,11 @@ class Archsight::Resources::BusinessActor < Archsight::Resources::Base
|
|
|
25
25
|
- External vendors or partners
|
|
26
26
|
- Support organizations
|
|
27
27
|
- Cross-functional groups
|
|
28
|
+
- Customers and providers: the parties a `BusinessContract` is `agreedBy`
|
|
29
|
+
- The party behind a `MotivationStakeholder`: the stakeholder is `representedBy` it
|
|
30
|
+
- The team behind infrastructure: a `TechnologyDevice`, `TechnologyEquipment`, `TechnologyNode` or
|
|
31
|
+
`TechnologyCommunicationNetwork` is `ownedBy` the team that operates it, and a device, equipment or node is
|
|
32
|
+
`servedBy` the team it is dedicated to (a test server, a cluster partition)
|
|
28
33
|
|
|
29
34
|
## Security and risk modelling
|
|
30
35
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BusinessContract represents an agreement between a provider and a consumer
|
|
4
|
+
class Archsight::Resources::BusinessContract < Archsight::Resources::Base
|
|
5
|
+
include_annotations :git, :architecture, :risk
|
|
6
|
+
|
|
7
|
+
description <<~MD
|
|
8
|
+
Represents an agreement between a provider and a consumer: the rights and obligations both agreed to.
|
|
9
|
+
|
|
10
|
+
## ArchiMate Definition
|
|
11
|
+
|
|
12
|
+
**Layer:** Business
|
|
13
|
+
**Aspect:** Passive Structure
|
|
14
|
+
|
|
15
|
+
A contract is a formal or informal specification of an agreement between a provider and a consumer that
|
|
16
|
+
specifies rights and obligations. It is a specialization of a business object. A product is accompanied by a
|
|
17
|
+
contract, and a contract can consist of parts.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Use BusinessContract to represent:
|
|
22
|
+
|
|
23
|
+
- Framework contracts with a customer
|
|
24
|
+
- Call-offs under a framework contract (an order for one more block of capacity)
|
|
25
|
+
- Service level agreements
|
|
26
|
+
- Amendments of a contract
|
|
27
|
+
|
|
28
|
+
A contract is a `BusinessContract`, not a `DataObject` and not text in a description: only then do the graph,
|
|
29
|
+
views and analyses see what it agrees, who agreed it and what delivered it.
|
|
30
|
+
|
|
31
|
+
## How it connects
|
|
32
|
+
|
|
33
|
+
- A `BusinessProduct` `aggregates` the contract that comes with it
|
|
34
|
+
- It is `agreedBy` its parties: the actual organisations (the customer, the provider), not a generic role
|
|
35
|
+
- It is `composedOf` its parts: call-offs, SLAs and amendments, which are contracts themselves (no cycles)
|
|
36
|
+
- It `covers` what it obliges the provider to deliver: equipment, nodes, technology and application services
|
|
37
|
+
- It is `realizedThrough` the `ImplementationDeliverable` that fulfils it; the `ImplementationWorkPackage` that
|
|
38
|
+
`realizes` the deliverable `affects` the equipment it installs
|
|
39
|
+
|
|
40
|
+
The other side shows these as incoming relations: the contracts an actor agreed, what covers a piece of
|
|
41
|
+
equipment or a service, the contract a deliverable fulfils.
|
|
42
|
+
MD
|
|
43
|
+
|
|
44
|
+
icon "journal-page"
|
|
45
|
+
layer "business"
|
|
46
|
+
|
|
47
|
+
annotation "contract/type",
|
|
48
|
+
description: "What kind of contract this is",
|
|
49
|
+
enum: %w[framework call-off sla amendment other],
|
|
50
|
+
filter: :word,
|
|
51
|
+
summary: true
|
|
52
|
+
annotation "contract/reference",
|
|
53
|
+
description: "The contract number",
|
|
54
|
+
title: "Reference",
|
|
55
|
+
summary: true
|
|
56
|
+
annotation "contract/from",
|
|
57
|
+
description: "When the contract starts (ISO 8601 date or time)",
|
|
58
|
+
title: "From",
|
|
59
|
+
validator: ->(value) { Archsight::Resources::Page.timestamp_error(value) }
|
|
60
|
+
annotation "contract/until",
|
|
61
|
+
description: "When the contract ends (ISO 8601 date or time)",
|
|
62
|
+
title: "Until",
|
|
63
|
+
validator: ->(value) { Archsight::Resources::Page.timestamp_error(value) }
|
|
64
|
+
|
|
65
|
+
relation :agreedBy, :businessActors, :BusinessActor
|
|
66
|
+
relation :composedOf, :businessContracts, :BusinessContract
|
|
67
|
+
relation :covers, :technologyEquipment, :TechnologyEquipment
|
|
68
|
+
relation :covers, :technologyNodes, :TechnologyNode
|
|
69
|
+
relation :covers, :technologyServices, :TechnologyService
|
|
70
|
+
relation :covers, :applicationServices, :ApplicationService
|
|
71
|
+
relation :realizedThrough, :implementationDeliverables, :ImplementationDeliverable
|
|
72
|
+
end
|
|
@@ -25,6 +25,17 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
|
|
|
25
25
|
- Kubernetes services
|
|
26
26
|
- Enterprise support packages
|
|
27
27
|
- API products
|
|
28
|
+
|
|
29
|
+
## Choosing this kind
|
|
30
|
+
|
|
31
|
+
**Question:** What does a customer buy or contract?
|
|
32
|
+
**Test:** It appears on a price list, catalog or customer documentation.
|
|
33
|
+
**Name:** The market name ("Online Checkout").
|
|
34
|
+
|
|
35
|
+
A product `realizes` a capability and is `servedBy` the services that deliver it. A product that nearly every
|
|
36
|
+
service serves is a catalog, not a product. See the modeling guide, "Choosing the Kind".
|
|
37
|
+
|
|
38
|
+
The contract that comes with the product is a `BusinessContract` the product `aggregates`.
|
|
28
39
|
MD
|
|
29
40
|
|
|
30
41
|
icon "box-iso"
|
|
@@ -204,4 +215,5 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
|
|
|
204
215
|
relation :servedBy, :applicationServices, :ApplicationService
|
|
205
216
|
relation :exposes, :applicationInterfaces, :ApplicationInterface
|
|
206
217
|
relation :provides, :complianceEvidences, :ComplianceEvidence
|
|
218
|
+
relation :aggregates, :businessContracts, :BusinessContract
|
|
207
219
|
end
|
|
@@ -37,6 +37,7 @@ class Archsight::Resources::BusinessRole < Archsight::Resources::Base
|
|
|
37
37
|
- A `BusinessProcess` is `performedBy` the role, a `BusinessControl` is `ownedBy` and `executedBy` it
|
|
38
38
|
- Assessments, principles, work packages, deliverables and implementation events are `ownedBy` it
|
|
39
39
|
- The role is `performedBy` the actors that hold it
|
|
40
|
+
- A `MotivationStakeholder` can be `representedBy` the role (the interest belongs to the role, whoever holds it)
|
|
40
41
|
- Pointing straight at an actor stays valid; use a role where the responsibility has a name of its own
|
|
41
42
|
|
|
42
43
|
## Security and risk modelling
|
|
@@ -26,6 +26,7 @@ class Archsight::Resources::ImplementationDeliverable < Archsight::Resources::Ba
|
|
|
26
26
|
## How it connects
|
|
27
27
|
|
|
28
28
|
- A `ImplementationWorkPackage` `realizes` it
|
|
29
|
+
- A `BusinessContract` is `realizedThrough` it: the delivery that fulfils the contract (a call-off)
|
|
29
30
|
- It is `ownedBy` an actor and `realizes` plateaus, requirements, goals, outcomes and `ComplianceEvidence`
|
|
30
31
|
|
|
31
32
|
## Security and risk modelling
|
|
@@ -25,9 +25,12 @@ class Archsight::Resources::ImplementationPlateau < Archsight::Resources::Base
|
|
|
25
25
|
|
|
26
26
|
## How it connects
|
|
27
27
|
|
|
28
|
-
- A plateau `contains` the components
|
|
28
|
+
- A plateau `contains` the application components and services, technology nodes, services, system
|
|
29
|
+
software and artifacts, business processes and requirements that belong to it. Listing the technology
|
|
30
|
+
elements lets a platform migration (platform A to platform B) be described state by state
|
|
29
31
|
- It `triggers` the next plateau (migration path)
|
|
30
|
-
- A `ImplementationDeliverable` `realizes` it; a `ImplementationGap` `compares` two plateaus
|
|
32
|
+
- A `ImplementationDeliverable` `realizes` it; a `ImplementationGap` `compares` two plateaus, so
|
|
33
|
+
the elements added, kept or removed between them show up per plateau
|
|
31
34
|
MD
|
|
32
35
|
|
|
33
36
|
icon "packages"
|
|
@@ -55,6 +58,9 @@ class Archsight::Resources::ImplementationPlateau < Archsight::Resources::Base
|
|
|
55
58
|
relation :contains, :applicationComponents, :ApplicationComponent
|
|
56
59
|
relation :contains, :applicationServices, :ApplicationService
|
|
57
60
|
relation :contains, :technologyNodes, :TechnologyNode
|
|
61
|
+
relation :contains, :technologyServices, :TechnologyService
|
|
62
|
+
relation :contains, :technologySystemSoftware, :TechnologySystemSoftware
|
|
63
|
+
relation :contains, :technologyArtifacts, :TechnologyArtifact
|
|
58
64
|
relation :contains, :businessProcesses, :BusinessProcess
|
|
59
65
|
relation :contains, :motivationRequirements, :MotivationRequirement
|
|
60
66
|
relation :triggers, :implementationPlateaus, :ImplementationPlateau
|
|
@@ -28,7 +28,7 @@ class Archsight::Resources::ImplementationWorkPackage < Archsight::Resources::Ba
|
|
|
28
28
|
|
|
29
29
|
- `ownedBy` the accountable actor or role, `performedBy` the actors or roles that carry it out
|
|
30
30
|
- `realizes` deliverables (its results), requirements and goals
|
|
31
|
-
- `affects` the assets it changes; the assessments (risks, findings) it treats are `mitigatedBy` it (written on the assessment)
|
|
31
|
+
- `affects` the assets it changes, for example the `TechnologyEquipment` a project installs; the assessments (risks, findings) it treats are `mitigatedBy` it (written on the assessment)
|
|
32
32
|
- `triggers` the work packages that follow it; an `ImplementationEvent` can trigger it
|
|
33
33
|
- A `ImplementationGap` is `closedBy` it
|
|
34
34
|
|
|
@@ -79,5 +79,6 @@ class Archsight::Resources::ImplementationWorkPackage < Archsight::Resources::Ba
|
|
|
79
79
|
relation :affects, :applicationComponents, :ApplicationComponent
|
|
80
80
|
relation :affects, :applicationServices, :ApplicationService
|
|
81
81
|
relation :affects, :technologyNodes, :TechnologyNode
|
|
82
|
+
relation :affects, :technologyEquipment, :TechnologyEquipment
|
|
82
83
|
relation :triggers, :implementationWorkPackages, :ImplementationWorkPackage
|
|
83
84
|
end
|
|
@@ -35,26 +35,52 @@ class Archsight::Resources::Import < Archsight::Resources::Base
|
|
|
35
35
|
icon "download"
|
|
36
36
|
layer "other"
|
|
37
37
|
|
|
38
|
-
# Handler selection
|
|
38
|
+
# Handler selection: a built-in handler or one the resources repository registers (import/handlerPath)
|
|
39
39
|
annotation "import/handler",
|
|
40
|
-
description: "
|
|
40
|
+
description: "Name of the handler that executes this import: a built-in one or one registered by the file " \
|
|
41
|
+
"in import/handlerPath",
|
|
41
42
|
title: "Handler",
|
|
42
43
|
summary: true,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
filter: :word,
|
|
45
|
+
validator: lambda { |value|
|
|
46
|
+
require "archsight/import/handler_loader"
|
|
47
|
+
Archsight::Import::HandlerLoader.load_builtin!
|
|
48
|
+
next if Archsight::Import::Registry[value]
|
|
49
|
+
|
|
50
|
+
"unknown import handler '#{value}'. Registered: #{Archsight::Import::Registry.handlers.sort.join(", ")}; " \
|
|
51
|
+
"a handler of the resources repository needs import/handlerPath"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
annotation "import/handlerPath",
|
|
55
|
+
description: "Ruby file of a handler that lives in the resources repository, relative to the resources " \
|
|
56
|
+
"root (e.g., 'importers/deployments.rb'). It registers the name used in import/handler.",
|
|
57
|
+
title: "Handler Path"
|
|
58
|
+
|
|
59
|
+
annotation "import/dependsOn",
|
|
60
|
+
description: "Imports that must run first, by name or glob pattern (e.g., 'Import:Repo:*'), comma " \
|
|
61
|
+
"separated. Adds to the dependency on the import that generated this one.",
|
|
62
|
+
title: "Depends On",
|
|
63
|
+
filter: :list,
|
|
64
|
+
sidebar: false
|
|
52
65
|
|
|
53
66
|
# Output configuration
|
|
54
67
|
annotation "import/outputPath",
|
|
55
68
|
description: "Output file path relative to resources root (e.g., 'imports/generated/gitlab.yaml')",
|
|
56
69
|
title: "Output Path"
|
|
57
70
|
|
|
71
|
+
annotation "generated/inputsHash",
|
|
72
|
+
description: "Hash of the files matched by import/config/inputs at the last run (for change detection)",
|
|
73
|
+
title: "Inputs Hash",
|
|
74
|
+
sidebar: false,
|
|
75
|
+
editor: false
|
|
76
|
+
|
|
77
|
+
annotation "generated/outputs",
|
|
78
|
+
description: "Files the last run wrote, relative to the resources root",
|
|
79
|
+
title: "Outputs",
|
|
80
|
+
filter: :list,
|
|
81
|
+
sidebar: false,
|
|
82
|
+
editor: false
|
|
83
|
+
|
|
58
84
|
# Control flags
|
|
59
85
|
annotation "import/enabled",
|
|
60
86
|
description: "Whether this import is enabled",
|