@xbg.solutions/create-backend 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.
- package/bin/create-backend.js +3 -0
- package/lib/cli.d.ts +12 -0
- package/lib/cli.js +55 -0
- package/lib/cli.js.map +1 -0
- package/lib/commands/add-util.d.ts +9 -0
- package/lib/commands/add-util.js +119 -0
- package/lib/commands/add-util.js.map +1 -0
- package/lib/commands/init.d.ts +11 -0
- package/lib/commands/init.js +372 -0
- package/lib/commands/init.js.map +1 -0
- package/lib/commands/sync.d.ts +10 -0
- package/lib/commands/sync.js +161 -0
- package/lib/commands/sync.js.map +1 -0
- package/lib/utils-registry.d.ts +25 -0
- package/lib/utils-registry.js +187 -0
- package/lib/utils-registry.js.map +1 -0
- package/package.json +38 -0
- package/src/project-template/__examples__/README.md +559 -0
- package/src/project-template/__examples__/blog-platform.model.ts +528 -0
- package/src/project-template/__examples__/communications-usage.ts +175 -0
- package/src/project-template/__examples__/ecommerce-store.model.ts +1200 -0
- package/src/project-template/__examples__/saas-multi-tenant.model.ts +798 -0
- package/src/project-template/__examples__/user.model.ts +221 -0
- package/src/project-template/__scripts__/deploy.js +115 -0
- package/src/project-template/__scripts__/generate.js +122 -0
- package/src/project-template/__scripts__/setup.js +425 -0
- package/src/project-template/__scripts__/validate.js +325 -0
- package/src/project-template/firebase.json +32 -0
- package/src/project-template/firestore.rules +12 -0
- package/src/project-template/functions/jest.config.js +49 -0
- package/src/project-template/functions/src/index.ts +46 -0
- package/src/project-template/functions/tsconfig.json +38 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blog Platform Data Model
|
|
3
|
+
*
|
|
4
|
+
* A complete blog platform with:
|
|
5
|
+
* - User authentication and profiles
|
|
6
|
+
* - Posts with categories and tags
|
|
7
|
+
* - Comments with threading
|
|
8
|
+
* - Social features (likes, follows)
|
|
9
|
+
* - Content moderation
|
|
10
|
+
*
|
|
11
|
+
* Features demonstrated:
|
|
12
|
+
* - One-to-many relationships (User → Posts)
|
|
13
|
+
* - Many-to-many relationships (Posts → Tags)
|
|
14
|
+
* - Self-referencing relationships (Comment replies)
|
|
15
|
+
* - Access control rules
|
|
16
|
+
* - Business rules and validation
|
|
17
|
+
* - Optimized indexes
|
|
18
|
+
*
|
|
19
|
+
* To use this model:
|
|
20
|
+
* 1. Copy to your project
|
|
21
|
+
* 2. Run: npm run generate __examples__/blog-platform.model.ts
|
|
22
|
+
* 3. Register controllers in functions/src/app.ts
|
|
23
|
+
* 4. Deploy: npm run deploy
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { DataModelSpecification } from '../functions/src/generator/types';
|
|
27
|
+
|
|
28
|
+
export const BlogPlatformModel: DataModelSpecification = {
|
|
29
|
+
entities: {
|
|
30
|
+
User: {
|
|
31
|
+
fields: {
|
|
32
|
+
email: {
|
|
33
|
+
type: 'email',
|
|
34
|
+
unique: true,
|
|
35
|
+
required: true,
|
|
36
|
+
},
|
|
37
|
+
username: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
unique: true,
|
|
40
|
+
required: true,
|
|
41
|
+
},
|
|
42
|
+
displayName: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
bio: {
|
|
47
|
+
type: 'text',
|
|
48
|
+
required: false,
|
|
49
|
+
},
|
|
50
|
+
avatarUrl: {
|
|
51
|
+
type: 'url',
|
|
52
|
+
required: false,
|
|
53
|
+
},
|
|
54
|
+
isVerified: {
|
|
55
|
+
type: 'boolean',
|
|
56
|
+
default: false,
|
|
57
|
+
},
|
|
58
|
+
role: {
|
|
59
|
+
type: 'enum',
|
|
60
|
+
values: ['reader', 'author', 'moderator', 'admin'],
|
|
61
|
+
default: 'reader',
|
|
62
|
+
},
|
|
63
|
+
status: {
|
|
64
|
+
type: 'enum',
|
|
65
|
+
values: ['active', 'suspended', 'deleted'],
|
|
66
|
+
default: 'active',
|
|
67
|
+
},
|
|
68
|
+
lastLoginAt: {
|
|
69
|
+
type: 'timestamp',
|
|
70
|
+
required: false,
|
|
71
|
+
},
|
|
72
|
+
createdAt: {
|
|
73
|
+
type: 'timestamp',
|
|
74
|
+
required: true,
|
|
75
|
+
},
|
|
76
|
+
updatedAt: {
|
|
77
|
+
type: 'timestamp',
|
|
78
|
+
required: true,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
relationships: {
|
|
82
|
+
posts: {
|
|
83
|
+
type: 'one-to-many',
|
|
84
|
+
entity: 'Post',
|
|
85
|
+
foreignKey: 'authorId',
|
|
86
|
+
cascadeDelete: false, // Keep posts when user is deleted (anonymize instead)
|
|
87
|
+
},
|
|
88
|
+
comments: {
|
|
89
|
+
type: 'one-to-many',
|
|
90
|
+
entity: 'Comment',
|
|
91
|
+
foreignKey: 'authorId',
|
|
92
|
+
cascadeDelete: false,
|
|
93
|
+
},
|
|
94
|
+
likedPosts: {
|
|
95
|
+
type: 'many-to-many',
|
|
96
|
+
entity: 'Post',
|
|
97
|
+
through: 'PostLike',
|
|
98
|
+
},
|
|
99
|
+
following: {
|
|
100
|
+
type: 'many-to-many',
|
|
101
|
+
entity: 'User',
|
|
102
|
+
through: 'UserFollow',
|
|
103
|
+
foreignKey: 'followerId',
|
|
104
|
+
relatedKey: 'followingId',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
access: {
|
|
108
|
+
create: ['public'], // Public registration
|
|
109
|
+
read: ['public'],
|
|
110
|
+
update: ['self', 'admin'],
|
|
111
|
+
delete: ['self', 'admin'],
|
|
112
|
+
},
|
|
113
|
+
validation: {
|
|
114
|
+
email: 'Must be a valid email address',
|
|
115
|
+
username: 'Must be 3-30 characters, alphanumeric and underscores only',
|
|
116
|
+
displayName: 'Must be 1-100 characters',
|
|
117
|
+
},
|
|
118
|
+
businessRules: [
|
|
119
|
+
'Email must be verified before user can publish posts',
|
|
120
|
+
'Suspended users cannot create posts or comments',
|
|
121
|
+
'Deleted users have their personal data anonymized',
|
|
122
|
+
'Users cannot follow themselves',
|
|
123
|
+
],
|
|
124
|
+
indexes: [
|
|
125
|
+
{ fields: ['email'], unique: true },
|
|
126
|
+
{ fields: ['username'], unique: true },
|
|
127
|
+
{ fields: ['status'] },
|
|
128
|
+
{ fields: ['createdAt'] },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
Post: {
|
|
133
|
+
fields: {
|
|
134
|
+
title: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
required: true,
|
|
137
|
+
},
|
|
138
|
+
slug: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
unique: true,
|
|
141
|
+
required: true,
|
|
142
|
+
},
|
|
143
|
+
content: {
|
|
144
|
+
type: 'text',
|
|
145
|
+
required: true,
|
|
146
|
+
},
|
|
147
|
+
excerpt: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
required: false,
|
|
150
|
+
},
|
|
151
|
+
coverImageUrl: {
|
|
152
|
+
type: 'url',
|
|
153
|
+
required: false,
|
|
154
|
+
},
|
|
155
|
+
status: {
|
|
156
|
+
type: 'enum',
|
|
157
|
+
values: ['draft', 'published', 'archived', 'flagged'],
|
|
158
|
+
default: 'draft',
|
|
159
|
+
},
|
|
160
|
+
publishedAt: {
|
|
161
|
+
type: 'timestamp',
|
|
162
|
+
required: false,
|
|
163
|
+
},
|
|
164
|
+
authorId: {
|
|
165
|
+
type: 'reference',
|
|
166
|
+
entity: 'User',
|
|
167
|
+
required: true,
|
|
168
|
+
},
|
|
169
|
+
categoryId: {
|
|
170
|
+
type: 'reference',
|
|
171
|
+
entity: 'Category',
|
|
172
|
+
required: true,
|
|
173
|
+
},
|
|
174
|
+
viewCount: {
|
|
175
|
+
type: 'number',
|
|
176
|
+
default: 0,
|
|
177
|
+
},
|
|
178
|
+
likeCount: {
|
|
179
|
+
type: 'number',
|
|
180
|
+
default: 0,
|
|
181
|
+
},
|
|
182
|
+
commentCount: {
|
|
183
|
+
type: 'number',
|
|
184
|
+
default: 0,
|
|
185
|
+
},
|
|
186
|
+
readingTimeMinutes: {
|
|
187
|
+
type: 'number',
|
|
188
|
+
required: false,
|
|
189
|
+
},
|
|
190
|
+
isFeatured: {
|
|
191
|
+
type: 'boolean',
|
|
192
|
+
default: false,
|
|
193
|
+
},
|
|
194
|
+
createdAt: {
|
|
195
|
+
type: 'timestamp',
|
|
196
|
+
required: true,
|
|
197
|
+
},
|
|
198
|
+
updatedAt: {
|
|
199
|
+
type: 'timestamp',
|
|
200
|
+
required: true,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
relationships: {
|
|
204
|
+
author: {
|
|
205
|
+
type: 'many-to-one',
|
|
206
|
+
entity: 'User',
|
|
207
|
+
},
|
|
208
|
+
category: {
|
|
209
|
+
type: 'many-to-one',
|
|
210
|
+
entity: 'Category',
|
|
211
|
+
},
|
|
212
|
+
comments: {
|
|
213
|
+
type: 'one-to-many',
|
|
214
|
+
entity: 'Comment',
|
|
215
|
+
foreignKey: 'postId',
|
|
216
|
+
cascadeDelete: true,
|
|
217
|
+
},
|
|
218
|
+
tags: {
|
|
219
|
+
type: 'many-to-many',
|
|
220
|
+
entity: 'Tag',
|
|
221
|
+
through: 'PostTag',
|
|
222
|
+
},
|
|
223
|
+
likes: {
|
|
224
|
+
type: 'many-to-many',
|
|
225
|
+
entity: 'User',
|
|
226
|
+
through: 'PostLike',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
access: {
|
|
230
|
+
create: ['author', 'admin'],
|
|
231
|
+
read: ['public'], // Anyone can read published posts
|
|
232
|
+
update: ['self', 'admin'],
|
|
233
|
+
delete: ['self', 'admin'],
|
|
234
|
+
},
|
|
235
|
+
validation: {
|
|
236
|
+
title: 'Must be 5-200 characters',
|
|
237
|
+
slug: 'Must be URL-safe and unique',
|
|
238
|
+
content: 'Must not be empty',
|
|
239
|
+
},
|
|
240
|
+
businessRules: [
|
|
241
|
+
'Slug is auto-generated from title',
|
|
242
|
+
'Published posts cannot be unpublished (only archived)',
|
|
243
|
+
'Posts must belong to an active category',
|
|
244
|
+
'Reading time is calculated from content length',
|
|
245
|
+
'Only verified users can publish posts',
|
|
246
|
+
],
|
|
247
|
+
indexes: [
|
|
248
|
+
{ fields: ['slug'], unique: true },
|
|
249
|
+
{ fields: ['authorId', 'status'] },
|
|
250
|
+
{ fields: ['categoryId', 'status'] },
|
|
251
|
+
{ fields: ['status', 'publishedAt'] },
|
|
252
|
+
{ fields: ['isFeatured', 'publishedAt'] },
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
Comment: {
|
|
257
|
+
fields: {
|
|
258
|
+
content: {
|
|
259
|
+
type: 'text',
|
|
260
|
+
required: true,
|
|
261
|
+
},
|
|
262
|
+
postId: {
|
|
263
|
+
type: 'reference',
|
|
264
|
+
entity: 'Post',
|
|
265
|
+
required: true,
|
|
266
|
+
},
|
|
267
|
+
authorId: {
|
|
268
|
+
type: 'reference',
|
|
269
|
+
entity: 'User',
|
|
270
|
+
required: true,
|
|
271
|
+
},
|
|
272
|
+
parentId: {
|
|
273
|
+
type: 'reference',
|
|
274
|
+
entity: 'Comment',
|
|
275
|
+
required: false,
|
|
276
|
+
},
|
|
277
|
+
status: {
|
|
278
|
+
type: 'enum',
|
|
279
|
+
values: ['visible', 'flagged', 'deleted'],
|
|
280
|
+
default: 'visible',
|
|
281
|
+
},
|
|
282
|
+
isEdited: {
|
|
283
|
+
type: 'boolean',
|
|
284
|
+
default: false,
|
|
285
|
+
},
|
|
286
|
+
createdAt: {
|
|
287
|
+
type: 'timestamp',
|
|
288
|
+
required: true,
|
|
289
|
+
},
|
|
290
|
+
updatedAt: {
|
|
291
|
+
type: 'timestamp',
|
|
292
|
+
required: true,
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
relationships: {
|
|
296
|
+
post: {
|
|
297
|
+
type: 'many-to-one',
|
|
298
|
+
entity: 'Post',
|
|
299
|
+
},
|
|
300
|
+
author: {
|
|
301
|
+
type: 'many-to-one',
|
|
302
|
+
entity: 'User',
|
|
303
|
+
},
|
|
304
|
+
parent: {
|
|
305
|
+
type: 'many-to-one',
|
|
306
|
+
entity: 'Comment',
|
|
307
|
+
optional: true,
|
|
308
|
+
},
|
|
309
|
+
replies: {
|
|
310
|
+
type: 'one-to-many',
|
|
311
|
+
entity: 'Comment',
|
|
312
|
+
foreignKey: 'parentId',
|
|
313
|
+
cascadeDelete: true,
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
access: {
|
|
317
|
+
create: ['authenticated'],
|
|
318
|
+
read: ['public'],
|
|
319
|
+
update: ['self', 'moderator', 'admin'],
|
|
320
|
+
delete: ['self', 'moderator', 'admin'],
|
|
321
|
+
},
|
|
322
|
+
validation: {
|
|
323
|
+
content: 'Must be 1-2000 characters',
|
|
324
|
+
},
|
|
325
|
+
businessRules: [
|
|
326
|
+
'Comments can be nested up to 3 levels deep',
|
|
327
|
+
'Deleted comments show [deleted] placeholder',
|
|
328
|
+
'Flagged comments are hidden from public view',
|
|
329
|
+
'Users can edit comments within 5 minutes of posting',
|
|
330
|
+
],
|
|
331
|
+
indexes: [
|
|
332
|
+
{ fields: ['postId', 'status', 'createdAt'] },
|
|
333
|
+
{ fields: ['authorId'] },
|
|
334
|
+
{ fields: ['parentId'] },
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
Category: {
|
|
339
|
+
fields: {
|
|
340
|
+
name: {
|
|
341
|
+
type: 'string',
|
|
342
|
+
unique: true,
|
|
343
|
+
required: true,
|
|
344
|
+
},
|
|
345
|
+
slug: {
|
|
346
|
+
type: 'string',
|
|
347
|
+
unique: true,
|
|
348
|
+
required: true,
|
|
349
|
+
},
|
|
350
|
+
description: {
|
|
351
|
+
type: 'text',
|
|
352
|
+
required: false,
|
|
353
|
+
},
|
|
354
|
+
color: {
|
|
355
|
+
type: 'string',
|
|
356
|
+
required: false,
|
|
357
|
+
},
|
|
358
|
+
icon: {
|
|
359
|
+
type: 'string',
|
|
360
|
+
required: false,
|
|
361
|
+
},
|
|
362
|
+
isActive: {
|
|
363
|
+
type: 'boolean',
|
|
364
|
+
default: true,
|
|
365
|
+
},
|
|
366
|
+
postCount: {
|
|
367
|
+
type: 'number',
|
|
368
|
+
default: 0,
|
|
369
|
+
},
|
|
370
|
+
order: {
|
|
371
|
+
type: 'number',
|
|
372
|
+
default: 0,
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
relationships: {
|
|
376
|
+
posts: {
|
|
377
|
+
type: 'one-to-many',
|
|
378
|
+
entity: 'Post',
|
|
379
|
+
foreignKey: 'categoryId',
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
access: {
|
|
383
|
+
create: ['admin'],
|
|
384
|
+
read: ['public'],
|
|
385
|
+
update: ['admin'],
|
|
386
|
+
delete: ['admin'],
|
|
387
|
+
},
|
|
388
|
+
validation: {
|
|
389
|
+
name: 'Must be 2-50 characters',
|
|
390
|
+
slug: 'Must be URL-safe',
|
|
391
|
+
},
|
|
392
|
+
businessRules: [
|
|
393
|
+
'Categories with posts cannot be deleted',
|
|
394
|
+
'At least one category must exist',
|
|
395
|
+
],
|
|
396
|
+
indexes: [
|
|
397
|
+
{ fields: ['slug'], unique: true },
|
|
398
|
+
{ fields: ['isActive', 'order'] },
|
|
399
|
+
],
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
Tag: {
|
|
403
|
+
fields: {
|
|
404
|
+
name: {
|
|
405
|
+
type: 'string',
|
|
406
|
+
unique: true,
|
|
407
|
+
required: true,
|
|
408
|
+
},
|
|
409
|
+
slug: {
|
|
410
|
+
type: 'string',
|
|
411
|
+
unique: true,
|
|
412
|
+
required: true,
|
|
413
|
+
},
|
|
414
|
+
postCount: {
|
|
415
|
+
type: 'number',
|
|
416
|
+
default: 0,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
relationships: {
|
|
420
|
+
posts: {
|
|
421
|
+
type: 'many-to-many',
|
|
422
|
+
entity: 'Post',
|
|
423
|
+
through: 'PostTag',
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
access: {
|
|
427
|
+
create: ['author', 'admin'],
|
|
428
|
+
read: ['public'],
|
|
429
|
+
update: ['admin'],
|
|
430
|
+
delete: ['admin'],
|
|
431
|
+
},
|
|
432
|
+
validation: {
|
|
433
|
+
name: 'Must be 2-30 characters',
|
|
434
|
+
},
|
|
435
|
+
businessRules: [
|
|
436
|
+
'Tags are automatically created when used in posts',
|
|
437
|
+
'Tags with zero posts are periodically cleaned up',
|
|
438
|
+
],
|
|
439
|
+
indexes: [
|
|
440
|
+
{ fields: ['slug'], unique: true },
|
|
441
|
+
{ fields: ['postCount'] },
|
|
442
|
+
],
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
PostLike: {
|
|
446
|
+
fields: {
|
|
447
|
+
postId: {
|
|
448
|
+
type: 'reference',
|
|
449
|
+
entity: 'Post',
|
|
450
|
+
required: true,
|
|
451
|
+
},
|
|
452
|
+
userId: {
|
|
453
|
+
type: 'reference',
|
|
454
|
+
entity: 'User',
|
|
455
|
+
required: true,
|
|
456
|
+
},
|
|
457
|
+
createdAt: {
|
|
458
|
+
type: 'timestamp',
|
|
459
|
+
required: true,
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
access: {
|
|
463
|
+
create: ['authenticated'],
|
|
464
|
+
read: ['public'],
|
|
465
|
+
delete: ['self'],
|
|
466
|
+
},
|
|
467
|
+
businessRules: [
|
|
468
|
+
'Users cannot like their own posts',
|
|
469
|
+
'Users can only like a post once',
|
|
470
|
+
],
|
|
471
|
+
indexes: [
|
|
472
|
+
{ fields: ['postId', 'userId'], unique: true },
|
|
473
|
+
{ fields: ['userId'] },
|
|
474
|
+
],
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
UserFollow: {
|
|
478
|
+
fields: {
|
|
479
|
+
followerId: {
|
|
480
|
+
type: 'reference',
|
|
481
|
+
entity: 'User',
|
|
482
|
+
required: true,
|
|
483
|
+
},
|
|
484
|
+
followingId: {
|
|
485
|
+
type: 'reference',
|
|
486
|
+
entity: 'User',
|
|
487
|
+
required: true,
|
|
488
|
+
},
|
|
489
|
+
createdAt: {
|
|
490
|
+
type: 'timestamp',
|
|
491
|
+
required: true,
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
access: {
|
|
495
|
+
create: ['authenticated'],
|
|
496
|
+
read: ['public'],
|
|
497
|
+
delete: ['self'],
|
|
498
|
+
},
|
|
499
|
+
businessRules: [
|
|
500
|
+
'Users cannot follow themselves',
|
|
501
|
+
'Users can only follow once (no duplicates)',
|
|
502
|
+
],
|
|
503
|
+
indexes: [
|
|
504
|
+
{ fields: ['followerId', 'followingId'], unique: true },
|
|
505
|
+
{ fields: ['followingId'] },
|
|
506
|
+
],
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
PostTag: {
|
|
510
|
+
fields: {
|
|
511
|
+
postId: {
|
|
512
|
+
type: 'reference',
|
|
513
|
+
entity: 'Post',
|
|
514
|
+
required: true,
|
|
515
|
+
},
|
|
516
|
+
tagId: {
|
|
517
|
+
type: 'reference',
|
|
518
|
+
entity: 'Tag',
|
|
519
|
+
required: true,
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
indexes: [
|
|
523
|
+
{ fields: ['postId', 'tagId'], unique: true },
|
|
524
|
+
{ fields: ['tagId'] },
|
|
525
|
+
],
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communication Utilities Usage Examples
|
|
3
|
+
* Demonstrates how to use SNS, Email, SMS, and CRM connectors
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
getSNSConnector,
|
|
8
|
+
getEmailConnector,
|
|
9
|
+
getSMSConnector,
|
|
10
|
+
getCRMConnector,
|
|
11
|
+
} from '../functions/src/utilities';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Example 1: Publish event to SNS
|
|
15
|
+
*/
|
|
16
|
+
export async function exampleSNSPublish() {
|
|
17
|
+
const snsConnector = getSNSConnector();
|
|
18
|
+
if (!snsConnector) {
|
|
19
|
+
console.log('SNS connector not configured');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await snsConnector.publishEvent(
|
|
24
|
+
process.env.SNS_USER_EVENTS_TOPIC!,
|
|
25
|
+
{
|
|
26
|
+
eventType: 'USER_REGISTERED',
|
|
27
|
+
entityType: 'User',
|
|
28
|
+
entityId: 'user-123',
|
|
29
|
+
data: {
|
|
30
|
+
email: 'user@example.com',
|
|
31
|
+
name: 'John Doe',
|
|
32
|
+
},
|
|
33
|
+
metadata: {
|
|
34
|
+
timestamp: new Date(),
|
|
35
|
+
correlationId: 'req-456',
|
|
36
|
+
userId: 'user-123',
|
|
37
|
+
source: 'web-app',
|
|
38
|
+
version: '1.0',
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Example 2: Send transactional email
|
|
46
|
+
*/
|
|
47
|
+
export async function exampleSendWelcomeEmail() {
|
|
48
|
+
const emailConnector = getEmailConnector();
|
|
49
|
+
if (!emailConnector) {
|
|
50
|
+
console.log('Email connector not configured');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await emailConnector.sendTransactional({
|
|
55
|
+
to: [
|
|
56
|
+
{
|
|
57
|
+
email: 'user@example.com',
|
|
58
|
+
name: 'John Doe',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
templateId: 'welcome-email',
|
|
62
|
+
variables: {
|
|
63
|
+
firstName: 'John',
|
|
64
|
+
activationLink: 'https://app.example.com/activate/token123',
|
|
65
|
+
},
|
|
66
|
+
tags: ['welcome', 'onboarding'],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Example 3: Send verification SMS
|
|
72
|
+
*/
|
|
73
|
+
export async function exampleSendVerificationSMS() {
|
|
74
|
+
const smsConnector = getSMSConnector();
|
|
75
|
+
if (!smsConnector) {
|
|
76
|
+
console.log('SMS connector not configured');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const verificationCode = '123456';
|
|
81
|
+
|
|
82
|
+
await smsConnector.sendMessage({
|
|
83
|
+
to: '+1234567890',
|
|
84
|
+
message: `Your verification code is: ${verificationCode}. Valid for 10 minutes.`,
|
|
85
|
+
validityPeriod: 600, // 10 minutes
|
|
86
|
+
tags: ['verification', 'auth'],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Example 4: Sync user to CRM
|
|
92
|
+
*/
|
|
93
|
+
export async function exampleSyncUserToCRM() {
|
|
94
|
+
const crmConnector = getCRMConnector();
|
|
95
|
+
if (!crmConnector) {
|
|
96
|
+
console.log('CRM connector not configured');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await crmConnector.createContact({
|
|
101
|
+
email: 'user@example.com',
|
|
102
|
+
firstName: 'John',
|
|
103
|
+
lastName: 'Doe',
|
|
104
|
+
phone: '+1234567890',
|
|
105
|
+
company: 'Acme Inc',
|
|
106
|
+
jobTitle: 'Software Engineer',
|
|
107
|
+
customFields: {
|
|
108
|
+
signup_date: new Date().toISOString(),
|
|
109
|
+
user_tier: 'premium',
|
|
110
|
+
referral_source: 'organic',
|
|
111
|
+
},
|
|
112
|
+
tags: ['new-user', 'premium'],
|
|
113
|
+
source: 'web_app',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Example 5: Log activity in CRM
|
|
119
|
+
*/
|
|
120
|
+
export async function exampleLogCRMActivity() {
|
|
121
|
+
const crmConnector = getCRMConnector();
|
|
122
|
+
if (!crmConnector) return;
|
|
123
|
+
|
|
124
|
+
await crmConnector.logActivity({
|
|
125
|
+
contactEmail: 'user@example.com',
|
|
126
|
+
type: 'purchase',
|
|
127
|
+
subject: 'Premium Plan Purchase',
|
|
128
|
+
description: 'User upgraded to premium plan for $99/month',
|
|
129
|
+
timestamp: new Date(),
|
|
130
|
+
customFields: {
|
|
131
|
+
plan_name: 'Premium',
|
|
132
|
+
plan_price: 99,
|
|
133
|
+
billing_cycle: 'monthly',
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Example 6: Event-driven communication flow
|
|
140
|
+
* This shows how the event bus automatically triggers communications
|
|
141
|
+
*/
|
|
142
|
+
export async function exampleEventDrivenFlow() {
|
|
143
|
+
// When a USER_CREATED event is published to the event bus,
|
|
144
|
+
// the communication subscribers automatically:
|
|
145
|
+
// 1. Stream the event to SNS
|
|
146
|
+
// 2. Send a welcome email
|
|
147
|
+
// 3. Create a contact in CRM
|
|
148
|
+
|
|
149
|
+
// No manual connector calls needed - just publish the event!
|
|
150
|
+
// See: functions/src/subscribers/communication-subscribers.ts
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Example 7: Bulk operations
|
|
155
|
+
*/
|
|
156
|
+
export async function exampleBulkOperations() {
|
|
157
|
+
const emailConnector = getEmailConnector();
|
|
158
|
+
if (!emailConnector) return;
|
|
159
|
+
|
|
160
|
+
const users = [
|
|
161
|
+
{ email: 'user1@example.com', name: 'User 1' },
|
|
162
|
+
{ email: 'user2@example.com', name: 'User 2' },
|
|
163
|
+
{ email: 'user3@example.com', name: 'User 3' },
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
await emailConnector.sendBulk({
|
|
167
|
+
emails: users.map((user) => ({
|
|
168
|
+
to: [user],
|
|
169
|
+
subject: 'Product Update',
|
|
170
|
+
htmlContent: '<h1>New Features Available!</h1>',
|
|
171
|
+
tags: ['product-update', 'marketing'],
|
|
172
|
+
})),
|
|
173
|
+
batchSize: 50,
|
|
174
|
+
});
|
|
175
|
+
}
|