@ketrics/ketrics-cli 0.5.0 → 0.6.1

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 (36) hide show
  1. package/dist/src/cli.d.ts.map +1 -1
  2. package/dist/src/cli.js +6 -0
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/commands/create.d.ts +1 -0
  5. package/dist/src/commands/create.d.ts.map +1 -1
  6. package/dist/src/commands/create.js +44 -13
  7. package/dist/src/commands/create.js.map +1 -1
  8. package/dist/src/services/local-template-service.d.ts +52 -0
  9. package/dist/src/services/local-template-service.d.ts.map +1 -0
  10. package/dist/src/services/local-template-service.js +216 -0
  11. package/dist/src/services/local-template-service.js.map +1 -0
  12. package/dist/src/services/remote-template-service.d.ts +41 -0
  13. package/dist/src/services/remote-template-service.d.ts.map +1 -0
  14. package/dist/src/services/remote-template-service.js +232 -0
  15. package/dist/src/services/remote-template-service.js.map +1 -0
  16. package/dist/src/services/template-cache-service.d.ts +44 -0
  17. package/dist/src/services/template-cache-service.d.ts.map +1 -0
  18. package/dist/src/services/template-cache-service.js +193 -0
  19. package/dist/src/services/template-cache-service.js.map +1 -0
  20. package/dist/src/services/template-service.d.ts +25 -31
  21. package/dist/src/services/template-service.d.ts.map +1 -1
  22. package/dist/src/services/template-service.js +136 -132
  23. package/dist/src/services/template-service.js.map +1 -1
  24. package/dist/src/types/index.d.ts +46 -0
  25. package/dist/src/types/index.d.ts.map +1 -1
  26. package/dist/src/types/index.js.map +1 -1
  27. package/dist/src/version.d.ts +1 -1
  28. package/dist/src/version.js +1 -1
  29. package/package.json +5 -1
  30. package/templates/HelloWorld/.claude/skills/ketrics-app/BACKEND_REFERENCE.md +693 -0
  31. package/templates/HelloWorld/.claude/skills/ketrics-app/CONFIG_AND_DEPLOY.md +278 -0
  32. package/templates/HelloWorld/.claude/skills/ketrics-app/FRONTEND_REFERENCE.md +325 -0
  33. package/templates/HelloWorld/.claude/skills/ketrics-app/SKILL.md +348 -0
  34. package/templates/HelloWorld/.env.example +20 -0
  35. package/templates/HelloWorld/.github/workflows/deploy.yml +51 -0
  36. package/templates/HelloWorld/backend/package.json +1 -1
