@hamak/smart-data-dico 1.0.4 → 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/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,120 +0,0 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
|
-
|
|
3
|
-
import { getCurrentUser, login } from '../controllers/authController.js';
|
|
4
|
-
import { diagramController } from '../controllers/diagramController.js';
|
|
5
|
-
import { createDictionary, getDictionaries, getDictionaryById, getDictionaryEntries, getEntityAttributes, getPackageByPath, getPackageHierarchy, getRelatedEntities, getTabularData, saveEntity, listAllPackagesAndEntities, getFlatEntitiesAndAttributes, getEntityHierarchy, createRootPackage, createPackageAtPath, updatePackageAtPath, deletePackageAtPath } from '../controllers/dictionaryController.js';
|
|
6
|
-
import { createEntity, deleteEntity, getAllServices, getEntitySchema, getGraphData, getServiceEntities, searchEntities, updateEntity, getPackageRelationships, createRelationship, updateRelationship, deleteRelationship, getImpactAnalysis, getLineage, submitEntity, approveEntity, returnEntity, getEntityComments, addEntityComment, resolveEntityComment } from '../controllers/serviceController.js';
|
|
7
|
-
import { getAllStereotypes, getStereotype, createStereotype, updateStereotype, deleteStereotype } from '../controllers/stereotypeController.js';
|
|
8
|
-
import { getAllPerspectives, getPerspective, createPerspective, updatePerspective, deletePerspective, resolvePerspective, getPerspectiveGraph, upsertPerspectiveNode } from '../controllers/perspectiveController.js';
|
|
9
|
-
import { commitChanges, getCommitHistory, revertToCommit } from '../controllers/versionController.js';
|
|
10
|
-
import { importJsonSchema, importSqlDdl, exportJsonSchema, exportMarkdown, getQualityReport } from '../controllers/importExportController.js';
|
|
11
|
-
import { authenticate, UserRole } from '../middleware/auth.js';
|
|
12
|
-
import { authorizeJwt, verifyToken } from '../middleware/jwtAuth.js';
|
|
13
|
-
|
|
14
|
-
const router = Router();
|
|
15
|
-
|
|
16
|
-
// API status route
|
|
17
|
-
router.get('/api/status', (req, res) => {
|
|
18
|
-
res.json({ status: 'operational' });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
router.get('/api/packages/hierarchy/:rootPackage', getPackageHierarchy);
|
|
22
|
-
router.get('/api/packages/tabular/:rootPackage', getTabularData);
|
|
23
|
-
|
|
24
|
-
// Package CRUD routes
|
|
25
|
-
router.post('/api/packages', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createRootPackage);
|
|
26
|
-
router.post('/api/packages/:rootPackage/subpackages/*', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createPackageAtPath);
|
|
27
|
-
router.put('/api/packages/:rootPackage/path/*', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), updatePackageAtPath);
|
|
28
|
-
router.delete('/api/packages/:rootPackage/path/*', authorizeJwt([UserRole.ADMIN]), deletePackageAtPath);
|
|
29
|
-
|
|
30
|
-
router.get('/api/packages/:rootPackage/path/*', getPackageByPath);
|
|
31
|
-
|
|
32
|
-
// Auth routes
|
|
33
|
-
router.post('/api/auth/login', login);
|
|
34
|
-
router.get('/api/auth/me', verifyToken, getCurrentUser);
|
|
35
|
-
|
|
36
|
-
// Legacy Dictionary routes
|
|
37
|
-
router.get('/api/dictionaries', getDictionaries);
|
|
38
|
-
router.post('/api/dictionaries', createDictionary);
|
|
39
|
-
router.get('/api/dictionaries/:id', getDictionaryById);
|
|
40
|
-
router.get('/api/dictionaries/:id/entries', getDictionaryEntries);
|
|
41
|
-
router.get('/api/entities/:microservice/:entityName/attributes', getEntityAttributes);
|
|
42
|
-
router.get('/api/entities/:microservice/:entityName/related', getRelatedEntities);
|
|
43
|
-
router.post('/api/entities', saveEntity);
|
|
44
|
-
|
|
45
|
-
// Data Dictionary/Entity/Package API extensions
|
|
46
|
-
router.get('/api/packages/all', listAllPackagesAndEntities);
|
|
47
|
-
router.get('/api/entities/flat', getFlatEntitiesAndAttributes);
|
|
48
|
-
router.get('/api/entities/hierarchy/:microservice/:entityName', getEntityHierarchy);
|
|
49
|
-
|
|
50
|
-
// New Service/Entity API routes
|
|
51
|
-
router.get('/api/services', getAllServices);
|
|
52
|
-
router.get('/api/services/:service/entities', getServiceEntities);
|
|
53
|
-
router.get('/api/services/:service/entities/:entity', getEntitySchema);
|
|
54
|
-
router.post('/api/services/:service/entities', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createEntity);
|
|
55
|
-
router.put('/api/services/:service/entities/:entity', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), updateEntity);
|
|
56
|
-
router.delete('/api/services/:service/entities/:entity', authorizeJwt([UserRole.ADMIN]), deleteEntity);
|
|
57
|
-
|
|
58
|
-
// Entity review workflow
|
|
59
|
-
router.post('/api/services/:service/entities/:entity/submit', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), submitEntity);
|
|
60
|
-
router.post('/api/services/:service/entities/:entity/approve', authorizeJwt([UserRole.ADMIN]), approveEntity);
|
|
61
|
-
router.post('/api/services/:service/entities/:entity/return', authorizeJwt([UserRole.ADMIN]), returnEntity);
|
|
62
|
-
router.get('/api/services/:service/entities/:entity/comments', getEntityComments);
|
|
63
|
-
router.post('/api/services/:service/entities/:entity/comments', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), addEntityComment);
|
|
64
|
-
router.put('/api/services/:service/entities/:entity/comments/:id', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), resolveEntityComment);
|
|
65
|
-
|
|
66
|
-
// Package-level relationship CRUD routes
|
|
67
|
-
router.get('/api/packages/:packageName/relationships', getPackageRelationships);
|
|
68
|
-
router.post('/api/packages/:packageName/relationships', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createRelationship);
|
|
69
|
-
router.put('/api/packages/:packageName/relationships/:uuid', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), updateRelationship);
|
|
70
|
-
router.delete('/api/packages/:packageName/relationships/:uuid', authorizeJwt([UserRole.ADMIN]), deleteRelationship);
|
|
71
|
-
|
|
72
|
-
// Stereotype API
|
|
73
|
-
router.get('/api/stereotypes', getAllStereotypes);
|
|
74
|
-
router.get('/api/stereotypes/:id', getStereotype);
|
|
75
|
-
router.post('/api/stereotypes', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createStereotype);
|
|
76
|
-
router.put('/api/stereotypes/:id', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), updateStereotype);
|
|
77
|
-
router.delete('/api/stereotypes/:id', authorizeJwt([UserRole.ADMIN]), deleteStereotype);
|
|
78
|
-
|
|
79
|
-
// Perspective API
|
|
80
|
-
router.get('/api/perspectives', getAllPerspectives);
|
|
81
|
-
router.get('/api/perspectives/:id', getPerspective);
|
|
82
|
-
router.post('/api/perspectives', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), createPerspective);
|
|
83
|
-
router.put('/api/perspectives/:id', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), updatePerspective);
|
|
84
|
-
router.delete('/api/perspectives/:id', authorizeJwt([UserRole.ADMIN]), deletePerspective);
|
|
85
|
-
router.get('/api/perspectives/:id/resolve', resolvePerspective);
|
|
86
|
-
router.get('/api/perspectives/:id/graph', getPerspectiveGraph);
|
|
87
|
-
router.put('/api/perspectives/:id/nodes', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), upsertPerspectiveNode);
|
|
88
|
-
|
|
89
|
-
// Search API
|
|
90
|
-
router.get('/api/search', searchEntities);
|
|
91
|
-
|
|
92
|
-
// Impact analysis & lineage
|
|
93
|
-
router.get('/api/entities/:uuid/impact', getImpactAnalysis);
|
|
94
|
-
router.get('/api/entities/:uuid/lineage', getLineage);
|
|
95
|
-
|
|
96
|
-
// Import/Export
|
|
97
|
-
router.post('/api/import/json-schema', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), importJsonSchema);
|
|
98
|
-
router.post('/api/import/sql-ddl', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), importSqlDdl);
|
|
99
|
-
router.get('/api/export/json-schema/:service', exportJsonSchema);
|
|
100
|
-
router.get('/api/export/markdown/:service', exportMarkdown);
|
|
101
|
-
|
|
102
|
-
// Quality
|
|
103
|
-
router.get('/api/quality/report', getQualityReport);
|
|
104
|
-
|
|
105
|
-
// Graph API for visualization
|
|
106
|
-
router.get('/api/graph/:service', getGraphData);
|
|
107
|
-
|
|
108
|
-
// Version control API
|
|
109
|
-
router.post('/api/commit', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), commitChanges);
|
|
110
|
-
router.get('/api/history', getCommitHistory);
|
|
111
|
-
router.post('/api/revert', authorizeJwt([UserRole.ADMIN]), revertToCommit);
|
|
112
|
-
|
|
113
|
-
// Diagram layout API
|
|
114
|
-
router.get('/api/diagrams', diagramController.listDiagramLayouts.bind(diagramController));
|
|
115
|
-
router.post('/api/diagrams', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), diagramController.saveDiagramLayout.bind(diagramController));
|
|
116
|
-
router.get('/api/diagrams/:id', diagramController.loadDiagramLayout.bind(diagramController));
|
|
117
|
-
router.put('/api/diagrams/:id', authorizeJwt([UserRole.ADMIN, UserRole.EDITOR]), diagramController.updateDiagramLayout.bind(diagramController));
|
|
118
|
-
router.delete('/api/diagrams/:id', authorizeJwt([UserRole.ADMIN]), diagramController.deleteDiagramLayout.bind(diagramController));
|
|
119
|
-
|
|
120
|
-
export default router;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ts-node
|
|
2
|
-
|
|
3
|
-
import { runAllMigrations } from '../utils/migration.js';
|
|
4
|
-
import { logger } from '../utils/logger.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Migration script to convert existing entities to UUID format
|
|
8
|
-
*/
|
|
9
|
-
async function main() {
|
|
10
|
-
try {
|
|
11
|
-
logger.info('Starting migration to UUID format...');
|
|
12
|
-
await runAllMigrations();
|
|
13
|
-
logger.info('Migration completed successfully!');
|
|
14
|
-
process.exit(0);
|
|
15
|
-
} catch (error) {
|
|
16
|
-
logger.error('Migration failed:', error);
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Run the migration if this script is executed directly
|
|
22
|
-
if (require.main === module) {
|
|
23
|
-
main();
|
|
24
|
-
}
|
package/backend/src/server.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import express, { Request, Response } from 'express';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import cors from 'cors';
|
|
5
|
-
import dotenv from 'dotenv';
|
|
6
|
-
import routes from './routes/index.js';
|
|
7
|
-
import { setupSwagger } from './utils/swagger.js';
|
|
8
|
-
import { logger } from './utils/logger.js';
|
|
9
|
-
import { config } from './kernel/config.js';
|
|
10
|
-
import { initializeFileSystem, getFileRouter } from './adapters/EntityFileAdapter.js';
|
|
11
|
-
import { createYamlFileInfoEnricher } from './adapters/YamlFileInfoEnricher.js';
|
|
12
|
-
|
|
13
|
-
// Load environment variables
|
|
14
|
-
dotenv.config();
|
|
15
|
-
|
|
16
|
-
// Initialize Express app
|
|
17
|
-
const app = express();
|
|
18
|
-
const port = config.port;
|
|
19
|
-
|
|
20
|
-
// Middleware
|
|
21
|
-
app.use(cors());
|
|
22
|
-
// Access logging middleware
|
|
23
|
-
app.use((req: Request, res: Response, next) => {
|
|
24
|
-
const start = process.hrtime();
|
|
25
|
-
res.on('finish', () => {
|
|
26
|
-
const diff = process.hrtime(start);
|
|
27
|
-
const executionTimeMs = Number((diff[0] * 1e3 + diff[1] / 1e6).toFixed(2));
|
|
28
|
-
logger.info('HTTP Access', {
|
|
29
|
-
method: req.method,
|
|
30
|
-
path: req.originalUrl,
|
|
31
|
-
status: res.statusCode,
|
|
32
|
-
executionTimeMs
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
next();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
app.use(express.json());
|
|
39
|
-
|
|
40
|
-
// API welcome route (only in dev — production serves frontend at /)
|
|
41
|
-
if (!config.isProduction) {
|
|
42
|
-
app.get('/', (req: Request, res: Response) => {
|
|
43
|
-
res.json({ message: 'Welcome to the Data Dictionary Management System API' });
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Health check endpoint
|
|
48
|
-
app.get('/health', (req: Request, res: Response) => {
|
|
49
|
-
res.json({ status: 'ok' });
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// API routes
|
|
53
|
-
app.use(routes);
|
|
54
|
-
|
|
55
|
-
// Setup Swagger documentation
|
|
56
|
-
setupSwagger(app);
|
|
57
|
-
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// Framework Filesystem & Git Routes (Phase 1)
|
|
60
|
-
// =============================================================================
|
|
61
|
-
|
|
62
|
-
async function mountFrameworkRoutes() {
|
|
63
|
-
try {
|
|
64
|
-
// Initialize filesystem framework
|
|
65
|
-
const { enricherRegistry } = await initializeFileSystem();
|
|
66
|
-
|
|
67
|
-
// Register YAML entity enricher
|
|
68
|
-
const yamlEnricher = createYamlFileInfoEnricher();
|
|
69
|
-
enricherRegistry.register(yamlEnricher);
|
|
70
|
-
|
|
71
|
-
// Initialize git service and routes
|
|
72
|
-
try {
|
|
73
|
-
const gitModule = await import('@hamak/ui-remote-git-fs-backend');
|
|
74
|
-
const workspaceRoots = new Map<string, string>([
|
|
75
|
-
['dictionaries', config.dataDir],
|
|
76
|
-
]);
|
|
77
|
-
|
|
78
|
-
const gitService = gitModule.createGitService(workspaceRoots);
|
|
79
|
-
const gitEnricher = gitModule.createGitFileInfoEnricher({
|
|
80
|
-
gitService,
|
|
81
|
-
workspaceRoots,
|
|
82
|
-
});
|
|
83
|
-
enricherRegistry.register(gitEnricher);
|
|
84
|
-
|
|
85
|
-
const gitRoutes = gitModule.createGitRoutes({ gitService, debug: !config.isProduction });
|
|
86
|
-
app.use('/api/git', gitRoutes as any);
|
|
87
|
-
app.use('/api/git', gitModule.gitErrorHandler as any);
|
|
88
|
-
|
|
89
|
-
logger.info('Git routes mounted at /api/git');
|
|
90
|
-
} catch (gitError) {
|
|
91
|
-
logger.warn(`Git integration not available: ${gitError}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Mount filesystem routes
|
|
95
|
-
const fsRouter = getFileRouter();
|
|
96
|
-
app.use('/fs', fsRouter);
|
|
97
|
-
|
|
98
|
-
logger.info('Filesystem routes mounted at /fs');
|
|
99
|
-
} catch (error) {
|
|
100
|
-
logger.warn(`Framework filesystem not initialized: ${error}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Mount framework routes (non-blocking — existing routes work regardless)
|
|
105
|
-
mountFrameworkRoutes().catch((err) => {
|
|
106
|
-
logger.warn(`Failed to mount framework routes: ${err}`);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// Serve frontend static files in production (BEFORE error handler)
|
|
111
|
-
if (config.isProduction) {
|
|
112
|
-
// Check multiple possible frontend dist locations
|
|
113
|
-
const candidates = [
|
|
114
|
-
path.join(process.cwd(), 'public'), // Docker (copied to public/)
|
|
115
|
-
path.join(process.cwd(), '..', 'frontend', 'dist'), // npm package / monorepo
|
|
116
|
-
path.join(process.cwd(), 'frontend', 'dist'), // alt layout
|
|
117
|
-
];
|
|
118
|
-
const publicDir = candidates.find(d => {
|
|
119
|
-
try { return fs.statSync(d).isDirectory(); } catch { return false; }
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (publicDir) {
|
|
123
|
-
app.use(express.static(publicDir));
|
|
124
|
-
// SPA fallback — only for navigation requests, not assets/API
|
|
125
|
-
app.get('*', (req, res, next) => {
|
|
126
|
-
if (req.path.startsWith('/api') || req.path.startsWith('/fs') || req.path.startsWith('/api-docs') || req.path.includes('.')) {
|
|
127
|
-
return next();
|
|
128
|
-
}
|
|
129
|
-
res.sendFile(path.join(publicDir, 'index.html'));
|
|
130
|
-
});
|
|
131
|
-
logger.info(`Serving frontend from ${publicDir}`);
|
|
132
|
-
} else {
|
|
133
|
-
logger.warn('Frontend dist not found. API-only mode.');
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Error handling middleware (after static files)
|
|
138
|
-
app.use((err: any, req: Request, res: Response, _next: any) => {
|
|
139
|
-
logger.error(`Unhandled error: ${err.message}`);
|
|
140
|
-
res.status(500).json({
|
|
141
|
-
message: 'Internal server error',
|
|
142
|
-
error: config.isProduction ? undefined : err.message
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// Start server only when run directly (not when imported by tests)
|
|
147
|
-
const isMainModule = process.argv[1] && (
|
|
148
|
-
process.argv[1].endsWith('server.ts') || process.argv[1].endsWith('server.js')
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
if (isMainModule) {
|
|
152
|
-
app.listen(port, () => {
|
|
153
|
-
logger.info(`Server running on port ${port}`);
|
|
154
|
-
logger.info(`API documentation available at http://localhost:${port}/api-docs`);
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export default app;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Entity, AttributeType } from '../../models/EntitySchema.js';
|
|
2
|
-
|
|
3
|
-
const mockEntities: Record<string, Entity> = {
|
|
4
|
-
'user-service.User': {
|
|
5
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
6
|
-
name: 'User',
|
|
7
|
-
description: 'User entity',
|
|
8
|
-
attributes: [
|
|
9
|
-
{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', description: 'User ID', type: AttributeType.STRING, required: true, primaryKey: true },
|
|
10
|
-
{ uuid: 'c5af3719-ee6f-4156-bb1a-e575d345f7a5', name: 'email', description: 'User email', type: AttributeType.STRING, required: true },
|
|
11
|
-
],
|
|
12
|
-
} as Entity,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// Mock entity service matching actual EntityService API
|
|
16
|
-
class EntityServiceMock {
|
|
17
|
-
validateEntity(entity: Entity) {
|
|
18
|
-
return { valid: true, errors: [] as string[] };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async validateRelationships(packageName: string, relationships: any[]) {
|
|
22
|
-
return { valid: true, errors: [] as string[] };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async saveEntity(entity: Entity, packageName: string) {
|
|
26
|
-
return { success: true, errors: [] as string[] };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async getEntity(packageName: string, entityName: string): Promise<Entity | null> {
|
|
30
|
-
return mockEntities[`${packageName}.${entityName}`] || null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async getRelatedEntities(packageName: string, entityName: string): Promise<Entity[]> {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const entityService = new EntityServiceMock();
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { AttributeType } from '../../models/EntitySchema.js';
|
|
2
|
-
|
|
3
|
-
// Mock service service matching actual ServiceService API
|
|
4
|
-
class ServiceServiceMock {
|
|
5
|
-
async getAllServices(): Promise<string[]> {
|
|
6
|
-
return ['user-service', 'product-service', 'order-service'];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async getServiceEntities(service: string) {
|
|
10
|
-
const serviceEntities: Record<string, any[]> = {
|
|
11
|
-
'user-service': [
|
|
12
|
-
{
|
|
13
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
14
|
-
name: 'User', description: 'User entity',
|
|
15
|
-
attributes: [
|
|
16
|
-
{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', description: 'User ID', type: AttributeType.STRING, required: true, primaryKey: true },
|
|
17
|
-
{ uuid: 'c5af3719-ee6f-4156-bb1a-e575d345f7a5', name: 'email', description: 'User email', type: AttributeType.STRING, required: true },
|
|
18
|
-
],
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
|
-
'product-service': [],
|
|
22
|
-
'order-service': [],
|
|
23
|
-
};
|
|
24
|
-
return serviceEntities[service] || [];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async getEntitySchema(service: string, entity: string) {
|
|
28
|
-
if (service === 'user-service' && entity === 'User') {
|
|
29
|
-
return {
|
|
30
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
31
|
-
name: 'User', description: 'User entity',
|
|
32
|
-
attributes: [
|
|
33
|
-
{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', description: 'User ID', type: AttributeType.STRING, required: true, primaryKey: true },
|
|
34
|
-
{ uuid: 'c5af3719-ee6f-4156-bb1a-e575d345f7a5', name: 'email', description: 'User email', type: AttributeType.STRING, required: true },
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async createEntity(service: string, entity: any) {
|
|
42
|
-
return { success: true, errors: [] };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async updateEntity(service: string, entity: any) {
|
|
46
|
-
return { success: true, errors: [] };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async deleteEntity(service: string, entityName: string) {
|
|
50
|
-
return { success: true, errors: [] };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async searchEntities(query: string) {
|
|
54
|
-
return [
|
|
55
|
-
{ entity: 'User', service: 'user-service', matches: ['name', 'description'] },
|
|
56
|
-
];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async getGraphData(service: string) {
|
|
60
|
-
return {
|
|
61
|
-
nodes: [
|
|
62
|
-
{ id: 'User', label: 'User', type: 'entity' },
|
|
63
|
-
{ id: 'Profile', label: 'Profile', type: 'entity' },
|
|
64
|
-
],
|
|
65
|
-
edges: [
|
|
66
|
-
{ source: 'User', target: 'Profile', label: 'hasOne' },
|
|
67
|
-
],
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async getPackageRelationships(packageName: string) {
|
|
72
|
-
return [];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async createRelationship(packageName: string, relationship: any) {
|
|
76
|
-
return { success: true, errors: [], relationship };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async updateRelationship(packageName: string, uuid: string, relationship: any) {
|
|
80
|
-
return { success: true, errors: [] };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async deleteRelationship(packageName: string, uuid: string) {
|
|
84
|
-
return { success: true, errors: [] };
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export const serviceService = new ServiceServiceMock();
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Mock version service matching actual VersionService API
|
|
2
|
-
class VersionServiceMock {
|
|
3
|
-
async commitChanges(message: string) {
|
|
4
|
-
return {
|
|
5
|
-
success: true,
|
|
6
|
-
errors: [] as string[],
|
|
7
|
-
commitHash: 'mock-commit-hash-abc123',
|
|
8
|
-
timestamp: new Date('2026-01-01T12:00:00Z'),
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async getCommitHistory(limit: number = 10) {
|
|
13
|
-
return [
|
|
14
|
-
{
|
|
15
|
-
hash: 'mock-commit-1',
|
|
16
|
-
message: 'Initial commit',
|
|
17
|
-
author: 'Test User',
|
|
18
|
-
date: '2023-01-01T12:00:00Z',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
hash: 'mock-commit-2',
|
|
22
|
-
message: 'Update User entity',
|
|
23
|
-
author: 'Test User',
|
|
24
|
-
date: '2023-01-02T12:00:00Z',
|
|
25
|
-
},
|
|
26
|
-
];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async revertToCommit(commitHash: string) {
|
|
30
|
-
return {
|
|
31
|
-
success: true,
|
|
32
|
-
errors: [] as string[],
|
|
33
|
-
newCommitHash: 'mock-revert-hash-def456',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const versionService = new VersionServiceMock();
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { listMicroserviceEntities, listAllDictionaries, readEntityFile } from '../../utils/fileOperations.js';
|
|
2
|
-
import { dictionaryService } from '../dictionaryService.js';
|
|
3
|
-
|
|
4
|
-
// Mock dependencies
|
|
5
|
-
jest.mock('../../utils/fileOperations');
|
|
6
|
-
jest.mock('../../utils/logger');
|
|
7
|
-
|
|
8
|
-
describe('DictionaryService', () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
jest.clearAllMocks();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('getAllDictionaries', () => {
|
|
14
|
-
it('should return all dictionaries', async () => {
|
|
15
|
-
(listAllDictionaries as jest.Mock).mockResolvedValue(['microservices/svc-a', 'microservices/svc-b']);
|
|
16
|
-
|
|
17
|
-
const dictionaries = await dictionaryService.getAllDictionaries();
|
|
18
|
-
|
|
19
|
-
expect(listAllDictionaries).toHaveBeenCalledTimes(1);
|
|
20
|
-
// getDictionaryById creates dictionaries from microservices/ IDs
|
|
21
|
-
expect(dictionaries).toHaveLength(2);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should return empty array on error', async () => {
|
|
25
|
-
(listAllDictionaries as jest.Mock).mockRejectedValueOnce(new Error('Test error'));
|
|
26
|
-
|
|
27
|
-
const dictionaries = await dictionaryService.getAllDictionaries();
|
|
28
|
-
|
|
29
|
-
expect(listAllDictionaries).toHaveBeenCalledTimes(1);
|
|
30
|
-
expect(dictionaries).toHaveLength(0);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('getEntityAttributes', () => {
|
|
35
|
-
it('should return attributes for an entity', async () => {
|
|
36
|
-
(readEntityFile as jest.Mock).mockResolvedValue({
|
|
37
|
-
id: 'User',
|
|
38
|
-
uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
|
|
39
|
-
name: 'User',
|
|
40
|
-
microservice: 'user-service',
|
|
41
|
-
version: '1.0.0',
|
|
42
|
-
attributes: [
|
|
43
|
-
{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', type: 'string', description: 'ID', required: true },
|
|
44
|
-
{ uuid: 'c5af3719-ee6f-4156-bb1a-e575d345f7a5', name: 'email', type: 'string', description: 'Email', required: true },
|
|
45
|
-
],
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const attributes = await dictionaryService.getEntityAttributes('user-service', 'User');
|
|
49
|
-
|
|
50
|
-
expect(readEntityFile).toHaveBeenCalledWith('user-service', 'User');
|
|
51
|
-
expect(attributes).toHaveLength(2);
|
|
52
|
-
expect(attributes[0].name).toBe('id');
|
|
53
|
-
expect(attributes[1].name).toBe('email');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should return empty array for non-existent entity', async () => {
|
|
57
|
-
(readEntityFile as jest.Mock).mockResolvedValue(null);
|
|
58
|
-
|
|
59
|
-
const attributes = await dictionaryService.getEntityAttributes('user-service', 'NonExistent');
|
|
60
|
-
|
|
61
|
-
expect(readEntityFile).toHaveBeenCalledWith('user-service', 'NonExistent');
|
|
62
|
-
expect(attributes).toHaveLength(0);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should return empty array on error', async () => {
|
|
66
|
-
(readEntityFile as jest.Mock).mockRejectedValueOnce(new Error('Test error'));
|
|
67
|
-
|
|
68
|
-
const attributes = await dictionaryService.getEntityAttributes('user-service', 'User');
|
|
69
|
-
|
|
70
|
-
expect(readEntityFile).toHaveBeenCalledWith('user-service', 'User');
|
|
71
|
-
expect(attributes).toHaveLength(0);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
});
|