Files
cmdb-insight/docs/refactor-plan.md
Bert Hausmans cdee0e8819 UI styling improvements: dashboard headers and navigation
- Restore blue PageHeader on Dashboard (/app-components)
- Update homepage (/) with subtle header design without blue bar
- Add uniform PageHeader styling to application edit page
- Fix Rapporten link on homepage to point to /reports overview
- Improve header descriptions spacing for better readability
2026-01-21 03:24:56 +01:00

30 KiB

Refactor Plan - Phase 1: Architecture Analysis

Created: 2025-01-XX
Status: Phase 1 - Analysis Only (No functional changes)

Executive Summary

This document provides a comprehensive analysis of the current architecture and a plan for refactoring the CMDB Insight codebase to improve maintainability, reduce duplication, and establish clearer separation of concerns.

Scope: This is Phase 1 - analysis and planning only. No code changes will be made in this phase.


Table of Contents

  1. Current Architecture Map
  2. Pain Points & Duplication
  3. Target Architecture
  4. Migration Steps
  5. Explicit Deletion List
  6. API Payload Contract & Recursion Insights

Current Architecture Map

File/Folder Structure

backend/src/
├── services/
│   ├── jiraAssets.ts              # High-level Jira Assets service (business logic, ~3454 lines)
│   ├── jiraAssetsClient.ts        # Low-level Jira Assets API client (~646 lines)
│   ├── schemaDiscoveryService.ts  # Discovers schema from Jira API (~520 lines)
│   ├── schemaCacheService.ts      # Caches schema metadata
│   ├── schemaConfigurationService.ts  # Manages enabled object types
│   ├── schemaMappingService.ts    # Maps object types to schema IDs
│   ├── syncEngine.ts              # Background sync service (full/incremental) (~630 lines)
│   ├── normalizedCacheStore.ts    # EAV pattern DB store (~1695 lines)
│   ├── cmdbService.ts             # Universal schema-driven CMDB service (~531 lines)
│   ├── queryBuilder.ts            # Dynamic SQL query builder (~278 lines)
│   ├── cacheStore.old.ts          # Legacy cache store (deprecated)
│   └── database/
│       ├── normalized-schema.ts   # DB schema definitions (Postgres/SQLite)
│       ├── factory.ts             # Database adapter factory
│       ├── interface.ts           # Database adapter interface
│       ├── postgresAdapter.ts     # PostgreSQL adapter
│       ├── sqliteAdapter.ts       # SQLite adapter
│       ├── migrate-to-normalized-schema.ts
│       └── fix-object-types-constraints.ts
├── routes/
│   ├── applications.ts            # Application-specific endpoints (~780 lines)
│   ├── objects.ts                 # Generic object endpoints (~185 lines)
│   ├── cache.ts                   # Cache/sync endpoints (~165 lines)
│   ├── schema.ts                  # Schema endpoints (~107 lines)
│   └── schemaConfiguration.ts     # Schema configuration endpoints
├── generated/
│   ├── jira-types.ts              # Generated TypeScript types (~934 lines)
│   └── jira-schema.ts             # Generated schema metadata (~895 lines)
└── scripts/
    ├── discover-schema.ts         # Schema discovery CLI
    ├── generate-types-from-db.ts  # Type generation from DB (~485 lines)
    └── generate-schema.ts         # Legacy schema generation

Module Responsibilities

1. Jira Assets API Client Calls

Primary Files:

  • services/jiraAssetsClient.ts - Low-level HTTP client

    • Methods: getObject(), searchObjects(), getAllObjectsOfType(), updateObject(), parseObject()
    • Handles authentication (service account token for reads, user PAT for writes)
    • API detection (Data Center vs Cloud)
    • Object parsing from Jira format to CMDB format
  • services/jiraAssets.ts - High-level business logic wrapper

    • Application-specific methods (e.g., getApplications(), updateApplication())
    • Dashboard data aggregation
    • Reference data caching
    • Team dashboard calculations
    • Legacy API methods

Dependencies:

  • Uses schemaCacheService for type lookups
  • Uses schemaMappingService for schema ID resolution

