@tdk-landscape/tdk-cli-core 1.3.34 → 1.3.36
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/discovery/discovery_orchestrator.star +4 -4
- package/discovery/manifest/loading.star +9 -5
- package/discovery/manifest/normalize.star +3 -3
- package/discovery/manifest/validation.star +1 -1
- package/discovery/validation.star +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +120 -6
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/resource.js +1 -1
- package/dist/commands/resource.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +2 -48
- package/dist/commands/up.js.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +11 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/resource-features.d.ts +1 -1
- package/dist/utils/resource-features.js +1 -1
- package/dist/utils/service-urls.d.ts +30 -0
- package/dist/utils/service-urls.d.ts.map +1 -0
- package/dist/utils/service-urls.js +93 -0
- package/dist/utils/service-urls.js.map +1 -0
- package/engine/REFACTORING_MANIFEST_SYSTEM.md +1 -1
- package/engine/lifecycle/orchestrator.star +4 -3
- package/engine/schemas/service-schema.json +5 -5
- package/engine/topologies/platform/docker/compose/compose.star +44 -24
- package/engine/topologies/platform/docker/constants.star +4 -0
- package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +1 -0
- package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +10 -6
- package/engine/topologies/platform/docker/networking/api_path_constants.star +30 -0
- package/engine/topologies/platform/docker/networking/traefik.star +2 -2
- package/engine/topologies/platform/net/AGENTS.md +64 -0
- package/engine/topologies/platform/security/AGENTS.md +49 -0
- package/engine/topologies/platform/state/AGENTS.md +64 -0
- package/engine/topologies/tilt/generators/vite/backend.star +1 -1
- package/engine/topologies/tilt/generators/vite/frontend.star +2 -1
- package/engine/topologies/tilt/generators/vite/helpers.star +1 -1
- package/engine/topologies/tilt/manifest/constants.star +1 -1
- package/engine/topologies/tilt/manifest/mapper.star +2 -2
- package/engine/topologies/tilt/manifest/parser.star +2 -2
- package/engine/topologies/tilt/manifest/schema.star +2 -2
- package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +3 -3
- package/engine/topologies/tilt/manifest/tests/test_validator.star +2 -2
- package/engine/topologies/tilt/manifest/validator.star +7 -7
- package/engine/topologies/tilt/resources/orchestrator/generators/env.star +3 -2
- package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +3 -2
- package/package.json +1 -1
- package/engine/schemas/manifest-schema.json +0 -301
|
@@ -16,6 +16,7 @@ load('../../../../topologies/tilt/manifest/constants.star', 'GENERATED_CONFIG_FI
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
load('./templates.star', 'TEMPLATE_VITE_FRONTEND', 'TEMPLATE_VITE_FRONTEND_BUILD')
|
|
19
|
+
load('../../../platform/docker/networking/api_path_constants.star', 'get_frontend_base_path')
|
|
19
20
|
load('./helpers.star',
|
|
20
21
|
'build_header',
|
|
21
22
|
'generate_frontend_internal_aliases',
|
|
@@ -56,7 +57,7 @@ def generate_frontend(manifest, backend_manifest=None, write_fn=None):
|
|
|
56
57
|
stack = manifest.get('stack', 'app')
|
|
57
58
|
port = manifest.get('port', BASE_PORT_FRONTEND)
|
|
58
59
|
hmr_port = port + 1000 # HMR port is always port + 1000
|
|
59
|
-
base_path = manifest
|
|
60
|
+
base_path = get_frontend_base_path(manifest)
|
|
60
61
|
vite_base_path = _normalize_vite_base_path(base_path)
|
|
61
62
|
app_name = manifest.get('appName', 'unknown')
|
|
62
63
|
|
|
@@ -164,7 +164,7 @@ def generate_backend_path_aliases(resource_path, manifest):
|
|
|
164
164
|
# hand-edited features: ["ddd"] with no key at all is still blocked, but real
|
|
165
165
|
# entitlement is checked client-side by hasDddLicense() in extension-fetch.ts
|
|
166
166
|
# before the CLI ever writes "ddd" into a resource's features array.
|
|
167
|
-
ddd_enabled = 'ddd' in manifest.get('
|
|
167
|
+
ddd_enabled = 'ddd' in manifest.get('featuresEnabled', []) and os.environ.get('TDK_LICENSE_KEY', '') != ''
|
|
168
168
|
|
|
169
169
|
if ddd_enabled:
|
|
170
170
|
ddd_aliases = [
|
|
@@ -31,7 +31,7 @@ FIELD_MAPPINGS = {
|
|
|
31
31
|
'replicas': ['replicas', 'instances', 'count', 'spec.replicas', 'metadata.replicas'],
|
|
32
32
|
|
|
33
33
|
# Feature flags
|
|
34
|
-
'
|
|
34
|
+
'featuresEnabled': ['featuresEnabled', 'capabilities', 'spec.features', 'enabledFeatures', 'app.features'],
|
|
35
35
|
|
|
36
36
|
# Dependencies
|
|
37
37
|
'dependsOn': [
|
|
@@ -199,7 +199,7 @@ def _to_yaml_format(internal_manifest):
|
|
|
199
199
|
'port': internal_manifest.get('port', 4000),
|
|
200
200
|
'runtime': internal_manifest.get('runtime', 'bun'),
|
|
201
201
|
'replicas': internal_manifest.get('replicas', 1),
|
|
202
|
-
'
|
|
202
|
+
'featuresEnabled': internal_manifest.get('featuresEnabled', []),
|
|
203
203
|
'envVars': internal_manifest.get('envVars', {}),
|
|
204
204
|
'dependencies': {
|
|
205
205
|
'internal': internal_manifest.get('dependsOn', []),
|
|
@@ -90,7 +90,7 @@ def normalize(manifest, resource_path=""):
|
|
|
90
90
|
# Copy all existing fields
|
|
91
91
|
for key, value in manifest.items():
|
|
92
92
|
normalized[key] = value
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
# 1. Apply defaults for missing fields
|
|
95
95
|
for field, default_value in MANIFEST_DEFAULTS.items():
|
|
96
96
|
if field not in normalized or normalized[field] == None:
|
|
@@ -111,7 +111,7 @@ def normalize(manifest, resource_path=""):
|
|
|
111
111
|
if normalized.get('syncs') == None or normalized.get('syncs') == []:
|
|
112
112
|
normalized['syncs'] = _compute_syncs(
|
|
113
113
|
normalized['appType'],
|
|
114
|
-
normalized.get('
|
|
114
|
+
normalized.get('featuresEnabled', [])
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
# Compute backendName for frontends if missing
|
|
@@ -117,7 +117,7 @@ MANIFEST_SCHEMA = {
|
|
|
117
117
|
'description': 'Runtime environment',
|
|
118
118
|
'default': RUNTIME,
|
|
119
119
|
},
|
|
120
|
-
'
|
|
120
|
+
'featuresEnabled': {
|
|
121
121
|
'type': 'list',
|
|
122
122
|
'required': False,
|
|
123
123
|
'constraints': {
|
|
@@ -263,7 +263,7 @@ CROSS_FIELD_CONSTRAINTS = {
|
|
|
263
263
|
'message': 'Frontend resources must specify backendName and basePath',
|
|
264
264
|
},
|
|
265
265
|
'prisma_requires_database': {
|
|
266
|
-
'condition': {'field': '
|
|
266
|
+
'condition': {'field': 'featuresEnabled', 'contains': 'prisma'},
|
|
267
267
|
'requires': ['databaseName'],
|
|
268
268
|
'severity': 'warning',
|
|
269
269
|
'message': 'Resources using Prisma should specify databaseName',
|
|
@@ -281,7 +281,7 @@ def _test_manifest_merging():
|
|
|
281
281
|
'appName': 'test-service',
|
|
282
282
|
'appType': 'backend',
|
|
283
283
|
'port': 4000,
|
|
284
|
-
'
|
|
284
|
+
'featuresEnabled': ['nats'],
|
|
285
285
|
'envVars': {
|
|
286
286
|
'SHARED_VAR': 'base_value',
|
|
287
287
|
},
|
|
@@ -289,7 +289,7 @@ def _test_manifest_merging():
|
|
|
289
289
|
|
|
290
290
|
overlay = {
|
|
291
291
|
'port': 4001, # Override
|
|
292
|
-
'
|
|
292
|
+
'featuresEnabled': ['prisma'], # Override
|
|
293
293
|
'envVars': {
|
|
294
294
|
'SHARED_VAR': 'overlay_value', # Override
|
|
295
295
|
'NEW_VAR': 'new_value', # Add
|
|
@@ -300,7 +300,7 @@ def _test_manifest_merging():
|
|
|
300
300
|
|
|
301
301
|
assert_equal('test-service', merged['appName'], "Should preserve base appName")
|
|
302
302
|
assert_equal(4001, merged['port'], "Should overlay port")
|
|
303
|
-
assert_equal(['prisma'], merged['
|
|
303
|
+
assert_equal(['prisma'], merged['featuresEnabled'], "Should overlay features")
|
|
304
304
|
assert_equal('overlay_value', merged['envVars']['SHARED_VAR'], "Should overlay nested env var")
|
|
305
305
|
assert_equal('new_value', merged['envVars']['NEW_VAR'], "Should add new env var")
|
|
306
306
|
|
|
@@ -213,7 +213,7 @@ def _test_cross_field_validation():
|
|
|
213
213
|
'appType': 'backend',
|
|
214
214
|
'stack': 'user',
|
|
215
215
|
'port': 4001,
|
|
216
|
-
'
|
|
216
|
+
'featuresEnabled': ['prisma'],
|
|
217
217
|
# Missing databaseName
|
|
218
218
|
}
|
|
219
219
|
|
|
@@ -312,7 +312,7 @@ def _test_full_validation():
|
|
|
312
312
|
'port': 4000,
|
|
313
313
|
'replicas': 1,
|
|
314
314
|
'runtime': 'bun',
|
|
315
|
-
'
|
|
315
|
+
'featuresEnabled': ['nats', 'prisma'],
|
|
316
316
|
'databaseName': 'TDK_user',
|
|
317
317
|
'dependsOn': [],
|
|
318
318
|
'traefik': {
|
|
@@ -316,16 +316,16 @@ def _validate_values(manifest, context):
|
|
|
316
316
|
stats['rules_passed'] += 1
|
|
317
317
|
|
|
318
318
|
# Validate features length
|
|
319
|
-
if '
|
|
319
|
+
if 'featuresEnabled' in manifest:
|
|
320
320
|
stats['fields_checked'] += 1
|
|
321
|
-
features = manifest
|
|
322
|
-
|
|
321
|
+
features = manifest.get('featuresEnabled', [])
|
|
322
|
+
|
|
323
323
|
if len(features) > VALIDATION_THRESHOLDS['max_features']:
|
|
324
324
|
warnings.append(ManifestErrors.new(
|
|
325
325
|
message="Too many features ({}), consider splitting resource".format(len(features)),
|
|
326
326
|
category=ManifestErrors.CATEGORY['VALIDATION'],
|
|
327
327
|
severity=ManifestErrors.SEVERITY['WARNING'],
|
|
328
|
-
context={'field': '
|
|
328
|
+
context={'field': 'featuresEnabled', 'count': len(features), 'max': VALIDATION_THRESHOLDS['max_features']},
|
|
329
329
|
))
|
|
330
330
|
else:
|
|
331
331
|
stats['rules_passed'] += 1
|
|
@@ -374,16 +374,16 @@ def _validate_cross_field(manifest, context):
|
|
|
374
374
|
stats['rules_passed'] += 1
|
|
375
375
|
|
|
376
376
|
# Prisma requires databaseName
|
|
377
|
-
features = manifest.get('
|
|
377
|
+
features = manifest.get('featuresEnabled', [])
|
|
378
378
|
if 'prisma' in features:
|
|
379
379
|
stats['fields_checked'] += 1
|
|
380
|
-
|
|
380
|
+
|
|
381
381
|
if not manifest.get('databaseName'):
|
|
382
382
|
warnings.append(ManifestErrors.new(
|
|
383
383
|
message="Resource with 'prisma' feature should specify databaseName",
|
|
384
384
|
category=ManifestErrors.CATEGORY['VALIDATION'],
|
|
385
385
|
severity=ManifestErrors.SEVERITY['WARNING'],
|
|
386
|
-
context={'field': 'databaseName', '
|
|
386
|
+
context={'field': 'databaseName', 'featuresEnabled': features},
|
|
387
387
|
))
|
|
388
388
|
else:
|
|
389
389
|
stats['rules_passed'] += 1
|
|
@@ -14,6 +14,7 @@ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
|
|
|
14
14
|
|
|
15
15
|
load("../../../../platform/docker/auth/auth.star", "AuthConfig")
|
|
16
16
|
load("../../../../platform/docker/networking/traefik_helpers.star", "get_api_path")
|
|
17
|
+
load("../../../../platform/docker/networking/api_path_constants.star", "get_frontend_base_path")
|
|
17
18
|
load("../../../../platform/docker/constants.star", "PlatformDockerConstants")
|
|
18
19
|
|
|
19
20
|
|
|
@@ -133,8 +134,8 @@ def _generate_params_env(manifest, backend_manifest=None, write_fn=None):
|
|
|
133
134
|
backend_name = manifest.get('backendName', stack + '-backend')
|
|
134
135
|
target_filename = '/' + OUTPUT.AUTOGENERATED_FOLDER + '/.env.frontend.autogenerated'
|
|
135
136
|
|
|
136
|
-
#
|
|
137
|
-
base_path = manifest
|
|
137
|
+
# Shared with the Traefik route and the Vite `base` -- see get_frontend_base_path.
|
|
138
|
+
base_path = get_frontend_base_path(manifest)
|
|
138
139
|
public_url = 'http://' + PlatformDockerConstants.LOCAL_DOMAIN + base_path
|
|
139
140
|
|
|
140
141
|
content = """# Generated by Tilt SDK - DO NOT EDIT
|
|
@@ -360,7 +360,8 @@ def _generate_all_configs_for_resource(
|
|
|
360
360
|
dockerfile_content = Docker.backend(
|
|
361
361
|
res_path=resource_path,
|
|
362
362
|
resource_name=resource_name,
|
|
363
|
-
use_golden=should_enable('golden-image')
|
|
363
|
+
use_golden=should_enable('golden-image'),
|
|
364
|
+
use_prisma='prisma' in manifest.get('featuresEnabled', [])
|
|
364
365
|
)
|
|
365
366
|
|
|
366
367
|
write_file(resource_path + "/" + OUTPUT.AUTOGENERATED_FOLDER + "/" + GENERATED_CONFIG_FILENAMES['dockerfile_app'], dockerfile_content)
|
|
@@ -404,7 +405,7 @@ def _generate_all_configs_for_resource(
|
|
|
404
405
|
TSConfig.frontend(resource_path, write_file, internal_deps=internal_deps_map, is_docker=False)
|
|
405
406
|
else:
|
|
406
407
|
prisma_path = resource_config.get('prisma_client_path', './node_modules/.prisma/client')
|
|
407
|
-
resource_features = manifest.get('
|
|
408
|
+
resource_features = manifest.get('featuresEnabled', [])
|
|
408
409
|
TSConfig.backend(resource_path, prisma_path, write_file, internal_deps=internal_deps_map, is_docker=True, features=resource_features)
|
|
409
410
|
TSConfig.backend(resource_path, prisma_path, write_file, internal_deps=internal_deps_map, is_docker=False, features=resource_features)
|
|
410
411
|
|
package/package.json
CHANGED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$id": "https://TDK Landscape.local/schemas/service-schema.json",
|
|
3
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
-
"additionalProperties": false,
|
|
5
|
-
"allOf": [
|
|
6
|
-
{
|
|
7
|
-
"if": {
|
|
8
|
-
"properties": {
|
|
9
|
-
"appType": {
|
|
10
|
-
"const": "backend"
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"then": {
|
|
15
|
-
"properties": {
|
|
16
|
-
"port": {
|
|
17
|
-
"maximum": 5999,
|
|
18
|
-
"minimum": 4000
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"required": [
|
|
22
|
-
"port"
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"if": {
|
|
28
|
-
"properties": {
|
|
29
|
-
"appType": {
|
|
30
|
-
"const": "frontend"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"then": {
|
|
35
|
-
"properties": {
|
|
36
|
-
"port": {
|
|
37
|
-
"maximum": 3999,
|
|
38
|
-
"minimum": 3000
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"if": {
|
|
45
|
-
"properties": {
|
|
46
|
-
"appType": {
|
|
47
|
-
"const": "worker"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"then": {
|
|
52
|
-
"properties": {
|
|
53
|
-
"features": {
|
|
54
|
-
"contains": {
|
|
55
|
-
"const": "nats"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
"required": [
|
|
60
|
-
"features"
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
],
|
|
65
|
-
"description": "Configuration for TDK Landscape services. Drives Tilt orchestration, Docker Compose generation, and dependency resolution. Supports both explicit service.json files and synthesis from directory structure (CEO Review: rename-service-manifest).",
|
|
66
|
-
"properties": {
|
|
67
|
-
"$schema": {
|
|
68
|
-
"description": "JSON Schema reference for IDE validation",
|
|
69
|
-
"type": "string"
|
|
70
|
-
},
|
|
71
|
-
"apiBasePath": {
|
|
72
|
-
"default": "/api",
|
|
73
|
-
"description": "Base path for API routes in Traefik.",
|
|
74
|
-
"pattern": "^/[a-z0-9/-]*$",
|
|
75
|
-
"type": "string"
|
|
76
|
-
},
|
|
77
|
-
"appName": {
|
|
78
|
-
"description": "Unique resource identifier. Must match directory name.\nFormat: {stack}-{function}-{type}\nExample: 'user-management-backend'",
|
|
79
|
-
"examples": [
|
|
80
|
-
"user-management-backend",
|
|
81
|
-
"order-planner-frontend"
|
|
82
|
-
],
|
|
83
|
-
"maxLength": 64,
|
|
84
|
-
"minLength": 3,
|
|
85
|
-
"pattern": "^[a-z][a-z0-9-]*[a-z0-9]$",
|
|
86
|
-
"type": "string"
|
|
87
|
-
},
|
|
88
|
-
"appType": {
|
|
89
|
-
"description": "Service type determining build strategy:\n• backend - Hono/Express API server\n• frontend - Vite/React application\n• sdk - Shared library package\n• worker - Background job processor\n• migrator - Database migration runner\n• library - Shared code library",
|
|
90
|
-
"enum": [
|
|
91
|
-
"backend",
|
|
92
|
-
"frontend",
|
|
93
|
-
"sdk",
|
|
94
|
-
"worker",
|
|
95
|
-
"migrator",
|
|
96
|
-
"library"
|
|
97
|
-
],
|
|
98
|
-
"type": "string"
|
|
99
|
-
},
|
|
100
|
-
"backendName": {
|
|
101
|
-
"description": "For frontends: associated backend service.\nAuto-computed from appName if not specified.",
|
|
102
|
-
"pattern": "^[a-z][a-z0-9-]*-backend$",
|
|
103
|
-
"type": "string"
|
|
104
|
-
},
|
|
105
|
-
"basePath": {
|
|
106
|
-
"description": "Base path for frontend routing on TDK Landscape.localhost. Default is /{stack}s when omitted.",
|
|
107
|
-
"pattern": "^/[a-z0-9/-]*$",
|
|
108
|
-
"type": "string"
|
|
109
|
-
},
|
|
110
|
-
"databaseName": {
|
|
111
|
-
"description": "Override auto-generated DB name.\nDefault: TDK_{stack}",
|
|
112
|
-
"pattern": "^TDK_[a-z_]+$",
|
|
113
|
-
"type": "string"
|
|
114
|
-
},
|
|
115
|
-
"dependencies": {
|
|
116
|
-
"description": "Deprecated. Use 'dependsOn' instead.",
|
|
117
|
-
"deprecated": true,
|
|
118
|
-
"items": {
|
|
119
|
-
"pattern": "^[a-z][a-z0-9-]*$",
|
|
120
|
-
"type": "string"
|
|
121
|
-
},
|
|
122
|
-
"type": "array",
|
|
123
|
-
"uniqueItems": true
|
|
124
|
-
},
|
|
125
|
-
"dockerfile": {
|
|
126
|
-
"default": "autogenerated/Dockerfile.app.autogenerated",
|
|
127
|
-
"description": "Custom Dockerfile path relative to service directory.",
|
|
128
|
-
"type": "string"
|
|
129
|
-
},
|
|
130
|
-
"stack": {
|
|
131
|
-
"description": "Technology stack this resource belongs to.\nUsed for:\n• Database naming: TDK_{stack}\n• Traefik routing: /api/{stack}\n• NATS queue: {stack}_backend_svc",
|
|
132
|
-
"enum": [
|
|
133
|
-
"user",
|
|
134
|
-
"team",
|
|
135
|
-
"auth",
|
|
136
|
-
"order",
|
|
137
|
-
"order-planner",
|
|
138
|
-
"service",
|
|
139
|
-
"inventory",
|
|
140
|
-
"billing",
|
|
141
|
-
"notification",
|
|
142
|
-
"analytics",
|
|
143
|
-
"profile",
|
|
144
|
-
"platform",
|
|
145
|
-
"product"
|
|
146
|
-
],
|
|
147
|
-
"type": "string"
|
|
148
|
-
},
|
|
149
|
-
"params": {
|
|
150
|
-
"additionalProperties": {
|
|
151
|
-
"type": "string"
|
|
152
|
-
},
|
|
153
|
-
"description": "Non-secret configuration parameters (BASE_URL, PORT, etc.). Secrets use 'secrets' section below.",
|
|
154
|
-
"type": "object"
|
|
155
|
-
},
|
|
156
|
-
"secrets": {
|
|
157
|
-
"description": "Secret references resolved via Infisical. NO secrets in params/envVars - security violation.",
|
|
158
|
-
"properties": {
|
|
159
|
-
"required": {
|
|
160
|
-
"description": "Required secret names. Service CRASHES if any are missing.",
|
|
161
|
-
"items": {
|
|
162
|
-
"type": "string",
|
|
163
|
-
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
|
164
|
-
},
|
|
165
|
-
"type": "array",
|
|
166
|
-
"uniqueItems": true
|
|
167
|
-
},
|
|
168
|
-
"optional": {
|
|
169
|
-
"description": "Optional secret names. Service starts but warns if missing.",
|
|
170
|
-
"items": {
|
|
171
|
-
"type": "string",
|
|
172
|
-
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
|
173
|
-
},
|
|
174
|
-
"type": "array",
|
|
175
|
-
"uniqueItems": true
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
"required": [
|
|
179
|
-
"required"
|
|
180
|
-
],
|
|
181
|
-
"type": "object"
|
|
182
|
-
},
|
|
183
|
-
"features": {
|
|
184
|
-
"description": "Platform features:\n• nats - NATS JetStream eventing\n• prisma - DB ORM & migrations\n• redis - Caching layer\n• infisical - Secrets management\n• vitest - Test framework\n• traefik - Reverse proxy routing\n• websocket - WS support\n• graphql - GraphQL server\n• grpc - gRPC protocol",
|
|
185
|
-
"items": {
|
|
186
|
-
"enum": [
|
|
187
|
-
"nats",
|
|
188
|
-
"prisma",
|
|
189
|
-
"redis",
|
|
190
|
-
"infisical",
|
|
191
|
-
"vitest",
|
|
192
|
-
"traefik",
|
|
193
|
-
"websocket",
|
|
194
|
-
"graphql",
|
|
195
|
-
"grpc"
|
|
196
|
-
],
|
|
197
|
-
"type": "string"
|
|
198
|
-
},
|
|
199
|
-
"type": "array",
|
|
200
|
-
"uniqueItems": true
|
|
201
|
-
},
|
|
202
|
-
"healthCheckPath": {
|
|
203
|
-
"default": "/health",
|
|
204
|
-
"description": "HTTP endpoint for health checks. Must return 200 OK.",
|
|
205
|
-
"pattern": "^/[a-z0-9/-]*$",
|
|
206
|
-
"type": "string"
|
|
207
|
-
},
|
|
208
|
-
"dependsOn": {
|
|
209
|
-
"description": "Resource dependencies used for startup ordering and frontend dependency env generation.\nEach entry can be a stack name (e.g. 'user') or resource name (e.g. 'user-management-backend').\nServices listed here start before this service. Used for focus mode, health checks, migration order.",
|
|
210
|
-
"items": {
|
|
211
|
-
"pattern": "^[a-z][a-z0-9-]*$",
|
|
212
|
-
"type": "string"
|
|
213
|
-
},
|
|
214
|
-
"type": "array",
|
|
215
|
-
"uniqueItems": true
|
|
216
|
-
},
|
|
217
|
-
"nats": {
|
|
218
|
-
"description": "Custom NATS configuration. Auto-generated if 'nats' in features.",
|
|
219
|
-
"properties": {
|
|
220
|
-
"queueGroup": {
|
|
221
|
-
"description": "NATS queue group for load balancing",
|
|
222
|
-
"type": "string"
|
|
223
|
-
},
|
|
224
|
-
"subjects": {
|
|
225
|
-
"description": "NATS subjects to subscribe",
|
|
226
|
-
"items": {
|
|
227
|
-
"type": "string"
|
|
228
|
-
},
|
|
229
|
-
"type": "array"
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
"type": "object"
|
|
233
|
-
},
|
|
234
|
-
"playwright": {
|
|
235
|
-
"default": false,
|
|
236
|
-
"description": "Generate Playwright config in .autogenerated/playwright.config.autogenerated.ts when true.",
|
|
237
|
-
"type": "boolean"
|
|
238
|
-
},
|
|
239
|
-
"port": {
|
|
240
|
-
"description": "External dev port (internal always 3000).\nAssignments:\n• 4000: user\n• 4001: service\n• 4002: order\n• 4003: team\n• 4004: auth",
|
|
241
|
-
"examples": [
|
|
242
|
-
4000,
|
|
243
|
-
4001,
|
|
244
|
-
4002,
|
|
245
|
-
4003,
|
|
246
|
-
4004
|
|
247
|
-
],
|
|
248
|
-
"maximum": 9999,
|
|
249
|
-
"minimum": 3000,
|
|
250
|
-
"type": "integer"
|
|
251
|
-
},
|
|
252
|
-
"replicas": {
|
|
253
|
-
"default": 1,
|
|
254
|
-
"description": "Container instances to run.\nCreates separate containers (service-1, service-2).\nTraefik load-balances between all replicas.",
|
|
255
|
-
"maximum": 10,
|
|
256
|
-
"minimum": 1,
|
|
257
|
-
"type": "integer"
|
|
258
|
-
},
|
|
259
|
-
"runtime": {
|
|
260
|
-
"default": "bun",
|
|
261
|
-
"description": "Runtime to use for this service",
|
|
262
|
-
"enum": [
|
|
263
|
-
"node",
|
|
264
|
-
"bun"
|
|
265
|
-
],
|
|
266
|
-
"type": "string"
|
|
267
|
-
},
|
|
268
|
-
"syncs": {
|
|
269
|
-
"description": "Directories to sync for hot-reload.\nAuto-computed if not specified:\n• backend: ['src', 'prisma']\n• frontend: ['src', 'public']",
|
|
270
|
-
"items": {
|
|
271
|
-
"type": "string"
|
|
272
|
-
},
|
|
273
|
-
"type": "array"
|
|
274
|
-
},
|
|
275
|
-
"traefik": {
|
|
276
|
-
"description": "Custom Traefik routing. Auto-generated if not specified.",
|
|
277
|
-
"properties": {
|
|
278
|
-
"healthCheck": {
|
|
279
|
-
"description": "Health check path for Traefik",
|
|
280
|
-
"type": "string"
|
|
281
|
-
},
|
|
282
|
-
"host": {
|
|
283
|
-
"description": "Custom hostname (e.g., 'user.backend.{project}.local')",
|
|
284
|
-
"type": "string"
|
|
285
|
-
},
|
|
286
|
-
"pathPrefix": {
|
|
287
|
-
"description": "URL path prefix (e.g., '/api/user')",
|
|
288
|
-
"type": "string"
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
"type": "object"
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
"required": [
|
|
295
|
-
"appName",
|
|
296
|
-
"appType",
|
|
297
|
-
"stack"
|
|
298
|
-
],
|
|
299
|
-
"title": "TDK Landscape Service Configuration",
|
|
300
|
-
"type": "object"
|
|
301
|
-
}
|