@hamak/smart-data-dico 1.0.3 → 1.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.
- package/backend/dist/server.mjs +82212 -0
- package/bin/cli.js +28 -17
- package/frontend/dist/assets/index-1b53cffe.js +431 -0
- package/frontend/dist/assets/index-fa72a51a.css +1 -0
- package/frontend/dist/index.html +15 -0
- package/package.json +28 -27
- package/backend/package.json +0 -51
- package/backend/src/__tests__/integration/api.test.ts +0 -149
- package/backend/src/__tests__/setup.ts +0 -24
- package/backend/src/__tests__/utils/testUtils.ts +0 -76
- package/backend/src/adapters/EntityFileAdapter.ts +0 -154
- package/backend/src/adapters/YamlFileInfoEnricher.ts +0 -52
- package/backend/src/controllers/authController.ts +0 -131
- package/backend/src/controllers/diagramController.ts +0 -143
- package/backend/src/controllers/dictionaryController.ts +0 -306
- package/backend/src/controllers/importExportController.ts +0 -64
- package/backend/src/controllers/perspectiveController.ts +0 -90
- package/backend/src/controllers/serviceController.ts +0 -418
- package/backend/src/controllers/stereotypeController.ts +0 -59
- package/backend/src/controllers/versionController.ts +0 -226
- package/backend/src/kernel/config.ts +0 -43
- package/backend/src/middleware/auth.ts +0 -128
- package/backend/src/middleware/jwtAuth.ts +0 -100
- package/backend/src/models/Dictionary.ts +0 -38
- package/backend/src/models/EntitySchema.ts +0 -393
- package/backend/src/models/__tests__/Dictionary.test.ts +0 -92
- package/backend/src/models/__tests__/EntitySchema.test.ts +0 -119
- package/backend/src/routes/index.ts +0 -120
- package/backend/src/scripts/migrate-to-uuid.ts +0 -24
- package/backend/src/server.ts +0 -158
- package/backend/src/services/__mocks__/entityService.ts +0 -38
- package/backend/src/services/__mocks__/serviceService.ts +0 -88
- package/backend/src/services/__mocks__/versionService.ts +0 -38
- package/backend/src/services/__tests__/dictionaryService.test.ts +0 -74
- package/backend/src/services/diagramService.ts +0 -165
- package/backend/src/services/dictionaryService.ts +0 -582
- package/backend/src/services/entityService.ts +0 -102
- package/backend/src/services/exportService.ts +0 -172
- package/backend/src/services/importService.ts +0 -208
- package/backend/src/services/perspectiveService.ts +0 -276
- package/backend/src/services/qualityService.ts +0 -121
- package/backend/src/services/serviceService.ts +0 -763
- package/backend/src/services/stereotypeService.ts +0 -98
- package/backend/src/services/versionService.ts +0 -135
- package/backend/src/setupTests.ts +0 -12
- package/backend/src/utils/__mocks__/fileOperations.ts +0 -116
- package/backend/src/utils/fileOperations.ts +0 -602
- package/backend/src/utils/logger.ts +0 -38
- package/backend/src/utils/migration.ts +0 -254
- package/backend/src/utils/swagger.ts +0 -358
- package/backend/src/utils/uuid.ts +0 -41
- package/backend/tsconfig.json +0 -20
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import YAML from 'yaml';
|
|
4
|
-
import { logger } from './logger.js';
|
|
5
|
-
import { generateUUID, generateEntityFilename } from './uuid.js';
|
|
6
|
-
import { Entity, EntityAttribute, EntityRelationship, createEntityWithUUIDs } from '../models/EntitySchema.js';
|
|
7
|
-
|
|
8
|
-
const DATA_DICTIONARIES_DIR = path.join(process.cwd(), '..', 'data-dictionaries');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Migrates all existing entities to use UUIDs
|
|
12
|
-
*/
|
|
13
|
-
export async function migrateEntitiesToUUID(): Promise<void> {
|
|
14
|
-
logger.info('Starting migration of entities to UUID format...');
|
|
15
|
-
|
|
16
|
-
const microservicesDir = path.join(DATA_DICTIONARIES_DIR, 'microservices');
|
|
17
|
-
|
|
18
|
-
if (!fs.existsSync(microservicesDir)) {
|
|
19
|
-
logger.info('No microservices directory found, nothing to migrate');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const microservices = fs.readdirSync(microservicesDir)
|
|
24
|
-
.filter(item => fs.statSync(path.join(microservicesDir, item)).isDirectory());
|
|
25
|
-
|
|
26
|
-
let migratedCount = 0;
|
|
27
|
-
let skippedCount = 0;
|
|
28
|
-
|
|
29
|
-
for (const microservice of microservices) {
|
|
30
|
-
const microservicePath = path.join(microservicesDir, microservice);
|
|
31
|
-
const files = fs.readdirSync(microservicePath)
|
|
32
|
-
.filter(file => file.endsWith('.yaml') || file.endsWith('.yml'));
|
|
33
|
-
|
|
34
|
-
for (const file of files) {
|
|
35
|
-
const filePath = path.join(microservicePath, file);
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
39
|
-
const entity = YAML.parse(content) as any;
|
|
40
|
-
|
|
41
|
-
// Check if entity already has UUID
|
|
42
|
-
if (entity.uuid) {
|
|
43
|
-
logger.debug(`Entity ${entity.name} already has UUID, skipping`);
|
|
44
|
-
skippedCount++;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Migrate entity to UUID format
|
|
49
|
-
const migratedEntity = migrateEntityToUUID(entity);
|
|
50
|
-
|
|
51
|
-
// Write to new UUID-based filename
|
|
52
|
-
const newFilename = generateEntityFilename(migratedEntity.uuid, migratedEntity.name);
|
|
53
|
-
const newFilePath = path.join(microservicePath, newFilename);
|
|
54
|
-
|
|
55
|
-
const yamlContent = YAML.stringify(migratedEntity);
|
|
56
|
-
fs.writeFileSync(newFilePath, yamlContent, 'utf8');
|
|
57
|
-
|
|
58
|
-
// Remove old file if it has a different name
|
|
59
|
-
if (file !== newFilename) {
|
|
60
|
-
fs.unlinkSync(filePath);
|
|
61
|
-
logger.info(`Migrated ${microservice}/${entity.name}: ${file} -> ${newFilename}`);
|
|
62
|
-
} else {
|
|
63
|
-
logger.info(`Updated ${microservice}/${entity.name} with UUIDs`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
migratedCount++;
|
|
67
|
-
|
|
68
|
-
} catch (error) {
|
|
69
|
-
logger.error(`Error migrating entity file ${filePath}: ${error}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
logger.info(`Migration completed: ${migratedCount} entities migrated, ${skippedCount} entities skipped`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Migrates a single entity to UUID format
|
|
79
|
-
*/
|
|
80
|
-
function migrateEntityToUUID(entity: any): Entity {
|
|
81
|
-
// Generate UUID for entity if not present
|
|
82
|
-
if (!entity.uuid) {
|
|
83
|
-
entity.uuid = generateUUID();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Migrate attributes
|
|
87
|
-
if (entity.attributes) {
|
|
88
|
-
entity.attributes = entity.attributes.map((attr: any) => migrateAttributeToUUID(attr));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Migrate relationships
|
|
92
|
-
if (entity.relationships) {
|
|
93
|
-
entity.relationships = entity.relationships.map((rel: any) => migrateRelationshipToUUID(rel));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return entity as Entity;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Migrates a single attribute to UUID format
|
|
101
|
-
*/
|
|
102
|
-
function migrateAttributeToUUID(attr: any): EntityAttribute {
|
|
103
|
-
if (!attr.uuid) {
|
|
104
|
-
attr.uuid = generateUUID();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Migrate nested properties if they exist
|
|
108
|
-
if (attr.properties) {
|
|
109
|
-
attr.properties = Object.fromEntries(
|
|
110
|
-
Object.entries(attr.properties).map(([key, prop]: [string, any]) => [
|
|
111
|
-
key,
|
|
112
|
-
migrateAttributeToUUID(prop)
|
|
113
|
-
])
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Migrate items if they exist
|
|
118
|
-
if (attr.items) {
|
|
119
|
-
attr.items = migrateAttributeToUUID(attr.items);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return attr as EntityAttribute;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Migrates a single relationship to UUID format
|
|
127
|
-
*/
|
|
128
|
-
function migrateRelationshipToUUID(rel: any): EntityRelationship {
|
|
129
|
-
if (!rel.uuid) {
|
|
130
|
-
rel.uuid = generateUUID();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return rel as EntityRelationship;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Migrates diagram layouts to use entity UUIDs instead of IDs
|
|
138
|
-
*/
|
|
139
|
-
export async function migrateDiagramLayoutsToUUID(): Promise<void> {
|
|
140
|
-
logger.info('Starting migration of diagram layouts to UUID format...');
|
|
141
|
-
|
|
142
|
-
const diagramsDir = path.join(DATA_DICTIONARIES_DIR, 'diagrams');
|
|
143
|
-
|
|
144
|
-
if (!fs.existsSync(diagramsDir)) {
|
|
145
|
-
logger.info('No diagrams directory found, nothing to migrate');
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const files = fs.readdirSync(diagramsDir)
|
|
150
|
-
.filter(file => file.endsWith('.json'));
|
|
151
|
-
|
|
152
|
-
let migratedCount = 0;
|
|
153
|
-
|
|
154
|
-
// First, build a mapping of entity names to UUIDs
|
|
155
|
-
const entityNameToUUID = await buildEntityNameToUUIDMapping();
|
|
156
|
-
|
|
157
|
-
for (const file of files) {
|
|
158
|
-
const filePath = path.join(diagramsDir, file);
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
162
|
-
const layout = JSON.parse(content);
|
|
163
|
-
|
|
164
|
-
// Check if layout already uses UUIDs (UUIDs are 36 characters with dashes)
|
|
165
|
-
const entityKeys = Object.keys(layout.entities || {});
|
|
166
|
-
const hasUUIDs = entityKeys.some(key => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(key));
|
|
167
|
-
|
|
168
|
-
if (hasUUIDs) {
|
|
169
|
-
logger.debug(`Diagram layout ${file} already uses UUIDs, skipping`);
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Migrate entity references from IDs to UUIDs
|
|
174
|
-
const newEntities: any = {};
|
|
175
|
-
|
|
176
|
-
for (const [entityId, entityData] of Object.entries(layout.entities || {})) {
|
|
177
|
-
const uuid = entityNameToUUID.get(entityId);
|
|
178
|
-
if (uuid) {
|
|
179
|
-
newEntities[uuid] = {
|
|
180
|
-
...(entityData as any),
|
|
181
|
-
name: entityId // Add name for readability
|
|
182
|
-
};
|
|
183
|
-
} else {
|
|
184
|
-
logger.warn(`Could not find UUID for entity ID: ${entityId}`);
|
|
185
|
-
// Keep the original ID as fallback
|
|
186
|
-
newEntities[entityId] = entityData;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
layout.entities = newEntities;
|
|
191
|
-
|
|
192
|
-
// Write back the migrated layout
|
|
193
|
-
fs.writeFileSync(filePath, JSON.stringify(layout, null, 2), 'utf8');
|
|
194
|
-
logger.info(`Migrated diagram layout: ${file}`);
|
|
195
|
-
migratedCount++;
|
|
196
|
-
|
|
197
|
-
} catch (error) {
|
|
198
|
-
logger.error(`Error migrating diagram layout ${filePath}: ${error}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
logger.info(`Diagram layout migration completed: ${migratedCount} layouts migrated`);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Builds a mapping from entity names to UUIDs by reading all entity files
|
|
207
|
-
*/
|
|
208
|
-
async function buildEntityNameToUUIDMapping(): Promise<Map<string, string>> {
|
|
209
|
-
const mapping = new Map<string, string>();
|
|
210
|
-
|
|
211
|
-
const microservicesDir = path.join(DATA_DICTIONARIES_DIR, 'microservices');
|
|
212
|
-
|
|
213
|
-
if (!fs.existsSync(microservicesDir)) {
|
|
214
|
-
return mapping;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const microservices = fs.readdirSync(microservicesDir)
|
|
218
|
-
.filter(item => fs.statSync(path.join(microservicesDir, item)).isDirectory());
|
|
219
|
-
|
|
220
|
-
for (const microservice of microservices) {
|
|
221
|
-
const microservicePath = path.join(microservicesDir, microservice);
|
|
222
|
-
const files = fs.readdirSync(microservicePath)
|
|
223
|
-
.filter(file => file.endsWith('.yaml') || file.endsWith('.yml'));
|
|
224
|
-
|
|
225
|
-
for (const file of files) {
|
|
226
|
-
const filePath = path.join(microservicePath, file);
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
230
|
-
const entity = YAML.parse(content) as Entity;
|
|
231
|
-
|
|
232
|
-
if (entity.uuid && entity.id) {
|
|
233
|
-
mapping.set(entity.id, entity.uuid);
|
|
234
|
-
}
|
|
235
|
-
} catch (error) {
|
|
236
|
-
logger.warn(`Error reading entity file for mapping: ${filePath}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return mapping;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Runs all migrations
|
|
246
|
-
*/
|
|
247
|
-
export async function runAllMigrations(): Promise<void> {
|
|
248
|
-
logger.info('Starting all migrations...');
|
|
249
|
-
|
|
250
|
-
await migrateEntitiesToUUID();
|
|
251
|
-
await migrateDiagramLayoutsToUUID();
|
|
252
|
-
|
|
253
|
-
logger.info('All migrations completed');
|
|
254
|
-
}
|
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import swaggerJsdoc from 'swagger-jsdoc';
|
|
2
|
-
import swaggerUi from 'swagger-ui-express';
|
|
3
|
-
import { Express } from 'express';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Swagger definition options
|
|
7
|
-
*/
|
|
8
|
-
const options: swaggerJsdoc.Options = {
|
|
9
|
-
definition: {
|
|
10
|
-
openapi: '3.0.0',
|
|
11
|
-
info: {
|
|
12
|
-
title: 'Data Dictionary Management System API',
|
|
13
|
-
version: '1.0.0',
|
|
14
|
-
description: 'API documentation for the Data Dictionary Management System',
|
|
15
|
-
license: {
|
|
16
|
-
name: 'MIT',
|
|
17
|
-
url: 'https://opensource.org/licenses/MIT',
|
|
18
|
-
},
|
|
19
|
-
contact: {
|
|
20
|
-
name: 'API Support',
|
|
21
|
-
email: 'support@datadictionary.com',
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
servers: [
|
|
25
|
-
{
|
|
26
|
-
url: 'http://localhost:3001',
|
|
27
|
-
description: 'Development server',
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
components: {
|
|
31
|
-
securitySchemes: {
|
|
32
|
-
basicAuth: {
|
|
33
|
-
type: 'http',
|
|
34
|
-
scheme: 'basic',
|
|
35
|
-
description: 'Basic authentication with username and password',
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
schemas: {
|
|
39
|
-
Entity: {
|
|
40
|
-
type: 'object',
|
|
41
|
-
required: ['id', 'name', 'description', 'microservice', 'version', 'attributes'],
|
|
42
|
-
properties: {
|
|
43
|
-
id: {
|
|
44
|
-
type: 'string',
|
|
45
|
-
description: 'Unique identifier for the entity',
|
|
46
|
-
},
|
|
47
|
-
name: {
|
|
48
|
-
type: 'string',
|
|
49
|
-
description: 'Name of the entity',
|
|
50
|
-
},
|
|
51
|
-
description: {
|
|
52
|
-
type: 'string',
|
|
53
|
-
description: 'Description of the entity',
|
|
54
|
-
},
|
|
55
|
-
microservice: {
|
|
56
|
-
type: 'string',
|
|
57
|
-
description: 'Microservice that the entity belongs to',
|
|
58
|
-
},
|
|
59
|
-
version: {
|
|
60
|
-
type: 'string',
|
|
61
|
-
description: 'Version of the entity schema',
|
|
62
|
-
},
|
|
63
|
-
attributes: {
|
|
64
|
-
type: 'array',
|
|
65
|
-
description: 'List of attributes for the entity',
|
|
66
|
-
items: {
|
|
67
|
-
$ref: '#/components/schemas/EntityAttribute',
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
relationships: {
|
|
71
|
-
type: 'array',
|
|
72
|
-
description: 'List of relationships for the entity',
|
|
73
|
-
items: {
|
|
74
|
-
$ref: '#/components/schemas/EntityRelationship',
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
metadata: {
|
|
78
|
-
type: 'object',
|
|
79
|
-
description: 'Additional metadata for the entity',
|
|
80
|
-
},
|
|
81
|
-
createdAt: {
|
|
82
|
-
type: 'string',
|
|
83
|
-
format: 'date-time',
|
|
84
|
-
description: 'Timestamp when the entity was created',
|
|
85
|
-
},
|
|
86
|
-
updatedAt: {
|
|
87
|
-
type: 'string',
|
|
88
|
-
format: 'date-time',
|
|
89
|
-
description: 'Timestamp when the entity was last updated',
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
EntityAttribute: {
|
|
94
|
-
type: 'object',
|
|
95
|
-
required: ['name', 'description', 'type', 'required'],
|
|
96
|
-
properties: {
|
|
97
|
-
name: {
|
|
98
|
-
type: 'string',
|
|
99
|
-
description: 'Name of the attribute',
|
|
100
|
-
},
|
|
101
|
-
description: {
|
|
102
|
-
type: 'string',
|
|
103
|
-
description: 'Description of the attribute',
|
|
104
|
-
},
|
|
105
|
-
type: {
|
|
106
|
-
type: 'string',
|
|
107
|
-
description: 'Data type of the attribute',
|
|
108
|
-
enum: ['string', 'number', 'integer', 'boolean', 'datetime', 'date', 'time', 'enum', 'object', 'array', 'reference'],
|
|
109
|
-
},
|
|
110
|
-
required: {
|
|
111
|
-
type: 'boolean',
|
|
112
|
-
description: 'Whether the attribute is required',
|
|
113
|
-
},
|
|
114
|
-
unique: {
|
|
115
|
-
type: 'boolean',
|
|
116
|
-
description: 'Whether the attribute value must be unique',
|
|
117
|
-
},
|
|
118
|
-
defaultValue: {
|
|
119
|
-
description: 'Default value for the attribute',
|
|
120
|
-
},
|
|
121
|
-
examples: {
|
|
122
|
-
type: 'array',
|
|
123
|
-
description: 'Example values for the attribute',
|
|
124
|
-
items: {
|
|
125
|
-
type: 'string',
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
minLength: {
|
|
129
|
-
type: 'integer',
|
|
130
|
-
description: 'Minimum length for string attributes',
|
|
131
|
-
},
|
|
132
|
-
maxLength: {
|
|
133
|
-
type: 'integer',
|
|
134
|
-
description: 'Maximum length for string attributes',
|
|
135
|
-
},
|
|
136
|
-
pattern: {
|
|
137
|
-
type: 'string',
|
|
138
|
-
description: 'Regex pattern for string attributes',
|
|
139
|
-
},
|
|
140
|
-
format: {
|
|
141
|
-
type: 'string',
|
|
142
|
-
description: 'Format for the attribute (e.g., email, uuid)',
|
|
143
|
-
},
|
|
144
|
-
minimum: {
|
|
145
|
-
type: 'number',
|
|
146
|
-
description: 'Minimum value for number attributes',
|
|
147
|
-
},
|
|
148
|
-
maximum: {
|
|
149
|
-
type: 'number',
|
|
150
|
-
description: 'Maximum value for number attributes',
|
|
151
|
-
},
|
|
152
|
-
precision: {
|
|
153
|
-
type: 'integer',
|
|
154
|
-
description: 'Precision for number attributes',
|
|
155
|
-
},
|
|
156
|
-
scale: {
|
|
157
|
-
type: 'integer',
|
|
158
|
-
description: 'Scale for number attributes',
|
|
159
|
-
},
|
|
160
|
-
enumValues: {
|
|
161
|
-
type: 'array',
|
|
162
|
-
description: 'Possible values for enum attributes',
|
|
163
|
-
items: {
|
|
164
|
-
type: 'string',
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
metadata: {
|
|
168
|
-
type: 'object',
|
|
169
|
-
description: 'Additional metadata for the attribute',
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
EntityRelationship: {
|
|
174
|
-
type: 'object',
|
|
175
|
-
required: ['name', 'description', 'type', 'target', 'required'],
|
|
176
|
-
properties: {
|
|
177
|
-
name: {
|
|
178
|
-
type: 'string',
|
|
179
|
-
description: 'Name of the relationship',
|
|
180
|
-
},
|
|
181
|
-
description: {
|
|
182
|
-
type: 'string',
|
|
183
|
-
description: 'Description of the relationship',
|
|
184
|
-
},
|
|
185
|
-
type: {
|
|
186
|
-
type: 'string',
|
|
187
|
-
description: 'Type of the relationship',
|
|
188
|
-
enum: ['hasOne', 'hasMany', 'belongsTo', 'manyToMany'],
|
|
189
|
-
},
|
|
190
|
-
target: {
|
|
191
|
-
type: 'string',
|
|
192
|
-
description: 'Target entity of the relationship (format: microservice.entity)',
|
|
193
|
-
},
|
|
194
|
-
inverseName: {
|
|
195
|
-
type: 'string',
|
|
196
|
-
description: 'Name of the inverse relationship in the target entity',
|
|
197
|
-
},
|
|
198
|
-
required: {
|
|
199
|
-
type: 'boolean',
|
|
200
|
-
description: 'Whether the relationship is required',
|
|
201
|
-
},
|
|
202
|
-
foreignKey: {
|
|
203
|
-
type: 'string',
|
|
204
|
-
description: 'Foreign key attribute name',
|
|
205
|
-
},
|
|
206
|
-
metadata: {
|
|
207
|
-
type: 'object',
|
|
208
|
-
description: 'Additional metadata for the relationship',
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
GraphData: {
|
|
213
|
-
type: 'object',
|
|
214
|
-
properties: {
|
|
215
|
-
nodes: {
|
|
216
|
-
type: 'array',
|
|
217
|
-
items: {
|
|
218
|
-
$ref: '#/components/schemas/GraphNode',
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
edges: {
|
|
222
|
-
type: 'array',
|
|
223
|
-
items: {
|
|
224
|
-
$ref: '#/components/schemas/GraphEdge',
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
GraphNode: {
|
|
230
|
-
type: 'object',
|
|
231
|
-
properties: {
|
|
232
|
-
id: {
|
|
233
|
-
type: 'string',
|
|
234
|
-
description: 'Unique identifier for the node',
|
|
235
|
-
},
|
|
236
|
-
label: {
|
|
237
|
-
type: 'string',
|
|
238
|
-
description: 'Label for the node',
|
|
239
|
-
},
|
|
240
|
-
type: {
|
|
241
|
-
type: 'string',
|
|
242
|
-
description: 'Type of the node',
|
|
243
|
-
},
|
|
244
|
-
service: {
|
|
245
|
-
type: 'string',
|
|
246
|
-
description: 'Service that the node belongs to',
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
GraphEdge: {
|
|
251
|
-
type: 'object',
|
|
252
|
-
properties: {
|
|
253
|
-
id: {
|
|
254
|
-
type: 'string',
|
|
255
|
-
description: 'Unique identifier for the edge',
|
|
256
|
-
},
|
|
257
|
-
source: {
|
|
258
|
-
type: 'string',
|
|
259
|
-
description: 'Source node ID',
|
|
260
|
-
},
|
|
261
|
-
target: {
|
|
262
|
-
type: 'string',
|
|
263
|
-
description: 'Target node ID',
|
|
264
|
-
},
|
|
265
|
-
label: {
|
|
266
|
-
type: 'string',
|
|
267
|
-
description: 'Label for the edge',
|
|
268
|
-
},
|
|
269
|
-
type: {
|
|
270
|
-
type: 'string',
|
|
271
|
-
description: 'Type of the edge',
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
CommitInfo: {
|
|
276
|
-
type: 'object',
|
|
277
|
-
properties: {
|
|
278
|
-
hash: {
|
|
279
|
-
type: 'string',
|
|
280
|
-
description: 'Commit hash',
|
|
281
|
-
},
|
|
282
|
-
date: {
|
|
283
|
-
type: 'string',
|
|
284
|
-
description: 'Commit date',
|
|
285
|
-
},
|
|
286
|
-
message: {
|
|
287
|
-
type: 'string',
|
|
288
|
-
description: 'Commit message',
|
|
289
|
-
},
|
|
290
|
-
author_name: {
|
|
291
|
-
type: 'string',
|
|
292
|
-
description: 'Author name',
|
|
293
|
-
},
|
|
294
|
-
author_email: {
|
|
295
|
-
type: 'string',
|
|
296
|
-
description: 'Author email',
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
SearchResult: {
|
|
301
|
-
type: 'object',
|
|
302
|
-
properties: {
|
|
303
|
-
type: {
|
|
304
|
-
type: 'string',
|
|
305
|
-
enum: ['entity', 'attribute'],
|
|
306
|
-
description: 'Type of search result',
|
|
307
|
-
},
|
|
308
|
-
service: {
|
|
309
|
-
type: 'string',
|
|
310
|
-
description: 'Service name',
|
|
311
|
-
},
|
|
312
|
-
entityName: {
|
|
313
|
-
type: 'string',
|
|
314
|
-
description: 'Entity name',
|
|
315
|
-
},
|
|
316
|
-
attributeName: {
|
|
317
|
-
type: 'string',
|
|
318
|
-
description: 'Attribute name (for attribute results)',
|
|
319
|
-
},
|
|
320
|
-
description: {
|
|
321
|
-
type: 'string',
|
|
322
|
-
description: 'Description of the entity or attribute',
|
|
323
|
-
},
|
|
324
|
-
path: {
|
|
325
|
-
type: 'string',
|
|
326
|
-
description: 'Path to the entity or attribute',
|
|
327
|
-
},
|
|
328
|
-
score: {
|
|
329
|
-
type: 'number',
|
|
330
|
-
description: 'Search relevance score',
|
|
331
|
-
},
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
apis: ['./src/routes/*.ts', './src/controllers/*.ts'],
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Swagger specification
|
|
342
|
-
*/
|
|
343
|
-
const swaggerSpec = swaggerJsdoc(options);
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Configure Swagger middleware for Express
|
|
347
|
-
* @param app Express application
|
|
348
|
-
*/
|
|
349
|
-
export const setupSwagger = (app: Express): void => {
|
|
350
|
-
// Swagger UI route
|
|
351
|
-
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
|
352
|
-
|
|
353
|
-
// Swagger JSON route
|
|
354
|
-
app.get('/api-docs.json', (req, res) => {
|
|
355
|
-
res.setHeader('Content-Type', 'application/json');
|
|
356
|
-
res.send(swaggerSpec);
|
|
357
|
-
});
|
|
358
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a UUID v4
|
|
5
|
-
* @returns A new UUID string
|
|
6
|
-
*/
|
|
7
|
-
export function generateUUID(): string {
|
|
8
|
-
return randomUUID();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Validates if a string is a valid UUID
|
|
13
|
-
* @param uuid String to validate
|
|
14
|
-
* @returns True if valid UUID
|
|
15
|
-
*/
|
|
16
|
-
export function isValidUUID(uuid: string): boolean {
|
|
17
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
18
|
-
return uuidRegex.test(uuid);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Generates a human-readable filename using UUID and name
|
|
23
|
-
* @param uuid The UUID of the entity
|
|
24
|
-
* @param name The name of the entity
|
|
25
|
-
* @returns A filename in format: uuid_name.yaml
|
|
26
|
-
*/
|
|
27
|
-
export function generateEntityFilename(uuid: string, name: string): string {
|
|
28
|
-
// Sanitize name for filename (remove special characters, replace spaces with underscores)
|
|
29
|
-
const sanitizedName = name.replace(/[^a-zA-Z0-9\s]/g, '').replace(/\s+/g, '_');
|
|
30
|
-
return `${uuid}_${sanitizedName}.yaml`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Extracts UUID from a filename
|
|
35
|
-
* @param filename The filename to extract UUID from
|
|
36
|
-
* @returns The UUID or null if not found
|
|
37
|
-
*/
|
|
38
|
-
export function extractUUIDFromFilename(filename: string): string | null {
|
|
39
|
-
const match = filename.match(/^([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/i);
|
|
40
|
-
return match ? match[1] : null;
|
|
41
|
-
}
|
package/backend/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": ["ES2020"],
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"resolveJsonModule": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"isolatedModules": true,
|
|
16
|
-
"types": ["node", "jest"]
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*"],
|
|
19
|
-
"exclude": ["node_modules"]
|
|
20
|
-
}
|