go-duck-cli 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 (49) hide show
  1. package/README.md +130 -0
  2. package/generators/cache.js +107 -0
  3. package/generators/config.js +173 -0
  4. package/generators/devops.js +212 -0
  5. package/generators/docs.js +74 -0
  6. package/generators/graphql.js +38 -0
  7. package/generators/kratos.js +157 -0
  8. package/generators/logger.js +68 -0
  9. package/generators/metering.js +143 -0
  10. package/generators/migrations.js +240 -0
  11. package/generators/mqtt.js +87 -0
  12. package/generators/multitenancy.js +130 -0
  13. package/generators/postgrest.js +115 -0
  14. package/generators/repository.js +28 -0
  15. package/generators/resilience.js +69 -0
  16. package/generators/security.js +168 -0
  17. package/generators/swagger.js +145 -0
  18. package/generators/telemetry.js +121 -0
  19. package/generators/websocket.js +162 -0
  20. package/index.js +592 -0
  21. package/package.json +23 -0
  22. package/parser/gdl.js +162 -0
  23. package/templates/application.yml.hbs +18 -0
  24. package/templates/docs/gin_bottle.png +0 -0
  25. package/templates/docs/index.html.hbs +226 -0
  26. package/templates/docs/intro.mp4 +0 -0
  27. package/templates/docs/kratos_mark.png +0 -0
  28. package/templates/docs/layout.hbs +106 -0
  29. package/templates/docs/logo.png +0 -0
  30. package/templates/docs/pages/audit.hbs +39 -0
  31. package/templates/docs/pages/cli.hbs +83 -0
  32. package/templates/docs/pages/gdl.hbs +223 -0
  33. package/templates/docs/pages/graphql.hbs +51 -0
  34. package/templates/docs/pages/grpc.hbs +100 -0
  35. package/templates/docs/pages/index.hbs +181 -0
  36. package/templates/docs/pages/integrations.hbs +83 -0
  37. package/templates/docs/pages/observability.hbs +34 -0
  38. package/templates/docs/pages/realtime.hbs +43 -0
  39. package/templates/docs/pages/rest.hbs +149 -0
  40. package/templates/docs/pages/security.hbs +31 -0
  41. package/templates/go/controller.go.hbs +236 -0
  42. package/templates/go/entity.go.hbs +34 -0
  43. package/templates/go/enum.go.hbs +7 -0
  44. package/templates/go/main.go.hbs +186 -0
  45. package/templates/graphql/resolver.go.hbs +50 -0
  46. package/templates/graphql/schema.graphql.hbs +64 -0
  47. package/templates/kratos/service.go.hbs +104 -0
  48. package/templates/proto/entity.proto.hbs +95 -0
  49. package/test_parser.js +9 -0