2. Schema Discovery/Sync

Primary Files:

  • services/schemaDiscoveryService.ts

    • Discovers object types from Jira API (/objectschema/{id}/objecttypes/flat)
    • Discovers attributes for each object type (/objecttype/{id}/attributes)
    • Stores schema in database (object_types, attributes tables)
    • Provides lookup methods: getAttribute(), getAttributesForType(), getObjectType()
  • services/schemaCacheService.ts

    • Caches schema from database
    • Provides runtime schema access
  • services/schemaConfigurationService.ts

    • Manages enabled/disabled object types
    • Schema-to-object-type mapping
    • Configuration validation
  • services/schemaMappingService.ts

    • Maps object type names to schema IDs
    • Legacy compatibility

Scripts:

  • scripts/discover-schema.ts - CLI tool to trigger schema discovery
  • scripts/generate-types-from-db.ts - Generates TypeScript types from database

3. Object Sync/Import

Primary Files:

  • services/syncEngine.ts
    • fullSync() - Syncs all enabled object types
    • incrementalSync() - Periodic sync of updated objects
    • syncType() - Sync single object type
    • syncObject() - Sync single object
    • Uses jiraAssetsClient.getAllObjectsOfType() for fetching
    • Uses normalizedCacheStore.batchUpsertObjects() for storage

Flow:

  1. Fetch objects from Jira via jiraAssetsClient
  2. Parse objects via jiraAssetsClient.parseObject()
  3. Store objects via normalizedCacheStore.batchUpsertObjects()
  4. Extract relations via normalizedCacheStore.extractAndStoreRelations()

4. DB Normalization Store (EAV)

Primary Files:

  • services/normalizedCacheStore.ts (~1695 lines)

    • Storage: normalizeObject(), batchUpsertObjects(), upsertObject()
    • Retrieval: getObject(), getObjects(), reconstructObject(), loadAttributeValues()
    • Relations: extractAndStoreRelations(), getRelatedObjects(), getReferencingObjects()
    • Query: queryWithFilters() (uses queryBuilder)
  • services/database/normalized-schema.ts

    • Defines EAV schema: objects, attributes, attribute_values, object_relations

EAV Pattern:

  • objects table: Minimal metadata (id, objectKey, label, type, timestamps)
  • attributes table: Schema metadata (jira_attr_id, field_name, type, is_multiple, etc.)
  • attribute_values table: Actual values (text_value, number_value, boolean_value, reference_object_id, array_index)
  • object_relations table: Extracted relationships (source_id, target_id, attribute_id)

5. Backend API Endpoints

Primary Files:

  • routes/applications.ts - Application-specific endpoints

    • POST /applications/search - Search with filters
    • GET /applications/:id - Get application details
    • PUT /applications/:id - Update application
    • GET /applications/:id/related/:type - Get related objects
    • Dashboard endpoints (/team-dashboard, /team-portfolio-health)
  • routes/objects.ts - Generic object endpoints

    • GET /objects - List supported types
    • GET /objects/:type - Get all objects of type
    • GET /objects/:type/:id - Get single object
    • GET /objects/:type/:id/related/:relationType - Get related objects
  • routes/cache.ts - Cache management

    • POST /cache/sync - Trigger full sync
    • POST /cache/sync/:objectType - Sync single type
    • POST /cache/refresh-application/:id - Refresh single object
  • routes/schema.ts - Schema endpoints

    • GET /schema - Get schema metadata
    • GET /schema/types - List object types
    • GET /schema/types/:type - Get type definition

Service Layer:

  • Routes delegate to cmdbService, dataService, syncEngine
  • cmdbService provides unified interface (read/write with conflict detection)
  • dataService provides application-specific business logic

6. Query Builder (Object Reconstruction)

Primary Files:

  • services/queryBuilder.ts
    • buildWhereClause() - Builds WHERE conditions from filters
    • buildFilterCondition() - Handles different attribute types (text, reference, number, etc.)
    • buildOrderBy() - ORDER BY clause
    • buildPagination() - LIMIT/OFFSET clause

