archsight 0.1.0
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 +7 -0
- data/CHANGELOG.md +24 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +186 -0
- data/Dockerfile +39 -0
- data/LICENSE.txt +201 -0
- data/README.md +170 -0
- data/SECURITY.md +27 -0
- data/exe/archsight +9 -0
- data/lib/archsight/annotations/aggregators.rb +109 -0
- data/lib/archsight/annotations/annotation.rb +168 -0
- data/lib/archsight/annotations/architecture_annotations.rb +59 -0
- data/lib/archsight/annotations/backup_annotations.rb +21 -0
- data/lib/archsight/annotations/computed.rb +264 -0
- data/lib/archsight/annotations/email_recipient.rb +35 -0
- data/lib/archsight/annotations/generated_annotations.rb +17 -0
- data/lib/archsight/annotations/git_annotations.rb +21 -0
- data/lib/archsight/annotations/relation_resolver.rb +160 -0
- data/lib/archsight/cli.rb +120 -0
- data/lib/archsight/configuration.rb +36 -0
- data/lib/archsight/database.rb +183 -0
- data/lib/archsight/documentation.rb +171 -0
- data/lib/archsight/graph.rb +113 -0
- data/lib/archsight/helpers.rb +210 -0
- data/lib/archsight/linter.rb +77 -0
- data/lib/archsight/mcp/analyze_resource_tool.rb +222 -0
- data/lib/archsight/mcp/base.rb +48 -0
- data/lib/archsight/mcp/query_tool.rb +113 -0
- data/lib/archsight/mcp/resource_doc_tool.rb +87 -0
- data/lib/archsight/mcp.rb +6 -0
- data/lib/archsight/query/ast.rb +279 -0
- data/lib/archsight/query/errors.rb +39 -0
- data/lib/archsight/query/evaluator.rb +707 -0
- data/lib/archsight/query/lexer.rb +289 -0
- data/lib/archsight/query/parser.rb +506 -0
- data/lib/archsight/query.rb +68 -0
- data/lib/archsight/renderer.rb +134 -0
- data/lib/archsight/resources/application_component.rb +346 -0
- data/lib/archsight/resources/application_interface.rb +54 -0
- data/lib/archsight/resources/application_service.rb +222 -0
- data/lib/archsight/resources/base.rb +300 -0
- data/lib/archsight/resources/business_actor.rb +195 -0
- data/lib/archsight/resources/business_constraint.rb +32 -0
- data/lib/archsight/resources/business_process.rb +37 -0
- data/lib/archsight/resources/business_product.rb +206 -0
- data/lib/archsight/resources/business_requirement.rb +56 -0
- data/lib/archsight/resources/compliance_evidence.rb +42 -0
- data/lib/archsight/resources/data_object.rb +49 -0
- data/lib/archsight/resources/motivation_goal.rb +37 -0
- data/lib/archsight/resources/motivation_outcome.rb +33 -0
- data/lib/archsight/resources/motivation_stakeholder.rb +38 -0
- data/lib/archsight/resources/strategy_capability.rb +38 -0
- data/lib/archsight/resources/technology_artifact.rb +154 -0
- data/lib/archsight/resources/technology_interface.rb +34 -0
- data/lib/archsight/resources/technology_node.rb +42 -0
- data/lib/archsight/resources/technology_service.rb +35 -0
- data/lib/archsight/resources/technology_system_software.rb +37 -0
- data/lib/archsight/resources/view.rb +51 -0
- data/lib/archsight/resources.rb +49 -0
- data/lib/archsight/template.rb +49 -0
- data/lib/archsight/version.rb +5 -0
- data/lib/archsight/web/application.rb +290 -0
- data/lib/archsight/web/doc/archimate.md +215 -0
- data/lib/archsight/web/doc/computed_annotations.md +316 -0
- data/lib/archsight/web/doc/icons.md +303 -0
- data/lib/archsight/web/doc/index.md.erb +74 -0
- data/lib/archsight/web/doc/modeling.md +200 -0
- data/lib/archsight/web/doc/search.md +227 -0
- data/lib/archsight/web/doc/togaf.md +255 -0
- data/lib/archsight/web/doc/tool.md +90 -0
- data/lib/archsight/web/public/css/artifact.css +985 -0
- data/lib/archsight/web/public/css/base.css +201 -0
- data/lib/archsight/web/public/css/graph.css +106 -0
- data/lib/archsight/web/public/css/highlight.min.css +10 -0
- data/lib/archsight/web/public/css/iconoir.css +22 -0
- data/lib/archsight/web/public/css/instance.css +329 -0
- data/lib/archsight/web/public/css/layout.css +421 -0
- data/lib/archsight/web/public/css/mermaid-layers.css +188 -0
- data/lib/archsight/web/public/css/pico.min.css +4 -0
- data/lib/archsight/web/public/favicon.ico +0 -0
- data/lib/archsight/web/public/img/archimate.png +0 -0
- data/lib/archsight/web/public/img/togaf-high-level.png +0 -0
- data/lib/archsight/web/public/js/graph-zoom.js +18 -0
- data/lib/archsight/web/public/js/highlight.min.js +3899 -0
- data/lib/archsight/web/public/js/htmx.min.js +1 -0
- data/lib/archsight/web/public/js/mermaid-init.js +88 -0
- data/lib/archsight/web/public/js/mermaid.min.js +2811 -0
- data/lib/archsight/web/public/js/sparkline.js +42 -0
- data/lib/archsight/web/public/js/svg-pan-zoom.min.js +3 -0
- data/lib/archsight/web/public/js/svg-zoom-controls.js +93 -0
- data/lib/archsight/web/views/index.haml +12 -0
- data/lib/archsight/web/views/partials/artifact/_activity.haml +55 -0
- data/lib/archsight/web/views/partials/artifact/_agentic.haml +25 -0
- data/lib/archsight/web/views/partials/artifact/_deployment.haml +29 -0
- data/lib/archsight/web/views/partials/artifact/_git_info.haml +16 -0
- data/lib/archsight/web/views/partials/artifact/_language_stats.haml +53 -0
- data/lib/archsight/web/views/partials/artifact/_links.haml +24 -0
- data/lib/archsight/web/views/partials/artifact/_project_estimate.haml +26 -0
- data/lib/archsight/web/views/partials/artifact/_repositories.haml +55 -0
- data/lib/archsight/web/views/partials/artifact/_team.haml +83 -0
- data/lib/archsight/web/views/partials/artifact/_workflow.haml +69 -0
- data/lib/archsight/web/views/partials/components/_activity.haml +37 -0
- data/lib/archsight/web/views/partials/components/_git.haml +17 -0
- data/lib/archsight/web/views/partials/components/_jira.haml +18 -0
- data/lib/archsight/web/views/partials/components/_languages.haml +29 -0
- data/lib/archsight/web/views/partials/components/_owner.haml +15 -0
- data/lib/archsight/web/views/partials/components/_repositories.haml +37 -0
- data/lib/archsight/web/views/partials/components/_status.haml +23 -0
- data/lib/archsight/web/views/partials/instance/_detail.haml +99 -0
- data/lib/archsight/web/views/partials/instance/_graph.haml +6 -0
- data/lib/archsight/web/views/partials/instance/_list.haml +84 -0
- data/lib/archsight/web/views/partials/instance/_relations.haml +43 -0
- data/lib/archsight/web/views/partials/instance/_requirements.haml +41 -0
- data/lib/archsight/web/views/partials/instance/_view_detail.haml +57 -0
- data/lib/archsight/web/views/partials/layout/_content.haml +40 -0
- data/lib/archsight/web/views/partials/layout/_error.haml +22 -0
- data/lib/archsight/web/views/partials/layout/_head.haml +24 -0
- data/lib/archsight/web/views/partials/layout/_navigation.haml +20 -0
- data/lib/archsight/web/views/partials/layout/_sidebar.haml +27 -0
- data/lib/archsight/web/views/search.haml +53 -0
- data/lib/archsight.rb +17 -0
- metadata +311 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../annotations/annotation"
|
|
4
|
+
|
|
5
|
+
module Archsight
|
|
6
|
+
module Resources
|
|
7
|
+
# Base is the base for all assets, should not be used directly, only by inheritance
|
|
8
|
+
class Base
|
|
9
|
+
attr_accessor :raw, :path_ref, :references
|
|
10
|
+
|
|
11
|
+
def self.inherited(subclass)
|
|
12
|
+
super
|
|
13
|
+
# Auto-register when class is defined
|
|
14
|
+
Archsight::Resources.register(subclass)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.relation(verb, kind, klass_name)
|
|
18
|
+
@relations ||= []
|
|
19
|
+
@relations << [verb, kind, klass_name]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.relations
|
|
23
|
+
@relations || []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Define an annotation using the Annotation class
|
|
27
|
+
def self.annotation(key, description: nil, filter: nil, title: nil, format: nil, enum: nil, sidebar: true,
|
|
28
|
+
type: nil, list: false)
|
|
29
|
+
@annotations ||= []
|
|
30
|
+
options = { description: description, filter: filter, title: title, format: format, enum: enum,
|
|
31
|
+
sidebar: sidebar, type: type, list: list }
|
|
32
|
+
@annotations << Archsight::Annotations::Annotation.new(key, options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get all annotation definitions
|
|
36
|
+
def self.annotations
|
|
37
|
+
@annotations || []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Define a computed annotation using a block
|
|
41
|
+
# Computed annotations are calculated from related resources after the database is loaded.
|
|
42
|
+
# Supports all the same options as regular annotations.
|
|
43
|
+
# @param key [String] The annotation key (e.g., 'computed/total_cost')
|
|
44
|
+
# @param description [String, nil] Human-readable description
|
|
45
|
+
# @param filter [Symbol, nil] Filter type (:word, :list, or nil)
|
|
46
|
+
# @param title [String, nil] Display title
|
|
47
|
+
# @param format [Symbol, nil] Rendering format (:markdown, :tag_word, :tag_list)
|
|
48
|
+
# @param enum [Array, nil] Allowed values
|
|
49
|
+
# @param sidebar [Boolean] Show in sidebar (default false for computed)
|
|
50
|
+
# @param type [Class, nil] Type for value coercion (Integer, Float, String)
|
|
51
|
+
# @param list [Boolean] Whether values are lists (default false)
|
|
52
|
+
# @yield Block that computes the annotation value, evaluated in Evaluator context
|
|
53
|
+
def self.computed_annotation(key, description: nil, filter: nil, title: nil, format: nil, enum: nil,
|
|
54
|
+
sidebar: false, type: nil, list: false, &)
|
|
55
|
+
require_relative "../annotations/computed"
|
|
56
|
+
@computed_annotations ||= []
|
|
57
|
+
@computed_annotations << Archsight::Annotations::Computed.new(key, description: description, type: type, &)
|
|
58
|
+
|
|
59
|
+
# Also register as a regular annotation so it passes validation and is recognized
|
|
60
|
+
@annotations ||= []
|
|
61
|
+
options = { description: description, filter: filter, title: title, format: format, enum: enum,
|
|
62
|
+
sidebar: sidebar, type: type, list: list }
|
|
63
|
+
@annotations << Archsight::Annotations::Annotation.new(key, options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Get all computed annotation definitions
|
|
67
|
+
def self.computed_annotations
|
|
68
|
+
@computed_annotations || []
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Find annotation definition matching a key (handles patterns)
|
|
72
|
+
def self.annotation_matching(key)
|
|
73
|
+
annotations.find { |a| a.matches?(key) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check if key matches any pattern annotation
|
|
77
|
+
def self.matches_annotation_pattern?(key)
|
|
78
|
+
annotations.any? { |a| a.pattern? && a.matches?(key) }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Get filterable annotations as array of Annotation objects
|
|
82
|
+
def self.filterable_annotations
|
|
83
|
+
annotations.select(&:filterable?).reject(&:pattern?)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Get annotations marked for list display
|
|
87
|
+
def self.list_annotations
|
|
88
|
+
annotations.select(&:list_display?).reject(&:pattern?)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.annotation_title(key)
|
|
92
|
+
annotation_matching(key)&.title || key.split("/").last.capitalize
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.annotation_format(key)
|
|
96
|
+
annotation_matching(key)&.format
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.annotation_enum(key)
|
|
100
|
+
annotation_matching(key)&.enum
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.icon(icon_name = nil)
|
|
104
|
+
if icon_name
|
|
105
|
+
@icon = icon_name
|
|
106
|
+
else
|
|
107
|
+
@icon || "page" # default icon
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.layer(layer_name = nil)
|
|
112
|
+
if layer_name
|
|
113
|
+
@layer = layer_name
|
|
114
|
+
else
|
|
115
|
+
@layer || "other" # default layer
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def self.description(text = nil)
|
|
120
|
+
if text
|
|
121
|
+
@description = text
|
|
122
|
+
else
|
|
123
|
+
@description
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Include annotation modules by symbol name
|
|
128
|
+
# @example include_annotations :git, :architecture, :backup
|
|
129
|
+
# @param names [Array<Symbol>] Symbols representing annotation modules (:git, :architecture, :backup, :generated)
|
|
130
|
+
def self.include_annotations(*names)
|
|
131
|
+
names.each do |name|
|
|
132
|
+
# Convert snake_case to CamelCase (e.g., :git -> 'Git', :my_module -> 'MyModule')
|
|
133
|
+
module_name = name.to_s.split("_").map(&:capitalize).join
|
|
134
|
+
mod = Archsight::Annotations.const_get(module_name)
|
|
135
|
+
include mod
|
|
136
|
+
rescue NameError
|
|
137
|
+
available = Archsight::Annotations.constants
|
|
138
|
+
.select { |c| Archsight::Annotations.const_get(c).is_a?(Module) && Archsight::Annotations.const_get(c).respond_to?(:included) }
|
|
139
|
+
.map { |c| ":#{c.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase}" }
|
|
140
|
+
.sort
|
|
141
|
+
Kernel.raise "Unknown annotation module :#{name}. Available: #{available.join(", ")}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.discovered_annotations
|
|
146
|
+
@discovered_annotations ||= Set.new
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def initialize(raw, path_ref)
|
|
150
|
+
@raw = raw
|
|
151
|
+
@path_ref = path_ref
|
|
152
|
+
@references = []
|
|
153
|
+
# Auto-discover annotation keys
|
|
154
|
+
return unless annotations
|
|
155
|
+
|
|
156
|
+
annotations.each_key do |key|
|
|
157
|
+
self.class.discovered_annotations.add(key)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def klass
|
|
162
|
+
self.class.name.split("::").last
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def kind
|
|
166
|
+
@raw["kind"]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def name
|
|
170
|
+
metadata["name"]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def annotations
|
|
174
|
+
metadata["annotations"] || {}
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Set a computed annotation value
|
|
178
|
+
# This writes to both the computed values cache and the annotations hash
|
|
179
|
+
# so computed values are accessible via the normal annotations interface.
|
|
180
|
+
# @param key [String] The annotation key
|
|
181
|
+
# @param value [Object] The computed value
|
|
182
|
+
def set_computed_annotation(key, value)
|
|
183
|
+
@computed_values ||= {}
|
|
184
|
+
@computed_values[key] = value
|
|
185
|
+
# Write to annotations hash for query compatibility
|
|
186
|
+
@raw["metadata"] ||= {}
|
|
187
|
+
@raw["metadata"]["annotations"] ||= {}
|
|
188
|
+
@raw["metadata"]["annotations"][key] = value
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Get a computed annotation value from the cache
|
|
192
|
+
# @param key [String] The annotation key
|
|
193
|
+
# @return [Object, nil] The computed value or nil
|
|
194
|
+
def computed_annotation_value(key)
|
|
195
|
+
@computed_values&.[](key)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def metadata
|
|
199
|
+
@raw["metadata"] || {}
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def spec
|
|
203
|
+
@raw["spec"] || {}
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def to_s
|
|
207
|
+
"#<#{self.class} name=#{name}>"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def abandoned?
|
|
211
|
+
annotations["activity/status"] == "abandoned"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def has_relations?
|
|
215
|
+
spec.any? { |_verb, kinds| kinds.is_a?(Hash) && kinds.values.any? { |v| v.is_a?(Array) && v.any? } }
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def verb_allowed?(verb)
|
|
219
|
+
self.class.relations.any? { |v, _, _| v.to_s == verb.to_s }
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def verb_kind_allowed?(verb, kind)
|
|
223
|
+
self.class.relations.any? { |v, k, _| v.to_s == verb.to_s && k.to_s == kind.to_s }
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def relations(verb, kind)
|
|
227
|
+
(spec[verb.to_s] || {})[kind.to_s] || []
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def set_relations(verb, kind, rels)
|
|
231
|
+
spec[verb.to_s][kind.to_s] = rels
|
|
232
|
+
rels.each { |rel| rel.referenced_by(self, verb) }
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def referenced_by(inst, verb = nil)
|
|
236
|
+
# Store reference with verb information for grouped display
|
|
237
|
+
existing = @references.find { |r| r[:instance] == inst && r[:verb] == verb }
|
|
238
|
+
@references << { instance: inst, verb: verb } unless existing
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Get references grouped by kind and verb for display (incoming)
|
|
242
|
+
# Returns: { "Kind" => { "verb" => [instances...] } }
|
|
243
|
+
def references_grouped
|
|
244
|
+
grouped = {}
|
|
245
|
+
@references.each do |ref|
|
|
246
|
+
inst = ref[:instance]
|
|
247
|
+
verb = ref[:verb]
|
|
248
|
+
kind = inst.klass
|
|
249
|
+
grouped[kind] ||= {}
|
|
250
|
+
grouped[kind][verb] ||= []
|
|
251
|
+
grouped[kind][verb] << inst
|
|
252
|
+
end
|
|
253
|
+
# Sort by kind name, then by verb name
|
|
254
|
+
grouped.sort.to_h.transform_values { |verbs| verbs.sort.to_h }
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Get outgoing relations grouped by verb and kind for display
|
|
258
|
+
# Returns: { "verb" => { "Kind" => [instances...] } }
|
|
259
|
+
def relations_grouped
|
|
260
|
+
grouped = {}
|
|
261
|
+
spec.each do |verb, kinds|
|
|
262
|
+
next unless kinds.is_a?(Hash)
|
|
263
|
+
|
|
264
|
+
kinds.each_value do |instances|
|
|
265
|
+
next unless instances.is_a?(Array) && instances.any?
|
|
266
|
+
|
|
267
|
+
instances.each do |inst|
|
|
268
|
+
kind = inst.klass
|
|
269
|
+
grouped[verb] ||= {}
|
|
270
|
+
grouped[verb][kind] ||= []
|
|
271
|
+
grouped[verb][kind] << inst
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
# Sort by verb name, then by kind name
|
|
276
|
+
grouped.sort.to_h.transform_values { |kinds| kinds.sort.to_h }
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def verify!
|
|
280
|
+
spec.each do |verb, kinds|
|
|
281
|
+
raise "unknown verb #{verb}" unless verb_allowed?(verb)
|
|
282
|
+
|
|
283
|
+
kinds.each_key do |kind, _|
|
|
284
|
+
raise "unknown verb #{verb} / kind #{kind} combination" unless verb_kind_allowed?(verb, kind)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def merge!(inst)
|
|
290
|
+
# NOTE: path reference is preserved from the original instance
|
|
291
|
+
@raw = Archsight::Helpers.deep_merge(@raw, inst.raw)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# raise provides a helper for better error messages including current path and line no
|
|
295
|
+
def raise(msg)
|
|
296
|
+
Kernel.raise(Archsight::ResourceError.new(msg, @path_ref))
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BusinessActor represents teams or organizational units
|
|
4
|
+
class Archsight::Resources::BusinessActor < Archsight::Resources::Base
|
|
5
|
+
include_annotations :git, :architecture, :generated
|
|
6
|
+
|
|
7
|
+
description <<~MD
|
|
8
|
+
Represents a team, organizational unit, or external entity that performs business behavior.
|
|
9
|
+
|
|
10
|
+
## ArchiMate Definition
|
|
11
|
+
|
|
12
|
+
**Layer:** Business
|
|
13
|
+
**Aspect:** Active Structure
|
|
14
|
+
|
|
15
|
+
A business actor represents a business entity that is capable of performing behavior.
|
|
16
|
+
Actors can be individuals, teams, departments, or external organizations that participate
|
|
17
|
+
in business processes or own/maintain system components.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Use BusinessActor to represent:
|
|
22
|
+
|
|
23
|
+
- Development teams
|
|
24
|
+
- Operations teams
|
|
25
|
+
- External vendors or partners
|
|
26
|
+
- Support organizations
|
|
27
|
+
- Cross-functional groups
|
|
28
|
+
MD
|
|
29
|
+
|
|
30
|
+
icon "community"
|
|
31
|
+
layer "business"
|
|
32
|
+
|
|
33
|
+
annotation "team/lead",
|
|
34
|
+
description: 'Team lead (format: "Name <email>" or "email")',
|
|
35
|
+
title: "Team Lead",
|
|
36
|
+
sidebar: false,
|
|
37
|
+
filter: :word,
|
|
38
|
+
format: :tag_word,
|
|
39
|
+
type: Archsight::Annotations::EmailRecipient
|
|
40
|
+
|
|
41
|
+
annotation "team/members",
|
|
42
|
+
description: 'Team members (format: "Name <email>" or "email")',
|
|
43
|
+
title: "Team Members",
|
|
44
|
+
sidebar: false,
|
|
45
|
+
filter: :list,
|
|
46
|
+
format: :tag_list,
|
|
47
|
+
type: Archsight::Annotations::EmailRecipient
|
|
48
|
+
|
|
49
|
+
annotation "team/jira",
|
|
50
|
+
description: "Jira project keys for issue tracking (primary queue first)",
|
|
51
|
+
title: "Jira Projects",
|
|
52
|
+
sidebar: false,
|
|
53
|
+
filter: :list,
|
|
54
|
+
format: :tag_list
|
|
55
|
+
|
|
56
|
+
annotation "jira/issues/created",
|
|
57
|
+
description: "Issues created per month (comma-separated, last 6 months)",
|
|
58
|
+
title: "Issues Created",
|
|
59
|
+
sidebar: false
|
|
60
|
+
|
|
61
|
+
annotation "jira/issues/resolved",
|
|
62
|
+
description: "Issues resolved per month (comma-separated, last 6 months)",
|
|
63
|
+
title: "Issues Resolved",
|
|
64
|
+
sidebar: false
|
|
65
|
+
|
|
66
|
+
# ITIL 4 General Management Practices
|
|
67
|
+
annotation "itil/general",
|
|
68
|
+
description: "ITIL general management practices",
|
|
69
|
+
title: "ITIL General Practices",
|
|
70
|
+
filter: :list,
|
|
71
|
+
format: :tag_list,
|
|
72
|
+
enum: %w[
|
|
73
|
+
strategy-management portfolio-management architecture-management
|
|
74
|
+
risk-management workforce-management continual-improvement
|
|
75
|
+
knowledge-management measurement-reporting change-management
|
|
76
|
+
project-management relationship-management supplier-management
|
|
77
|
+
financial-management
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
# ITIL 4 Service Management Practices
|
|
81
|
+
annotation "itil/service",
|
|
82
|
+
description: "ITIL service management practices",
|
|
83
|
+
title: "ITIL Service Practices",
|
|
84
|
+
filter: :list,
|
|
85
|
+
format: :tag_list,
|
|
86
|
+
enum: %w[
|
|
87
|
+
service-design service-catalog service-level-management
|
|
88
|
+
availability-management capacity-management continuity-management
|
|
89
|
+
security-management configuration-management
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
# ITIL 4 Technical Management Practices
|
|
93
|
+
annotation "itil/technical",
|
|
94
|
+
description: "ITIL technical management practices",
|
|
95
|
+
title: "ITIL Technical Practices",
|
|
96
|
+
filter: :list,
|
|
97
|
+
format: :tag_list,
|
|
98
|
+
enum: %w[
|
|
99
|
+
deployment-management infrastructure-management software-development
|
|
100
|
+
release-management change-enablement service-validation
|
|
101
|
+
incident-management problem-management service-desk
|
|
102
|
+
monitoring-management
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
relation :compositeOf, :businessActors, :BusinessActor
|
|
106
|
+
|
|
107
|
+
# Computed Annotations
|
|
108
|
+
computed_annotation "team/size",
|
|
109
|
+
title: "Team Size",
|
|
110
|
+
description: "Number of team members (including sub-teams)",
|
|
111
|
+
list: true,
|
|
112
|
+
type: Integer do
|
|
113
|
+
# Count members from this team
|
|
114
|
+
members = @instance.annotations["team/members"]
|
|
115
|
+
count = if members.nil? || members.empty?
|
|
116
|
+
0
|
|
117
|
+
else
|
|
118
|
+
members.split(/[,\n]/).map(&:strip).reject(&:empty?).size
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Add members from sub-teams (teams that are composites of this team)
|
|
122
|
+
incoming_transitive(:BusinessActor).each do |subteam|
|
|
123
|
+
subteam_members = subteam.annotations["team/members"]
|
|
124
|
+
next if subteam_members.nil? || subteam_members.empty?
|
|
125
|
+
|
|
126
|
+
count += subteam_members.split(/[,\n]/).map(&:strip).reject(&:empty?).size
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
count
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
computed_annotation "team/lead/size",
|
|
133
|
+
title: "Team Leads",
|
|
134
|
+
description: "Number of team leads (including sub-teams)",
|
|
135
|
+
type: Integer do
|
|
136
|
+
# Count lead from this team
|
|
137
|
+
count = @instance.annotations["team/lead"] ? 1 : 0
|
|
138
|
+
|
|
139
|
+
# Add leads from sub-teams
|
|
140
|
+
incoming_transitive(:BusinessActor).each do |subteam|
|
|
141
|
+
count += 1 if subteam.annotations["team/lead"]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
count
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
computed_annotation "repository/artifacts/total",
|
|
148
|
+
title: "Maintained Repositories",
|
|
149
|
+
description: "Number of git repositories maintained by this team",
|
|
150
|
+
type: Integer do
|
|
151
|
+
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo"'))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
computed_annotation "repository/artifacts/active",
|
|
155
|
+
title: "Active Repositories",
|
|
156
|
+
description: "Number of active git repositories maintained by this team",
|
|
157
|
+
type: Integer do
|
|
158
|
+
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "active"'))
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
computed_annotation "repository/artifacts/highBusFactor",
|
|
162
|
+
title: "High Bus Factor Repositories",
|
|
163
|
+
description: "Number of active git repositories with high bus factor maintained by this team",
|
|
164
|
+
type: Integer do
|
|
165
|
+
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "active" & activity/busFactor == "high"'))
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
computed_annotation "repository/artifacts/abandoned",
|
|
169
|
+
title: "Abandoned Repositories",
|
|
170
|
+
description: "Number of abandoned git repositories maintained by this team",
|
|
171
|
+
type: Integer do
|
|
172
|
+
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "abandoned"'))
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
computed_annotation "repository/artifacts/archived",
|
|
176
|
+
title: "Archived Repositories",
|
|
177
|
+
description: "Number of archived git repositories maintained by this team",
|
|
178
|
+
type: Integer do
|
|
179
|
+
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "archived"'))
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
computed_annotation "jira/projectUrl",
|
|
183
|
+
title: "Jira Board",
|
|
184
|
+
description: "Link to Jira board (computed from team/jira)",
|
|
185
|
+
format: :link do
|
|
186
|
+
jira_key = @instance.annotations["team/jira"]
|
|
187
|
+
next nil if jira_key.nil? || jira_key.empty?
|
|
188
|
+
|
|
189
|
+
# Use first key if multiple (comma/newline separated)
|
|
190
|
+
primary_key = jira_key.split(/[,\n]/).first&.strip
|
|
191
|
+
next nil if primary_key.nil? || primary_key.empty?
|
|
192
|
+
|
|
193
|
+
"https://jira.example.com/projects/#{primary_key}/issues"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BusinessConstraint represents restrictions or limitations on architecture
|
|
4
|
+
class Archsight::Resources::BusinessConstraint < Archsight::Resources::Base
|
|
5
|
+
include_annotations :git, :architecture
|
|
6
|
+
|
|
7
|
+
description <<~MD
|
|
8
|
+
Represents a factor that limits the realization of goals or influences architecture decisions.
|
|
9
|
+
|
|
10
|
+
## ArchiMate Definition
|
|
11
|
+
|
|
12
|
+
**Layer:** Motivation
|
|
13
|
+
**Aspect:** Passive Structure
|
|
14
|
+
|
|
15
|
+
A constraint represents a factor that prevents or obstructs the realization of goals.
|
|
16
|
+
Constraints are typically imposed by external factors such as regulations, organizational
|
|
17
|
+
policies, or technical limitations.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Use BusinessConstraint to represent:
|
|
22
|
+
|
|
23
|
+
- Regulatory requirements (GDPR, SOX, PCI-DSS)
|
|
24
|
+
- Security policies
|
|
25
|
+
- Organizational standards
|
|
26
|
+
- Technical limitations
|
|
27
|
+
- Budget or resource constraints
|
|
28
|
+
MD
|
|
29
|
+
|
|
30
|
+
icon "prohibition"
|
|
31
|
+
layer "business"
|
|
32
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BusinessProcess represents a structured business workflow or procedure
|
|
4
|
+
class Archsight::Resources::BusinessProcess < Archsight::Resources::Base
|
|
5
|
+
include_annotations :git, :architecture
|
|
6
|
+
|
|
7
|
+
description <<~MD
|
|
8
|
+
Represents a sequence of business behaviors that achieves a specific outcome.
|
|
9
|
+
|
|
10
|
+
## ArchiMate Definition
|
|
11
|
+
|
|
12
|
+
**Layer:** Business
|
|
13
|
+
**Aspect:** Behavior
|
|
14
|
+
|
|
15
|
+
A business process represents a sequence of business behaviors that achieves a specific
|
|
16
|
+
outcome such as a defined set of products or business services. It orchestrates the
|
|
17
|
+
activities performed by business actors using application services.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Use BusinessProcess to represent:
|
|
22
|
+
|
|
23
|
+
- Customer onboarding workflows
|
|
24
|
+
- Incident response procedures
|
|
25
|
+
- Change management processes
|
|
26
|
+
- Release deployment pipelines
|
|
27
|
+
- Support escalation processes
|
|
28
|
+
MD
|
|
29
|
+
|
|
30
|
+
icon "kanban-board"
|
|
31
|
+
layer "business"
|
|
32
|
+
|
|
33
|
+
relation :realizes, :businessConstraints, :BusinessConstraint
|
|
34
|
+
relation :realizes, :businessRequirements, :BusinessRequirement
|
|
35
|
+
relation :servedBy, :applicationServices, :ApplicationService
|
|
36
|
+
relation :performedBy, :businessActors, :BusinessActor
|
|
37
|
+
end
|