@@ -0,0 +1,83 @@
1
+ <div class="mb-10 border-b border-slate-200 pb-8">
2
+ <div class="inline-flex items-center px-3 py-1 rounded-full bg-slate-200 text-slate-700 text-xs font-semibold tracking-wide uppercase mb-4">
3
+ Generator Engine
4
+ </div>
5
+ <h1 class="text-4xl lg:text-5xl font-extrabold text-slate-900 tracking-tight leading-tight mb-4">CLI Usage & Evolution</h1>
6
+ <p class="text-lg lg:text-xl text-slate-600 max-w-2xl leading-relaxed">How to safely use the GO-DUCK Generator without destroying your manual Go code edits over time.</p>
7
+ </div>
8
+
9
+ <section class="mb-12">
10
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
11
+ <span class="w-8 h-8 rounded-lg bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 text-sm">
12
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
13
+ </span>
14
+ 1. The Command Pipeline
15
+ </h2>
16
+ <p class="mb-6 text-slate-600 leading-relaxed">The GO-DUCK-CLI operates on basically two commands. The initialization of your system, and the continuous evolution pipeline.</p>
17
+
18
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg mb-4">
19
+ <div class="bg-[#2d2d2d] px-4 py-2 border-b border-[#404040] flex items-center justify-between">
20
+ <div class="flex items-center">
21
+ <div class="flex space-x-1.5 mr-4">
22
+ <div class="w-3 h-3 rounded-full bg-rose-500"></div>
23
+ <div class="w-3 h-3 rounded-full bg-amber-500"></div>
24
+ <div class="w-3 h-3 rounded-full bg-emerald-500"></div>
25
+ </div>
26
+ <span class="text-xs text-slate-300 font-mono">Terminal</span>
27
+ </div>
28
+ <span class="text-[10px] text-slate-400 font-bold uppercase tracking-widest">Bash</span>
29
+ </div>
30
+ <div class="p-5 overflow-x-auto text-sm">
31
+ <pre><code class="language-bash"># Command 1: Fresh Creation
32
+ # Scaffold an entirely new ecosystem. This generates ALL baseline infrastructure.
33
+ go-duck create -o ./MY_APP -c config.yaml -g initial_schema.gdl
34
+
35
+ # Command 2: Incremental Stateful Update
36
+ # Used whenever you modify your GDL (add an entity, drop a column, add a link)
37
+ go-duck import-gdl my_new_schema.gdl -o ./MY_APP</code></pre>
38
+ </div>
39
+ </div>
40
+ </section>
41
+
42
+ <section class="mb-12">
43
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
44
+ <span class="w-8 h-8 rounded-lg bg-emerald-100 text-emerald-600 flex items-center justify-center mr-3 text-sm">
45
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"></path></svg>
46
+ </span>
47
+ 2. Persistence Intelligence & the `.go-duck/` Folder
48
+ </h2>
49
+ <p class="mb-4 text-slate-600 leading-relaxed font-medium">"If I run the generator twice, will it overwrite my database migrations?" <strong>No.</strong></p>
50
+
51
+ <p class="mb-6 text-slate-600 leading-relaxed">The generator maintains a stateful snapshot of every entity it has ever generated inside the hidden <code class="bg-slate-100 px-1 py-0.5 rounded text-slate-800 font-mono text-sm">.go-duck/</code> directory at the root of your target project. When you run <code>import-gdl</code>, the code parser literally diffs your new file against the JSON representations in <code>.go-duck/</code> to intelligently assess the exact Table changes necessary without executing ghost migrations.</p>
52
+
53
+ <div class="bg-rose-50 border border-rose-200 p-5 mb-6 rounded-xl flex items-start shadow-sm shadow-rose-100/50">
54
+ <svg class="w-6 h-6 text-rose-500 mt-0.5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>
55
+ <div>
56
+ <h4 class="font-bold text-rose-900 mb-1">Warning</h4>
57
+ <p class="text-rose-800 text-sm leading-relaxed"><strong>Never delete `.go-duck/`</strong> unless you are intentionally wiping the database and starting configuration completely from zero.</p>
58
+ </div>
59
+ </div>
60
+ </section>
61
+
62
+ <section class="mb-10">
63
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
64
+ <span class="w-8 h-8 rounded-lg bg-orange-100 text-orange-600 flex items-center justify-center mr-3 text-sm">
65
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path></svg>
66
+ </span>
67
+ 3. JHipster-Style "Needles" (Safe Code Injection)
68
+ </h2>
69
+ <p class="mb-4 text-slate-600 leading-relaxed font-medium">"If I write custom endpoints in `main.go`, will running the generator wipe them out?" <strong class="text-indigo-600">No, as long as you use Needles!</strong></p>
70
+
71
+ <p class="mb-4 text-slate-600 leading-relaxed">The generator utilizes carefully placed specific comments called "needles". For example, inside <code>main.go</code>, you will see markers exactly like <code class="bg-slate-100 px-1 py-0.5 rounded text-slate-800 font-mono text-sm">// go-duck-needle-add-init-server</code>.</p>
72
+
73
+ <p class="mb-8 text-slate-600 leading-relaxed">When the generator runs an incremental update, it doesn't arbitrarily overwrite <code>main.go</code> via a template. It opens the <em>existing</em> compiled <code>main.go</code> file on your machine, locates the Needle anchor point via REGEX, and safely inserts the new syntax directly below it.</p>
74
+
75
+ <div class="bg-white border text-sm border-slate-200 rounded-xl overflow-hidden shadow-sm">
76
+ <div class="px-5 py-3 border-b border-slate-100 bg-slate-50 font-bold text-slate-700">Active Go Needle Locations (DO NOT DELETE)</div>
77
+ <ul class="divide-y divide-slate-100 font-mono text-slate-600">
78
+ <li class="px-5 py-3 flex items-center"><svg class="w-4 h-4 text-indigo-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>// go-duck-needle-add-import (main.go)</li>
79
+ <li class="px-5 py-3 flex items-center"><svg class="w-4 h-4 text-indigo-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>// go-duck-needle-add-init-repository (main.go)</li>
80
+ <li class="px-5 py-3 flex items-center"><svg class="w-4 h-4 text-indigo-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>// go-duck-needle-add-grpc-service (internal/server/grpc.go)</li>
81
+ </ul>
82
+ </div>
83
+ </section>
@@ -0,0 +1,223 @@
1
+ <div class="mb-10 text-center lg:text-left border-b border-slate-200 pb-8">
2
+ <div class="inline-flex items-center px-3 py-1 rounded-full bg-emerald-100 text-emerald-700 text-xs font-semibold tracking-wide uppercase mb-4">
3
+ Domain Driven Design
4
+ </div>
5
+ <h1 class="text-4xl lg:text-5xl font-extrabold text-slate-900 tracking-tight leading-tight mb-4">GDL (Go-Duck Language)</h1>
6
+ <p class="text-lg lg:text-xl text-slate-600 max-w-2xl leading-relaxed">The standard DSL for generating your massive suite of code from a simple text file.</p>
7
+ </div>
8
+
9
+ <section class="mb-12">
10
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
11
+ <span class="w-8 h-8 rounded-lg bg-emerald-100 text-emerald-600 flex items-center justify-center mr-3 text-sm">
12
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
13
+ </span>
14
+ GDL Syntax & Structure
15
+ </h2>
16
+ <p class="mb-6 text-slate-600 leading-relaxed">GDL allows you to define your core business entities and the relationships between them. It looks and acts slightly similarly to JHipster's JDL.</p>
17
+
18
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg mb-4">
19
+ <div class="bg-[#2d2d2d] px-4 py-2 border-b border-[#404040] flex items-center justify-between">
20
+ <div class="flex items-center">
21
+ <div class="flex space-x-1.5 mr-4">
22
+ <div class="w-3 h-3 rounded-full bg-rose-500"></div>
23
+ <div class="w-3 h-3 rounded-full bg-amber-500"></div>
24
+ <div class="w-3 h-3 rounded-full bg-emerald-500"></div>
25
+ </div>
26
+ <span class="text-xs text-slate-300 font-mono">schema.gdl</span>
27
+ </div>
28
+ </div>
29
+ <div class="p-5 overflow-x-auto text-sm">
30
+ <pre><code class="language-plaintext">@Audited
31
+ entity Article {
32
+ title String required unique
33
+ content Text required
34
+ status ArticleStatus required
35
+ publishedDate LocalDate
36
+ views Integer
37
+ metadata JSONB
38
+ }
39
+
40
+ enum ArticleStatus {
41
+ DRAFT, PUBLISHED, ARCHIVED
42
+ }
43
+
44
+ entity Author {
45
+ name String required
46
+ biography Text
47
+ settings JSON
48
+ }
49
+
50
+ relationship OneToMany {
51
+ Author{article} to Article{author} required
52
+ }</code></pre>
53
+ </div>
54
+ </div>
55
+ </section>
56
+
57
+ <section class="mb-12">
58
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
59
+ <span class="w-8 h-8 rounded-lg bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 text-sm">
60
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"></path></svg>
61
+ </span>
62
+ Supported Data Types
63
+ </h2>
64
+ <div class="overflow-x-auto rounded-xl border border-slate-200">
65
+ <table class="min-w-full text-left bg-white">
66
+ <thead>
67
+ <tr class="bg-slate-50 border-b border-slate-200 text-slate-500 uppercase text-xs tracking-wider">
68
+ <th class="p-4 font-semibold">GDL Type</th>
69
+ <th class="p-4 font-semibold">Go Struct Type</th>
70
+ <th class="p-4 font-semibold">Postgres / SQL Type</th>
71
+ <th class="p-4 font-semibold">GraphQL / Proto</th>
72
+ </tr>
73
+ </thead>
74
+ <tbody class="text-sm text-slate-700 divide-y divide-slate-100">
75
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">String</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">string</code></td><td class="p-4">VARCHAR(255)</td><td class="p-4">String / string</td></tr>
76
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">String(N)</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">string</code></td><td class="p-4">VARCHAR(N)</td><td class="p-4">String / string</td></tr>
77
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Text</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">string</code></td><td class="p-4">TEXT</td><td class="p-4">String / string</td></tr>
78
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">JSON</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">datatypes.JSON</code></td><td class="p-4 text-emerald-600 font-semibold">JSON</td><td class="p-4">String / string</td></tr>
79
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">JSONB</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">datatypes.JSON</code></td><td class="p-4 text-emerald-600 font-semibold">JSONB</td><td class="p-4">String / string</td></tr>
80
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Integer</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">int</code></td><td class="p-4">INT</td><td class="p-4">Int / int32</td></tr>
81
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Long</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">int64</code></td><td class="p-4">BIGINT</td><td class="p-4">ID / int64</td></tr>
82
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Float</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">float64</code></td><td class="p-4">DECIMAL</td><td class="p-4">Float / float32</td></tr>
83
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">BigDecimal</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">float64</code></td><td class="p-4">DECIMAL</td><td class="p-4">Float / double</td></tr>
84
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Boolean</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">bool</code></td><td class="p-4">BOOLEAN</td><td class="p-4">Boolean / bool</td></tr>
85
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">LocalDate</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">time.Time</code></td><td class="p-4">DATE</td><td class="p-4">String / string</td></tr>
86
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Instant</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">time.Time</code></td><td class="p-4">TIMESTAMP</td><td class="p-4">String / string</td></tr>
87
+ <tr class="hover:bg-slate-50 transition-colors"><td class="p-4 font-semibold font-mono text-indigo-600">Enum</td><td class="p-4"><code class="bg-slate-100 px-1 py-0.5 rounded text-xs text-slate-800">CustomType</code></td><td class="p-4">VARCHAR(50)</td><td class="p-4">String / string</td></tr>
88
+ </tbody>
89
+ </table>
90
+ </div>
91
+ </section>
92
+
93
+ <section class="mb-12">
94
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
95
+ <span class="w-8 h-8 rounded-lg bg-pink-100 text-pink-600 flex items-center justify-center mr-3 text-sm">
96
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path></svg>
97
+ </span>
98
+ Enumerations
99
+ </h2>
100
+ <p class="mb-6 text-slate-600 leading-relaxed">GDL supports custom Enum types for fields that have a predefined set of allowed values. Enums are generated as Go types with constants and mapped to safe string columns in the database.</p>
101
+
102
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg">
103
+ <div class="p-5 overflow-x-auto text-sm text-slate-300">
104
+ <pre><code class="language-plaintext">enum Language {
105
+ ENGLISH, FRENCH, GERMAN
106
+ }
107
+
108
+ entity Person {
109
+ name String required
110
+ nativeLanguage Language
111
+ }</code></pre>
112
+ </div>
113
+ </div>
114
+ </section>
115
+
116
+ <section class="mb-12">
117
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
118
+ <span class="w-8 h-8 rounded-lg bg-teal-100 text-teal-600 flex items-center justify-center mr-3 text-sm">
119
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path></svg>
120
+ </span>
121
+ Modifiers & Annotations
122
+ </h2>
123
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-5 mb-8">
124
+ <div class="p-5 rounded-2xl border border-slate-200 bg-white">
125
+ <h3 class="font-bold text-slate-900 mb-2 font-mono text-indigo-600">required</h3>
126
+ <p class="text-sm text-slate-600 leading-relaxed">Forces the field to be NOT NULL in the database, missing fields are blocked by the Gin validator natively.</p>
127
+ </div>
128
+ <div class="p-5 rounded-2xl border border-slate-200 bg-white">
129
+ <h3 class="font-bold text-slate-900 mb-2 font-mono text-indigo-600">unique</h3>
130
+ <p class="text-sm text-slate-600 leading-relaxed">Adds a standard UNIQUE constraint indexing configuration at the database level.</p>
131
+ </div>
132
+ </div>
133
+ <div class="p-6 rounded-2xl border border-rose-200 bg-rose-50/50">
134
+ <h3 class="font-bold text-rose-900 mb-2 font-mono drop-shadow-sm">@Audited</h3>
135
+ <p class="text-sm text-rose-800 leading-relaxed">An entity annotation that completely re-wires the structural behavior of the model. Standard <code class="bg-rose-100 px-1 py-0.5 rounded text-rose-900">created_at</code> triggers are bypassed and 5 highly-detailed audit columns are injected: <code>created_by, created_date, last_modified_by, last_modified_date, last_modified_user_id</code>. All changes are captured implicitly by the JWT middleware.</p>
136
+ </div>
137
+ </section>
138
+
139
+ <section class="mb-10">
140
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
141
+ <span class="w-8 h-8 rounded-lg bg-orange-100 text-orange-600 flex items-center justify-center mr-3 text-sm">
142
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg>
143
+ </span>
144
+ Incremental Migration Engine
145
+ </h2>
146
+ <p class="mb-4 text-slate-600 leading-relaxed">Running <code class="bg-slate-100 px-1 py-0.5 rounded text-slate-800 font-mono text-sm">go-duck import-gdl app.gdl</code> compares your GDL file against the physical <code>.go-duck/</code> snapshot state securely stored in the repo.</p>
147
+ <p class="mb-6 text-slate-600 leading-relaxed">It detects exactly what changed (such as removing a field, changing field types, adding new nested JSON) and generates precise atomic standard Liquibase XML <code>migrations/liquibase/changelogs/</code> scripts to evolve the live database safely without destroying data.</p>
148
+
149
+ <div class="bg-blue-50/80 border border-blue-200 p-5 rounded-xl flex items-start shadow-sm">
150
+ <svg class="w-6 h-6 text-blue-500 mt-0.5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
151
+ <div>
152
+ <h4 class="font-semibold text-blue-900 mb-1">Golden Rule</h4>
153
+ <p class="text-blue-800 text-sm leading-relaxed mb-2">Avoid editing Liquibase XML manually unless correcting an anomaly. Let the GDL manage your migrations.</p>
154
+ </div>
155
+ </div>
156
+ </section>
157
+
158
+ <section class="mb-12">
159
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
160
+ <span class="w-8 h-8 rounded-lg bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 text-sm">
161
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"></path></svg>
162
+ </span>
163
+ Managing Relationships
164
+ </h2>
165
+ <p class="mb-6 text-slate-600 leading-relaxed">Relationships in GDL define how entities connect at the database level (foreign keys) and how they are represented in Go structs and GraphQL schemas. Just like JHipster, we support four primary types.</p>
166
+
167
+ <!-- One-to-Many -->
168
+ <div class="mb-8">
169
+ <h3 class="text-xl font-semibold text-slate-800 mb-4 flex items-center">
170
+ One-to-Many
171
+ <span class="ml-3 px-2 py-0.5 rounded bg-blue-100 text-blue-700 text-xs font-bold uppercase tracking-wider">Most Common</span>
172
+ </h3>
173
+ <p class="text-slate-600 mb-4 text-sm bg-slate-50 p-3 border-l-4 border-blue-400 rounded-r-lg">Example: An <code class="font-bold">Author</code> has many <code class="font-bold">Articles</code>.</p>
174
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg">
175
+ <div class="p-4 overflow-x-auto text-sm">
176
+ <pre><code class="language-plaintext">relationship OneToMany {
177
+ Author{article} to Article{author}
178
+ }</code></pre>
179
+ </div>
180
+ </div>
181
+ <p class="mt-4 text-sm text-slate-500 italic">This generates a <code>author_id</code> foreign key in the <code>article</code> table and a slice of Articles in the Author struct.</p>
182
+ </div>
183
+
184
+ <!-- Many-to-One -->
185
+ <div class="mb-8">
186
+ <h3 class="text-xl font-semibold text-slate-800 mb-4">Many-to-One</h3>
187
+ <p class="text-slate-600 mb-4 text-sm bg-slate-50 p-3 border-l-4 border-slate-300 rounded-r-lg">Essentially the inverse of One-to-Many, used to specify the owner side explicitly.</p>
188
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg">
189
+ <div class="p-4 overflow-x-auto text-sm">
190
+ <pre><code class="language-plaintext">relationship ManyToOne {
191
+ Article{author} to Author
192
+ }</code></pre>
193
+ </div>
194
+ </div>
195
+ </div>
196
+
197
+ <!-- One-to-One -->
198
+ <div class="mb-8">
199
+ <h3 class="text-xl font-semibold text-slate-800 mb-4">One-to-One</h3>
200
+ <p class="text-slate-600 mb-4 text-sm bg-slate-50 p-3 border-l-4 border-indigo-400 rounded-r-lg">Example: A <code class="font-bold">User</code> has exactly one <code class="font-bold">Profile</code>.</p>
201
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg">
202
+ <div class="p-4 overflow-x-auto text-sm">
203
+ <pre><code class="language-plaintext">relationship OneToOne {
204
+ User{profile} to Profile{user}
205
+ }</code></pre>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <!-- Many-to-Many -->
211
+ <div class="mb-8">
212
+ <h3 class="text-xl font-semibold text-slate-800 mb-4">Many-to-Many</h3>
213
+ <p class="text-slate-600 mb-4 text-sm bg-slate-50 p-3 border-l-4 border-purple-400 rounded-r-lg">Example: <code class="font-bold">Students</code> enrolled in many <code class="font-bold">Courses</code>.</p>
214
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-lg">
215
+ <div class="p-4 overflow-x-auto text-sm">
216
+ <pre><code class="language-plaintext">relationship ManyToMany {
217
+ Student{course} to Course{student}
218
+ }</code></pre>
219
+ </div>
220
+ </div>
221
+ <p class="mt-4 text-sm text-slate-500 italic">This triggers the automatic generation of a join table (e.g., <code>student_course</code>) in Liquibase.</p>
222
+ </div>
223
+ </section>
@@ -0,0 +1,51 @@
1
+ <h1 class="text-4xl font-extrabold text-gray-900 mb-4">GraphQL Integration</h1>
2
+ <p class="text-lg text-gray-600 mb-8">Access all generated GDL entities through a single unified endpoint with high-efficiency queries.</p>
3
+
4
+ <section class="mb-10">
5
+ <h2 class="text-2xl font-bold text-gray-800 mb-4 border-b pb-2">Single Unified Endpoint</h2>
6
+ <p class="mb-4">Rather than relying entirely on REST endpoints, your application supports GraphQL via <code>POST /graphql</code>.</p>
7
+
8
+ <div class="bg-indigo-50 border-l-4 border-indigo-500 p-4 mb-6 rounded-r">
9
+ <p class="text-indigo-900"><strong>Note:</strong> Just like REST, GraphQL requires standard Keycloak JWT headers to be attached to queries and mutations!</p>
10
+ </div>
11
+
12
+ <pre><code class="language-graphql"># Example: Querying Multiple Data Models (GORM Relational Mapping Handles JOINs)
13
+ query {
14
+ get{{capitalize (defaultStr (lookup entities "0.name") "Entity")}}(id: 1) {
15
+ id
16
+ {{#if entities.length}}
17
+ {{#if entities.[0].fields.length}}
18
+ {{entities.[0].fields.[0].name}}
19
+ {{/if}}
20
+ {{/if}}
21
+ }
22
+ }</code></pre>
23
+ </section>
24
+
25
+ <section class="mb-10">
26
+ <h2 class="text-2xl font-bold text-gray-800 mb-4 border-b pb-2">Working with Frontend Libraries</h2>
27
+ <p class="mb-4">Here is how to seamlessly execute your generated queries inside modern JavaScript frameworks using <code>fetch</code>.</p>
28
+
29
+ <pre><code class="language-javascript">const fetchEntity = async () => {
30
+ const query = \`
31
+ query {
32
+ list{{capitalize (defaultStr (lookup entities "0.name") "Entity")}}s(page: 1, size: 5) {
33
+ id
34
+ {{#if entities.length}}{{#if entities.[0].fields.length}}{{entities.[0].fields.[0].name}}{{/if}}{{/if}}
35
+ }
36
+ }
37
+ \`;
38
+
39
+ const response = await fetch('http://localhost:8080/graphql', {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ 'Authorization': 'Bearer YOUR_JWT'
44
+ },
45
+ body: JSON.stringify({ query })
46
+ });
47
+
48
+ const { data } = await response.json();
49
+ console.log('Result array:', data);
50
+ };</code></pre>
51
+ </section>
@@ -0,0 +1,100 @@
1
+ <div class="mb-10 border-b border-slate-200 pb-8">
2
+ <div class="inline-flex items-center px-3 py-1 rounded-full bg-rose-100 text-rose-700 text-xs font-semibold tracking-wide uppercase mb-4">
3
+ Protocol Buffer APIs
4
+ </div>
5
+ <h1 class="text-4xl font-extrabold text-slate-900 tracking-tight mb-4">Secured Kratos gRPC APIs</h1>
6
+ <p class="text-lg text-slate-600">Access the generated microservices over ultra-fast gRPC using Kratos framework, fully authenticated by Keycloak.</p>
7
+ </div>
8
+
9
+ <section class="mb-10">
10
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
11
+ <span class="w-8 h-8 rounded-lg bg-slate-100 text-slate-600 flex items-center justify-center mr-3 text-sm">
12
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
13
+ </span>
14
+ Overview
15
+ </h2>
16
+ <p class="mb-4 text-slate-600 leading-relaxed">The GO-DUCK CLI generated app binds the Gin REST webserver on port 8080 and simultaneously spins up an optimized <strong>Go-Kratos</strong> gRPC listener on <code class="bg-slate-100 px-1.5 py-0.5 rounded text-slate-800 font-mono text-sm">port 9000</code>. Both the REST and gRPC handlers share the exact same clean <code>Repository</code> architecture underneath, guaranteeing 100% data and logic consistency.</p>
17
+
18
+ <div class="bg-emerald-50/80 border border-emerald-200 p-5 mt-6 rounded-xl flex items-start shadow-sm">
19
+ <svg class="w-6 h-6 text-emerald-500 mt-0.5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
20
+ <div>
21
+ <h4 class="font-semibold text-emerald-900 mb-1">Automatic Compilation</h4>
22
+ <p class="text-emerald-800 text-sm leading-relaxed"><code class="bg-emerald-100 text-emerald-900 px-1 py-0.5 rounded">api/v1/*.proto</code> definitions are generated automatically whenever you add an entity or change fields.</p>
23
+ </div>
24
+ </div>
25
+ </section>
26
+
27
+ <section class="mb-12">
28
+ <h2 class="text-2xl font-bold text-slate-800 mb-6 flex items-center">
29
+ <span class="w-8 h-8 rounded-lg bg-indigo-100 text-indigo-600 flex items-center justify-center mr-3 text-sm">
30
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
31
+ </span>
32
+ Client Connection Example (Go)
33
+ </h2>
34
+ <p class="mb-6 text-slate-600 leading-relaxed">This snippet demonstrates how a developer orchestrating another microservice connects securely using Google's <code class="bg-slate-100 px-1.5 py-0.5 rounded text-slate-800 font-mono text-sm">clientcredentials</code> to fulfill the Kratos Auth Header standards.</p>
35
+
36
+ <div class="bg-blue-50/80 border border-blue-200 p-5 mt-6 mb-6 rounded-xl flex items-start shadow-sm">
37
+ <svg class="w-6 h-6 text-blue-500 mt-0.5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
38
+ <div>
39
+ <h4 class="font-semibold text-blue-900 mb-1">Crucial Architecture Note (Server-to-Server)</h4>
40
+ <p class="text-blue-800 text-sm leading-relaxed mb-2">If an event triggers a gRPC call asynchronously in the background (meaning there is NO active human user pushing a token from a frontend), the calling microservice must authenticate itself using a <strong>Keycloak Service Account</strong>.</p>
41
+ <p class="text-blue-800 text-sm leading-relaxed">The calling server sends its own <code class="bg-blue-100 px-1 py-0.5 rounded">Client ID</code> and <code class="bg-blue-100 px-1 py-0.5 rounded">Client Secret</code> directly to Keycloak's Token Endpoint using the <strong>Client Credentials Grant</strong> flow. Keycloak responds with a valid JWT representing the "Server", which is then injected into the gRPC dialer below.</p>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="bg-[#1e1e1e] rounded-xl overflow-hidden shadow-xl mb-4">
46
+ <div class="bg-[#2d2d2d] px-4 py-2 border-b border-[#404040] flex items-center justify-between">
47
+ <div class="flex items-center">
48
+ <div class="flex space-x-1.5 mr-4">
49
+ <div class="w-3 h-3 rounded-full bg-rose-500"></div>
50
+ <div class="w-3 h-3 rounded-full bg-amber-500"></div>
51
+ <div class="w-3 h-3 rounded-full bg-emerald-500"></div>
52
+ </div>
53
+ <span class="text-xs text-slate-300 font-mono">grpc_client.go</span>
54
+ </div>
55
+ <span class="text-[10px] text-slate-400 font-bold uppercase tracking-widest">Go</span>
56
+ </div>
57
+ <div class="p-5 overflow-x-auto text-sm">
58
+ <pre><code class="language-go">import (
59
+ "context"
60
+ "log"
61
+ "google.golang.org/grpc"
62
+ "golang.org/x/oauth2/clientcredentials"
63
+ pb "{{appName}}/api/v1"
64
+ )
65
+
66
+ func main() {
67
+ // 1. Configure the Client Credentials Flow
68
+ // These values should match your go-duck.security block in application-dev.yml
69
+ config := clientcredentials.Config{
70
+ ClientID: "internal", // Matches keycloak-client-id
71
+ ClientSecret: "internal", // Matches keycloak-secret
72
+ TokenURL: "http://localhost:9080/realms/master/protocol/openid-connect/token",
73
+ }
74
+
75
+ // 2. Fetch the token dynamically from Keycloak
76
+ tokenSource := config.TokenSource(context.Background())
77
+
78
+ // 3. Dial the local port 9000 (GoDuck Server)
79
+ // grpc.WithPerRPCCredentials injects the automatically updating token into every request!
80
+ conn, err := grpc.Dial("localhost:9000", grpc.WithInsecure(), grpc.WithPerRPCCredentials(tokenSource))
81
+ if err != nil {
82
+ log.Fatalf("did not connect: %v", err)
83
+ }
84
+ defer conn.Close()
85
+
86
+ // 4. Initialize the Kratos-generated gRPC Client
87
+ client := pb.New{{capitalize (defaultStr (lookup entities "0.name") "Entity")}}ServiceClient(conn)
88
+
89
+ // 5. Execute Native Network Call over gRPC
90
+ res, err := client.Get{{capitalize (defaultStr (lookup entities "0.name") "Entity")}}(context.Background(), &pb.Get{{capitalize (defaultStr (lookup entities "0.name") "Entity")}}Request{Id: 1})
91
+ if err != nil {
92
+ log.Fatalf("RPC failed: %v", err)
93
+ }
94
+
95
+ log.Printf("Successfully Received Data Pipeline Object OVER gRPC: %v", res)
96
+ }
97
+ </code></pre>
98
+ </div>
99
+ </div>
100
+ </section>