@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.
Files changed (50) hide show
  1. package/README.md +292 -0
  2. package/backend/package.json +51 -0
  3. package/backend/src/__tests__/integration/api.test.ts +149 -0
  4. package/backend/src/__tests__/setup.ts +24 -0
  5. package/backend/src/__tests__/utils/testUtils.ts +76 -0
  6. package/backend/src/adapters/EntityFileAdapter.ts +154 -0
  7. package/backend/src/adapters/YamlFileInfoEnricher.ts +52 -0
  8. package/backend/src/controllers/authController.ts +131 -0
  9. package/backend/src/controllers/diagramController.ts +143 -0
  10. package/backend/src/controllers/dictionaryController.ts +306 -0
  11. package/backend/src/controllers/importExportController.ts +64 -0
  12. package/backend/src/controllers/perspectiveController.ts +90 -0
  13. package/backend/src/controllers/serviceController.ts +418 -0
  14. package/backend/src/controllers/stereotypeController.ts +59 -0
  15. package/backend/src/controllers/versionController.ts +226 -0
  16. package/backend/src/kernel/config.ts +43 -0
  17. package/backend/src/middleware/auth.ts +128 -0
  18. package/backend/src/middleware/jwtAuth.ts +100 -0
  19. package/backend/src/models/Dictionary.ts +38 -0
  20. package/backend/src/models/EntitySchema.ts +393 -0
  21. package/backend/src/models/__tests__/Dictionary.test.ts +92 -0
  22. package/backend/src/models/__tests__/EntitySchema.test.ts +119 -0
  23. package/backend/src/routes/index.ts +120 -0
  24. package/backend/src/scripts/migrate-to-uuid.ts +24 -0
  25. package/backend/src/server.ts +140 -0
  26. package/backend/src/services/__mocks__/entityService.ts +38 -0
  27. package/backend/src/services/__mocks__/serviceService.ts +88 -0
  28. package/backend/src/services/__mocks__/versionService.ts +38 -0
  29. package/backend/src/services/__tests__/dictionaryService.test.ts +74 -0
  30. package/backend/src/services/diagramService.ts +165 -0
  31. package/backend/src/services/dictionaryService.ts +582 -0
  32. package/backend/src/services/entityService.ts +102 -0
  33. package/backend/src/services/exportService.ts +172 -0
  34. package/backend/src/services/importService.ts +208 -0
  35. package/backend/src/services/perspectiveService.ts +276 -0
  36. package/backend/src/services/qualityService.ts +121 -0
  37. package/backend/src/services/serviceService.ts +763 -0
  38. package/backend/src/services/stereotypeService.ts +98 -0
  39. package/backend/src/services/versionService.ts +135 -0
  40. package/backend/src/setupTests.ts +12 -0
  41. package/backend/src/utils/__mocks__/fileOperations.ts +116 -0
  42. package/backend/src/utils/fileOperations.ts +602 -0
  43. package/backend/src/utils/logger.ts +38 -0
  44. package/backend/src/utils/migration.ts +254 -0
  45. package/backend/src/utils/swagger.ts +358 -0
  46. package/backend/src/utils/uuid.ts +41 -0
  47. package/backend/tsconfig.json +20 -0
  48. package/bin/cli.js +129 -0
  49. package/data-dictionaries/stereotypes.yaml +91 -0
  50. package/package.json +42 -0
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # Smart Data Dictionary
2
+
3
+ A collaborative data dictionary management system for modeling, documenting, and governing your organization's data landscape. Built on a microkernel plugin architecture for modularity, with file-based persistence (YAML/Git) designed for both technical and non-technical users.
4
+
5
+ ## Core Concepts
6
+
7
+ ### Packages
8
+
9
+ Packages organize entities into logical groups reflecting your system architecture (microservices, modules, bounded contexts). They are hierarchical -- packages can contain sub-packages, forming a tree that mirrors your application structure.
10
+
11
+ - Navigable via nested URLs: `/packages/eShop/ordering/entities/Order`
12
+ - Each package has a dashboard with entity counts, relationship counts, and metadata
13
+ - Package names follow kebab-case convention
14
+
15
+ ### Entities & Attributes
16
+
17
+ Entities are the primary modeling unit -- they represent data structures (tables, documents, events, value objects). Each entity has:
18
+
19
+ - **Attributes** with types (string, number, integer, boolean, datetime, enum, object, array), constraints (min/max length, pattern, precision), and metadata
20
+ - **Nested attributes** for object and array types (e.g. `shippingAddress.postalCode`)
21
+ - **Status lifecycle**: draft -> submitted -> approved (or returned)
22
+ - **UUID-based identity** for stable cross-references
23
+
24
+ ### Relationships
25
+
26
+ Relationships connect entities across packages. They are stored at the package level and define:
27
+
28
+ - **Source and target** entity (by UUID) with cardinality (one/many)
29
+ - **Navigation property names** for path traversal
30
+ - **Metadata** on the relationship itself
31
+
32
+ ### Stereotypes
33
+
34
+ Stereotypes define metadata schemas that apply to specific element types (entity, attribute, or package). When assigned, they auto-populate required and optional metadata fields, ensuring consistency.
35
+
36
+ **Predefined stereotypes:**
37
+
38
+ | Stereotype | Applies To | Required Fields |
39
+ |-----------|-----------|-----------------|
40
+ | Aggregate Root | Entity | bounded-context |
41
+ | Reference Data | Entity | cacheable (flag) |
42
+ | Domain Event | Entity | event-source |
43
+ | Value Object | Entity | immutable (flag) |
44
+ | PII | Attribute | pii-category |
45
+ | Indexed | Attribute | - |
46
+ | Deprecated | Attribute | deprecated-since |
47
+
48
+ **Metadata types**: string, number, boolean, date, **flag** (semantic boolean rendered as toggle), **rule** (text + severity: info/warning/error).
49
+
50
+ ### Perspectives
51
+
52
+ A Perspective captures a business view over a subset of the data model scoped to a business process (e.g. "Ordering", "Billing"). It is the core differentiating concept of the application.
53
+
54
+ **How it works:**
55
+
56
+ 1. Select **root entities** -- the starting points of the business process
57
+ 2. The system performs **BFS traversal** through relationships to discover all reachable entities
58
+ 3. Each entity is identified by its **relationship path from root** (e.g. `Order/orderItems/product`)
59
+ 4. The same entity reached via different paths is treated as separate usages
60
+
61
+ **Path grammar** -- uniform `/` navigation for all levels:
62
+ ```
63
+ Order -- root entity
64
+ Order/totalAmount -- attribute on root
65
+ Order/orderItems -- relationship -> OrderItem
66
+ Order/orderItems/quantity -- attribute on OrderItem
67
+ Order/orderItems/product/sku -- deep chain -> attribute
68
+ Order/shippingAddress/postalCode -- attribute via relationship
69
+ Order/billingAddress/postalCode -- same attribute, different path
70
+ ```
71
+
72
+ **PerspectiveNode** annotations on any path:
73
+ - **`traverse: false`** -- frontier node (include but stop BFS here)
74
+ - **`exclude: true`** -- prune this path entirely
75
+ - **`metadata`** -- path-scoped annotations (not overrides -- new metadata specific to this perspective usage)
76
+
77
+ ### Review Workflow
78
+
79
+ Entities go through a status lifecycle for team governance:
80
+
81
+ ```
82
+ draft --> submitted --> approved
83
+ \-> returned (with comments) --> submitted
84
+ ```
85
+
86
+ - **Comments** can target specific attributes (e.g. "Missing validation rule on discountRate")
87
+ - **Status transitions** are role-gated (editors submit, admins approve/return)
88
+ - Comments are stored as sidecar YAML files per entity
89
+
90
+ ### Quality Metrics
91
+
92
+ The quality dashboard tracks documentation completeness:
93
+
94
+ - **Description coverage** -- % of entities/attributes with descriptions
95
+ - **Metadata compliance** -- % of entities with correct stereotype metadata
96
+ - **Relationship coverage** -- % of entities with at least one relationship
97
+ - **Per-entity scoring** -- weighted composite (30% description, 30% attribute descriptions, 20% relationships, 20% stereotype compliance)
98
+ - **Drill-down** from package level to individual entity gaps
99
+
100
+ ## User Journeys
101
+
102
+ ### Journey 1: Model a New Domain (Data Architect)
103
+
104
+ > *Alice documents the data model for an e-commerce platform.*
105
+
106
+ 1. **Create packages** -- `eShop > Ordering`, `Catalog`, `Billing` via the package dashboard
107
+ 2. **Define entities** -- `Order`, `OrderLine`, `Customer` with typed attributes and constraints
108
+ 3. **Define relationships** -- `Order` to `OrderLine` (one-to-many) at the package level
109
+ 4. **Assign stereotypes** -- Mark `Order` as `aggregate-root`, auto-populating `bounded-context` metadata
110
+ 5. **Add metadata** -- Flag `Customer.email` as PII, add business rules
111
+ 6. **Visualize** -- Open the Cytoscape.js interactive graph, verify the model, save the layout
112
+ 7. **Save & publish** -- Save (commit to workspace), publish (push to shared)
113
+
114
+ ### Journey 2: Define a Perspective (Business Analyst)
115
+
116
+ > *Bob captures the billing-specific view of the data model.*
117
+
118
+ 1. **Create perspective** -- "Billing" with `Invoice` and `Payment` as root entities
119
+ 2. **Review resolved paths** -- BFS walks relationships, discovers `Order`, `Customer`, `LineItem`
120
+ 3. **Set frontiers** -- Mark `Product` as frontier (`traverse: false`) -- include but don't follow further
121
+ 4. **Exclude paths** -- Exclude `Order/audit` (not relevant to billing)
122
+ 5. **Add annotations** -- On `Order/billingAddress/postalCode`, add validation rule "Must match payment country"
123
+ 6. **Visualize** -- Graph overlay highlights perspective members, dims others
124
+
125
+ ### Journey 3: Review & Approve (Data Steward)
126
+
127
+ > *Carol reviews changes submitted by the team.*
128
+
129
+ 1. **See pending entities** -- Order is in `submitted` status
130
+ 2. **Add comments** -- "Missing description on id field" targeting specific attribute
131
+ 3. **Return for revision** -- Status changes to `returned`, author gets notification
132
+ 4. **Approve** -- After fixes, approve. Status moves to `approved`
133
+ 5. **Check quality** -- Quality dashboard shows 90% for order-service, up from 80%
134
+
135
+ ### Journey 4: Explore & Discover (Developer)
136
+
137
+ > *Dave needs to understand the data model for implementation.*
138
+
139
+ 1. **Browse** -- Navigate `/packages/order-service` to see the dashboard with stats
140
+ 2. **Search** -- Search "order" returns 27 results across entities, attributes, metadata, relationships, packages
141
+ 3. **Filter** -- Faceted search: filter by type=relationship, service=order-service, stereotype=aggregate-root
142
+ 4. **Impact analysis** -- Check "Impact" tab on Order: 2 relationships, 1 perspective reference
143
+ 5. **Export** -- Export order-service as JSON Schema for code generation, or Markdown for documentation
144
+
145
+ ### Journey 5: Version & Collaborate (Team Lead)
146
+
147
+ > *Eve manages versioning aligned with application releases.*
148
+
149
+ 1. **Create workspace** -- Creates `workspace/billing-v2` (git branch with friendly name)
150
+ 2. **Monitor status** -- Navbar shows "MAIN 8" (branch + unsaved count), dropdown shows ahead/behind
151
+ 3. **Save & publish** -- Save page shows changed files, commit with message, push to remote
152
+ 4. **Switch workspaces** -- Workspaces page lists branches, switch with one click
153
+ 5. **Merge** -- Merge page selects source workspace, previews diff, merges
154
+
155
+ ## Architecture
156
+
157
+ ### Monorepo
158
+
159
+ ```
160
+ smart-data-dico/
161
+ backend/ Express + TypeScript (controllers > services > models)
162
+ frontend/ React 18 + Vite + TypeScript + Tailwind CSS + DaisyUI
163
+ data-dictionaries/ YAML entity files, relationships, perspectives, stereotypes
164
+ Dockerfile Multi-stage production build
165
+ docker-compose.yml One-command deployment
166
+ ```
167
+
168
+ ### Microkernel Plugin Architecture
169
+
170
+ The frontend uses `@hamak/app-framework` with 11 plugins:
171
+
172
+ | Plugin | Responsibility |
173
+ |--------|---------------|
174
+ | **store** | Redux state management (10 domain slices) |
175
+ | **shell** | Layout, theming (synced with DaisyUI) |
176
+ | **auth** | JWT authentication with Auth0 |
177
+ | **data-dictionary** | Entity, package, relationship CRUD |
178
+ | **visualization** | Interactive Cytoscape.js graph |
179
+ | **search** | Full-text and faceted search |
180
+ | **version-control** | Save/publish, history |
181
+ | **perspective** | Perspective management and resolution |
182
+ | **remote-fs** | File operations via `@hamak/filesystem-server-impl` |
183
+ | **remote-git** | Git operations via `@hamak/ui-remote-git-fs-impl` |
184
+ | **notification** | Toast notifications |
185
+
186
+ ### Data Model
187
+
188
+ ```
189
+ Package
190
+ +-- Entity (uuid, name, description, stereotype, status, attributes[], metadata[])
191
+ | +-- Attribute (uuid, name, type, required, constraints, metadata[])
192
+ +-- Relationship (uuid, source, target, cardinality, metadata[])
193
+ +-- Sub-packages
194
+
195
+ Stereotype (id, name, appliesTo, metadataDefinitions[])
196
+ Perspective (uuid, name, rootEntities[], nodes[], maxDepth)
197
+ +-- PerspectiveNode (path, traverse?, exclude?, metadata[])
198
+ +-- ResolvedNode (entityUuid, path, hopDistance, isRoot, isFrontier)
199
+ ```
200
+
201
+ ### Persistence
202
+
203
+ ```
204
+ data-dictionaries/
205
+ microservices/{package}/
206
+ {uuid}_{name}.yaml -- entity files
207
+ {uuid}.comments.yaml -- review comments (sidecar)
208
+ relationships.yaml -- package-level relationships
209
+ metadata.yaml -- package metadata
210
+ perspectives/{uuid}.yaml -- perspective definitions
211
+ stereotypes.yaml -- stereotype definitions
212
+ diagrams/{id}.json -- saved diagram layouts
213
+ ```
214
+
215
+ All files are git-tracked for versioning, branching, and collaboration.
216
+
217
+ ### API Surface
218
+
219
+ | Area | Endpoints |
220
+ |------|-----------|
221
+ | Entities | CRUD on `/api/services/:service/entities/:entity` |
222
+ | Packages | CRUD on `/api/packages`, hierarchy, path navigation |
223
+ | Relationships | CRUD on `/api/packages/:pkg/relationships` |
224
+ | Stereotypes | CRUD on `/api/stereotypes` |
225
+ | Perspectives | CRUD + resolve + graph on `/api/perspectives` |
226
+ | Search | `GET /api/search?q=...&type=...&service=...&stereotype=...` |
227
+ | Impact | `GET /api/entities/:uuid/impact` |
228
+ | Review | Submit/approve/return + comments on entities |
229
+ | Import | `POST /api/import/json-schema`, `POST /api/import/sql-ddl` |
230
+ | Export | `GET /api/export/json-schema/:service`, `GET /api/export/markdown/:service` |
231
+ | Quality | `GET /api/quality/report` |
232
+ | Git | Full git operations via `/api/git/dictionaries/*` (framework routes) |
233
+ | Version | Commit, history, revert via `/api/commit`, `/api/history` |
234
+
235
+ ## Getting Started
236
+
237
+ ### Prerequisites
238
+
239
+ - Node.js v18+
240
+ - npm
241
+
242
+ ### Quick Start
243
+
244
+ ```bash
245
+ # Install dependencies
246
+ cd backend && npm install
247
+ cd ../frontend && npm install
248
+
249
+ # Start (two terminals)
250
+ cd backend && npm run dev # port 3001
251
+ cd frontend && npm run dev # port 3000
252
+ ```
253
+
254
+ - Frontend: http://localhost:3000
255
+ - Backend API: http://localhost:3001
256
+ - API docs: http://localhost:3001/api-docs
257
+
258
+ ### Docker
259
+
260
+ ```bash
261
+ docker-compose up
262
+ # App available at http://localhost:3001
263
+ ```
264
+
265
+ ### Dev Credentials
266
+
267
+ | User | Password | Role |
268
+ |------|----------|------|
269
+ | admin | admin123 | ADMIN (full access) |
270
+ | editor | editor123 | EDITOR (create/edit) |
271
+ | viewer | viewer123 | VIEWER (read-only) |
272
+
273
+ ### Configuration Profiles
274
+
275
+ Set via `PROFILE` environment variable:
276
+
277
+ | Profile | Auth | Git | Use Case |
278
+ |---------|------|-----|----------|
279
+ | **local** | None | Local only | Single user, desktop |
280
+ | **team** | Basic/JWT | Remote | Small team sharing a repo |
281
+ | **server** | Auth0/SSO | Remote | Organization-wide deployment |
282
+
283
+ ## Technologies
284
+
285
+ | Layer | Stack |
286
+ |-------|-------|
287
+ | Backend | Node.js, Express, TypeScript (ESM), YAML, Git |
288
+ | Frontend | React 18, Vite, TypeScript, Tailwind CSS, DaisyUI, Redux |
289
+ | Framework | @hamak/app-framework (microkernel, DI, plugins) |
290
+ | Visualization | Cytoscape.js (dagre + fcose layouts) |
291
+ | Auth | JWT + Auth0 (mock mode for dev) |
292
+ | Deployment | Docker (multi-stage build) |
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "data-dictionary-backend",
3
+ "version": "0.1.0",
4
+ "description": "Backend for Data Dictionary Management System",
5
+ "type": "module",
6
+ "main": "dist/server.js",
7
+ "scripts": {
8
+ "start": "node dist/server.js",
9
+ "dev": "nodemon --exec tsx src/server.ts",
10
+ "build": "tsc",
11
+ "test": "jest",
12
+ "lint": "eslint . --ext .ts",
13
+ "test:coverage": "jest --coverage"
14
+ },
15
+ "dependencies": {
16
+ "@hamak/filesystem-server-api": "^0.5.1",
17
+ "@hamak/filesystem-server-impl": "^0.5.1",
18
+ "@hamak/filesystem-server-spi": "^0.5.1",
19
+ "@hamak/shared-utils": "^0.5.1",
20
+ "@hamak/ui-remote-git-fs-backend": "file:../../app-framework/packages/ui-remote-git-fs/backend/ui-remote-git-fs-backend",
21
+ "@types/jsonwebtoken": "^9.0.9",
22
+ "cors": "^2.8.5",
23
+ "dotenv": "^16.3.1",
24
+ "express": "^4.18.2",
25
+ "jsonschema": "^1.4.1",
26
+ "jsonwebtoken": "^9.0.2",
27
+ "swagger-jsdoc": "^6.2.8",
28
+ "swagger-ui-express": "^5.0.1",
29
+ "yaml": "^2.3.1"
30
+ },
31
+ "devDependencies": {
32
+ "@jest/globals": "^30.3.0",
33
+ "@types/cors": "^2.8.13",
34
+ "@types/express": "^4.17.17",
35
+ "@types/jest": "^29.5.3",
36
+ "@types/node": "^20.17.50",
37
+ "@types/supertest": "^6.0.3",
38
+ "@types/swagger-jsdoc": "^6.0.4",
39
+ "@types/swagger-ui-express": "^4.1.8",
40
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
41
+ "@typescript-eslint/parser": "^6.0.0",
42
+ "eslint": "^8.45.0",
43
+ "jest": "^29.6.2",
44
+ "nodemon": "^3.0.1",
45
+ "supertest": "^7.1.1",
46
+ "ts-jest": "^29.1.1",
47
+ "ts-node": "^10.9.1",
48
+ "tsx": "^4.21.0",
49
+ "typescript": "^5.1.6"
50
+ }
51
+ }
@@ -0,0 +1,149 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import request from 'supertest';
3
+
4
+ import { UserRole } from '../../middleware/auth.js';
5
+ import app from '../../server.js';
6
+
7
+ // Extend Request type to include user property
8
+ declare global {
9
+ namespace Express {
10
+ interface Request {
11
+ user?: {
12
+ id: string;
13
+ role: string;
14
+ };
15
+ }
16
+ }
17
+ }
18
+
19
+ // Mock auth middleware to bypass authentication
20
+ jest.mock('../../middleware/auth', () => ({
21
+ UserRole: {
22
+ ADMIN: 'admin',
23
+ EDITOR: 'editor',
24
+ VIEWER: 'viewer',
25
+ },
26
+ authenticate: jest.fn().mockImplementation((_roles: string[]) => (req: Request, _res: Response, next: NextFunction) => {
27
+ req.user = { id: 'test-user', role: 'admin' };
28
+ next();
29
+ }),
30
+ }));
31
+
32
+ // Mock JWT auth to bypass token verification
33
+ jest.mock('../../middleware/jwtAuth', () => ({
34
+ verifyToken: jest.fn().mockImplementation((req: Request, _res: Response, next: NextFunction) => {
35
+ req.user = { id: 'test-user', role: 'admin' };
36
+ next();
37
+ }),
38
+ authorizeJwt: jest.fn().mockImplementation((_roles: string[]) => (req: Request, _res: Response, next: NextFunction) => {
39
+ req.user = { id: 'test-user', role: 'admin' };
40
+ next();
41
+ }),
42
+ }));
43
+
44
+ // Mock services (uses __mocks__ directory auto-mocks)
45
+ jest.mock('../../services/dictionaryService');
46
+ jest.mock('../../services/entityService');
47
+ jest.mock('../../services/serviceService');
48
+ jest.mock('../../services/versionService');
49
+ jest.mock('../../utils/logger');
50
+
51
+ describe('API Integration Tests', () => {
52
+ describe('Health & Status', () => {
53
+ it('should return health status', async () => {
54
+ const response = await request(app).get('/health');
55
+ expect(response.status).toBe(200);
56
+ expect(response.body).toHaveProperty('status', 'ok');
57
+ });
58
+ });
59
+
60
+ describe('Service Endpoints', () => {
61
+ it('GET /api/services should return service list', async () => {
62
+ const response = await request(app).get('/api/services');
63
+ expect(response.status).toBe(200);
64
+ expect(response.body).toHaveProperty('data');
65
+ expect(Array.isArray(response.body.data)).toBe(true);
66
+ expect(response.body.data).toContain('user-service');
67
+ });
68
+
69
+ it('GET /api/services/:service/entities should return entities', async () => {
70
+ const response = await request(app).get('/api/services/user-service/entities');
71
+ expect(response.status).toBe(200);
72
+ });
73
+
74
+ it('GET /api/services/:service/entities/:entity should return entity schema', async () => {
75
+ const response = await request(app).get('/api/services/user-service/entities/User');
76
+ expect(response.status).toBe(200);
77
+ });
78
+
79
+ it('POST /api/services/:service/entities should create entity', async () => {
80
+ const response = await request(app)
81
+ .post('/api/services/user-service/entities')
82
+ .send({
83
+ uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
84
+ name: 'NewEntity',
85
+ description: 'A new entity',
86
+ attributes: [{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', description: 'ID', type: 'string', required: true }],
87
+ });
88
+ expect(response.status).toBe(201);
89
+ });
90
+
91
+ it('PUT /api/services/:service/entities/:entity should update entity', async () => {
92
+ const response = await request(app)
93
+ .put('/api/services/user-service/entities/User')
94
+ .send({
95
+ uuid: 'a38d1597-cc4f-4934-bb08-c876c023f693',
96
+ name: 'User',
97
+ description: 'Updated user',
98
+ attributes: [{ uuid: 'b49e2608-dd5f-4045-aa09-d464c234e694', name: 'id', description: 'ID', type: 'string', required: true }],
99
+ });
100
+ expect(response.status).toBe(200);
101
+ });
102
+
103
+ it('DELETE /api/services/:service/entities/:entity should delete entity', async () => {
104
+ const response = await request(app).delete('/api/services/user-service/entities/User');
105
+ expect(response.status).toBe(200);
106
+ });
107
+ });
108
+
109
+ describe('Search & Graph', () => {
110
+ it('GET /api/search should return results', async () => {
111
+ const response = await request(app).get('/api/search?q=user');
112
+ expect(response.status).toBe(200);
113
+ });
114
+
115
+ it('GET /api/graph/:service should return graph data', async () => {
116
+ const response = await request(app).get('/api/graph/user-service');
117
+ expect(response.status).toBe(200);
118
+ });
119
+ });
120
+
121
+ describe('Version Control', () => {
122
+ it('POST /api/commit should commit changes', async () => {
123
+ const response = await request(app)
124
+ .post('/api/commit')
125
+ .send({ message: 'Test commit' });
126
+ expect(response.status).toBe(200);
127
+ });
128
+
129
+ it('GET /api/history should return commit history', async () => {
130
+ const response = await request(app).get('/api/history');
131
+ expect(response.status).toBe(200);
132
+ });
133
+
134
+ it('POST /api/revert should revert to commit', async () => {
135
+ const response = await request(app)
136
+ .post('/api/revert')
137
+ .send({ commitHash: 'mock-commit-1' });
138
+ expect(response.status).toBe(200);
139
+ });
140
+ });
141
+
142
+ describe('Relationship Endpoints', () => {
143
+ it('GET /api/packages/:packageName/relationships should return relationships', async () => {
144
+ const response = await request(app).get('/api/packages/user-service/relationships');
145
+ expect(response.status).toBe(200);
146
+ expect(response.body).toHaveProperty('data');
147
+ });
148
+ });
149
+ });
@@ -0,0 +1,24 @@
1
+ import dotenv from 'dotenv';
2
+
3
+ // Load environment variables for testing
4
+ dotenv.config({ path: '.env.test' });
5
+
6
+ // Mock logger to prevent console output during tests
7
+ jest.mock('../utils/logger', () => ({
8
+ logger: {
9
+ info: jest.fn(),
10
+ error: jest.fn(),
11
+ warn: jest.fn(),
12
+ debug: jest.fn(),
13
+ },
14
+ }));
15
+
16
+ // Global test setup
17
+ beforeAll(() => {
18
+ // Setup any global test requirements here
19
+ });
20
+
21
+ // Global test teardown
22
+ afterAll(() => {
23
+ // Clean up any global test resources here
24
+ });
@@ -0,0 +1,76 @@
1
+ import { Express } from 'express';
2
+ import request from 'supertest';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ /**
7
+ * Creates a test client for making HTTP requests to the Express app
8
+ * @param app Express application
9
+ * @returns Supertest instance
10
+ */
11
+ export const createTestClient = (app: Express) => {
12
+ return request(app);
13
+ };
14
+
15
+ /**
16
+ * Creates a temporary test directory for file operations
17
+ * @param dirPath Directory path to create
18
+ */
19
+ export const createTestDirectory = (dirPath: string): void => {
20
+ if (!fs.existsSync(dirPath)) {
21
+ fs.mkdirSync(dirPath, { recursive: true });
22
+ }
23
+ };
24
+
25
+ /**
26
+ * Removes a test directory and all its contents
27
+ * @param dirPath Directory path to remove
28
+ */
29
+ export const removeTestDirectory = (dirPath: string): void => {
30
+ if (fs.existsSync(dirPath)) {
31
+ fs.rmSync(dirPath, { recursive: true, force: true });
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Creates a test YAML file with the given content
37
+ * @param filePath Path to create the file
38
+ * @param content Content to write to the file
39
+ */
40
+ export const createTestYamlFile = (filePath: string, content: string): void => {
41
+ const dir = path.dirname(filePath);
42
+ if (!fs.existsSync(dir)) {
43
+ fs.mkdirSync(dir, { recursive: true });
44
+ }
45
+ fs.writeFileSync(filePath, content);
46
+ };
47
+
48
+ /**
49
+ * Generates a random entity for testing
50
+ * @param overrides Properties to override in the generated entity
51
+ * @returns A test entity
52
+ */
53
+ export const generateTestEntity = (overrides = {}) => {
54
+ return {
55
+ id: `test-entity-${Date.now()}`,
56
+ name: 'TestEntity',
57
+ description: 'A test entity for unit tests',
58
+ microservice: 'test-service',
59
+ version: '1.0.0',
60
+ attributes: [
61
+ {
62
+ name: 'id',
63
+ description: 'Primary identifier',
64
+ type: 'string',
65
+ required: true,
66
+ },
67
+ {
68
+ name: 'name',
69
+ description: 'Entity name',
70
+ type: 'string',
71
+ required: true,
72
+ },
73
+ ],
74
+ ...overrides,
75
+ };
76
+ };