@hamak/smart-data-dico 1.0.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/README.md +292 -0
- package/backend/package.json +51 -0
- package/backend/src/__tests__/integration/api.test.ts +149 -0
- package/backend/src/__tests__/setup.ts +24 -0
- package/backend/src/__tests__/utils/testUtils.ts +76 -0
- package/backend/src/adapters/EntityFileAdapter.ts +154 -0
- package/backend/src/adapters/YamlFileInfoEnricher.ts +52 -0
- package/backend/src/controllers/authController.ts +131 -0
- package/backend/src/controllers/diagramController.ts +143 -0
- package/backend/src/controllers/dictionaryController.ts +306 -0
- package/backend/src/controllers/importExportController.ts +64 -0
- package/backend/src/controllers/perspectiveController.ts +90 -0
- package/backend/src/controllers/serviceController.ts +418 -0
- package/backend/src/controllers/stereotypeController.ts +59 -0
- package/backend/src/controllers/versionController.ts +226 -0
- package/backend/src/kernel/config.ts +43 -0
- package/backend/src/middleware/auth.ts +128 -0
- package/backend/src/middleware/jwtAuth.ts +100 -0
- package/backend/src/models/Dictionary.ts +38 -0
- package/backend/src/models/EntitySchema.ts +393 -0
- package/backend/src/models/__tests__/Dictionary.test.ts +92 -0
- package/backend/src/models/__tests__/EntitySchema.test.ts +119 -0
- package/backend/src/routes/index.ts +120 -0
- package/backend/src/scripts/migrate-to-uuid.ts +24 -0
- package/backend/src/server.ts +140 -0
- package/backend/src/services/__mocks__/entityService.ts +38 -0
- package/backend/src/services/__mocks__/serviceService.ts +88 -0
- package/backend/src/services/__mocks__/versionService.ts +38 -0
- package/backend/src/services/__tests__/dictionaryService.test.ts +74 -0
- package/backend/src/services/diagramService.ts +165 -0
- package/backend/src/services/dictionaryService.ts +582 -0
- package/backend/src/services/entityService.ts +102 -0
- package/backend/src/services/exportService.ts +172 -0
- package/backend/src/services/importService.ts +208 -0
- package/backend/src/services/perspectiveService.ts +276 -0
- package/backend/src/services/qualityService.ts +121 -0
- package/backend/src/services/serviceService.ts +763 -0
- package/backend/src/services/stereotypeService.ts +98 -0
- package/backend/src/services/versionService.ts +135 -0
- package/backend/src/setupTests.ts +12 -0
- package/backend/src/utils/__mocks__/fileOperations.ts +116 -0
- package/backend/src/utils/fileOperations.ts +602 -0
- package/backend/src/utils/logger.ts +38 -0
- package/backend/src/utils/migration.ts +254 -0
- package/backend/src/utils/swagger.ts +358 -0
- package/backend/src/utils/uuid.ts +41 -0
- package/backend/tsconfig.json +20 -0
- package/bin/cli.js +129 -0
- package/data-dictionaries/stereotypes.yaml +91 -0
- package/package.json +42 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join, resolve } from 'path';
|
|
5
|
+
import { existsSync, mkdirSync, cpSync } from 'fs';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const PKG_ROOT = join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
// Parse CLI arguments
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const flags = {};
|
|
15
|
+
for (let i = 0; i < args.length; i++) {
|
|
16
|
+
if (args[i] === '--port' && args[i + 1]) { flags.port = args[++i]; }
|
|
17
|
+
else if (args[i] === '--data-dir' && args[i + 1]) { flags.dataDir = args[++i]; }
|
|
18
|
+
else if (args[i] === '--no-open') { flags.noOpen = true; }
|
|
19
|
+
else if (args[i] === '--help' || args[i] === '-h') { flags.help = true; }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (flags.help) {
|
|
23
|
+
console.log(`
|
|
24
|
+
smart-data-dico - Collaborative Data Dictionary Management
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
smart-data-dico [options]
|
|
28
|
+
npx smart-data-dico [options]
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--port <number> Server port (default: 3001)
|
|
32
|
+
--data-dir <path> Data directory path (default: ./data-dictionaries)
|
|
33
|
+
--no-open Don't open browser automatically
|
|
34
|
+
-h, --help Show this help
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
smart-data-dico
|
|
38
|
+
smart-data-dico --port 4000
|
|
39
|
+
smart-data-dico --data-dir ~/my-dictionaries
|
|
40
|
+
`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const port = flags.port || process.env.PORT || '3001';
|
|
45
|
+
const dataDir = resolve(flags.dataDir || process.env.DATA_DIR || './data-dictionaries');
|
|
46
|
+
|
|
47
|
+
// Ensure data directory exists
|
|
48
|
+
if (!existsSync(dataDir)) {
|
|
49
|
+
mkdirSync(dataDir, { recursive: true });
|
|
50
|
+
console.log(`Created data directory: ${dataDir}`);
|
|
51
|
+
|
|
52
|
+
const defaultStereotypes = join(PKG_ROOT, 'data-dictionaries', 'stereotypes.yaml');
|
|
53
|
+
if (existsSync(defaultStereotypes)) {
|
|
54
|
+
cpSync(defaultStereotypes, join(dataDir, 'stereotypes.yaml'));
|
|
55
|
+
console.log('Copied default stereotypes');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
mkdirSync(join(dataDir, 'microservices'), { recursive: true });
|
|
59
|
+
mkdirSync(join(dataDir, 'perspectives'), { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const serverTs = join(PKG_ROOT, 'backend', 'src', 'server.ts');
|
|
63
|
+
const frontendDist = join(PKG_ROOT, 'frontend', 'dist');
|
|
64
|
+
|
|
65
|
+
if (!existsSync(serverTs)) {
|
|
66
|
+
console.error('Error: Backend source not found.');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(`
|
|
71
|
+
Smart Data Dictionary
|
|
72
|
+
|
|
73
|
+
Port: ${port}
|
|
74
|
+
Data: ${dataDir}
|
|
75
|
+
Profile: ${process.env.PROFILE || 'local'}
|
|
76
|
+
Frontend: ${existsSync(frontendDist) ? 'bundled' : 'dev (use frontend dev server on :3000)'}
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
// Find tsx binary — check local node_modules first, then global
|
|
80
|
+
const tsxPaths = [
|
|
81
|
+
join(PKG_ROOT, 'node_modules', '.bin', 'tsx'),
|
|
82
|
+
join(PKG_ROOT, 'backend', 'node_modules', '.bin', 'tsx'),
|
|
83
|
+
];
|
|
84
|
+
let tsxBin = tsxPaths.find(p => existsSync(p)) || 'npx';
|
|
85
|
+
const tsxArgs = tsxBin === 'npx' ? ['tsx', serverTs] : [serverTs];
|
|
86
|
+
|
|
87
|
+
const child = spawn(tsxBin, tsxArgs, {
|
|
88
|
+
cwd: join(PKG_ROOT, 'backend'),
|
|
89
|
+
env: {
|
|
90
|
+
...process.env,
|
|
91
|
+
PORT: port,
|
|
92
|
+
NODE_ENV: existsSync(frontendDist) ? 'production' : 'development',
|
|
93
|
+
PROFILE: process.env.PROFILE || 'local',
|
|
94
|
+
DATA_DIR: dataDir,
|
|
95
|
+
},
|
|
96
|
+
stdio: 'inherit',
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
child.on('error', (err) => {
|
|
100
|
+
console.error('Failed to start server:', err.message);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
105
|
+
|
|
106
|
+
// Open browser after short delay
|
|
107
|
+
if (!flags.noOpen) {
|
|
108
|
+
setTimeout(async () => {
|
|
109
|
+
const url = `http://localhost:${port}`;
|
|
110
|
+
console.log(`Opening ${url} ...`);
|
|
111
|
+
try {
|
|
112
|
+
const { exec } = await import('child_process');
|
|
113
|
+
const cmd = process.platform === 'darwin' ? 'open' :
|
|
114
|
+
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
115
|
+
exec(`${cmd} ${url}`);
|
|
116
|
+
} catch {
|
|
117
|
+
console.log(`Open ${url} in your browser`);
|
|
118
|
+
}
|
|
119
|
+
}, 3000);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
process.on('SIGINT', () => {
|
|
123
|
+
console.log('\nShutting down...');
|
|
124
|
+
child.kill('SIGINT');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
process.on('SIGTERM', () => {
|
|
128
|
+
child.kill('SIGTERM');
|
|
129
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
- id: aggregate-root
|
|
2
|
+
name: Aggregate Root
|
|
3
|
+
appliesTo: entity
|
|
4
|
+
description: Root entity of an aggregate boundary
|
|
5
|
+
metadataDefinitions:
|
|
6
|
+
- name: bounded-context
|
|
7
|
+
type: string
|
|
8
|
+
required: true
|
|
9
|
+
description: Name of the bounded context this aggregate belongs to
|
|
10
|
+
- name: invariants
|
|
11
|
+
type: rule
|
|
12
|
+
description: Business invariants enforced by this aggregate
|
|
13
|
+
|
|
14
|
+
- id: reference-data
|
|
15
|
+
name: Reference Data
|
|
16
|
+
appliesTo: entity
|
|
17
|
+
description: Slowly-changing lookup/reference data
|
|
18
|
+
metadataDefinitions:
|
|
19
|
+
- name: cacheable
|
|
20
|
+
type: flag
|
|
21
|
+
required: true
|
|
22
|
+
description: Whether this data can be cached
|
|
23
|
+
- name: update-frequency
|
|
24
|
+
type: string
|
|
25
|
+
description: How often this data changes (daily, weekly, rarely)
|
|
26
|
+
|
|
27
|
+
- id: event
|
|
28
|
+
name: Domain Event
|
|
29
|
+
appliesTo: entity
|
|
30
|
+
description: An event that represents something that happened in the domain
|
|
31
|
+
metadataDefinitions:
|
|
32
|
+
- name: event-source
|
|
33
|
+
type: string
|
|
34
|
+
required: true
|
|
35
|
+
description: The aggregate or service that emits this event
|
|
36
|
+
- name: idempotent
|
|
37
|
+
type: flag
|
|
38
|
+
description: Whether processing this event is idempotent
|
|
39
|
+
|
|
40
|
+
- id: value-object
|
|
41
|
+
name: Value Object
|
|
42
|
+
appliesTo: entity
|
|
43
|
+
description: An immutable object defined by its attributes rather than identity
|
|
44
|
+
metadataDefinitions:
|
|
45
|
+
- name: immutable
|
|
46
|
+
type: flag
|
|
47
|
+
required: true
|
|
48
|
+
|
|
49
|
+
- id: pii
|
|
50
|
+
name: PII
|
|
51
|
+
appliesTo: attribute
|
|
52
|
+
description: Personally Identifiable Information
|
|
53
|
+
metadataDefinitions:
|
|
54
|
+
- name: pii-category
|
|
55
|
+
type: string
|
|
56
|
+
required: true
|
|
57
|
+
description: "Category: direct, indirect, or sensitive"
|
|
58
|
+
- name: retention-days
|
|
59
|
+
type: number
|
|
60
|
+
description: Data retention period in days
|
|
61
|
+
- name: encryption-required
|
|
62
|
+
type: flag
|
|
63
|
+
description: Whether this field must be encrypted at rest
|
|
64
|
+
|
|
65
|
+
- id: indexed
|
|
66
|
+
name: Indexed
|
|
67
|
+
appliesTo: attribute
|
|
68
|
+
description: Database-indexed attribute
|
|
69
|
+
metadataDefinitions:
|
|
70
|
+
- name: index-type
|
|
71
|
+
type: string
|
|
72
|
+
description: "Index type: btree, hash, gin, gist"
|
|
73
|
+
- name: unique-index
|
|
74
|
+
type: flag
|
|
75
|
+
description: Whether the index enforces uniqueness
|
|
76
|
+
|
|
77
|
+
- id: deprecated
|
|
78
|
+
name: Deprecated
|
|
79
|
+
appliesTo: attribute
|
|
80
|
+
description: Attribute scheduled for removal
|
|
81
|
+
metadataDefinitions:
|
|
82
|
+
- name: deprecated-since
|
|
83
|
+
type: date
|
|
84
|
+
required: true
|
|
85
|
+
description: Date when this attribute was deprecated
|
|
86
|
+
- name: replacement
|
|
87
|
+
type: string
|
|
88
|
+
description: Name of the replacement attribute
|
|
89
|
+
- name: removal-target
|
|
90
|
+
type: date
|
|
91
|
+
description: Target date for removal
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hamak/smart-data-dico",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Collaborative data dictionary management system — model, document, and govern your data landscape",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"smart-data-dico": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "cd frontend && npm run build",
|
|
11
|
+
"start": "node bin/cli.js",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"backend/src/",
|
|
17
|
+
"backend/package.json",
|
|
18
|
+
"backend/tsconfig.json",
|
|
19
|
+
"frontend/dist/",
|
|
20
|
+
"data-dictionaries/stereotypes.yaml"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"tsx": "^4.0.0"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"data-dictionary",
|
|
27
|
+
"data-modeling",
|
|
28
|
+
"data-governance",
|
|
29
|
+
"schema-management",
|
|
30
|
+
"yaml",
|
|
31
|
+
"git"
|
|
32
|
+
],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/amah/smart-data-dico.git"
|
|
41
|
+
}
|
|
42
|
+
}
|