@cdmbase/wiki-browser 12.0.18-alpha.30 → 12.0.18-alpha.32
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.
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
|
+
{
|
|
4
|
+
"contentId": "botinstruction-zep_neo4j_knowledge_graph_guide",
|
|
5
|
+
"slug": "zep_neo4j_knowledge_graph_guide",
|
|
6
|
+
"filePath": "/content/docs/BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
7
|
+
"relativePath": "BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
8
|
+
"categoryId": "BotInstruction",
|
|
9
|
+
"title": "ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE",
|
|
10
|
+
"description": "",
|
|
11
|
+
"author": "Documentation",
|
|
12
|
+
"updatedAt": "Recently",
|
|
13
|
+
"frontmatter": {}
|
|
14
|
+
},
|
|
3
15
|
{
|
|
4
16
|
"contentId": "generators-project-generate-fullproject",
|
|
5
17
|
"slug": "project-generate-fullproject",
|
|
@@ -33,6 +45,18 @@
|
|
|
33
45
|
"updatedAt": "Recently",
|
|
34
46
|
"frontmatter": {}
|
|
35
47
|
},
|
|
48
|
+
{
|
|
49
|
+
"contentId": "llm-templates_folder_and_codegen_guide",
|
|
50
|
+
"slug": "templates_folder_and_codegen_guide",
|
|
51
|
+
"filePath": "/content/docs/LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
52
|
+
"relativePath": "LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
53
|
+
"categoryId": "LLM",
|
|
54
|
+
"title": "TEMPLATES_FOLDER_AND_CODEGEN_GUIDE",
|
|
55
|
+
"description": "",
|
|
56
|
+
"author": "Documentation",
|
|
57
|
+
"updatedAt": "Recently",
|
|
58
|
+
"frontmatter": {}
|
|
59
|
+
},
|
|
36
60
|
{
|
|
37
61
|
"contentId": "llm-backend-proxies-services-llm",
|
|
38
62
|
"slug": "backend-proxies-services-llm",
|
|
@@ -3533,6 +3557,23 @@
|
|
|
3533
3557
|
}
|
|
3534
3558
|
],
|
|
3535
3559
|
"categories": {
|
|
3560
|
+
"BotInstruction": {
|
|
3561
|
+
"id": "BotInstruction",
|
|
3562
|
+
"title": "BotInstruction",
|
|
3563
|
+
"description": "BotInstruction Documentation",
|
|
3564
|
+
"iconType": "Documentation",
|
|
3565
|
+
"articles": [
|
|
3566
|
+
{
|
|
3567
|
+
"id": "botinstruction-zep_neo4j_knowledge_graph_guide",
|
|
3568
|
+
"title": "ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE",
|
|
3569
|
+
"description": "",
|
|
3570
|
+
"slug": "zep_neo4j_knowledge_graph_guide",
|
|
3571
|
+
"author": "Documentation",
|
|
3572
|
+
"updatedAt": "Recently",
|
|
3573
|
+
"categoryId": "BotInstruction"
|
|
3574
|
+
}
|
|
3575
|
+
]
|
|
3576
|
+
},
|
|
3536
3577
|
"Generators": {
|
|
3537
3578
|
"id": "Generators",
|
|
3538
3579
|
"title": "Generators",
|
|
@@ -3681,6 +3722,15 @@
|
|
|
3681
3722
|
"author": "Documentation",
|
|
3682
3723
|
"updatedAt": "Recently",
|
|
3683
3724
|
"categoryId": "LLM"
|
|
3725
|
+
},
|
|
3726
|
+
{
|
|
3727
|
+
"id": "llm-templates_folder_and_codegen_guide",
|
|
3728
|
+
"title": "TEMPLATES_FOLDER_AND_CODEGEN_GUIDE",
|
|
3729
|
+
"description": "",
|
|
3730
|
+
"slug": "templates_folder_and_codegen_guide",
|
|
3731
|
+
"author": "Documentation",
|
|
3732
|
+
"updatedAt": "Recently",
|
|
3733
|
+
"categoryId": "LLM"
|
|
3684
3734
|
}
|
|
3685
3735
|
]
|
|
3686
3736
|
},
|
|
@@ -5359,8 +5409,10 @@
|
|
|
5359
5409
|
}
|
|
5360
5410
|
},
|
|
5361
5411
|
"contentPathMap": {
|
|
5412
|
+
"botinstruction-zep_neo4j_knowledge_graph_guide": "/content/docs/BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
5362
5413
|
"generators-project-generate-fullproject": "/content/docs/Generators/Project/generate-fullproject.md",
|
|
5363
5414
|
"llm-logger.llm": "/content/docs/LLM/Logger.llm.md",
|
|
5415
|
+
"llm-templates_folder_and_codegen_guide": "/content/docs/LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
5364
5416
|
"llm-backend-proxies-services-llm": "/content/docs/LLM/backend-proxies-services-llm.md",
|
|
5365
5417
|
"llm-backend-service-llm": "/content/docs/LLM/backend-service-llm.md",
|
|
5366
5418
|
"llm-db_migration_llm": "/content/docs/LLM/db_migration_llm.md",
|
|
@@ -6304,6 +6356,28 @@
|
|
|
6304
6356
|
}
|
|
6305
6357
|
]
|
|
6306
6358
|
},
|
|
6359
|
+
{
|
|
6360
|
+
"type": "directory",
|
|
6361
|
+
"name": "BotInstruction",
|
|
6362
|
+
"path": "BotInstruction",
|
|
6363
|
+
"children": [
|
|
6364
|
+
{
|
|
6365
|
+
"type": "file",
|
|
6366
|
+
"name": "ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE",
|
|
6367
|
+
"title": "ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE",
|
|
6368
|
+
"path": "BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
6369
|
+
"contentId": "botinstruction-zep_neo4j_knowledge_graph_guide",
|
|
6370
|
+
"slug": "zep_neo4j_knowledge_graph_guide",
|
|
6371
|
+
"categoryId": "BotInstruction",
|
|
6372
|
+
"filePath": "/content/docs/BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
6373
|
+
"relativePath": "BotInstruction/ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE.md",
|
|
6374
|
+
"description": "",
|
|
6375
|
+
"author": "Documentation",
|
|
6376
|
+
"updatedAt": "Recently",
|
|
6377
|
+
"frontmatter": {}
|
|
6378
|
+
}
|
|
6379
|
+
]
|
|
6380
|
+
},
|
|
6307
6381
|
{
|
|
6308
6382
|
"type": "directory",
|
|
6309
6383
|
"name": "chrome-extension",
|
|
@@ -8519,6 +8593,21 @@
|
|
|
8519
8593
|
"author": "Documentation",
|
|
8520
8594
|
"updatedAt": "Recently",
|
|
8521
8595
|
"frontmatter": {}
|
|
8596
|
+
},
|
|
8597
|
+
{
|
|
8598
|
+
"type": "file",
|
|
8599
|
+
"name": "TEMPLATES_FOLDER_AND_CODEGEN_GUIDE",
|
|
8600
|
+
"title": "TEMPLATES_FOLDER_AND_CODEGEN_GUIDE",
|
|
8601
|
+
"path": "LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
8602
|
+
"contentId": "llm-templates_folder_and_codegen_guide",
|
|
8603
|
+
"slug": "templates_folder_and_codegen_guide",
|
|
8604
|
+
"categoryId": "LLM",
|
|
8605
|
+
"filePath": "/content/docs/LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
8606
|
+
"relativePath": "LLM/TEMPLATES_FOLDER_AND_CODEGEN_GUIDE.md",
|
|
8607
|
+
"description": "",
|
|
8608
|
+
"author": "Documentation",
|
|
8609
|
+
"updatedAt": "Recently",
|
|
8610
|
+
"frontmatter": {}
|
|
8522
8611
|
}
|
|
8523
8612
|
]
|
|
8524
8613
|
},
|
|
@@ -10294,6 +10383,19 @@
|
|
|
10294
10383
|
],
|
|
10295
10384
|
"isFile": false
|
|
10296
10385
|
},
|
|
10386
|
+
{
|
|
10387
|
+
"title": "BotInstruction",
|
|
10388
|
+
"path": null,
|
|
10389
|
+
"children": [
|
|
10390
|
+
{
|
|
10391
|
+
"title": "ZEP_NEO4J_KNOWLEDGE_GRAPH_GUIDE",
|
|
10392
|
+
"path": "/help/BotInstruction/zep_neo4j_knowledge_graph_guide",
|
|
10393
|
+
"children": [],
|
|
10394
|
+
"isFile": true
|
|
10395
|
+
}
|
|
10396
|
+
],
|
|
10397
|
+
"isFile": false
|
|
10398
|
+
},
|
|
10297
10399
|
{
|
|
10298
10400
|
"title": "Chrome Extension",
|
|
10299
10401
|
"path": null,
|
|
@@ -10996,6 +11098,12 @@
|
|
|
10996
11098
|
"path": "/help/LLM/tailwind-css-llm",
|
|
10997
11099
|
"children": [],
|
|
10998
11100
|
"isFile": true
|
|
11101
|
+
},
|
|
11102
|
+
{
|
|
11103
|
+
"title": "TEMPLATES_FOLDER_AND_CODEGEN_GUIDE",
|
|
11104
|
+
"path": "/help/LLM/templates_folder_and_codegen_guide",
|
|
11105
|
+
"children": [],
|
|
11106
|
+
"isFile": true
|
|
10999
11107
|
}
|
|
11000
11108
|
],
|
|
11001
11109
|
"isFile": false
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Zep + Neo4j Knowledge Graph Guide for LLM Agents
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide documents how to use Zep CE (Community Edition) backed by Neo4j as a knowledge graph for LLM-assisted development. It enables semantic search across all CDEBase documentation, auto-extraction of entities and relationships, and a self-improving knowledge loop.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
LLM Agent → Zep CE API (store messages) → Neo4j (entities, relationships, embeddings)
|
|
11
|
+
↗
|
|
12
|
+
LLM Agent → Neo4j HTTP API (direct queries, graph traversal)
|
|
13
|
+
↗
|
|
14
|
+
LLM Agent → Zep Search API (semantic fact search)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
### Zep API
|
|
20
|
+
- **URL**: `https://zep.cdebase.dev`
|
|
21
|
+
- **Auth Header**: `Authorization: Api-Key <your-api-key>`
|
|
22
|
+
- **Message limit**: 2500 chars per message (chunk larger content at 2400 chars)
|
|
23
|
+
|
|
24
|
+
### Neo4j (Zep Backend)
|
|
25
|
+
- **HTTP API**: `https://neo4j.cdebase.dev/db/neo4j/tx/commit`
|
|
26
|
+
- **Bolt**: `neo4j-bolt.cdebase.dev:443`
|
|
27
|
+
- **Auth**: Basic auth (username/password)
|
|
28
|
+
|
|
29
|
+
### Zep Sessions
|
|
30
|
+
- `cdebase-llm-guides` — All CDEBase wiki docs (LLM guides, adminide-modules, remix, feature-api, etc.)
|
|
31
|
+
- Create additional sessions per project or user as needed
|
|
32
|
+
|
|
33
|
+
## Semantic Search
|
|
34
|
+
|
|
35
|
+
The most powerful feature — search across all stored knowledge by meaning, not just keywords.
|
|
36
|
+
|
|
37
|
+
### Search Endpoint
|
|
38
|
+
```bash
|
|
39
|
+
curl -s -X POST "https://zep.cdebase.dev/api/v2/sessions/search" \
|
|
40
|
+
-H "Authorization: Api-Key <your-api-key>" \
|
|
41
|
+
-H "Content-Type: application/json" \
|
|
42
|
+
-d '{
|
|
43
|
+
"text": "DataLoader implementation pattern",
|
|
44
|
+
"session_ids": ["cdebase-llm-guides"],
|
|
45
|
+
"limit": 10
|
|
46
|
+
}'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**CRITICAL**: The search endpoint is **top-level** (`/api/v2/sessions/search`), NOT per-session (`/sessions/{id}/search`). The `session_ids` array in the request body filters results.
|
|
50
|
+
|
|
51
|
+
### Search Returns Facts
|
|
52
|
+
Zep automatically extracts **facts** from stored messages. Search returns these facts ranked by semantic similarity:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"results": [
|
|
57
|
+
{
|
|
58
|
+
"fact": {
|
|
59
|
+
"uuid": "...",
|
|
60
|
+
"fact": "DataLoader Pattern ensures Consistency by resolving all object references through the same pattern.",
|
|
61
|
+
"created_at": "2026-02-17T01:06:03Z"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Storing Content
|
|
69
|
+
|
|
70
|
+
### Add Messages to Zep
|
|
71
|
+
```bash
|
|
72
|
+
curl -s -X POST "https://zep.cdebase.dev/api/v2/sessions/<session_id>/memory" \
|
|
73
|
+
-H "Authorization: Api-Key <your-api-key>" \
|
|
74
|
+
-H "Content-Type: application/json" \
|
|
75
|
+
-d '{
|
|
76
|
+
"messages": [
|
|
77
|
+
{"role": "user", "role_type": "user", "content": "Topic label"},
|
|
78
|
+
{"role": "assistant", "role_type": "assistant", "content": "Actual content here (max 2500 chars)"}
|
|
79
|
+
]
|
|
80
|
+
}'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Chunking Large Documents
|
|
84
|
+
For documents > 2500 chars, split into chunks:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import json, math, urllib.request
|
|
88
|
+
|
|
89
|
+
ZEP_URL = "https://zep.cdebase.dev"
|
|
90
|
+
ZEP_KEY = "your-api-key"
|
|
91
|
+
MAX_CHARS = 2400 # Under 2500 limit
|
|
92
|
+
|
|
93
|
+
def push_to_zep(session_id, name, content):
|
|
94
|
+
chunks = math.ceil(len(content) / MAX_CHARS)
|
|
95
|
+
for i in range(chunks):
|
|
96
|
+
chunk = content[i*MAX_CHARS:(i+1)*MAX_CHARS]
|
|
97
|
+
part = f" (part {i+1}/{chunks})" if chunks > 1 else ""
|
|
98
|
+
payload = {
|
|
99
|
+
"messages": [
|
|
100
|
+
{"role": "user", "role_type": "user", "content": f"{name}{part}"},
|
|
101
|
+
{"role": "assistant", "role_type": "assistant", "content": chunk}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
req = urllib.request.Request(
|
|
105
|
+
f"{ZEP_URL}/api/v2/sessions/{session_id}/memory",
|
|
106
|
+
data=json.dumps(payload).encode(),
|
|
107
|
+
headers={"Authorization": f"Api-Key {ZEP_KEY}", "Content-Type": "application/json"},
|
|
108
|
+
method="POST"
|
|
109
|
+
)
|
|
110
|
+
urllib.request.urlopen(req)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Neo4j Direct Queries
|
|
114
|
+
|
|
115
|
+
For graph traversal and raw text search, query Neo4j directly.
|
|
116
|
+
|
|
117
|
+
### Query Template
|
|
118
|
+
```bash
|
|
119
|
+
curl -s -X POST "https://neo4j.cdebase.dev/db/neo4j/tx/commit" \
|
|
120
|
+
-H "Content-Type: application/json" \
|
|
121
|
+
-u "username:password" \
|
|
122
|
+
-d '{"statements": [{"statement": "YOUR CYPHER QUERY"}]}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Useful Queries
|
|
126
|
+
|
|
127
|
+
**Graph stats:**
|
|
128
|
+
```cypher
|
|
129
|
+
MATCH (n:Entity) RETURN count(n) as entities
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**List all entities:**
|
|
133
|
+
```cypher
|
|
134
|
+
MATCH (n:Entity) WHERE n.name <> 'User '
|
|
135
|
+
RETURN DISTINCT n.name ORDER BY n.name
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Find relationships for a concept:**
|
|
139
|
+
```cypher
|
|
140
|
+
MATCH (n:Entity {name: 'GraphQL'})-[r]-(related)
|
|
141
|
+
RETURN n.name, type(r), related.name LIMIT 20
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Text search across content:**
|
|
145
|
+
```cypher
|
|
146
|
+
MATCH (n) WHERE n.content CONTAINS 'createServiceFunc'
|
|
147
|
+
RETURN substring(n.content, 0, 300) LIMIT 5
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Visual graph (use in Neo4j Browser):**
|
|
151
|
+
```cypher
|
|
152
|
+
MATCH (a:Entity)-[r]->(b:Entity)
|
|
153
|
+
WHERE a.name <> 'User ' AND b.name <> 'User '
|
|
154
|
+
RETURN a, r, b LIMIT 200
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Self-Improving Knowledge Loop
|
|
158
|
+
|
|
159
|
+
When an LLM agent encounters missing or poor context:
|
|
160
|
+
|
|
161
|
+
1. **Search Zep** → `POST /api/v2/sessions/search` with the topic
|
|
162
|
+
2. **If poor results** → Query Neo4j raw for related content
|
|
163
|
+
3. **Write new guide** → Create/update a `.md` file with the discovered patterns
|
|
164
|
+
4. **Save locally** → Keep in workspace `references/` directory
|
|
165
|
+
5. **Push to Zep** → Chunk and send to `cdebase-llm-guides` session
|
|
166
|
+
6. **PR to wiki** → Branch from `develop`, add to `docs/LLM/` or appropriate folder, PR to `cdmbase/cdebase-wiki`
|
|
167
|
+
|
|
168
|
+
This creates a feedback loop where the knowledge graph improves with every coding task.
|
|
169
|
+
|
|
170
|
+
## Node Labels in Neo4j
|
|
171
|
+
|
|
172
|
+
Zep CE creates these node types:
|
|
173
|
+
- `Entity` — Extracted concepts (GraphQL, Mongoose, DataLoader, etc.)
|
|
174
|
+
- `Episodic` — Individual message memories
|
|
175
|
+
- `Community` — Clustered topic groups
|
|
176
|
+
|
|
177
|
+
### Relationship Types
|
|
178
|
+
- `RELATES_TO` — General relationship between entities
|
|
179
|
+
- `MENTIONS` — Entity mentioned in an episodic memory
|
|
180
|
+
- `HAS_MEMBER` — Community membership
|
|
181
|
+
|
|
182
|
+
## MCP Server Integration
|
|
183
|
+
|
|
184
|
+
A lightweight MCP server (`server.mjs`) exposes Zep to VS Code Copilot and other MCP clients:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"mcpServers": {
|
|
189
|
+
"zep": {
|
|
190
|
+
"command": "node",
|
|
191
|
+
"args": ["server.mjs"],
|
|
192
|
+
"env": {
|
|
193
|
+
"ZEP_API_URL": "https://zep.cdebase.dev",
|
|
194
|
+
"ZEP_API_KEY": "your-api-key"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### MCP Tools
|
|
202
|
+
| Tool | Description |
|
|
203
|
+
|------|-------------|
|
|
204
|
+
| `search_memory` | Semantic search across session facts |
|
|
205
|
+
| `get_session_messages` | Retrieve messages from a session |
|
|
206
|
+
| `get_session_memory` | Get memory summary and context |
|
|
207
|
+
| `list_sessions` | List all sessions |
|
|
208
|
+
| `list_users` / `get_user` | User management |
|
|
209
|
+
|
|
210
|
+
## Best Practices
|
|
211
|
+
|
|
212
|
+
1. **Always search before coding** — Query Zep for patterns before writing code for any CDEBase project
|
|
213
|
+
2. **Chunk at 2400 chars** — Stay under the 2500 char message limit
|
|
214
|
+
3. **Use descriptive labels** — Name chunks clearly (e.g., "CDEBase LLM guide: backend-service (part 3/8)")
|
|
215
|
+
4. **Dedicated sessions** — Use `cdebase-llm-guides` for docs, create separate sessions for project-specific context
|
|
216
|
+
5. **Keep local copies** — Always save `.md` files locally before pushing to Zep
|
|
217
|
+
6. **PR everything** — New guides must be PR'd to the wiki repo for persistence
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# Templates Folder Pattern & Code Generation Pipeline
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `packages/common/` package in both adminIde-stack and forms-stack is **entirely auto-generated**. You should **NEVER manually edit** files in `packages/common/`. Instead, all service interfaces, repository interfaces, SERVER_TYPES entries, and service-schemas are generated from **templates folders** inside each server module, combined with GraphQL schema codegen.
|
|
6
|
+
|
|
7
|
+
## The Templates Folder Pattern
|
|
8
|
+
|
|
9
|
+
### Location
|
|
10
|
+
|
|
11
|
+
Every server module has a `templates/` folder at:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
packages-modules/{module}/server/src/templates/
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or in forms-stack:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
packages/{module}/server/src/templates/
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
templates/
|
|
27
|
+
├── constants/
|
|
28
|
+
│ ├── SERVER_TYPES.ts.template ← Symbol.for() DI tokens for this module
|
|
29
|
+
│ ├── DB_COLL_NAMES.ts.template ← MongoDB collection names
|
|
30
|
+
│ └── DB_SLUG_NAMES.ts.template ← (optional) slug name constants
|
|
31
|
+
├── repositories/
|
|
32
|
+
│ └── {EntityName}Repository.ts.template ← Repository interface (I{EntityName}Repository)
|
|
33
|
+
└── services/
|
|
34
|
+
├── {EntityName}Service.ts.template ← Service interface (I{EntityName}Service)
|
|
35
|
+
└── {EntityName}DataLoader.ts.template ← DataLoader interface (optional)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Template File Format
|
|
39
|
+
|
|
40
|
+
Template files use `.ts.template` extension but are **plain TypeScript** — NOT Handlebars/EJS. They are authoritative source files that get **copied/merged** into `packages/common/src/` during the `regenerateGraphql` process.
|
|
41
|
+
|
|
42
|
+
#### Example: SERVER_TYPES.ts.template
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// packages-modules/marketplace/server/src/templates/constants/SERVER_TYPES.ts.template
|
|
46
|
+
export const SERVER_TYPES = {
|
|
47
|
+
IRegistryExtensionService: Symbol.for('IRegistryExtensionService'),
|
|
48
|
+
IRegistryExtensionRepository: Symbol.for('IRegistryExtensionRepository'),
|
|
49
|
+
IExtensionContributionService: Symbol.for('IExtensionContributionService'),
|
|
50
|
+
IExtensionContributesProvider: Symbol.for('IExtensionContributesProvider'),
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Example: Service Interface Template
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// packages-modules/marketplace/server/src/templates/services/ExtensionContributionService.ts.template
|
|
58
|
+
import { IExtensionContributes } from 'common/server'; // ← reuse the generated GraphQL type
|
|
59
|
+
|
|
60
|
+
export interface IExtensionContributesProvider {
|
|
61
|
+
getContributes(extensionId: string, version?: string): Promise<IExtensionContributes>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface IExtensionContributionService {
|
|
65
|
+
registerProvider(sourceCollection: string, provider: IExtensionContributesProvider): void;
|
|
66
|
+
getContributions(extensionId: string, version?: string): Promise<IExtensionContributes | null>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare module '../apollo-context' {
|
|
70
|
+
interface ServerContext {
|
|
71
|
+
extensionContributionService: IExtensionContributionService;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> **Preference: Reuse Generated GraphQL Types**
|
|
77
|
+
>
|
|
78
|
+
> When a type is already defined in the `.graphql` schema and gets generated as a TypeScript type in `generated-models.ts`, the template should **import and reuse** that generated type via `import { ITypeName } from 'common/server'` rather than redefining its own version. This avoids type duplication and keeps a single source of truth for the type shape.
|
|
79
|
+
>
|
|
80
|
+
> See [Reusing Generated GraphQL Types in Templates](#reusing-generated-graphql-types-in-templates) for details.
|
|
81
|
+
|
|
82
|
+
### What Gets Generated Where
|
|
83
|
+
|
|
84
|
+
| Template Source | Generated Destination |
|
|
85
|
+
| ------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
86
|
+
| `templates/constants/SERVER_TYPES.ts.template` | **MERGED** into `packages/common/src/constants/SERVER_TYPES.ts` |
|
|
87
|
+
| `templates/services/{Entity}Service.ts.template` | **COPIED** to `packages/common/src/services/{Entity}Service.ts` |
|
|
88
|
+
| `templates/repositories/{Entity}Repository.ts.template` | **COPIED** to `packages/common/src/services/{Entity}Repository.ts` |
|
|
89
|
+
| `templates/constants/DB_COLL_NAMES.ts.template` | **MERGED** into `packages/common/src/constants/DB_COLL_NAMES.ts` |
|
|
90
|
+
| _(barrel exports)_ | `packages/common/src/services/index.ts` is **auto-updated** |
|
|
91
|
+
|
|
92
|
+
The merged SERVER_TYPES.ts has comments showing which module contributed each block:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// from package: platform-server
|
|
96
|
+
IAccountService: Symbol.for('IAccountService'),
|
|
97
|
+
// from package: marketplace-module-server
|
|
98
|
+
IRegistryExtensionService: Symbol.for('IRegistryExtensionService'),
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Code Generation Pipeline
|
|
102
|
+
|
|
103
|
+
### Commands
|
|
104
|
+
|
|
105
|
+
| Command | Script | Purpose |
|
|
106
|
+
| ------------------------ | ---------------------------------------- | ---------------------------------------------------------- |
|
|
107
|
+
| `yarn regenerateGraphql` | `tools/codegenGenerator.mjs` | Discover schemas + copy templates → generates `codegen.ts` |
|
|
108
|
+
| `yarn generateGraphql` | `graphql-codegen-esm` (reads codegen.ts) | Generate TypeScript types, Zod schemas, Apollo hooks |
|
|
109
|
+
| `postgenerateGraphql` | `lerna run build --scope=common` | Build the common package (auto-runs after generateGraphql) |
|
|
110
|
+
|
|
111
|
+
### Step 1: `yarn regenerateGraphql`
|
|
112
|
+
|
|
113
|
+
Runs `tools/codegenGenerator.mjs` which:
|
|
114
|
+
|
|
115
|
+
1. Reads `cdecode-config.json` for configuration
|
|
116
|
+
2. Calls `@common-stack/rollup-vite-utils` codegen utilities
|
|
117
|
+
3. **Discovers** all `.graphql` / `.gql` schemas from:
|
|
118
|
+
- `node_modules/@adminide-stack/*/lib/**/*.graphql` (npm packages)
|
|
119
|
+
- `packages/*/server/src/**/*.graphql` (local packages)
|
|
120
|
+
4. **Copies all templates/** to `packages/common/src/`:
|
|
121
|
+
- Merges all `SERVER_TYPES.ts.template` into one `SERVER_TYPES.ts`
|
|
122
|
+
- Copies service/repository interfaces to `services/`
|
|
123
|
+
- Updates `services/index.ts` barrel exports
|
|
124
|
+
5. **Generates** `codegen.ts` with resolved schema paths
|
|
125
|
+
|
|
126
|
+
### Step 2: `yarn generateGraphql`
|
|
127
|
+
|
|
128
|
+
Runs `graphql-codegen-esm` which reads the generated `codegen.ts` and produces 4 output files in `packages/common/src/generated/`:
|
|
129
|
+
|
|
130
|
+
| Output File | Plugin | Purpose |
|
|
131
|
+
| -------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------- |
|
|
132
|
+
| `generated-models.ts` | typescript, typescript-operations, typescript-resolvers, typescript-mongodb | TypeScript interfaces/types from GraphQL schema |
|
|
133
|
+
| `generated-zod-schemas.ts` | `@common-stack/codegen-zod/graphql` | Zod validation schemas from GraphQL types |
|
|
134
|
+
| `generated.tsx` | typescript-react-apollo | React Apollo query/mutation hooks |
|
|
135
|
+
| `introspection-result.ts` | fragment-matcher | Apollo cache fragment matching |
|
|
136
|
+
|
|
137
|
+
After writing all files, two **afterAllFileWrite** hooks run:
|
|
138
|
+
|
|
139
|
+
1. `node scripts/fix-enum-references.js` — Fixes enum reference issues in generated code
|
|
140
|
+
2. `node node_modules/@common-stack/codegen-zod/dist/service/generateAllServiceSchemas.js` — Generates `service-schemas.ts`
|
|
141
|
+
|
|
142
|
+
### Step 3: `generateAllServiceSchemas.js`
|
|
143
|
+
|
|
144
|
+
This script (from `@common-stack/codegen-zod`):
|
|
145
|
+
|
|
146
|
+
1. Reads `cdecode-config.json` → `serviceSchemas` section:
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"serviceSchemas": {
|
|
150
|
+
"servicesDir": "packages/common/src/services",
|
|
151
|
+
"outputFile": "packages/common/src/generated/service-schemas.ts",
|
|
152
|
+
"skipServices": ["AuthBackendClient", "PubSub", ...],
|
|
153
|
+
"graphqlSchemasPath": "packages/common/src/generated/generated-zod-schemas.ts"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
2. **Scans** `packages/common/src/services/` for all `.ts` files
|
|
158
|
+
3. **Parses** each file with TypeScript compiler API looking for `export interface I*Service` or `I*Manager`
|
|
159
|
+
4. **Extracts** method signatures (parameter names, types, optionality)
|
|
160
|
+
5. **Cross-references** with `generated-zod-schemas.ts` to find Zod schemas for GraphQL types
|
|
161
|
+
6. **Generates** `service-schemas.ts` with:
|
|
162
|
+
- A `{ServiceName}Schemas` object per service interface
|
|
163
|
+
- Zod schemas for each method's parameters
|
|
164
|
+
- A `topic` property (Moleculer service name)
|
|
165
|
+
- An aggregated `AllServiceSchemas` export
|
|
166
|
+
|
|
167
|
+
### Step 4: `postgenerateGraphql`
|
|
168
|
+
|
|
169
|
+
Automatically runs after `generateGraphql`:
|
|
170
|
+
|
|
171
|
+
- `lerna run build --scope=common` — Compiles the common package so other packages can use the new types
|
|
172
|
+
|
|
173
|
+
## Complete Pipeline Diagram
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
177
|
+
│ yarn regenerateGraphql │
|
|
178
|
+
│ └─ tools/codegenGenerator.mjs │
|
|
179
|
+
│ └─ reads cdecode-config.json │
|
|
180
|
+
│ └─ calls @common-stack/rollup-vite-utils/codegen │
|
|
181
|
+
│ ├─ Discovers .graphql/.gql schemas from node_modules + │
|
|
182
|
+
│ │ local packages │
|
|
183
|
+
│ ├─ Generates codegen.ts with resolved paths │
|
|
184
|
+
│ ├─ Copies all templates/ → packages/common/src/ │
|
|
185
|
+
│ │ ├─ services/*.ts.template → services/*.ts │
|
|
186
|
+
│ │ ├─ constants/SERVER_TYPES.ts.template → MERGED into │
|
|
187
|
+
│ │ │ constants/SERVER_TYPES.ts │
|
|
188
|
+
│ │ └─ Updates services/index.ts barrel exports │
|
|
189
|
+
│ └─ Sets up common package boilerplate │
|
|
190
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
191
|
+
│ yarn generateGraphql │
|
|
192
|
+
│ └─ graphql-codegen-esm (reads codegen.ts) │
|
|
193
|
+
│ └─ Generates 4 files in packages/common/src/generated/: │
|
|
194
|
+
│ ├─ generated-models.ts (TS types from .graphql) │
|
|
195
|
+
│ ├─ generated-zod-schemas.ts (Zod schemas) │
|
|
196
|
+
│ ├─ generated.tsx (React Apollo hooks) │
|
|
197
|
+
│ └─ introspection-result.ts (fragment matcher) │
|
|
198
|
+
│ └─ afterAllFileWrite hooks: │
|
|
199
|
+
│ ├─ fix-enum-references.js │
|
|
200
|
+
│ └─ generateAllServiceSchemas.js │
|
|
201
|
+
│ └─ Scans services/ interfaces → generates │
|
|
202
|
+
│ service-schemas.ts (Zod schemas for Moleculer) │
|
|
203
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
204
|
+
│ postgenerateGraphql (auto-runs) │
|
|
205
|
+
│ └─ lerna run build --scope=common │
|
|
206
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## How to Add a New Backend Service
|
|
210
|
+
|
|
211
|
+
### Step 1: Create the GraphQL Schema
|
|
212
|
+
|
|
213
|
+
Create a `.graphql` file in the server module:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
packages-modules/{module}/server/src/graphql/schemas/{entity}.graphql
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Define types, queries, mutations.
|
|
220
|
+
|
|
221
|
+
### Step 2: Create Template Files
|
|
222
|
+
|
|
223
|
+
Create template files in the server module's `templates/` folder:
|
|
224
|
+
|
|
225
|
+
**SERVICE_TYPES entries:**
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
packages-modules/{module}/server/src/templates/constants/SERVER_TYPES.ts.template
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Add Symbol.for() entries for new service/repository/dataloader.
|
|
232
|
+
|
|
233
|
+
**Service interface:**
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
packages-modules/{module}/server/src/templates/services/{EntityName}Service.ts.template
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Define the `I{EntityName}Service` interface with method signatures.
|
|
240
|
+
|
|
241
|
+
**Repository interface (if needed):**
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
packages-modules/{module}/server/src/templates/repositories/{EntityName}Repository.ts.template
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Step 3: Run Code Generation
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
yarn regenerateGraphql # Discovers schemas + copies templates to common
|
|
251
|
+
yarn generateGraphql # Generates TS types, Zod schemas, Apollo hooks, service-schemas
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
After this, `packages/common/` will have:
|
|
255
|
+
|
|
256
|
+
- Updated `SERVER_TYPES.ts` with new symbols
|
|
257
|
+
- New service interface file in `services/`
|
|
258
|
+
- Updated `services/index.ts` barrel exports
|
|
259
|
+
- Updated `generated-models.ts` with GraphQL types
|
|
260
|
+
- Updated `service-schemas.ts` with Moleculer schemas
|
|
261
|
+
|
|
262
|
+
### Step 4: Implement the Service
|
|
263
|
+
|
|
264
|
+
Create the concrete implementation:
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
packages-modules/{module}/server/src/services/{entity-name}-service.ts
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Step 5: Create Container Module
|
|
271
|
+
|
|
272
|
+
Bind the service in the container:
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
packages-modules/{module}/server/src/containers/module.ts
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Step 6: Create Resolver
|
|
279
|
+
|
|
280
|
+
Create the GraphQL resolver:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
packages-modules/{module}/server/src/graphql/resolvers/{entity-name}-resolver.ts
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Step 7: Wire into Feature Module
|
|
287
|
+
|
|
288
|
+
Update the Feature in:
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
packages-modules/{module}/server/src/module.ts
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Reusing Generated GraphQL Types in Templates
|
|
295
|
+
|
|
296
|
+
When writing `.ts.template` files, **always prefer importing types that are already generated from GraphQL schemas** rather than defining duplicate interfaces manually.
|
|
297
|
+
|
|
298
|
+
### Why
|
|
299
|
+
|
|
300
|
+
The `yarn generateGraphql` step produces TypeScript types in `packages/common/src/generated/generated-models.ts` for every GraphQL type, query, and mutation. These generated types are the **single source of truth** for the shape of data flowing through the GraphQL layer. If a template redefines the same structure (even with a different name), the two can drift apart when the schema evolves.
|
|
301
|
+
|
|
302
|
+
### How
|
|
303
|
+
|
|
304
|
+
Template files are copied into `packages/common/src/services/` — so they can import from `'common/server'` just like any other file in the common package. The generated types are re-exported through `common/server`.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// ✅ CORRECT — import the generated type
|
|
308
|
+
import { IExtensionContributes } from 'common/server';
|
|
309
|
+
|
|
310
|
+
export interface IExtensionContributesProvider {
|
|
311
|
+
getContributes(extensionId: string, version?: string): Promise<IExtensionContributes>;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
// ❌ WRONG — manually redefining the same shape
|
|
317
|
+
export interface IExtensionContributesResult {
|
|
318
|
+
uiLayout?: Record<string, unknown>[];
|
|
319
|
+
configuration?: Record<string, unknown>[];
|
|
320
|
+
// ... duplicates the GraphQL-generated IExtensionContributes
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export interface IExtensionContributesProvider {
|
|
324
|
+
getContributes(extensionId: string, version?: string): Promise<IExtensionContributesResult>;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### When to Define Your Own Types
|
|
329
|
+
|
|
330
|
+
Only define a type locally in the template when:
|
|
331
|
+
|
|
332
|
+
- The type has **no corresponding GraphQL schema definition** (e.g., an internal-only DTO not exposed via the API)
|
|
333
|
+
- The type intentionally **differs** from the GraphQL type (e.g., a partial/extended variant)
|
|
334
|
+
- The type is a **generic utility** interface not tied to a schema entity
|
|
335
|
+
|
|
336
|
+
### Existing Templates That Import Generated Types
|
|
337
|
+
|
|
338
|
+
Many existing templates already follow this pattern:
|
|
339
|
+
|
|
340
|
+
| Template | Imports from `'common/server'` |
|
|
341
|
+
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
342
|
+
| `ExtensionGalleryService.ts.template` | `IGalleryExtension`, `IExtensionManifest`, `IGalleryPager`, `AsDomainType`, `IRegistryExtensionModel` |
|
|
343
|
+
| `ExtensionGalleryDataLoader.ts.template` | `IGalleryExtension`, `IDataLoader` |
|
|
344
|
+
| `InstalledExtensionService.ts.template` | Multiple model types |
|
|
345
|
+
| `MarketplacePublisherService.ts.template` | `IMarketplacePublisherModel`, `AsDomainType` |
|
|
346
|
+
| `ExtensionContributionService.ts.template` | `IExtensionContributes` |
|
|
347
|
+
|
|
348
|
+
### Pipeline Order Consideration
|
|
349
|
+
|
|
350
|
+
Since `yarn regenerateGraphql` (copies templates) runs **before** `yarn generateGraphql` (generates types), you might wonder: how can a template import a type that hasn't been generated yet?
|
|
351
|
+
|
|
352
|
+
The answer is that generated types from **previous runs** are already present in `packages/common/src/generated/`. The pipeline is designed to be run incrementally:
|
|
353
|
+
|
|
354
|
+
1. First run: Define the `.graphql` schema → `generateGraphql` produces the types
|
|
355
|
+
2. Second run (or same session): Create the template that imports those types → `regenerateGraphql` copies the template → `generateGraphql` regenerates (types already exist)
|
|
356
|
+
|
|
357
|
+
In practice, you always run both commands together, so the generated types are available by the time the common package is compiled.
|
|
358
|
+
|
|
359
|
+
## Key Rules
|
|
360
|
+
|
|
361
|
+
1. **NEVER manually edit `packages/common/`** — all files are generated
|
|
362
|
+
2. **ALWAYS create `.ts.template` files** in your module's `templates/` folder for new interfaces
|
|
363
|
+
3. **ALWAYS run `yarn regenerateGraphql`** after creating/modifying template files
|
|
364
|
+
4. **ALWAYS run `yarn generateGraphql`** after creating/modifying `.graphql` schema files
|
|
365
|
+
5. **The `postgenerateGraphql` script runs automatically** — no need to manually build common
|
|
366
|
+
6. **SERVER_TYPES.ts is a merge of ALL modules'** `SERVER_TYPES.ts.template` files
|
|
367
|
+
7. **service-schemas.ts is auto-generated** from service interfaces in `packages/common/src/services/`
|
|
368
|
+
8. **PREFER importing generated GraphQL types** (`import { ITypeName } from 'common/server'`) over redefining the same shape in templates — the GraphQL schema is the single source of truth for API types
|
|
369
|
+
|
|
370
|
+
## Downstream Stacks (e.g., forms-stack)
|
|
371
|
+
|
|
372
|
+
Downstream stacks consume upstream npm packages. The flow:
|
|
373
|
+
|
|
374
|
+
1. Upstream (adminIde-stack) publishes `@adminide-stack/*` packages with compiled `.graphql` schemas in `lib/`
|
|
375
|
+
2. Downstream `codegen.ts` picks up schemas from `node_modules/@adminide-stack/*/lib/**/*.graphql`
|
|
376
|
+
3. Downstream `yarn regenerateGraphql` copies templates from both:
|
|
377
|
+
- npm packages (upstream templates)
|
|
378
|
+
- Local packages (downstream-only templates)
|
|
379
|
+
4. This is why downstream common packages have upstream types — they come through the template copy process
|
|
380
|
+
|
|
381
|
+
### Adding a New Service in Downstream Stack
|
|
382
|
+
|
|
383
|
+
If the service interface already exists in the upstream npm package:
|
|
384
|
+
|
|
385
|
+
- Just run `yarn regenerateGraphql` — it will copy the template from `node_modules/`
|
|
386
|
+
- Then run `yarn generateGraphql` — it will pick up `.graphql` schemas from `node_modules/`
|
|
387
|
+
|
|
388
|
+
If the upstream package hasn't been published yet:
|
|
389
|
+
|
|
390
|
+
- Define interfaces **locally** in the module (NOT in common)
|
|
391
|
+
- Use `Symbol.for()` for DI tokens to ensure cross-container compatibility
|
|
392
|
+
- Once upstream publishes, run `yarn regenerateGraphql` to get the official templates
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdmbase/wiki-browser",
|
|
3
|
-
"version": "12.0.18-alpha.
|
|
3
|
+
"version": "12.0.18-alpha.32",
|
|
4
4
|
"description": "Sample core for higher packages to depend on",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
}
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "68d47d67cfcd0834d97daa5c81223473354bffd2",
|
|
69
69
|
"typescript": {
|
|
70
70
|
"definition": "lib/index.d.ts"
|
|
71
71
|
}
|