go-duck-cli 1.3.0 → 1.3.2
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/generators/ai_docs.js +6 -0
- package/generators/devops.js +68 -20
- package/package.json +1 -1
- package/templates/docs/pages/index.hbs +10 -0
package/generators/ai_docs.js
CHANGED
|
@@ -43,6 +43,12 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
|
|
|
43
43
|
archContent += `- **Elasticsearch Sync**: ${config.search?.elasticsearch?.enabled ? 'Enabled (via @Searchable)' : 'Disabled'}\n`;
|
|
44
44
|
archContent += `- **OpenTelemetry**: ${config.telemetry?.otel?.enabled ? 'Enabled' : 'Disabled'}\n`;
|
|
45
45
|
|
|
46
|
+
archContent += `\n## Deployment (Kubernetes)\n`;
|
|
47
|
+
archContent += `- **Network Isolation**: Strict per-service isolated namespaces (e.g., \`[shortName]-[service]-k8s\`).\n`;
|
|
48
|
+
archContent += `- **Internal Routing**: Services communicate via explicit Fully Qualified Domain Names (FQDN).\n`;
|
|
49
|
+
archContent += `- **External Exposure**: Infrastructure services are exposed via explicit NodePort mappings (Range: 30000+).\n`;
|
|
50
|
+
archContent += `- **Self-Contained Manifests**: All manifests inject their own \`kind: Namespace\` block for auto-provisioning.\n`;
|
|
51
|
+
|
|
46
52
|
await fs.writeFile(path.join(aiDocsDir, 'ARCHITECTURE.md'), archContent);
|
|
47
53
|
|
|
48
54
|
// 2. ENDPOINTS.md
|
package/generators/devops.js
CHANGED
|
@@ -14,6 +14,8 @@ export const generateDeploymentArtifacts = async (config, projectRootDir) => {
|
|
|
14
14
|
await fs.ensureDir(githubDir);
|
|
15
15
|
|
|
16
16
|
const appName = config.name || 'go-duck';
|
|
17
|
+
const parts = appName.split(/[-_]/);
|
|
18
|
+
const shortName = (parts.length > 1 ? parts.map(w => w[0]).join('') : appName).substring(0, 10).toLowerCase() || 'goduck';
|
|
17
19
|
const appPort = config.server?.port || 8080;
|
|
18
20
|
const keycloakHost = config.security?.['keycloak-host'] || 'http://localhost:8180';
|
|
19
21
|
const keycloakPort = keycloakHost.includes(':') ? keycloakHost.split(':').pop() : '8080';
|
|
@@ -117,6 +119,7 @@ services:
|
|
|
117
119
|
mosquitto:
|
|
118
120
|
image: eclipse-mosquitto:2.0.18
|
|
119
121
|
container_name: ${appName}-mqtt
|
|
122
|
+
command: ["sh", "-c", "mosquitto_passwd -c -b /tmp/mosquitto_passwd ${config.messaging?.mqtt?.username || 'dev_user'} ${config.messaging?.mqtt?.password || 'dev_password'} && chown 1883:1883 /tmp/mosquitto_passwd && exec /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf"]
|
|
120
123
|
ports:
|
|
121
124
|
- "${mqttPort}:1883"
|
|
122
125
|
- "9001:9001"
|
|
@@ -269,7 +272,8 @@ networks:
|
|
|
269
272
|
listener 1883
|
|
270
273
|
listener 9001
|
|
271
274
|
protocol websockets
|
|
272
|
-
allow_anonymous
|
|
275
|
+
allow_anonymous false
|
|
276
|
+
password_file /tmp/mosquitto_passwd
|
|
273
277
|
`;
|
|
274
278
|
|
|
275
279
|
// --- 6. GitHub Actions CI/CD ---
|
|
@@ -454,7 +458,7 @@ spec:
|
|
|
454
458
|
- name: GO_DUCK_SERVER_REST_PORT
|
|
455
459
|
value: "${appPort}"
|
|
456
460
|
- name: GO_DUCK_DATASOURCE_HOST
|
|
457
|
-
value: postgres
|
|
461
|
+
value: postgres.${shortName}-postgres-k8s.svc.cluster.local
|
|
458
462
|
- name: GO_DUCK_DATASOURCE_USERNAME
|
|
459
463
|
value: "${config.datasource?.username || 'postgres'}"
|
|
460
464
|
- name: GO_DUCK_DATASOURCE_PASSWORD
|
|
@@ -464,17 +468,17 @@ spec:
|
|
|
464
468
|
- name: GO_DUCK_DATASOURCE_PORT
|
|
465
469
|
value: "5432"
|
|
466
470
|
- name: GO_DUCK_CACHE_REDIS_HOST
|
|
467
|
-
value: redis:6379
|
|
471
|
+
value: redis.${shortName}-redis-k8s.svc.cluster.local:6379
|
|
468
472
|
- name: GO_DUCK_MESSAGING_MQTT_BROKER
|
|
469
|
-
value: tcp://mosquitto:1883
|
|
473
|
+
value: tcp://mosquitto.${shortName}-mosquitto-k8s.svc.cluster.local:1883
|
|
470
474
|
- name: GO_DUCK_MESSAGING_NATS_URL
|
|
471
|
-
value: nats://nats:4222
|
|
475
|
+
value: nats://nats.${shortName}-nats-k8s.svc.cluster.local:4222
|
|
472
476
|
- name: GO_DUCK_TELEMETRY_OTEL_ENDPOINT
|
|
473
|
-
value: otel-collector:4317
|
|
477
|
+
value: otel-collector.${shortName}-otel-collector-k8s.svc.cluster.local:4317
|
|
474
478
|
- name: GO_DUCK_ELASTICSEARCH_ADDRESSES
|
|
475
|
-
value: http://elasticsearch:9200
|
|
479
|
+
value: http://elasticsearch.${shortName}-elasticsearch-k8s.svc.cluster.local:9200
|
|
476
480
|
- name: GO_DUCK_SECURITY_KEYCLOAK_HOST
|
|
477
|
-
value: http://keycloak:8080
|
|
481
|
+
value: http://keycloak.${shortName}-keycloak-k8s.svc.cluster.local:8080
|
|
478
482
|
ports:
|
|
479
483
|
- name: http
|
|
480
484
|
containerPort: ${appPort}
|
|
@@ -486,13 +490,16 @@ kind: Service
|
|
|
486
490
|
metadata:
|
|
487
491
|
name: ${appName}
|
|
488
492
|
spec:
|
|
493
|
+
type: NodePort
|
|
489
494
|
ports:
|
|
490
495
|
- name: http
|
|
491
496
|
port: ${appPort}
|
|
492
497
|
targetPort: http
|
|
498
|
+
nodePort: 30080
|
|
493
499
|
- name: grpc
|
|
494
500
|
port: 9000
|
|
495
501
|
targetPort: grpc
|
|
502
|
+
nodePort: 30090
|
|
496
503
|
selector:
|
|
497
504
|
app: ${appName}
|
|
498
505
|
`;
|
|
@@ -549,8 +556,10 @@ kind: Service
|
|
|
549
556
|
metadata:
|
|
550
557
|
name: postgres
|
|
551
558
|
spec:
|
|
559
|
+
type: NodePort
|
|
552
560
|
ports:
|
|
553
561
|
- port: 5432
|
|
562
|
+
nodePort: 30432
|
|
554
563
|
selector:
|
|
555
564
|
app: postgres
|
|
556
565
|
`;
|
|
@@ -582,8 +591,10 @@ kind: Service
|
|
|
582
591
|
metadata:
|
|
583
592
|
name: redis
|
|
584
593
|
spec:
|
|
594
|
+
type: NodePort
|
|
585
595
|
ports:
|
|
586
596
|
- port: 6379
|
|
597
|
+
nodePort: 30379
|
|
587
598
|
selector:
|
|
588
599
|
app: redis
|
|
589
600
|
`;
|
|
@@ -615,8 +626,10 @@ kind: Service
|
|
|
615
626
|
metadata:
|
|
616
627
|
name: nats
|
|
617
628
|
spec:
|
|
629
|
+
type: NodePort
|
|
618
630
|
ports:
|
|
619
631
|
- port: 4222
|
|
632
|
+
nodePort: 30222
|
|
620
633
|
selector:
|
|
621
634
|
app: nats
|
|
622
635
|
`;
|
|
@@ -630,7 +643,8 @@ data:
|
|
|
630
643
|
listener 1883
|
|
631
644
|
listener 9001
|
|
632
645
|
protocol websockets
|
|
633
|
-
allow_anonymous
|
|
646
|
+
allow_anonymous false
|
|
647
|
+
password_file /tmp/mosquitto_passwd
|
|
634
648
|
---
|
|
635
649
|
apiVersion: apps/v1
|
|
636
650
|
kind: Deployment
|
|
@@ -651,6 +665,7 @@ spec:
|
|
|
651
665
|
containers:
|
|
652
666
|
- name: mosquitto
|
|
653
667
|
image: eclipse-mosquitto:2.0.18
|
|
668
|
+
command: ["sh", "-c", "mosquitto_passwd -c -b /tmp/mosquitto_passwd ${config.messaging?.mqtt?.username || 'dev_user'} ${config.messaging?.mqtt?.password || 'dev_password'} && chown 1883:1883 /tmp/mosquitto_passwd && exec /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf"]
|
|
654
669
|
ports:
|
|
655
670
|
- containerPort: 1883
|
|
656
671
|
- containerPort: 9001
|
|
@@ -668,11 +683,14 @@ kind: Service
|
|
|
668
683
|
metadata:
|
|
669
684
|
name: mosquitto
|
|
670
685
|
spec:
|
|
686
|
+
type: NodePort
|
|
671
687
|
ports:
|
|
672
688
|
- name: mqtt
|
|
673
689
|
port: 1883
|
|
690
|
+
nodePort: 31883
|
|
674
691
|
- name: ws
|
|
675
692
|
port: 9001
|
|
693
|
+
nodePort: 30001
|
|
676
694
|
selector:
|
|
677
695
|
app: mosquitto
|
|
678
696
|
`;
|
|
@@ -711,8 +729,10 @@ kind: Service
|
|
|
711
729
|
metadata:
|
|
712
730
|
name: elasticsearch
|
|
713
731
|
spec:
|
|
732
|
+
type: NodePort
|
|
714
733
|
ports:
|
|
715
734
|
- port: 9200
|
|
735
|
+
nodePort: 30200
|
|
716
736
|
selector:
|
|
717
737
|
app: elasticsearch
|
|
718
738
|
`;
|
|
@@ -748,11 +768,14 @@ kind: Service
|
|
|
748
768
|
metadata:
|
|
749
769
|
name: jaeger
|
|
750
770
|
spec:
|
|
771
|
+
type: NodePort
|
|
751
772
|
ports:
|
|
752
773
|
- name: ui
|
|
753
774
|
port: 16686
|
|
775
|
+
nodePort: 30686
|
|
754
776
|
- name: otlp-grpc
|
|
755
777
|
port: 4317
|
|
778
|
+
nodePort: 30317
|
|
756
779
|
selector:
|
|
757
780
|
app: jaeger
|
|
758
781
|
`;
|
|
@@ -824,11 +847,14 @@ kind: Service
|
|
|
824
847
|
metadata:
|
|
825
848
|
name: otel-collector
|
|
826
849
|
spec:
|
|
850
|
+
type: NodePort
|
|
827
851
|
ports:
|
|
828
852
|
- name: otlp-grpc
|
|
829
853
|
port: 4317
|
|
854
|
+
nodePort: 30317
|
|
830
855
|
- name: otlp-http
|
|
831
856
|
port: 4318
|
|
857
|
+
nodePort: 30318
|
|
832
858
|
selector:
|
|
833
859
|
app: otel-collector
|
|
834
860
|
`;
|
|
@@ -890,8 +916,10 @@ kind: Service
|
|
|
890
916
|
metadata:
|
|
891
917
|
name: keycloak
|
|
892
918
|
spec:
|
|
919
|
+
type: NodePort
|
|
893
920
|
ports:
|
|
894
921
|
- port: 8080
|
|
922
|
+
nodePort: 30880
|
|
895
923
|
selector:
|
|
896
924
|
app: keycloak
|
|
897
925
|
`;
|
|
@@ -909,17 +937,33 @@ spec:
|
|
|
909
937
|
await fs.writeFile(path.join(devopsDir, 'app.yml'), appYaml);
|
|
910
938
|
await fs.writeFile(path.join(devopsDir, 'docker-compose.yml'), dockerCompose);
|
|
911
939
|
await fs.writeFile(path.join(k8sDir, 'mosquitto.conf'), mosquittoConf);
|
|
940
|
+
// Namespace calculation: unique namespace per service
|
|
941
|
+
const applyNs = (yamlString, serviceName) => {
|
|
942
|
+
const nsName = `${shortName}-${serviceName}-k8s`;
|
|
943
|
+
const nsBlock = `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${nsName}\n---\n`;
|
|
944
|
+
return nsBlock + yamlString.replace(/^metadata:$/gm, `metadata:\n namespace: ${nsName}`);
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
const servicesList = ['app', 'postgres', 'redis', 'nats', 'mosquitto', 'elasticsearch', 'jaeger', 'otel-collector', 'keycloak'];
|
|
948
|
+
if (config.datasource?.mongodb?.enabled) servicesList.push('mongodb');
|
|
912
949
|
|
|
950
|
+
// We conditionally add minio if storage is enabled (or any blob provider), but for safety we'll just generate its namespace always.
|
|
951
|
+
servicesList.push('minio');
|
|
952
|
+
|
|
953
|
+
const k8sNamespaceYaml = servicesList.map(svc => `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${shortName}-${svc}-k8s`).join('\n---\n');
|
|
954
|
+
|
|
955
|
+
await fs.writeFile(path.join(k8sDir, 'namespace.yaml'), k8sNamespaceYaml);
|
|
956
|
+
|
|
913
957
|
// Write Kubernetes manifest assets
|
|
914
|
-
await fs.writeFile(path.join(k8sDir, 'app.yaml'), k8sAppYaml);
|
|
915
|
-
await fs.writeFile(path.join(k8sDir, 'postgres.yaml'), k8sPostgresYaml);
|
|
916
|
-
await fs.writeFile(path.join(k8sDir, 'redis.yaml'), k8sRedisYaml);
|
|
917
|
-
await fs.writeFile(path.join(k8sDir, 'nats.yaml'), k8sNatsYaml);
|
|
918
|
-
await fs.writeFile(path.join(k8sDir, 'mosquitto.yaml'), k8sMosquittoYaml);
|
|
919
|
-
await fs.writeFile(path.join(k8sDir, 'elasticsearch.yaml'), k8sElasticsearchYaml);
|
|
920
|
-
await fs.writeFile(path.join(k8sDir, 'jaeger.yaml'), k8sJaegerYaml);
|
|
921
|
-
await fs.writeFile(path.join(k8sDir, 'otel-collector-k8s.yaml'), k8sOtelCollectorYaml);
|
|
922
|
-
await fs.writeFile(path.join(k8sDir, 'keycloak.yaml'), k8sKeycloakYaml);
|
|
958
|
+
await fs.writeFile(path.join(k8sDir, 'app.yaml'), applyNs(k8sAppYaml, 'app'));
|
|
959
|
+
await fs.writeFile(path.join(k8sDir, 'postgres.yaml'), applyNs(k8sPostgresYaml, 'postgres'));
|
|
960
|
+
await fs.writeFile(path.join(k8sDir, 'redis.yaml'), applyNs(k8sRedisYaml, 'redis'));
|
|
961
|
+
await fs.writeFile(path.join(k8sDir, 'nats.yaml'), applyNs(k8sNatsYaml, 'nats'));
|
|
962
|
+
await fs.writeFile(path.join(k8sDir, 'mosquitto.yaml'), applyNs(k8sMosquittoYaml, 'mosquitto'));
|
|
963
|
+
await fs.writeFile(path.join(k8sDir, 'elasticsearch.yaml'), applyNs(k8sElasticsearchYaml, 'elasticsearch'));
|
|
964
|
+
await fs.writeFile(path.join(k8sDir, 'jaeger.yaml'), applyNs(k8sJaegerYaml, 'jaeger'));
|
|
965
|
+
await fs.writeFile(path.join(k8sDir, 'otel-collector-k8s.yaml'), applyNs(k8sOtelCollectorYaml, 'otel-collector'));
|
|
966
|
+
await fs.writeFile(path.join(k8sDir, 'keycloak.yaml'), applyNs(k8sKeycloakYaml, 'keycloak'));
|
|
923
967
|
|
|
924
968
|
// Additional optional services manifests
|
|
925
969
|
const k8sMongoYaml = `apiVersion: apps/v1
|
|
@@ -949,8 +993,10 @@ kind: Service
|
|
|
949
993
|
metadata:
|
|
950
994
|
name: mongodb
|
|
951
995
|
spec:
|
|
996
|
+
type: NodePort
|
|
952
997
|
ports:
|
|
953
998
|
- port: 27017
|
|
999
|
+
nodePort: 30017
|
|
954
1000
|
selector:
|
|
955
1001
|
app: mongodb`;
|
|
956
1002
|
const k8sMinioYaml = `apiVersion: apps/v1
|
|
@@ -988,12 +1034,14 @@ kind: Service
|
|
|
988
1034
|
metadata:
|
|
989
1035
|
name: minio
|
|
990
1036
|
spec:
|
|
1037
|
+
type: NodePort
|
|
991
1038
|
ports:
|
|
992
1039
|
- port: 9000
|
|
1040
|
+
nodePort: 30900
|
|
993
1041
|
selector:
|
|
994
1042
|
app: minio`;
|
|
995
|
-
await fs.writeFile(path.join(k8sDir, 'mongodb.yaml'), k8sMongoYaml);
|
|
996
|
-
await fs.writeFile(path.join(k8sDir, 'minio.yaml'), k8sMinioYaml);
|
|
1043
|
+
await fs.writeFile(path.join(k8sDir, 'mongodb.yaml'), applyNs(k8sMongoYaml, 'mongodb'));
|
|
1044
|
+
await fs.writeFile(path.join(k8sDir, 'minio.yaml'), applyNs(k8sMinioYaml, 'minio'));
|
|
997
1045
|
|
|
998
1046
|
await fs.writeFile(path.join(githubDir, 'ci.yml'), ciWorkflow);
|
|
999
1047
|
await fs.writeFile(path.join(githubDir, 'cd.yml'), cdWorkflow);
|
package/package.json
CHANGED
|
@@ -120,6 +120,16 @@
|
|
|
120
120
|
<span class="px-4 py-1.5 bg-orange-100 text-orange-700 text-[9px] font-black rounded-lg">WSO2 REST PROXY</span>
|
|
121
121
|
</div>
|
|
122
122
|
</div>
|
|
123
|
+
|
|
124
|
+
<div class="lg:col-span-12 bg-white p-10 rounded-[2.5rem] border border-fuchsia-100 shadow-sm hover:shadow-2xl transition-all group relative overflow-hidden cursor-crosshair bg-gradient-to-br from-white to-fuchsia-50/30">
|
|
125
|
+
<p class="text-[9px] font-bold text-fuchsia-600 uppercase tracking-widest mb-4">Elite Extension (+12%)</p>
|
|
126
|
+
<h4 class="text-2xl font-black text-slate-900 mb-3 tracking-tight italic">K8s Network Isolation & NodePorts</h4>
|
|
127
|
+
<p class="text-slate-600 leading-relaxed mb-8">Deploys every microservice component into its own dynamically generated namespace. Uses internal FQDN routing for secure communication and predictable NodePorts for host access.</p>
|
|
128
|
+
<div class="flex gap-3">
|
|
129
|
+
<span class="px-4 py-1.5 bg-fuchsia-100 text-fuchsia-700 text-[9px] font-black rounded-lg">ISOLATED NAMESPACES</span>
|
|
130
|
+
<span class="px-4 py-1.5 bg-fuchsia-100 text-fuchsia-700 text-[9px] font-black rounded-lg">FQDN ROUTING</span>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
123
133
|
</div>
|
|
124
134
|
</div>
|
|
125
135
|
</section>
|