@@ -0,0 +1,348 @@
1
+ ---
2
+ name: ketrics-app
3
+ description: Scaffolds and builds Ketrics tenant applications with backend handlers, frontend React UI, and platform SDK integrations. Use when creating a new Ketrics app, adding backend handlers, setting up database connections, DocumentDB storage, Excel exports, Volume file storage, messaging, comments, environment variables, or deploying to the Ketrics platform.
4
+ ---
5
+
6
+ # Ketrics Application Builder
7
+
8
+ Build tenant applications on the Ketrics platform. This skill covers project scaffolding, backend handler development, frontend React integration, and deployment.
9
+
10
+ ## Architecture overview
11
+
12
+ A Ketrics app has two parts:
13
+
14
+ 1. **Backend** (`backend/src/index.ts`): Single TypeScript file exporting async handler functions. Uses the global `ketrics` object (typed by `@ketrics/sdk-backend`) with no imports needed. Built with esbuild into a single bundle.
15
+ 2. **Frontend** (`frontend/src/`): React app (Vite + TypeScript) embedded as an iframe. Uses `@ketrics/sdk-frontend` for auth. Calls backend handlers via a service layer.
16
+
17
+ A `ketrics.config.json` at the project root declares the app name, runtime, action names, entry point, and resources.
18
+
19
+ ## Project structure
20
+
21
+ ```
22
+ my-ketrics-app/
23
+ ├── ketrics.config.json # App config (actions, resources)
24
+ ├── CLAUDE.md # Dev instructions
25
+ ├── backend/
26
+ │ ├── package.json # devDeps: @ketrics/sdk-backend, esbuild, typescript
27
+ │ ├── tsconfig.json
28
+ │ └── src/
29
+ │ └── index.ts # All handler functions (single file)
30
+ ├── frontend/
31
+ │ ├── package.json # deps: react, @ketrics/sdk-frontend, vite
32
+ │ ├── tsconfig.json
33
+ │ ├── vite.config.ts
34
+ │ ├── index.html
35
+ │ └── src/
36
+ │ ├── App.tsx # Main component
37
+ │ ├── main.tsx # React entry point
38
+ │ ├── types.ts # Shared TypeScript interfaces
39
+ │ ├── services/
40
+ │ │ └── index.ts # callFunction service layer
41
+ │ └── mocks/
42
+ │ └── handlers.ts # Dev-mode mock handlers
43
+ └── .github/
44
+ └── workflows/
45
+ └── deploy.yml # CI/CD pipeline
46
+ ```
47
+
48
+ ## Step-by-step: Create a new app
49
+
50
+ ### 1. Initialize the project
51
+
52
+ ```bash
53
+ mkdir my-ketrics-app && cd my-ketrics-app
54
+ ```
55
+
56
+ ### 2. Create `ketrics.config.json`
57
+
58
+ ```json
59
+ {
60
+ "name": "my-ketrics-app",
61
+ "version": "1.0.0",
62
+ "description": "My Ketrics application",
63
+ "runtime": "nodejs18",
64
+ "actions": [
65
+ "listItems",
66
+ "getItem",
67
+ "createItem",
68
+ "updateItem",
69
+ "deleteItem"
70
+ ],
71
+ "entry": "dist/index.js",
72
+ "include": ["dist/**/*"],
73
+ "exclude": ["node_modules", "*.test.js"],
74
+ "resources": {
75
+ "documentdb": [
76
+ { "code": "app-data", "description": "Main data store" }
77
+ ]
78
+ }
79
+ }
80
+ ```
81
+
82
+ **Key rules:**
83
+ - `actions` array MUST match the exported handler names in `backend/src/index.ts`
84
+ - `resources` declares DocumentDB collections and Volumes the app needs
85
+ - Add `"volume"` entries under resources when the app needs file storage
86
+
87
+ ### 3. Set up the backend
88
+
89
+ ```bash
90
+ mkdir -p backend/src
91
+ cd backend
92
+ npm init -y
93
+ npm install -D @ketrics/sdk-backend@0.11.0 esbuild typescript @types/node
94
+ ```
95
+
96
+ **`backend/package.json` scripts:**
97
+ ```json
98
+ {
99
+ "scripts": {
100
+ "build": "esbuild src/index.ts --bundle --platform=node --target=es2020 --outfile=dist/index.js"
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### 4. Write backend handlers
106
+
107
+ See [BACKEND_REFERENCE.md](BACKEND_REFERENCE.md) for the complete SDK API and patterns.
108
+
109
+ Every handler is an `async` function that receives a typed payload and returns a result object:
110
+
111
+ ```typescript
112
+ const myHandler = async (payload: { id: string }) => {
113
+ const userId = ketrics.requestor.userId;
114
+ // ... handler logic using ketrics.* SDK
115
+ return { result: "value" };
116
+ };
117
+
118
+ export { myHandler };
119
+ ```
120
+
121
+ ### 5. Set up the frontend
122
+
123
+ ```bash
124
+ mkdir -p frontend/src/services frontend/src/mocks
125
+ cd frontend
126
+ npm init -y
127
+ npm install react react-dom @ketrics/sdk-frontend
128
+ npm install -D @vitejs/plugin-react vite typescript @types/react @types/react-dom
129
+ ```
130
+
131
+ See [FRONTEND_REFERENCE.md](FRONTEND_REFERENCE.md) for the service layer, auth, and mock handler patterns.
132
+
133
+ ### 6. Deploy
134
+
135
+ See [CONFIG_AND_DEPLOY.md](CONFIG_AND_DEPLOY.md) for ketrics.config.json details and GitHub Actions CI/CD.
136
+
137
+ ```bash
138
+ # Manual deploy (requires .env with KETRICS_TOKEN)
139
+ ketrics deploy --env .env
140
+ ```
141
+
142
+ ## SDK quick reference
143
+
144
+ The `ketrics` global object is available in all backend handlers with no imports. Here's a quick overview of each subsystem:
145
+
146
+ ### Environment variables
147
+
148
+ ```typescript
149
+ const value = ketrics.environment["MY_VAR"];
150
+ ```
151
+
152
+ Read app-specific configuration. Common pattern: store JSON arrays for connection configs, resource codes, feature flags.
153
+
154
+ ### Requestor context
155
+
156
+ ```typescript
157
+ ketrics.requestor.userId // Current user ID
158
+ ketrics.requestor.name // Display name
159
+ ketrics.requestor.email // Email
160
+ ketrics.requestor.applicationPermissions // ["editor", ...]
161
+ ```
162
+
163
+ ### Database (SQL queries)
164
+
165
+ ```typescript
166
+ const db = await ketrics.Database.connect(connectionCode);
167
+ try {
168
+ const result = await db.query<Record<string, unknown>>(sql, params);
169
+ // result.rows, result.rowCount
170
+ } finally {
171
+ await db.close();
172
+ }
173
+ ```
174
+
175
+ ### DocumentDB (NoSQL storage)
176
+
177
+ DynamoDB-style pk/sk model with `put`, `get`, `delete`, `list` operations.
178
+
179
+ ```typescript
180
+ const docdb = await ketrics.DocumentDb.connect(resourceCode);
181
+ await docdb.put(pk, sk, item);
182
+ const item = await docdb.get(pk, sk);
183
+ const result = await docdb.list(pk, { skPrefix: "PREFIX#" });
184
+ await docdb.delete(pk, sk);
185
+ ```
186
+
187
+ ### Excel generation
188
+
189
+ ```typescript
190
+ const excel = ketrics.Excel.create();
191
+ const sheet = excel.addWorksheet("Sheet1");
192
+ sheet.columns = columns.map(col => ({ header: col, key: col, width: 15 }));
193
+ sheet.addRows(rows);
194
+ const buffer = await excel.toBuffer();
195
+ ```
196
+
197
+ ### Volume (file storage)
198
+
199
+ ```typescript
200
+ const volume = await ketrics.Volume.connect(volumeCode);
201
+ await volume.put(fileKey, buffer);
202
+ const { url } = await volume.generateDownloadUrl(fileKey);
203
+ ```
204
+
205
+ ### Messages (notifications)
206
+
207
+ ```typescript
208
+ await ketrics.Messages.sendBulk({
209
+ userIds: ["user1", "user2"],
210
+ type: "CUSTOM_TYPE",
211
+ subject: "Subject line",
212
+ body: "**Markdown** body",
213
+ priority: "MEDIUM",
214
+ });
215
+ ```
216
+
217
+ ### Users
218
+
219
+ ```typescript
220
+ const users = await ketrics.Users.list();
221
+ // [{ id, firstName, lastName, email }, ...]
222
+ ```
223
+
224
+ ### Logging
225
+
226
+ ```typescript
227
+ ketrics.console.error("Non-critical error message");
228
+ ```
229
+
230
+ ### Application context
231
+
232
+ ```typescript
233
+ ketrics.application.id // Application UUID
234
+ ```
235
+
236
+ ## Common patterns
237
+
238
+ ### Permission checking
239
+
240
+ ```typescript
241
+ function requireEditor(): void {
242
+ if (!ketrics.requestor.applicationPermissions.includes("editor")) {
243
+ throw new Error("Permission denied: editor role required");
244
+ }
245
+ }
246
+ ```
247
+
248
+ ### Ownership verification
249
+
250
+ ```typescript
251
+ const existing = await docdb.get(pk, sk);
252
+ if (!existing) throw new Error("Not found");
253
+ if (existing.createdBy !== userId) {
254
+ throw new Error("You can only modify your own resources");
255
+ }
256
+ ```
257
+
258
+ ### DocumentDB key design
259
+
260
+ Use prefixed composite keys for multi-entity storage in a single DocumentDB:
261
+
262
+ | Entity | pk | sk |
263
+ |--------|----|----|
264
+ | User items | `USER#${userId}` | `ITEM#${itemId}` |
265
+ | Tenant-wide | `TENANT_ITEMS` | `ITEM#${itemId}` |
266
+ | Comments | `COMMENTS#${targetId}` | `COMMENT#${createdAt}#${commentId}` |
267
+ | Index | `INDEX#${scope}` | `KEY#${lookupKey}` |
268
+
269
+ ### Export to Excel via Volume
270
+
271
+ ```typescript
272
+ const exportToExcel = async (payload: { data: unknown[] }) => {
273
+ const volumeCode = ketrics.environment["EXPORTS_VOLUME"];
274
+ if (!volumeCode) throw new Error("EXPORTS_VOLUME not configured");
275
+
276
+ // Generate Excel
277
+ const excel = ketrics.Excel.create();
278
+ const sheet = excel.addWorksheet("Export");
279
+ // ... add columns and rows
280
+ const buffer = await excel.toBuffer();
281
+
282
+ // Save to Volume and get download URL
283
+ const filename = `export_${Date.now()}.xlsx`;
284
+ const fileKey = `${ketrics.application.id}/${filename}`;
285
+ const volume = await ketrics.Volume.connect(volumeCode);
286
+ await volume.put(fileKey, buffer);
287
+ const { url } = await volume.generateDownloadUrl(fileKey);
288
+
289
+ return { url, filename };
290
+ };
291
+ ```
292
+
293
+ ### Comment system
294
+
295
+ Store comments with composite keys for efficient queries. Use a separate index for fast count lookups:
296
+
297
+ ```typescript
298
+ // Store comment
299
+ await docdb.put(
300
+ `COMMENTS#${targetId}`,
301
+ `COMMENT#${createdAt}#${commentId}`,
302
+ commentData
303
+ );
304
+
305
+ // Update count index
306
+ const indexItem = await docdb.get(`INDEX#${scope}`, `KEY#${targetId}`);
307
+ const count = indexItem ? (indexItem.count as number) : 0;
308
+ await docdb.put(`INDEX#${scope}`, `KEY#${targetId}`, {
309
+ targetId,
310
+ count: count + 1,
311
+ lastCommentAt: now,
312
+ });
313
+ ```
314
+
315
+ ### Shared resources with access control
316
+
317
+ ```typescript
318
+ // Filter: owned by me OR shared with me OR shared with all
319
+ const items = result.items.filter((item) => {
320
+ if (item.owner === userId) return true;
321
+ if (item.visibility !== "shared") return false;
322
+ const sw = item.sharedWith;
323
+ if (sw === "all") return true;
324
+ if (Array.isArray(sw) && sw.includes(userId)) return true;
325
+ return false;
326
+ });
327
+ ```
328
+
329
+ ## Additional resources
330
+
331
+ - **Backend SDK reference**: See [BACKEND_REFERENCE.md](BACKEND_REFERENCE.md) for complete API docs and all handler patterns
332
+ - **Frontend patterns**: See [FRONTEND_REFERENCE.md](FRONTEND_REFERENCE.md) for the service layer, auth manager, mock handlers, and type definitions
333
+ - **Config and deployment**: See [CONFIG_AND_DEPLOY.md](CONFIG_AND_DEPLOY.md) for ketrics.config.json schema, GitHub Actions workflow, and environment setup
334
+
335
+ ## Checklist for new apps
336
+
337
+ ```
338
+ - [ ] Create ketrics.config.json with correct actions and resources
339
+ - [ ] Set up backend with @ketrics/sdk-backend and esbuild
340
+ - [ ] Write handler functions using ketrics.* global
341
+ - [ ] Export all handlers and sync with config actions array
342
+ - [ ] Set up frontend with React, Vite, and @ketrics/sdk-frontend
343
+ - [ ] Create callFunction service layer with dev/prod branching
344
+ - [ ] Write mock handlers for local development
345
+ - [ ] Define TypeScript interfaces in types.ts
346
+ - [ ] Set up GitHub Actions deploy workflow
347
+ - [ ] Configure environment variables in Ketrics dashboard
348
+ ```
@@ -0,0 +1,20 @@
1
+ # Ketrics Deployment Configuration
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # API URL (default for production)
5
+ KETRICS_API_URL=https://api.ketrics.io/api/v1
6
+
7
+ # RUNTIME API URL (default for production)
8
+ KETRICS_RUNTIME_URL=https://runtime.ketrics.io
9
+
10
+ # Your tenant ID
11
+ KETRICS_TENANT_ID=TENANT_ID_HERE
12
+
13
+ # Application ID for this backend
14
+ KETRICS_APPLICATION_ID=APPLICATION_ID_HERE
15
+
16
+ # Deployment token from Ketrics dashboard
17
+ KETRICS_TOKEN=KETRICS_TOKEN_HERE
18
+
19
+ # Optional: Custom authentication token (JWT) for Ketrics API
20
+ KETRICS_AUTH_TOKEN=KETRICS_AUTH_TOKEN_HERE
@@ -0,0 +1,51 @@
1
+ name: Deploy to Ketrics
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ env:
8
+ KETRICS_API_URL: https://api.ketrics.io/api/v1
9
+ KETRICS_RUNTIME_URL: https://runtime.ketrics.io
10
+ KETRICS_TENANT_ID: KETRICS_TENANT_ID
11
+ KETRICS_APPLICATION_ID: KETRICS_APPLICATION_ID
12
+
13
+ jobs:
14
+ deploy:
15
+ runs-on: ubuntu-latest
16
+ environment: prod
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - uses: actions/setup-node@v4
21
+ with:
22
+ node-version: 18
23
+
24
+ # Install Ketrics CLI
25
+ - run: npm install -g @ketrics/ketrics-cli
26
+
27
+ # Generate .env file (only KETRICS_TOKEN is a secret)
28
+ - name: Generate .env file
29
+ run: |
30
+ cat <<EOF > .env
31
+ KETRICS_API_URL=$KETRICS_API_URL
32
+ KETRICS_RUNTIME_URL=$KETRICS_RUNTIME_URL
33
+ KETRICS_TENANT_ID=$KETRICS_TENANT_ID
34
+ KETRICS_APPLICATION_ID=$KETRICS_APPLICATION_ID
35
+ KETRICS_TOKEN=${{ secrets.KETRICS_TOKEN }}
36
+ EOF
37
+
38
+ # Backend: install + build
39
+ - run: npm ci
40
+ working-directory: backend
41
+ - run: npm run build
42
+ working-directory: backend
43
+
44
+ # Frontend: install + build
45
+ - run: npm ci
46
+ working-directory: frontend
47
+ - run: npm run build
48
+ working-directory: frontend
49
+
50
+ # Deploy
51
+ - run: ketrics deploy --env .env
@@ -9,7 +9,7 @@
9
9
  "clean": "rm -rf dist"
10
10
  },
11
11
  "devDependencies": {
12
- "@ketrics/sdk-backend": "0.8.0",
12
+ "@ketrics/sdk-backend": "0.11.0",
13
13
  "@types/node": ">=24.0.0",
14
14
  "esbuild": "^0.27.2",
15
15
  "ts-node": "^1.7.1",