archsight 0.1.2 → 0.1.3

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -5
  3. data/lib/archsight/analysis/executor.rb +112 -0
  4. data/lib/archsight/analysis/result.rb +174 -0
  5. data/lib/archsight/analysis/sandbox.rb +319 -0
  6. data/lib/archsight/analysis.rb +11 -0
  7. data/lib/archsight/annotations/architecture_annotations.rb +2 -2
  8. data/lib/archsight/cli.rb +163 -0
  9. data/lib/archsight/database.rb +6 -2
  10. data/lib/archsight/helpers/analysis_renderer.rb +83 -0
  11. data/lib/archsight/helpers/formatting.rb +95 -0
  12. data/lib/archsight/helpers.rb +20 -4
  13. data/lib/archsight/import/concurrent_progress.rb +341 -0
  14. data/lib/archsight/import/executor.rb +466 -0
  15. data/lib/archsight/import/git_analytics.rb +626 -0
  16. data/lib/archsight/import/handler.rb +263 -0
  17. data/lib/archsight/import/handlers/github.rb +161 -0
  18. data/lib/archsight/import/handlers/gitlab.rb +202 -0
  19. data/lib/archsight/import/handlers/jira_base.rb +189 -0
  20. data/lib/archsight/import/handlers/jira_discover.rb +161 -0
  21. data/lib/archsight/import/handlers/jira_metrics.rb +179 -0
  22. data/lib/archsight/import/handlers/openapi_schema_parser.rb +279 -0
  23. data/lib/archsight/import/handlers/repository.rb +439 -0
  24. data/lib/archsight/import/handlers/rest_api.rb +293 -0
  25. data/lib/archsight/import/handlers/rest_api_index.rb +183 -0
  26. data/lib/archsight/import/progress.rb +91 -0
  27. data/lib/archsight/import/registry.rb +54 -0
  28. data/lib/archsight/import/shared_file_writer.rb +67 -0
  29. data/lib/archsight/import/team_matcher.rb +195 -0
  30. data/lib/archsight/import.rb +14 -0
  31. data/lib/archsight/resources/analysis.rb +91 -0
  32. data/lib/archsight/resources/application_component.rb +2 -2
  33. data/lib/archsight/resources/application_service.rb +12 -12
  34. data/lib/archsight/resources/business_product.rb +12 -12
  35. data/lib/archsight/resources/data_object.rb +1 -1
  36. data/lib/archsight/resources/import.rb +79 -0
  37. data/lib/archsight/resources/technology_artifact.rb +23 -2
  38. data/lib/archsight/version.rb +1 -1
  39. data/lib/archsight/web/api/docs.rb +17 -0
  40. data/lib/archsight/web/api/json_helpers.rb +164 -0
  41. data/lib/archsight/web/api/openapi/spec.yaml +500 -0
  42. data/lib/archsight/web/api/routes.rb +101 -0
  43. data/lib/archsight/web/application.rb +66 -43
  44. data/lib/archsight/web/doc/import.md +458 -0
  45. data/lib/archsight/web/doc/index.md.erb +1 -0
  46. data/lib/archsight/web/public/css/artifact.css +10 -0
  47. data/lib/archsight/web/public/css/graph.css +14 -0
  48. data/lib/archsight/web/public/css/instance.css +489 -0
  49. data/lib/archsight/web/views/api_docs.erb +19 -0
  50. data/lib/archsight/web/views/partials/artifact/_project_estimate.haml +14 -8
  51. data/lib/archsight/web/views/partials/instance/_analysis_detail.haml +74 -0
  52. data/lib/archsight/web/views/partials/instance/_analysis_result.haml +64 -0
  53. data/lib/archsight/web/views/partials/instance/_detail.haml +7 -3
  54. data/lib/archsight/web/views/partials/instance/_import_detail.haml +87 -0
  55. data/lib/archsight/web/views/partials/instance/_relations.haml +4 -4
  56. data/lib/archsight/web/views/partials/layout/_content.haml +4 -0
  57. data/lib/archsight/web/views/partials/layout/_navigation.haml +6 -5
  58. metadata +78 -1
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archsight; end
4
+ module Archsight::Web; end
5
+ module Archsight::Web::API; end
6
+
7
+ # Shared helpers for JSON API responses
8
+ module Archsight::Web::API::JsonHelpers
9
+ DEFAULT_LIMIT = 50
10
+ MAX_LIMIT = 500
11
+
12
+ def json_response(data, status: 200)
13
+ content_type :json
14
+ halt status, JSON.pretty_generate(data)
15
+ end
16
+
17
+ def json_error(message, status:, error_type: "Error", query: nil)
18
+ content_type :json
19
+ error = { error: error_type, message: message }
20
+ error[:query] = query if query
21
+ halt status, JSON.pretty_generate(error)
22
+ end
23
+
24
+ def resource_summary(resource, output:, omit_kind: false)
25
+ case output
26
+ when "brief"
27
+ Archsight::MCP.brief_summary(resource, omit_kind: omit_kind)
28
+ else # "complete"
29
+ Archsight::MCP.complete_summary(resource, omit_kind: omit_kind)
30
+ end
31
+ end
32
+
33
+ def paginate(collection, limit:, offset:)
34
+ limit = [[limit.to_i, 1].max, MAX_LIMIT].min
35
+ offset = [offset.to_i, 0].max
36
+ {
37
+ items: collection.drop(offset).take(limit),
38
+ limit: limit,
39
+ offset: offset,
40
+ total: collection.length
41
+ }
42
+ end
43
+
44
+ def parse_pagination_params
45
+ limit = (params[:limit] || DEFAULT_LIMIT).to_i
46
+ offset = (params[:offset] || 0).to_i
47
+ [limit, offset]
48
+ end
49
+
50
+ def parse_output_param
51
+ params[:output] || "complete"
52
+ end
53
+
54
+ def build_kinds_list
55
+ kinds = Archsight::Resources.resource_classes.map do |kind_name, klass|
56
+ count = db.instances_by_kind(kind_name).length
57
+ {
58
+ kind: kind_name,
59
+ description: klass.description,
60
+ layer: klass.layer,
61
+ icon: klass.icon,
62
+ instance_count: count
63
+ }
64
+ end
65
+ kinds.sort_by { |k| k[:kind] }
66
+ end
67
+
68
+ def build_list_response(kind, pagination, instances)
69
+ {
70
+ kind: kind,
71
+ total: pagination[:total],
72
+ limit: pagination[:limit],
73
+ offset: pagination[:offset],
74
+ count: instances.length,
75
+ instances: instances
76
+ }
77
+ end
78
+
79
+ def build_instance_response(kind, instance)
80
+ {
81
+ kind: kind,
82
+ name: instance.name,
83
+ metadata: { annotations: instance.annotations },
84
+ spec: serialize_spec(instance.spec),
85
+ relations: extract_relations(instance),
86
+ references: extract_references(instance)
87
+ }
88
+ end
89
+
90
+ def serialize_spec(spec)
91
+ spec.transform_values do |kinds|
92
+ next kinds unless kinds.is_a?(Hash)
93
+
94
+ kinds.transform_values do |instances|
95
+ next instances unless instances.is_a?(Array)
96
+
97
+ instances.map { |i| i.is_a?(Archsight::Resources::Base) ? i.name : i }
98
+ end
99
+ end
100
+ end
101
+
102
+ def build_count_response(query, results, query_time_ms)
103
+ by_kind = results.group_by { |r| r.class.to_s.split("::").last }
104
+ .transform_values(&:length)
105
+ {
106
+ query: query,
107
+ total: results.length,
108
+ query_time_ms: query_time_ms,
109
+ by_kind: by_kind
110
+ }
111
+ end
112
+
113
+ def build_search_response(query, results, parsed_query, query_time_ms)
114
+ limit, offset = parse_pagination_params
115
+ output = parse_output_param
116
+ omit_kind = !parsed_query.kind_filter.nil?
117
+ sorted = results.sort_by(&:name)
118
+ pagination = paginate(sorted, limit: limit, offset: offset)
119
+
120
+ instances = pagination[:items].map do |r|
121
+ resource_summary(r, output: output, omit_kind: omit_kind)
122
+ end
123
+
124
+ {
125
+ query: query,
126
+ total: pagination[:total],
127
+ limit: pagination[:limit],
128
+ offset: pagination[:offset],
129
+ count: instances.length,
130
+ query_time_ms: query_time_ms,
131
+ instances: instances
132
+ }
133
+ end
134
+
135
+ def extract_relations(instance)
136
+ relations = {}
137
+
138
+ instance.class.relations.each do |verb, kind_name, _|
139
+ rels = instance.relations(verb, kind_name).map(&:name)
140
+ next if rels.empty?
141
+
142
+ relations[verb] ||= {}
143
+ relations[verb][kind_name] = rels
144
+ end
145
+
146
+ relations
147
+ end
148
+
149
+ def extract_references(instance)
150
+ references = {}
151
+
152
+ instance.references.each do |ref|
153
+ inst = ref[:instance]
154
+ verb = ref[:verb]
155
+ kind = inst.klass
156
+
157
+ references[kind] ||= {}
158
+ references[kind][verb] ||= []
159
+ references[kind][verb] << inst.name
160
+ end
161
+
162
+ references
163
+ end
164
+ end
@@ -0,0 +1,500 @@
1
+ openapi: 3.1.0
2
+ info:
3
+ title: Archsight API
4
+ description: |
5
+ REST API for Archsight enterprise architecture visualization and modeling tool.
6
+
7
+ ## Query Language
8
+
9
+ The search endpoint supports a powerful query language:
10
+
11
+ ### Name Search
12
+ - `kubernetes` - shortcut for `name =~ "kubernetes"`
13
+ - `name == "ExactName"` - exact name match
14
+ - `name =~ "pattern"` - regex pattern match
15
+
16
+ ### Kind Filter Prefix
17
+ - `TechnologyArtifact: ...` - restricts search to that resource type
18
+
19
+ ### Annotation Filters
20
+ - `activity/status == "active"` - equals
21
+ - `scc/language/Go/loc > 5000` - numeric comparison
22
+ - Operators: `==`, `!=`, `=~`, `>`, `<`, `>=`, `<=`
23
+
24
+ ### Relation Queries
25
+ - `-> Kind` - has outgoing relation to kind
26
+ - `-> "Name"` - has outgoing relation to specific instance
27
+ - `<- Kind` - has incoming relation from kind
28
+ - `~> Kind` - transitively reaches kind
29
+ - `<~ Kind` - transitively reached by kind
30
+ - `-> none` - no outgoing relations
31
+ - `<- none` - no incoming relations (orphan detection)
32
+
33
+ ### Sub-query Targets
34
+ - `-> $(expression)` - relates to any resource matching expression
35
+ - `~> $(expr)` - transitively reaches any matching resource
36
+ - `<- $(expr)` - incoming from any matching resource
37
+
38
+ ### Logical Operators
39
+ - `AND`, `and`, `&` - logical AND
40
+ - `OR`, `or`, `|` - logical OR
41
+ - `NOT`, `not`, `!` - logical NOT
42
+ - Parentheses for grouping
43
+
44
+ ### Examples
45
+ - `kubernetes` - resources with "kubernetes" in name
46
+ - `TechnologyArtifact: activity/status == "active"` - active TechnologyArtifacts
47
+ - `-> ApplicationInterface & repository/artifacts == "container"` - containerized services exposing APIs
48
+ - `<- none` - resources not referenced by anything (potential orphans)
49
+ - `-> none & <- none` - true orphans with no relations at all
50
+ version: 1.0.0
51
+ contact:
52
+ name: Archsight
53
+ servers:
54
+ - url: /
55
+ description: Current server
56
+
57
+ paths:
58
+ /api/v1/kinds:
59
+ get:
60
+ summary: List all resource kinds
61
+ description: Returns all available resource kinds with their instance counts and metadata.
62
+ operationId: listKinds
63
+ tags:
64
+ - Kinds
65
+ responses:
66
+ '200':
67
+ description: List of resource kinds
68
+ content:
69
+ application/json:
70
+ schema:
71
+ $ref: '#/components/schemas/KindList'
72
+
73
+ /api/v1/kinds/{kind}:
74
+ get:
75
+ summary: List instances of a kind
76
+ description: |
77
+ Returns paginated list of instances for a specific resource kind.
78
+
79
+ Response includes: kind, name, metadata, spec (no relations/references).
80
+ operationId: listInstances
81
+ tags:
82
+ - Kinds
83
+ parameters:
84
+ - $ref: '#/components/parameters/kind'
85
+ - $ref: '#/components/parameters/limit'
86
+ - $ref: '#/components/parameters/offset'
87
+ - $ref: '#/components/parameters/output'
88
+ responses:
89
+ '200':
90
+ description: Paginated list of instances
91
+ content:
92
+ application/json:
93
+ schema:
94
+ $ref: '#/components/schemas/InstanceList'
95
+ '404':
96
+ description: Kind not found
97
+ content:
98
+ application/json:
99
+ schema:
100
+ $ref: '#/components/schemas/Error'
101
+
102
+ /api/v1/kinds/{kind}/instances/{name}:
103
+ get:
104
+ summary: Get instance details
105
+ description: |
106
+ Returns detailed information about a specific instance.
107
+
108
+ Response includes: kind, name, metadata, spec, relations, references.
109
+ operationId: getInstance
110
+ tags:
111
+ - Instances
112
+ parameters:
113
+ - $ref: '#/components/parameters/kind'
114
+ - $ref: '#/components/parameters/name'
115
+ responses:
116
+ '200':
117
+ description: Instance details
118
+ content:
119
+ application/json:
120
+ schema:
121
+ $ref: '#/components/schemas/Instance'
122
+ '404':
123
+ description: Kind or instance not found
124
+ content:
125
+ application/json:
126
+ schema:
127
+ $ref: '#/components/schemas/Error'
128
+
129
+ /api/v1/search:
130
+ get:
131
+ summary: Search instances
132
+ description: |
133
+ Search and filter architecture instances using the query language.
134
+ See the API description for full query language documentation.
135
+
136
+ Response includes: kind, name, metadata, spec (no relations/references).
137
+ Additional fields: query, query_time_ms, by_kind (count mode).
138
+ operationId: search
139
+ tags:
140
+ - Search
141
+ parameters:
142
+ - name: q
143
+ in: query
144
+ required: true
145
+ description: Query string using the query language syntax
146
+ schema:
147
+ type: string
148
+ examples:
149
+ simple:
150
+ value: kubernetes
151
+ summary: Simple name search
152
+ kind_filter:
153
+ value: 'TechnologyArtifact: activity/status == "active"'
154
+ summary: Kind filter with annotation
155
+ relation:
156
+ value: '-> ApplicationInterface'
157
+ summary: Has relation to kind
158
+ orphan:
159
+ value: '<- none'
160
+ summary: Find orphan resources
161
+ - $ref: '#/components/parameters/limit'
162
+ - $ref: '#/components/parameters/offset'
163
+ - $ref: '#/components/parameters/output'
164
+ responses:
165
+ '200':
166
+ description: Search results
167
+ content:
168
+ application/json:
169
+ schema:
170
+ $ref: '#/components/schemas/InstanceList'
171
+ '400':
172
+ description: Invalid query or missing parameter
173
+ content:
174
+ application/json:
175
+ schema:
176
+ $ref: '#/components/schemas/QueryError'
177
+
178
+ /mcp:
179
+ get:
180
+ summary: MCP Server endpoint
181
+ description: |
182
+ Model Context Protocol (MCP) endpoint for AI assistant integration.
183
+ Uses Server-Sent Events (SSE) for bidirectional communication.
184
+
185
+ Available tools:
186
+ - `query` - Search and filter architecture resources using the query language
187
+ - `analyze_resource` - Get detailed analysis of a specific resource
188
+ - `resource_doc` - Get documentation for a resource type
189
+ operationId: mcpEndpoint
190
+ tags:
191
+ - MCP
192
+ responses:
193
+ '200':
194
+ description: SSE stream for MCP communication
195
+ content:
196
+ text/event-stream:
197
+ schema:
198
+ type: string
199
+
200
+ /kinds.json:
201
+ get:
202
+ summary: List all resource kinds (simple)
203
+ description: Simple URL for listing all resource kinds
204
+ operationId: listKindsSimple
205
+ tags:
206
+ - Kinds
207
+ responses:
208
+ '200':
209
+ description: List of resource kinds
210
+ content:
211
+ application/json:
212
+ schema:
213
+ $ref: '#/components/schemas/KindList'
214
+
215
+ /kinds/{kind}.json:
216
+ get:
217
+ summary: List instances of a kind (simple)
218
+ description: |
219
+ Simple URL for listing instances of a kind.
220
+
221
+ Response includes: kind, name, metadata, spec (no relations/references).
222
+ operationId: listInstancesSimple
223
+ tags:
224
+ - Kinds
225
+ parameters:
226
+ - $ref: '#/components/parameters/kind'
227
+ - $ref: '#/components/parameters/limit'
228
+ - $ref: '#/components/parameters/offset'
229
+ - $ref: '#/components/parameters/output'
230
+ responses:
231
+ '200':
232
+ description: Paginated list of instances
233
+ content:
234
+ application/json:
235
+ schema:
236
+ $ref: '#/components/schemas/InstanceList'
237
+ '404':
238
+ description: Kind not found
239
+ content:
240
+ application/json:
241
+ schema:
242
+ $ref: '#/components/schemas/Error'
243
+
244
+ /kinds/{kind}/instances/{name}.json:
245
+ get:
246
+ summary: Get instance details (simple)
247
+ description: |
248
+ Simple URL for getting instance details.
249
+
250
+ Response includes: kind, name, metadata, spec, relations, references.
251
+ operationId: getInstanceSimple
252
+ tags:
253
+ - Instances
254
+ parameters:
255
+ - $ref: '#/components/parameters/kind'
256
+ - $ref: '#/components/parameters/name'
257
+ responses:
258
+ '200':
259
+ description: Instance details
260
+ content:
261
+ application/json:
262
+ schema:
263
+ $ref: '#/components/schemas/Instance'
264
+ '404':
265
+ description: Kind or instance not found
266
+ content:
267
+ application/json:
268
+ schema:
269
+ $ref: '#/components/schemas/Error'
270
+
271
+ components:
272
+ parameters:
273
+ kind:
274
+ name: kind
275
+ in: path
276
+ required: true
277
+ description: Instance kind name (e.g., TechnologyArtifact, ApplicationComponent)
278
+ schema:
279
+ type: string
280
+ example: TechnologyArtifact
281
+
282
+ name:
283
+ name: name
284
+ in: path
285
+ required: true
286
+ description: Instance name
287
+ schema:
288
+ type: string
289
+ example: my-service
290
+
291
+ limit:
292
+ name: limit
293
+ in: query
294
+ required: false
295
+ description: Maximum number of results to return (1-500, default 50)
296
+ schema:
297
+ type: integer
298
+ minimum: 1
299
+ maximum: 500
300
+ default: 50
301
+
302
+ offset:
303
+ name: offset
304
+ in: query
305
+ required: false
306
+ description: Number of results to skip for pagination
307
+ schema:
308
+ type: integer
309
+ minimum: 0
310
+ default: 0
311
+
312
+ output:
313
+ name: output
314
+ in: query
315
+ required: false
316
+ description: |
317
+ Output format:
318
+ - `complete` (default): Full resource details including annotations and spec
319
+ - `brief`: Minimal output with just kind and name
320
+ - `count`: Only totals grouped by kind (search only)
321
+ schema:
322
+ type: string
323
+ enum:
324
+ - complete
325
+ - brief
326
+ - count
327
+ default: complete
328
+
329
+ schemas:
330
+ Kind:
331
+ type: object
332
+ required:
333
+ - kind
334
+ - instance_count
335
+ properties:
336
+ kind:
337
+ type: string
338
+ description: Instance kind name
339
+ description:
340
+ type: string
341
+ description: Human-readable description of the kind
342
+ layer:
343
+ type: string
344
+ description: Architecture layer (application, technology, business, etc.)
345
+ icon:
346
+ type: string
347
+ description: Icon identifier for UI display
348
+ instance_count:
349
+ type: integer
350
+ description: Number of instances of this kind
351
+
352
+ KindList:
353
+ type: object
354
+ required:
355
+ - total
356
+ - total_instances
357
+ - kinds
358
+ properties:
359
+ total:
360
+ type: integer
361
+ description: Total number of kinds
362
+ total_instances:
363
+ type: integer
364
+ description: Total number of instances across all kinds
365
+ query_time_ms:
366
+ type: number
367
+ format: float
368
+ description: Query execution time in milliseconds
369
+ kinds:
370
+ type: array
371
+ items:
372
+ $ref: '#/components/schemas/Kind'
373
+
374
+ Instance:
375
+ type: object
376
+ required:
377
+ - name
378
+ properties:
379
+ kind:
380
+ type: string
381
+ description: Instance kind (omitted when filtering by kind)
382
+ name:
383
+ type: string
384
+ description: Instance name
385
+ metadata:
386
+ type: object
387
+ properties:
388
+ annotations:
389
+ type: object
390
+ additionalProperties: true
391
+ description: Instance annotations
392
+ spec:
393
+ type: object
394
+ additionalProperties: true
395
+ description: Instance specification
396
+ relations:
397
+ type: object
398
+ additionalProperties:
399
+ type: object
400
+ additionalProperties:
401
+ type: array
402
+ items:
403
+ type: string
404
+ description: Outgoing relations grouped by verb and kind (detail view only)
405
+ example:
406
+ exposes:
407
+ ApplicationInterface:
408
+ - api-v1
409
+ - api-v2
410
+ references:
411
+ type: object
412
+ additionalProperties:
413
+ type: object
414
+ additionalProperties:
415
+ type: array
416
+ items:
417
+ type: string
418
+ description: Incoming references grouped by kind and verb (detail view only)
419
+ example:
420
+ TechnologyArtifact:
421
+ dependsOn:
422
+ - other-service
423
+
424
+ InstanceList:
425
+ type: object
426
+ required:
427
+ - total
428
+ - instances
429
+ properties:
430
+ kind:
431
+ type: string
432
+ description: Instance kind name (when listing by kind)
433
+ query:
434
+ type: string
435
+ description: The executed query string (search only)
436
+ total:
437
+ type: integer
438
+ description: Total number of instances
439
+ limit:
440
+ type: integer
441
+ description: Maximum results per page
442
+ offset:
443
+ type: integer
444
+ description: Number of results skipped
445
+ count:
446
+ type: integer
447
+ description: Number of results in this response
448
+ query_time_ms:
449
+ type: number
450
+ format: float
451
+ description: Query execution time in milliseconds
452
+ by_kind:
453
+ type: object
454
+ additionalProperties:
455
+ type: integer
456
+ description: Result counts by kind (count mode only)
457
+ instances:
458
+ type: array
459
+ items:
460
+ $ref: '#/components/schemas/Instance'
461
+
462
+ Error:
463
+ type: object
464
+ required:
465
+ - error
466
+ - message
467
+ properties:
468
+ error:
469
+ type: string
470
+ description: Error type
471
+ message:
472
+ type: string
473
+ description: Error message
474
+
475
+ QueryError:
476
+ type: object
477
+ required:
478
+ - error
479
+ - message
480
+ - query
481
+ properties:
482
+ error:
483
+ type: string
484
+ description: Error type (QueryError)
485
+ message:
486
+ type: string
487
+ description: Error message describing the query problem
488
+ query:
489
+ type: string
490
+ description: The invalid query string
491
+
492
+ tags:
493
+ - name: Kinds
494
+ description: Instance kind operations
495
+ - name: Instances
496
+ description: Instance operations
497
+ - name: Search
498
+ description: Search and query operations
499
+ - name: MCP
500
+ description: Model Context Protocol for AI assistant integration