Usage:

  • Used by normalizedCacheStore.queryWithFilters() to build dynamic SQL
  • Handles complex filters (exact match, exists, contains, reference filters)

7. Generated Types/Reflect Scripts

Primary Files:

  • scripts/generate-types-from-db.ts
    • Reads from object_types and attributes tables
    • Generates generated/jira-types.ts (TypeScript interfaces)
    • Generates generated/jira-schema.ts (Schema metadata with lookup maps)

Generated Output:

  • jira-types.ts: TypeScript interfaces for each object type (e.g., ApplicationComponent, Server)
  • jira-schema.ts: OBJECT_TYPES record, lookup maps (TYPE_ID_TO_NAME, JIRA_NAME_TO_TYPE), helper functions

Pain Points & Duplication

1. Dual API Clients (jiraAssets.ts vs jiraAssetsClient.ts)

Issue: Two separate services handling Jira API calls:

  • jiraAssetsClient.ts - Low-level, focused on API communication
  • jiraAssets.ts - High-level, contains business logic + API calls

Problems:

  • Duplication of API request logic
  • Inconsistent error handling
  • Mixed concerns (business logic + infrastructure)
  • jiraAssets.ts is huge (~3454 lines) and hard to maintain

Location:

  • backend/src/services/jiraAssets.ts - Contains both API calls and business logic
  • backend/src/services/jiraAssetsClient.ts - Clean separation but incomplete

2. Schema Discovery/Caching Duplication

Issue: Multiple services handling schema metadata:

  • schemaDiscoveryService.ts - Discovers and stores schema
  • schemaCacheService.ts - Caches schema from DB
  • schemaConfigurationService.ts - Manages enabled types
  • schemaMappingService.ts - Maps types to schema IDs

Problems:

  • Unclear boundaries between services
  • Potential for stale cache
  • Complex initialization dependencies

Location:

  • backend/src/services/schema*.ts files

3. Mixed Responsibilities in normalizedCacheStore.ts

Issue: Large file (~1695 lines) handling multiple concerns:

  • Database operations (EAV storage/retrieval)
  • Object reconstruction (TypeScript object building)
  • Reference resolution (fetching missing referenced objects)
  • Relation extraction

Problems:

  • Hard to test individual concerns
  • Difficult to optimize specific operations
  • Violates single responsibility principle

Location:

  • backend/src/services/normalizedCacheStore.ts

4. Application-Specific Logic in Generic Services

Issue: Application-specific business logic scattered:

  • routes/applications.ts - Application-specific endpoints (~780 lines)
  • services/dataService.ts - Application business logic
  • services/jiraAssets.ts - Application aggregation logic
  • services/cmdbService.ts - Generic service used by applications

Problems:

  • Hard to extend to other object types
  • Tight coupling between routes and services
  • Business logic mixed with data access

Location:

  • backend/src/routes/applications.ts
  • backend/src/services/dataService.ts

5. Type Generation Pipeline Complexity

Issue: Multiple scripts and services involved in type generation:

  • scripts/discover-schema.ts - Triggers schema discovery
  • services/schemaDiscoveryService.ts - Discovers schema
  • scripts/generate-types-from-db.ts - Generates TypeScript files
  • generated/jira-types.ts - Generated output (must be regenerated when schema changes)

Problems:

  • Unclear workflow
  • Manual steps required
  • Generated files can get out of sync

