go-duck-cli 1.2.1 → 1.2.3
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 +74 -1
- package/generators/ai_docs.js +22 -8
- package/generators/config.js +13 -7
- package/generators/devops.js +591 -1
- package/generators/elasticsearch.js +3 -4
- package/generators/postman.js +156 -6
- package/generators/security.js +2 -2
- package/index.js +62 -7
- package/package.json +1 -1
- package/parser/gdl.js +2 -0
- package/templates/docs/index.html.hbs +24 -1
- package/templates/docs/pages/cli.hbs +20 -4
- package/templates/docs/pages/gdl-annotations.hbs +17 -0
- package/templates/docs/pages/rest.hbs +21 -0
- package/templates/go/controller.go.hbs +107 -20
- package/templates/go/main.go.hbs +16 -2
- package/templates/kratos/service.go.hbs +25 -2
- package/templates/proto/entity.proto.hbs +1 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://badge.fury.io/js/go-duck-cli"><img src="https://badge.fury.io/js/go-duck-cli.svg" alt="npm version"></a>
|
|
15
15
|
<a href="https://opensource.org/licenses/ISC"><img src="https://img.shields.io/badge/License-ISC-blue.svg" alt="License: ISC"></a>
|
|
16
|
+

|
|
16
17
|
</p>
|
|
17
18
|
|
|
18
19
|
---
|
|
@@ -64,6 +65,8 @@ GO-DUCK has officially reached the **410% Achievement Status**, evolving from a
|
|
|
64
65
|
### ✨ Primary Features (The 410% Core)
|
|
65
66
|
|
|
66
67
|
* **Federated Multi-Tenancy**: Side-by-side **Database-per-Tenant isolation** with a **Master-Tenant Registry** (Role ↔ DB ↔ Opaque UUID).
|
|
68
|
+
* **Multi-Protocol REST**: Dynamically switchable REST rendering using standard `json` or high-performance `messagepack` based on configuration.
|
|
69
|
+
* **gRPC-Web Native Proxy**: Natively wraps Kratos gRPC to automatically serve a web proxy (e.g. on port `9090`) to allow direct frontend Protobuf interaction.
|
|
67
70
|
* **Industrial-Grade Parallel Harvester**: Asynchronous goroutine-based data aggregation across multiple silos with `?federated=true` opt-in.
|
|
68
71
|
* **Precision Harvesting**: Surgical multi-silo selection via comma-separated `X-Tenant-ID` headers.
|
|
69
72
|
* **Super Admin Security Boundaries**: Strict architectural separation between Business APIs and Infrastructure Control APIs.
|
|
@@ -72,7 +75,7 @@ GO-DUCK has officially reached the **410% Achievement Status**, evolving from a
|
|
|
72
75
|
* **Distributed Saga Consistency**: Integrated **Transactional Outbox** pattern and background workers in every silo to guarantee eventual consistency across the federation.
|
|
73
76
|
* **Zero-Trust Identity Registry**: Decoupled mapping layer ensuring physical database names and internal IDs never leak to the client.
|
|
74
77
|
* **Universal Storage Mesh**: Dynamic Multi-Provider Registry allowing hot-swapping at runtime via `?provider=` queries, alongside Distributed Cross-Scan endpoints to auto-locate files across AWS, GCS, SFTP, and GitHub lakes.
|
|
75
|
-
* **Spring-style Elasticsearch Search**: Real-time sync for entities marked with `@Searchable`, supporting
|
|
78
|
+
* **Spring-style Elasticsearch Search**: Real-time sync for entities marked with `@Searchable`, supporting native `query_string` syntax (wildcards like `*`, booleans, ranges, and fuzzy matching).
|
|
76
79
|
* **SaaS Quota Engine**: Redis-backed API bandwidth tracking with dynamic, hierarchical limits (User vs. Role mapping).
|
|
77
80
|
* **Resilience Layer**: Sony/Gobreaker Integration + Zero-Trust Distributed Redis Rate Limiter.
|
|
78
81
|
* **Comprehensive GDL Schema Evolution**: Detects structural deltas intelligently and automatically generates Goose SQL for dropped entities (`DROP TABLE`), dropped fields (`DROP COLUMN`), and altered fields (`ALTER TYPE`, constraints) to keep databases in absolute sync.
|
|
@@ -104,6 +107,15 @@ Ensure your development environment meets the following requirements:
|
|
|
104
107
|
* **Docker:** v20+
|
|
105
108
|
* **Composability:** v2+
|
|
106
109
|
|
|
110
|
+
## Quick‑Start
|
|
111
|
+
|
|
112
|
+
Follow these four steps to get a generated microservice running locally and in Kubernetes:
|
|
113
|
+
|
|
114
|
+
1. **Create**: `go-duck create -o ./my-app -c config.yaml`
|
|
115
|
+
2. **Enter**: `cd my-app`
|
|
116
|
+
3. **Build & Push**: `./push.sh my-registry/my-app:1.0.0`
|
|
117
|
+
4. **Deploy**: `kubectl apply -f devops/k8s/`
|
|
118
|
+
|
|
107
119
|
## 🚀 Scaffold & Run
|
|
108
120
|
|
|
109
121
|
Follow these steps to create and run a new microservice with GO-DUCK:
|
|
@@ -114,6 +126,36 @@ go-duck create -o ./my-app -c config.yaml
|
|
|
114
126
|
|
|
115
127
|
# 2. Enter the application directory
|
|
116
128
|
cd my-app
|
|
129
|
+
|
|
130
|
+
# 3. Build, tag, and push Docker image (updates app.yaml)
|
|
131
|
+
./push.sh my-registry/my-app:1.0.0
|
|
132
|
+
|
|
133
|
+
# 4. Deploy to Kubernetes
|
|
134
|
+
kubectl apply -f devops/k8s/
|
|
135
|
+
|
|
136
|
+
### 🚢 Deploy to Kubernetes & Push Images
|
|
137
|
+
|
|
138
|
+
The generated project includes a **devops/k8s** directory with ready‑to‑apply Kubernetes manifests:
|
|
139
|
+
|
|
140
|
+
- `mongo.yaml` – StatefulSet & Service for MongoDB.
|
|
141
|
+
- `minio.yaml` – Deployment & Service for MinIO object storage.
|
|
142
|
+
- `app.yaml` – Deployment for the generated Go microservice, referencing a placeholder image name (`<app‑name>:latest`). Replace the image with the tag you push.
|
|
143
|
+
|
|
144
|
+
A helper script **push.sh** (located at the project root) automates the Docker build, tag, push, and then updates the `app.yaml` image field:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
./push.sh my-registry/my-app:1.0.0
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
After pushing, deploy everything with:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
kubectl apply -f devops/k8s/
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> [!NOTE]
|
|
157
|
+
> The K8s manifests use placeholder values (e.g., resource limits, storage class). Adjust them to match your cluster requirements before applying.
|
|
158
|
+
|
|
117
159
|
```
|
|
118
160
|
|
|
119
161
|
### 🏗️ Compiling Protobuf & gRPC Contracts
|
|
@@ -156,6 +198,37 @@ docker-compose up -d
|
|
|
156
198
|
go run main.go
|
|
157
199
|
```
|
|
158
200
|
|
|
201
|
+
## 🌐 Calling the Multi-Protocol Endpoints
|
|
202
|
+
|
|
203
|
+
GO-DUCK automatically exposes your microservice across three distinct ports to serve different architectural needs without code duplication:
|
|
204
|
+
|
|
205
|
+
1. **REST API (Port 8080 by default)**
|
|
206
|
+
Standard HTTP endpoints for web browsers and legacy clients.
|
|
207
|
+
- **JSON (Default):** Perfect for general use.
|
|
208
|
+
- **MessagePack (High Performance):** To switch to binary MessagePack, update your `config.yaml` before generation:
|
|
209
|
+
```yaml
|
|
210
|
+
server:
|
|
211
|
+
rest:
|
|
212
|
+
port: 8080
|
|
213
|
+
protocol: "messagepack"
|
|
214
|
+
```
|
|
215
|
+
Clients must send the `Accept: application/msgpack` and `Content-Type: application/msgpack` headers to consume this endpoint correctly.
|
|
216
|
+
- **Pagination & Sorting:** All `GetAll` endpoints support pagination via `?page=1&size=20`, and dynamic sorting via `?sort=field,asc` or `?sort=field,desc` (e.g. `?sort=name,desc`).
|
|
217
|
+
|
|
218
|
+
2. **Native Kratos gRPC (Port 9000 by default)**
|
|
219
|
+
Pure HTTP/2 Protobuf communication. Used strictly for internal **backend-to-backend** communication (e.g., Microservice A calling Microservice B) where maximum throughput is required.
|
|
220
|
+
|
|
221
|
+
3. **gRPC-Web Proxy (Port 9090 by default)**
|
|
222
|
+
Web browsers cannot speak raw HTTP/2 gRPC. This port acts as an HTTP/1.1 proxy bridge, allowing frontend frameworks (React, Angular, Vue) to interact directly with the Protobuf gRPC contracts.
|
|
223
|
+
To disable or change the proxy port, update your `config.yaml`:
|
|
224
|
+
```yaml
|
|
225
|
+
server:
|
|
226
|
+
grpc:
|
|
227
|
+
web_enabled: true
|
|
228
|
+
web_port: 9090
|
|
229
|
+
```
|
|
230
|
+
*Frontend Tip: Use the `grpc-web` npm package to generate a frontend client that communicates with this port!*
|
|
231
|
+
|
|
159
232
|
## Usage
|
|
160
233
|
|
|
161
234
|
The `go-duck-cli` has two main commands: `create` and `import-gdl`.
|
package/generators/ai_docs.js
CHANGED
|
@@ -52,7 +52,7 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
|
|
|
52
52
|
for (const entity of entities) {
|
|
53
53
|
const routeName = entity.name.toLowerCase() + 's';
|
|
54
54
|
endpointsContent += `\n#### ${entity.name}\n`;
|
|
55
|
-
endpointsContent += `- \`GET /api/${routeName}\` (Pagination, e.g. \`?page=1&size=10&eager=true\`)\n`;
|
|
55
|
+
endpointsContent += `- \`GET /api/${routeName}\` (Pagination & dynamic sorting, e.g. \`?page=1&size=10&eager=true&sort=id,asc\`)\n`;
|
|
56
56
|
endpointsContent += `- \`GET /api/${routeName}/:id\`\n`;
|
|
57
57
|
endpointsContent += `- \`POST /api/${routeName}\`\n`;
|
|
58
58
|
endpointsContent += `- \`PUT /api/${routeName}/:id\`\n`;
|
|
@@ -88,6 +88,7 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
|
|
|
88
88
|
if (entity.isSearchable) entitiesContent += `- \`@Searchable\`\n`;
|
|
89
89
|
if (entity.isAudited) entitiesContent += `- \`@Audited\`\n`;
|
|
90
90
|
if (entity.isFederated) entitiesContent += `- \`@Federated\`\n`;
|
|
91
|
+
if (entity.isDelete) entitiesContent += `- \`@Delete\`\n`;
|
|
91
92
|
|
|
92
93
|
entitiesContent += `\nFields:\n`;
|
|
93
94
|
for (const field of entity.fields) {
|
|
@@ -101,16 +102,20 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
|
|
|
101
102
|
// 4. PROTOCOLS.md
|
|
102
103
|
let protoContent = `# Additional Network Protocols\n\n`;
|
|
103
104
|
protoContent += `## GraphQL Surface\n`;
|
|
104
|
-
protoContent += `- **Endpoint**: \`POST /
|
|
105
|
-
protoContent += `- **Playground**:
|
|
105
|
+
protoContent += `- **Endpoint**: \`POST /graphql\` (Secured via JWT and Tenant headers)\n`;
|
|
106
|
+
protoContent += `- **Playground**: GraphQL Playground UI is enabled on the server.\n`;
|
|
107
|
+
protoContent += `- **Queries**: \`list[Entity]s(page: Int, size: Int)\`, \`get[Entity](id: ID!)\`\n`;
|
|
108
|
+
protoContent += `- **Mutations**: \`create[Entity](input: CreateInput)\`, \`update[Entity](id: ID!, input: UpdateInput)\`, \`delete[Entity](id: ID!)\`\n`;
|
|
109
|
+
protoContent += `- **Postman Collection Integration**: The auto-generated Postman collection includes a comprehensive **GraphQL Federation Layer** folder containing test queries and mutations for all entities.\n\n`;
|
|
106
110
|
|
|
107
111
|
protoContent += `## WebSocket Engine\n`;
|
|
108
|
-
protoContent += `- **Endpoint**: \`ws[s]://host/ws\`\n`;
|
|
109
|
-
protoContent += `- **Format**: JSON Envelope Payload \`{ "type": "...", "payload": {...} }\`\n\n`;
|
|
112
|
+
protoContent += `- **Endpoint**: \`ws[s]://host/ws?token={JWT}\`\n`;
|
|
113
|
+
protoContent += `- **Format**: JSON Envelope Payload with HMAC-SHA256 digital signature: \`{ "type": "...", "payload": {...} }\`\n\n`;
|
|
110
114
|
|
|
111
|
-
protoContent += `## gRPC
|
|
112
|
-
protoContent += `- **Port**: \`9000\` (
|
|
113
|
-
protoContent += `- **
|
|
115
|
+
protoContent += `## gRPC & gRPC-Web Engine\n`;
|
|
116
|
+
protoContent += `- **Native Kratos gRPC Port**: \`9000\` (TCP)\n`;
|
|
117
|
+
protoContent += `- **gRPC-Web Proxy Port**: \`9090\` (HTTP/1.1 for web clients)\n`;
|
|
118
|
+
protoContent += `- **Proto Definitions**: Located in \`api/v1/*.proto\`\n`;
|
|
114
119
|
|
|
115
120
|
await fs.writeFile(path.join(aiDocsDir, 'PROTOCOLS.md'), protoContent);
|
|
116
121
|
|
|
@@ -118,6 +123,15 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
|
|
|
118
123
|
let agentInstructions = `# LLM / AI AGENT INSTRUCTIONS 🤖\n\n`;
|
|
119
124
|
agentInstructions += `Welcome to the generated codebase for **${appName}**.\n\n`;
|
|
120
125
|
agentInstructions += `This application was generated by the GO-DUCK-CLI (An advanced Evolutionary Go Code Generator).\n\n`;
|
|
126
|
+
agentInstructions += `### High-Velocity Commands:\n`;
|
|
127
|
+
agentInstructions += `- **Build Project**: \`go build ./...\`\n`;
|
|
128
|
+
agentInstructions += `- **Protobuf Compilation**: \`./generate.sh\` (or \`.\\generate.bat\` on Windows)\n`;
|
|
129
|
+
agentInstructions += `- **Local Dependencies & Dev Boot**: \`docker-compose up -d && go run main.go\`\n`;
|
|
130
|
+
agentInstructions += `- **Docker Build & Push**: \`./push.sh\` (Builds and pushes the Docker image to registry)\n\n`;
|
|
131
|
+
agentInstructions += `### GDL Evolution & Schema Deletions:\n`;
|
|
132
|
+
agentInstructions += `- **Snapshot Merging (Multi-File GDL)**: The generator implements stateful snapshot merging. Running \`import-gdl\` on a single GDL file will NOT wipe out other entities; previous snapshots are retrieved from the \`.go-duck/\` state folder and merged automatically.\n`;
|
|
133
|
+
agentInstructions += `- **Altering/Dropping Fields**: To add, drop, or edit fields within an entity, update the fields inline in the GDL entity block. Running \`import-gdl\` generates targeted Goose SQL column-level migrations.\n`;
|
|
134
|
+
agentInstructions += `- **Dropping Entities**: To completely delete an entity, its database table, all generated code files, and its snapshot, append the \`@Delete\` annotation above the entity definition block and run \`import-gdl\`.\n\n`;
|
|
121
135
|
agentInstructions += `### How to navigate this system:\n`;
|
|
122
136
|
agentInstructions += `The full system specifications and dynamically generated blueprints have been exported for you in the \`docs/ai/\` folder. Look there before attempting any code modifications.\n\n`;
|
|
123
137
|
agentInstructions += `- **[docs/ai/ARCHITECTURE.md](docs/ai/ARCHITECTURE.md)**: Describes the databases, caching layers, configuration structure, and middleware enabled in this project.\n`;
|
package/generators/config.js
CHANGED
|
@@ -25,13 +25,16 @@ type Config struct {
|
|
|
25
25
|
Description string \`mapstructure:"description"\`
|
|
26
26
|
|
|
27
27
|
Server struct {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
REST struct {
|
|
29
|
+
Port int \`mapstructure:"port"\`
|
|
30
|
+
Protocol string \`mapstructure:"protocol"\`
|
|
31
|
+
} \`mapstructure:"rest"\`
|
|
31
32
|
GRPC struct {
|
|
32
|
-
Addr
|
|
33
|
-
Network
|
|
34
|
-
Timeout
|
|
33
|
+
Addr string \`mapstructure:"addr"\`
|
|
34
|
+
Network string \`mapstructure:"network"\`
|
|
35
|
+
Timeout time.Duration \`mapstructure:"timeout"\`
|
|
36
|
+
WebEnabled bool \`mapstructure:"web_enabled"\`
|
|
37
|
+
WebPort int \`mapstructure:"web_port"\`
|
|
35
38
|
} \`mapstructure:"grpc"\`
|
|
36
39
|
CORS struct {
|
|
37
40
|
AllowOrigins []string \`mapstructure:"allow-origins"\`
|
|
@@ -237,7 +240,8 @@ func LoadConfig() (*Config, error) {
|
|
|
237
240
|
v.AddConfigPath(".")
|
|
238
241
|
|
|
239
242
|
// Default values
|
|
240
|
-
v.SetDefault("go-duck.server.port", 8080)
|
|
243
|
+
v.SetDefault("go-duck.server.rest.port", 8080)
|
|
244
|
+
v.SetDefault("go-duck.server.rest.protocol", "json")
|
|
241
245
|
v.SetDefault("go-duck.security.rate-limit.rps", 100.0)
|
|
242
246
|
v.SetDefault("go-duck.security.rate-limit.burst", 200)
|
|
243
247
|
v.SetDefault("go-duck.logging.datadog.enabled", false)
|
|
@@ -254,6 +258,8 @@ func LoadConfig() (*Config, error) {
|
|
|
254
258
|
v.SetDefault("go-duck.server.grpc.addr", ":9000")
|
|
255
259
|
v.SetDefault("go-duck.server.grpc.network", "tcp")
|
|
256
260
|
v.SetDefault("go-duck.server.grpc.timeout", "1s")
|
|
261
|
+
v.SetDefault("go-duck.server.grpc.web_enabled", false)
|
|
262
|
+
v.SetDefault("go-duck.server.grpc.web_port", 9090)
|
|
257
263
|
v.SetDefault("go-duck.resilience.circuit-breaker.enabled", true)
|
|
258
264
|
v.SetDefault("go-duck.resilience.circuit-breaker.failure-threshold", 5)
|
|
259
265
|
v.SetDefault("go-duck.resilience.circuit-breaker.timeout", "60s")
|