Location:

  • backend/scripts/discover-schema.ts
  • backend/scripts/generate-types-from-db.ts
  • backend/src/generated/*.ts

6. Legacy Code (cacheStore.old.ts)

Issue: Old cache store still present in codebase:

  • services/cacheStore.old.ts - Deprecated implementation

Problems:

  • Confusing for new developers
  • Takes up space
  • No longer used

Location:

  • backend/src/services/cacheStore.old.ts

7. Inconsistent Error Handling

Issue: Different error handling patterns across services:

  • Some use try/catch with logger
  • Some throw errors
  • Some return null/undefined
  • Inconsistent error messages

Problems:

  • Hard to debug issues
  • Inconsistent API responses
  • No centralized error handling

Location:

  • Throughout codebase

Target Architecture

Domain/Infrastructure/Services/API Separation

backend/src/
├── domain/                          # Domain models & business logic
│   ├── cmdb/
│   │   ├── Object.ts                # CMDBObject base interface
│   │   ├── ObjectType.ts            # ObjectTypeDefinition
│   │   ├── Attribute.ts             # AttributeDefinition
│   │   └── Reference.ts             # ObjectReference
│   ├── schema/
│   │   ├── Schema.ts                # Schema domain model
│   │   └── SchemaDiscovery.ts       # Schema discovery business logic
│   └── sync/
│       ├── SyncEngine.ts            # Sync orchestration logic
│       └── SyncStrategy.ts          # Sync strategies (full, incremental)
│
├── infrastructure/                  # External integrations & infrastructure
│   ├── jira/
│   │   ├── JiraAssetsClient.ts      # Low-level HTTP client (pure API calls)
│   │   ├── JiraAssetsApi.ts         # API contract definitions
│   │   └── JiraResponseParser.ts    # Response parsing utilities
│   └── database/
│       ├── adapters/                # Database adapters (Postgres, SQLite)
│       ├── schema/                  # Schema definitions
│       └── migrations/              # Database migrations
│
├── services/                        # Application services (use cases)
│   ├── cmdb/
│   │   ├── CmdbReadService.ts       # Read operations
│   │   ├── CmdbWriteService.ts      # Write operations with conflict detection
│   │   └── CmdbQueryService.ts      # Query operations
│   ├── schema/
│   │   ├── SchemaService.ts         # Schema CRUD operations
│   │   └── SchemaDiscoveryService.ts # Schema discovery orchestration
│   └── sync/
│       └── SyncService.ts           # Sync orchestration
│
├── repositories/                    # Data access layer
│   ├── ObjectRepository.ts          # Object CRUD (uses EAV store)
│   ├── AttributeRepository.ts       # Attribute value access
│   ├── RelationRepository.ts        # Relationship access
│   └── SchemaRepository.ts          # Schema metadata access
│
├── stores/                          # Storage implementations
│   ├── NormalizedObjectStore.ts     # EAV pattern implementation
│   ├── ObjectReconstructor.ts       # Object reconstruction from EAV
│   └── RelationExtractor.ts         # Relation extraction logic
│
├── api/                             # HTTP API layer
│   ├── routes/
│   │   ├── objects.ts               # Generic object endpoints
│   │   ├── schema.ts                # Schema endpoints
│   │   └── sync.ts                  # Sync endpoints
│   ├── handlers/                    # Request handlers (thin layer)
│   │   ├── ObjectHandler.ts
│   │   ├── SchemaHandler.ts
│   │   └── SyncHandler.ts
│   └── middleware/                  # Auth, validation, etc.
│
├── queries/                         # Query builders
│   ├── ObjectQueryBuilder.ts        # SQL query construction
│   └── FilterBuilder.ts             # Filter condition builder
│
└── scripts/                         # CLI tools
    ├── discover-schema.ts           # Schema discovery CLI
    └── generate-types.ts            # Type generation CLI

Key Principles

  1. Domain Layer: Pure business logic, no infrastructure dependencies
  2. Infrastructure Layer: External integrations (Jira API, database)
  3. Services Layer: Orchestrates domain logic and infrastructure
  4. Repository Layer: Data access abstraction
  5. Store Layer: Storage implementations (EAV, caching)
  6. API Layer: Thin HTTP handlers that delegate to services

Migration Steps

Step 1: Extract Jira API Client (Infrastructure)

Goal: Create pure infrastructure client with no business logic

  1. Consolidate jiraAssetsClient.ts and jiraAssets.ts API methods into single JiraAssetsClient
  2. Extract API contract types to infrastructure/jira/JiraAssetsApi.ts
  3. Move response parsing to infrastructure/jira/JiraResponseParser.ts
  4. Remove business logic from API client (delegate to services)

Files to Create:

  • infrastructure/jira/JiraAssetsClient.ts
  • infrastructure/jira/JiraAssetsApi.ts
  • infrastructure/jira/JiraResponseParser.ts

Files to Modify:

  • services/jiraAssets.ts - Remove API calls, keep business logic
  • services/jiraAssetsClient.ts - Merge into infrastructure client

Files to Delete:

  • None (yet - deprecate old files after migration)

Step 2: Extract Schema Domain & Services

Goal: Separate schema discovery business logic from infrastructure

  1. Create domain/schema/ with domain models
  2. Move schema discovery logic to services/schema/SchemaDiscoveryService.ts
  3. Consolidate schema caching in services/schema/SchemaService.ts
  4. Remove duplication between schemaCacheService, schemaConfigurationService, schemaMappingService

Files to Create:

  • domain/schema/Schema.ts
  • services/schema/SchemaService.ts
  • services/schema/SchemaDiscoveryService.ts

Files to Modify:

  • services/schemaDiscoveryService.ts - Split into domain + service
  • services/schemaCacheService.ts - Merge into SchemaService
  • services/schemaConfigurationService.ts - Merge into SchemaService
  • services/schemaMappingService.ts - Merge into SchemaService

Files to Delete:

  • services/schemaCacheService.ts (after merge)
  • services/schemaMappingService.ts (after merge)

Step 3: Extract Repository Layer

Goal: Abstract data access from business logic

  1. Create repositories/ObjectRepository.ts - Interface for object CRUD
  2. Create repositories/AttributeRepository.ts - Interface for attribute access
  3. Create repositories/RelationRepository.ts - Interface for relationships
  4. Implement repositories using NormalizedObjectStore

Files to Create:

  • repositories/ObjectRepository.ts
  • repositories/AttributeRepository.ts
  • repositories/RelationRepository.ts
  • repositories/SchemaRepository.ts

Files to Modify:

  • services/normalizedCacheStore.ts - Extract repository implementations

Step 4: Extract Store Implementations

Goal: Separate storage implementations from business logic

  1. Extract EAV storage to stores/NormalizedObjectStore.ts
  2. Extract object reconstruction to stores/ObjectReconstructor.ts
  3. Extract relation extraction to stores/RelationExtractor.ts

Files to Create:

  • stores/NormalizedObjectStore.ts - EAV storage/retrieval
  • stores/ObjectReconstructor.ts - TypeScript object reconstruction
  • stores/RelationExtractor.ts - Relation extraction from objects

Files to Modify:

  • services/normalizedCacheStore.ts - Split into store classes

Step 5: Extract Query Builders

Goal: Separate query construction from execution

  1. Move queryBuilder.ts to queries/ObjectQueryBuilder.ts
  2. Extract filter building to queries/FilterBuilder.ts

Files to Create:

  • queries/ObjectQueryBuilder.ts
  • queries/FilterBuilder.ts

Files to Modify:

  • services/queryBuilder.ts - Move to queries/

Step 6: Extract CMDB Services

Goal: Separate read/write/query concerns

  1. Create services/cmdb/CmdbReadService.ts - Read operations
  2. Create services/cmdb/CmdbWriteService.ts - Write operations with conflict detection
  3. Create services/cmdb/CmdbQueryService.ts - Query operations

Files to Create:

  • services/cmdb/CmdbReadService.ts
  • services/cmdb/CmdbWriteService.ts
  • services/cmdb/CmdbQueryService.ts

Files to Modify:

  • services/cmdbService.ts - Split into read/write/query services

Step 7: Extract Sync Service

Goal: Separate sync orchestration from storage

  1. Create domain/sync/SyncEngine.ts - Sync business logic
  2. Create services/sync/SyncService.ts - Sync orchestration

Files to Create:

  • domain/sync/SyncEngine.ts
  • services/sync/SyncService.ts

Files to Modify:

  • services/syncEngine.ts - Split into domain + service

Step 8: Refactor API Routes

Goal: Thin HTTP handlers delegating to services

  1. Create api/handlers/ directory
  2. Move route logic to handlers
  3. Routes become thin wrappers around handlers

Files to Create:

  • api/handlers/ObjectHandler.ts
  • api/handlers/SchemaHandler.ts
  • api/handlers/SyncHandler.ts

Files to Modify:

  • routes/applications.ts - Extract handlers
  • routes/objects.ts - Extract handlers
  • routes/cache.ts - Extract handlers
  • routes/schema.ts - Extract handlers

Step 9: Clean Up Legacy Code

Goal: Remove deprecated files

Files to Delete:

  • services/cacheStore.old.ts
  • Deprecated service files after migration complete

Step 10: Update Type Generation

Goal: Simplify type generation workflow

  1. Consolidate type generation logic
  2. Add automatic type generation on schema discovery
  3. Update documentation

Files to Modify:

  • scripts/generate-types-from-db.ts - Enhance with auto-discovery
  • scripts/discover-schema.ts - Auto-generate types after discovery

Explicit Deletion List

Phase 2 (After Migration Complete)

  1. backend/src/services/cacheStore.old.ts

    • Reason: Legacy implementation, replaced by normalizedCacheStore.ts
    • Deprecation date: TBD
  2. backend/src/services/jiraAssets.ts (after extracting business logic)

    • Reason: API calls moved to infrastructure layer, business logic to services
    • Replacement: infrastructure/jira/JiraAssetsClient.ts + services/cmdb/Cmdb*Service.ts
  3. backend/src/services/schemaCacheService.ts (after consolidation)

    • Reason: Merged into services/schema/SchemaService.ts
  4. backend/src/services/schemaMappingService.ts (after consolidation)

    • Reason: Merged into services/schema/SchemaService.ts
  5. backend/scripts/generate-schema.ts (if still present)

    • Reason: Replaced by generate-types-from-db.ts

Notes

  • Keep old files until migration is complete and tested
  • Mark as deprecated with @deprecated JSDoc comments
  • Add migration guide for each deprecated file

API Payload Contract & Recursion Insights

Jira Assets API Payload Structure

The Jira Assets API returns objects with the following nested structure:

interface JiraAssetsSearchResponse {
  objectEntries: JiraAssetsObject[];  // Top-level array of objects
  // ... pagination metadata
}

interface JiraAssetsObject {
  id: number;
  objectKey: string;
  label: string;
  objectType: {
    id: number;
    name: string;
  };
  attributes: JiraAssetsAttribute[];  // Array of attributes
  updated?: string;
  created?: string;
}

interface JiraAssetsAttribute {
  objectTypeAttributeId: number;
  objectTypeAttribute?: {
    id: number;
    name: string;
  };
  objectAttributeValues: Array<{  // Union type of value representations
    value?: string;                // For scalar values (text, number, etc.)
    displayValue?: string;         // Human-readable value
    referencedObject?: {           // For reference attributes
      id: number;
      objectKey: string;
      label: string;
      // ⚠️ CRITICAL: referencedObject may include attributes (level 2)
      attributes?: JiraAssetsAttribute[];  // Recursive structure
    };
    status?: {                     // For status attributes
      name: string;
    };
    // ... other type-specific fields
  }>;
}

Key Insights

1. Recursive Structure

Issue: referencedObject may include attributes[] array (level 2 recursion).

Current Handling:

  • jiraAssetsClient.ts uses includeAttributesDeep=2 parameter
  • This causes referenced objects to include their attributes
  • Referenced objects' attributes may themselves contain referenced objects (level 3, 4, etc.)
  • Cycles are possible (Object A references Object B, Object B references Object A)

Current Code Location:

  • backend/src/services/jiraAssetsClient.ts:222 - includeAttributesDeep=2
  • backend/src/services/jiraAssetsClient.ts:259-260 - Search with deep attributes
  • backend/src/services/jiraAssetsClient.ts:285-286 - POST search with deep attributes

Impact:

  • Response payloads can be very large (deeply nested)
  • Memory usage increases with depth
  • Parsing becomes more complex

2. Shallow Referenced Objects

Issue: When attributes[] is absent on a shallow referencedObject, do not wipe attributes.

Current Behavior:

  • Some code paths may clear attributes if attributes is missing
  • This is incorrect - absence of attributes array does not mean "no attributes"
  • It simply means "attributes not included in this response"

Critical Rule:

// ❌ WRONG: Don't do this
if (!referencedObject.attributes) {
  referencedObject.attributes = [];  // This wipes existing attributes!
}

// ✅ CORRECT: Preserve existing attributes if missing from response
if (referencedObject.attributes === undefined) {
  // Don't modify - attributes simply not included in this response
  // Keep any existing attributes that were previously loaded
}

Code Locations to Review:

  • backend/src/services/jiraAssetsClient.ts:parseObject() - Object parsing
  • backend/src/services/jiraAssetsClient.ts:parseAttributeValue() - Reference parsing
  • backend/src/services/normalizedCacheStore.ts:loadAttributeValues() - Reference reconstruction

3. Attribute Values Union Type

Issue: objectAttributeValues is a union type - different value representations based on attribute type.

Value Types:

  • Scalar (text, number, boolean): { value?: string, displayValue?: string }
  • Reference: { referencedObject?: { id, objectKey, label, attributes? } }
  • Status: { status?: { name: string } }
  • Date/Datetime: { value?: string } (ISO string)

Current Handling:

  • jiraAssetsClient.ts:parseAttributeValue() uses switch on attrDef.type
  • Different parsing logic for each type
  • Reference types extract referencedObject, others use value or displayValue

Code Location:

  • backend/src/services/jiraAssetsClient.ts:521-628 - parseAttributeValue() method

4. Cycles and Recursion Depth

Issue: Recursive references can create cycles.

Examples:

  • Application A references Team X
  • Team X references Application A (via some attribute)
  • This creates a cycle at depth 2

Current Handling:

  • No explicit cycle detection
  • includeAttributesDeep=2 limits depth but doesn't prevent cycles
  • Potential for infinite loops during reconstruction

Recommendation:

  • Add cycle detection during object reconstruction
  • Use visited set to track processed object IDs
  • Limit recursion depth explicitly (not just via API parameter)

Code Locations:

  • backend/src/services/normalizedCacheStore.ts:loadAttributeValues() - Reference resolution
  • backend/src/services/normalizedCacheStore.ts:reconstructObject() - Object reconstruction

Refactoring Considerations

  1. Create dedicated parser module for handling recursive payloads
  2. Add cycle detection utility
  3. Separate shallow vs deep parsing logic
  4. Preserve attribute state when attributes array is absent
  5. Document recursion depth limits clearly

Appendix: Module Dependency Graph

┌─────────────────────────────────────────────────────────┐
│                    API Routes                           │
│  (applications.ts, objects.ts, cache.ts, schema.ts)    │
└────────────┬────────────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────────┐
│                 Application Services                    │
│  (cmdbService.ts, dataService.ts)                      │
└────────────┬────────────────────────────────────────────┘
             │
    ┌────────┴────────┐
    ▼                 ▼
┌────────────┐  ┌──────────────────────────────┐
│  Sync      │  │     Normalized Cache Store   │
│  Engine    │  │     (EAV Pattern)            │
└─────┬──────┘  └──────────┬───────────────────┘
      │                    │
      │                    ▼
      │            ┌─────────────────┐
      │            │  Query Builder  │
      │            └─────────────────┘
      │
      ▼
┌─────────────────────────────────────────┐
│      Jira Assets Client                 │
│  (jiraAssetsClient.ts, jiraAssets.ts)   │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│      Schema Services                    │
│  (schemaDiscovery, schemaCache, etc.)   │
└─────────────────────────────────────────┘

Next Steps (Phase 2)

  1. Review and approve this plan
  2. Create detailed task breakdown for each migration step
  3. Set up feature branch for refactoring
  4. Implement changes incrementally with tests
  5. Update documentation as we go

End of Phase 1 - Analysis Document