@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.
Files changed (32) hide show
  1. package/bin/create-backend.js +3 -0
  2. package/lib/cli.d.ts +12 -0
  3. package/lib/cli.js +55 -0
  4. package/lib/cli.js.map +1 -0
  5. package/lib/commands/add-util.d.ts +9 -0
  6. package/lib/commands/add-util.js +119 -0
  7. package/lib/commands/add-util.js.map +1 -0
  8. package/lib/commands/init.d.ts +11 -0
  9. package/lib/commands/init.js +372 -0
  10. package/lib/commands/init.js.map +1 -0
  11. package/lib/commands/sync.d.ts +10 -0
  12. package/lib/commands/sync.js +161 -0
  13. package/lib/commands/sync.js.map +1 -0
  14. package/lib/utils-registry.d.ts +25 -0
  15. package/lib/utils-registry.js +187 -0
  16. package/lib/utils-registry.js.map +1 -0
  17. package/package.json +38 -0
  18. package/src/project-template/__examples__/README.md +559 -0
  19. package/src/project-template/__examples__/blog-platform.model.ts +528 -0
  20. package/src/project-template/__examples__/communications-usage.ts +175 -0
  21. package/src/project-template/__examples__/ecommerce-store.model.ts +1200 -0
  22. package/src/project-template/__examples__/saas-multi-tenant.model.ts +798 -0
  23. package/src/project-template/__examples__/user.model.ts +221 -0
  24. package/src/project-template/__scripts__/deploy.js +115 -0
  25. package/src/project-template/__scripts__/generate.js +122 -0
  26. package/src/project-template/__scripts__/setup.js +425 -0
  27. package/src/project-template/__scripts__/validate.js +325 -0
  28. package/src/project-template/firebase.json +32 -0
  29. package/src/project-template/firestore.rules +12 -0
  30. package/src/project-template/functions/jest.config.js +49 -0
  31. package/src/project-template/functions/src/index.ts +46 -0
  32. package/src/project-template/functions/tsconfig.json +38 -0
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Configuration Validation Script
5
+ * Validates that the backend project is properly configured
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { execSync } = require('child_process');
11
+
12
+ const colors = {
13
+ reset: '\x1b[0m',
14
+ bright: '\x1b[1m',
15
+ dim: '\x1b[2m',
16
+ green: '\x1b[32m',
17
+ blue: '\x1b[34m',
18
+ yellow: '\x1b[33m',
19
+ red: '\x1b[31m',
20
+ cyan: '\x1b[36m',
21
+ };
22
+
23
+ const CHECK_MARK = '✓';
24
+ const CROSS_MARK = '✗';
25
+ const WARNING_MARK = '⚠';
26
+
27
+ let errors = 0;
28
+ let warnings = 0;
29
+ let checks = 0;
30
+
31
+ function printHeader(title) {
32
+ console.log(`\n${colors.bright}${colors.blue}${title}${colors.reset}`);
33
+ console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
34
+ }
35
+
36
+ function printSuccess(message) {
37
+ checks++;
38
+ console.log(`${colors.green}${CHECK_MARK}${colors.reset} ${message}`);
39
+ }
40
+
41
+ function printWarning(message) {
42
+ checks++;
43
+ warnings++;
44
+ console.log(`${colors.yellow}${WARNING_MARK}${colors.reset} ${message}`);
45
+ }
46
+
47
+ function printError(message) {
48
+ checks++;
49
+ errors++;
50
+ console.log(`${colors.red}${CROSS_MARK}${colors.reset} ${message}`);
51
+ }
52
+
53
+ function fileExists(filePath) {
54
+ return fs.existsSync(path.join(__dirname, '..', filePath));
55
+ }
56
+
57
+ function readEnvFile() {
58
+ const envPath = path.join(__dirname, '../functions/.env');
59
+ if (!fs.existsSync(envPath)) {
60
+ return null;
61
+ }
62
+
63
+ const envContent = fs.readFileSync(envPath, 'utf8');
64
+ const env = {};
65
+
66
+ envContent.split('\n').forEach(line => {
67
+ const trimmed = line.trim();
68
+ if (trimmed && !trimmed.startsWith('#')) {
69
+ const [key, ...valueParts] = trimmed.split('=');
70
+ env[key.trim()] = valueParts.join('=').trim();
71
+ }
72
+ });
73
+
74
+ return env;
75
+ }
76
+
77
+ function checkCommand(command, name) {
78
+ try {
79
+ execSync(`which ${command}`, { stdio: 'ignore' });
80
+ return true;
81
+ } catch {
82
+ return false;
83
+ }
84
+ }
85
+
86
+ function runCommand(command, cwd) {
87
+ try {
88
+ execSync(command, {
89
+ cwd: cwd || path.join(__dirname, '../functions'),
90
+ stdio: 'pipe',
91
+ encoding: 'utf8',
92
+ });
93
+ return true;
94
+ } catch (error) {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ console.log(`
100
+ ${colors.bright}${colors.blue}╔════════════════════════════════════════════════════════════╗
101
+ ║ ║
102
+ ║ 🔍 Backend Boilerplate Validation ║
103
+ ║ ║
104
+ ╚════════════════════════════════════════════════════════════╝${colors.reset}
105
+ `);
106
+
107
+ // Check prerequisites
108
+ printHeader('Prerequisites');
109
+
110
+ if (checkCommand('node', 'Node.js')) {
111
+ const nodeVersion = execSync('node --version', { encoding: 'utf8' }).trim();
112
+ printSuccess(`Node.js installed (${nodeVersion})`);
113
+
114
+ // Check Node.js version
115
+ const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
116
+ if (majorVersion < 22) {
117
+ printWarning(`Node.js version ${nodeVersion} is below recommended 22+`);
118
+ }
119
+ } else {
120
+ printError('Node.js not found - install from https://nodejs.org');
121
+ }
122
+
123
+ if (checkCommand('npm', 'npm')) {
124
+ const npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim();
125
+ printSuccess(`npm installed (v${npmVersion})`);
126
+ } else {
127
+ printError('npm not found');
128
+ }
129
+
130
+ if (checkCommand('firebase', 'Firebase CLI')) {
131
+ const firebaseVersion = execSync('firebase --version', { encoding: 'utf8' }).trim();
132
+ printSuccess(`Firebase CLI installed (${firebaseVersion})`);
133
+ } else {
134
+ printWarning('Firebase CLI not found - install with: npm install -g firebase-tools');
135
+ }
136
+
137
+ // Check project structure
138
+ printHeader('Project Structure');
139
+
140
+ const requiredFiles = [
141
+ 'functions/package.json',
142
+ 'functions/tsconfig.json',
143
+ 'functions/src/index.ts',
144
+ 'firebase.json',
145
+ '.firebaserc',
146
+ ];
147
+
148
+ requiredFiles.forEach(file => {
149
+ if (fileExists(file)) {
150
+ printSuccess(`Found ${file}`);
151
+ } else {
152
+ printError(`Missing required file: ${file}`);
153
+ }
154
+ });
155
+
156
+ const requiredDirs = [
157
+ 'functions/src/config',
158
+ 'functions/src/base',
159
+ 'functions/src/middleware',
160
+ 'functions/src/utilities',
161
+ '__scripts__',
162
+ '__docs__',
163
+ '__examples__',
164
+ ];
165
+
166
+ requiredDirs.forEach(dir => {
167
+ if (fileExists(dir)) {
168
+ printSuccess(`Found directory: ${dir}`);
169
+ } else {
170
+ printWarning(`Directory not found: ${dir}`);
171
+ }
172
+ });
173
+
174
+ // Check environment configuration
175
+ printHeader('Environment Configuration');
176
+
177
+ const env = readEnvFile();
178
+
179
+ if (env) {
180
+ printSuccess('.env file exists');
181
+
182
+ // Check for required environment variables
183
+ const requiredVars = [
184
+ 'APP_NAME',
185
+ 'NODE_ENV',
186
+ 'FIREBASE_PROJECT_ID',
187
+ 'API_BASE_PATH',
188
+ ];
189
+
190
+ const optionalVars = [
191
+ 'CORS_ORIGINS',
192
+ 'LOG_LEVEL',
193
+ 'RATE_LIMIT_ENABLED',
194
+ ];
195
+
196
+ requiredVars.forEach(varName => {
197
+ if (env[varName]) {
198
+ if (env[varName].includes('FIXME') || env[varName].includes('your-')) {
199
+ printWarning(`${varName} is set but contains placeholder value`);
200
+ } else {
201
+ printSuccess(`${varName} is configured`);
202
+ }
203
+ } else {
204
+ printError(`Missing required environment variable: ${varName}`);
205
+ }
206
+ });
207
+
208
+ optionalVars.forEach(varName => {
209
+ if (env[varName]) {
210
+ printSuccess(`${varName} is configured`);
211
+ } else {
212
+ printWarning(`Optional variable ${varName} not set`);
213
+ }
214
+ });
215
+
216
+ } else {
217
+ printError('.env file not found - run: npm run setup');
218
+ }
219
+
220
+ // Check dependencies
221
+ printHeader('Dependencies');
222
+
223
+ const packageJsonPath = path.join(__dirname, '../functions/package.json');
224
+ if (fs.existsSync(packageJsonPath)) {
225
+ printSuccess('package.json found');
226
+
227
+ const nodeModulesPath = path.join(__dirname, '../functions/node_modules');
228
+ if (fs.existsSync(nodeModulesPath)) {
229
+ printSuccess('node_modules directory exists');
230
+ } else {
231
+ printError('node_modules not found - run: npm install');
232
+ }
233
+ } else {
234
+ printError('package.json not found');
235
+ }
236
+
237
+ // Check TypeScript compilation
238
+ printHeader('TypeScript Compilation');
239
+
240
+ console.log(`${colors.dim}Running TypeScript compiler check...${colors.reset}`);
241
+ if (runCommand('npx tsc --noEmit')) {
242
+ printSuccess('TypeScript compilation check passed');
243
+ } else {
244
+ printWarning('TypeScript compilation has errors - run: npm run build');
245
+ }
246
+
247
+ // Check linting (if requested)
248
+ const skipLint = process.argv.includes('--skip-lint');
249
+ if (!skipLint) {
250
+ printHeader('Code Quality');
251
+
252
+ console.log(`${colors.dim}Running ESLint...${colors.reset}`);
253
+ if (runCommand('npm run lint')) {
254
+ printSuccess('ESLint passed');
255
+ } else {
256
+ printWarning('ESLint found issues - run: npm run lint:fix');
257
+ }
258
+ }
259
+
260
+ // Check tests (if requested)
261
+ const skipTests = process.argv.includes('--skip-tests');
262
+ if (!skipTests) {
263
+ printHeader('Tests');
264
+
265
+ console.log(`${colors.dim}Running test suite...${colors.reset}`);
266
+ if (runCommand('npm test')) {
267
+ printSuccess('All tests passed');
268
+ } else {
269
+ printError('Some tests failed - run: npm test');
270
+ }
271
+ }
272
+
273
+ // Check build (if requested)
274
+ const skipBuild = process.argv.includes('--skip-build');
275
+ if (!skipBuild) {
276
+ printHeader('Build');
277
+
278
+ console.log(`${colors.dim}Running production build...${colors.reset}`);
279
+ if (runCommand('npm run build')) {
280
+ printSuccess('Production build succeeded');
281
+ } else {
282
+ printError('Build failed - check TypeScript errors');
283
+ }
284
+ }
285
+
286
+ // Firebase configuration
287
+ printHeader('Firebase Configuration');
288
+
289
+ const firebaseRcPath = path.join(__dirname, '../.firebaserc');
290
+ if (fs.existsSync(firebaseRcPath)) {
291
+ try {
292
+ const firebaseRc = JSON.parse(fs.readFileSync(firebaseRcPath, 'utf8'));
293
+ if (firebaseRc.projects && firebaseRc.projects.default) {
294
+ printSuccess(`Firebase project: ${firebaseRc.projects.default}`);
295
+ } else {
296
+ printWarning('Firebase project not configured in .firebaserc');
297
+ }
298
+ } catch {
299
+ printError('Could not parse .firebaserc file');
300
+ }
301
+ } else {
302
+ printError('.firebaserc not found - run: firebase init');
303
+ }
304
+
305
+ // Summary
306
+ printHeader('Summary');
307
+
308
+ console.log(`
309
+ ${colors.bright}Validation Results:${colors.reset}
310
+ ${colors.green}${CHECK_MARK} ${checks - errors - warnings} checks passed${colors.reset}
311
+ ${warnings > 0 ? `${colors.yellow}${WARNING_MARK} ${warnings} warnings${colors.reset}` : ''}
312
+ ${errors > 0 ? `${colors.red}${CROSS_MARK} ${errors} errors${colors.reset}` : ''}
313
+ `);
314
+
315
+ if (errors === 0 && warnings === 0) {
316
+ console.log(`${colors.green}${colors.bright}✨ All checks passed! Your project is properly configured.${colors.reset}\n`);
317
+ process.exit(0);
318
+ } else if (errors === 0) {
319
+ console.log(`${colors.yellow}${colors.bright}⚠️ Validation completed with warnings. Review warnings above.${colors.reset}\n`);
320
+ process.exit(0);
321
+ } else {
322
+ console.log(`${colors.red}${colors.bright}❌ Validation failed. Fix the errors above before proceeding.${colors.reset}\n`);
323
+ console.log(`${colors.dim}Tip: Run ${colors.bright}npm run setup${colors.reset}${colors.dim} to configure the project automatically.${colors.reset}\n`);
324
+ process.exit(1);
325
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "firestore": {
3
+ "rules": "firestore.rules"
4
+ },
5
+ "functions": {
6
+ "source": "functions",
7
+ "runtime": "nodejs22",
8
+ "ignore": [
9
+ "node_modules",
10
+ ".git",
11
+ "firebase-debug.log",
12
+ "firebase-debug.*.log"
13
+ ],
14
+ "predeploy": [
15
+ "npm --prefix \"$RESOURCE_DIR\" run lint",
16
+ "npm --prefix \"$RESOURCE_DIR\" run build"
17
+ ]
18
+ },
19
+ "emulators": {
20
+ "functions": {
21
+ "port": 5001
22
+ },
23
+ "firestore": {
24
+ "port": 8080
25
+ },
26
+ "ui": {
27
+ "enabled": true,
28
+ "port": 4000
29
+ },
30
+ "singleProjectMode": true
31
+ }
32
+ }
@@ -0,0 +1,12 @@
1
+ rules_version = '2';
2
+ service cloud.firestore {
3
+ match /databases/{database}/documents {
4
+ // Deny all client SDK access by default.
5
+ // This backend uses the Admin SDK (which bypasses rules).
6
+ // These rules act as defense-in-depth against accidental
7
+ // client-side database exposure.
8
+ match /{document=**} {
9
+ allow read, write: if false;
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,49 @@
1
+ module.exports = {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'node',
4
+ roots: ['<rootDir>/src'],
5
+ testMatch: [
6
+ '**/__tests__/**/*.test.ts',
7
+ '**/?(*.)+(spec|test).ts'
8
+ ],
9
+ transform: {
10
+ '^.+\\.ts$': 'ts-jest',
11
+ },
12
+ collectCoverageFrom: [
13
+ 'src/**/*.ts',
14
+ '!src/**/*.d.ts',
15
+ '!src/**/__tests__/**',
16
+ '!src/index.ts',
17
+ '!src/server.ts',
18
+ '!src/generated/**',
19
+ ],
20
+ coverageDirectory: 'coverage',
21
+ coverageReporters: ['text', 'lcov', 'html'],
22
+ coverageThreshold: {
23
+ global: {
24
+ branches: 70,
25
+ functions: 70,
26
+ lines: 70,
27
+ statements: 70,
28
+ },
29
+ },
30
+ setupFilesAfterEnv: ['<rootDir>/src/__tests__/setup.ts'],
31
+ moduleNameMapper: {
32
+ '^@/(.*)$': '<rootDir>/src/$1',
33
+ '^@utilities/(.*)$': '<rootDir>/src/utilities/$1',
34
+ '^@base/(.*)$': '<rootDir>/src/base/$1',
35
+ '^@middleware/(.*)$': '<rootDir>/src/middleware/$1',
36
+ '^@config/(.*)$': '<rootDir>/src/config/$1',
37
+ '^@generated/(.*)$': '<rootDir>/src/generated/$1',
38
+ },
39
+ globals: {
40
+ 'ts-jest': {
41
+ tsconfig: {
42
+ esModuleInterop: true,
43
+ allowSyntheticDefaultImports: true,
44
+ },
45
+ },
46
+ },
47
+ testTimeout: 10000,
48
+ verbose: true,
49
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Firebase Functions Entry Point
3
+ * Exports HTTP functions for Firebase deployment
4
+ */
5
+
6
+ import * as functions from 'firebase-functions';
7
+ import { createApp } from '@xbg/backend-core';
8
+ import { logger } from '@xbg/utils-logger';
9
+
10
+ // Import controllers here as they are created
11
+ // import { UserController } from './generated/controllers/UserController';
12
+
13
+ /**
14
+ * Initialize controllers
15
+ * Add your generated or custom controllers here
16
+ */
17
+ function initializeControllers(): Array<{ getRouter: () => any; getBasePath: () => string }> {
18
+ const controllers: Array<{ getRouter: () => any; getBasePath: () => string }> = [];
19
+
20
+ // Example:
21
+ // const userController = new UserController(userService, '/users');
22
+ // controllers.push(userController);
23
+
24
+ return controllers;
25
+ }
26
+
27
+ /**
28
+ * Create Express app with controllers
29
+ */
30
+ const expressApp = createApp({
31
+ controllers: initializeControllers(),
32
+ });
33
+
34
+ /**
35
+ * Export as Firebase HTTPS Function
36
+ */
37
+ export const api = functions.https.onRequest(expressApp);
38
+
39
+ /**
40
+ * Export for local development
41
+ */
42
+ export { expressApp };
43
+
44
+ logger.info('Firebase Functions initialized', {
45
+ environment: process.env.NODE_ENV || 'development',
46
+ });
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "moduleResolution": "node",
5
+ "noImplicitReturns": true,
6
+ "noUnusedLocals": true,
7
+ "outDir": "lib",
8
+ "sourceMap": true,
9
+ "strict": true,
10
+ "target": "es2017",
11
+ "esModuleInterop": true,
12
+ "skipLibCheck": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "noImplicitAny": true,
18
+ "strictNullChecks": true,
19
+ "strictFunctionTypes": true,
20
+ "strictBindCallApply": true,
21
+ "strictPropertyInitialization": true,
22
+ "noImplicitThis": true,
23
+ "alwaysStrict": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "experimentalDecorators": true,
26
+ "emitDecoratorMetadata": true,
27
+ "baseUrl": "."
28
+ },
29
+ "compileOnSave": true,
30
+ "include": [
31
+ "src/**/*"
32
+ ],
33
+ "exclude": [
34
+ "node_modules",
35
+ "**/*.spec.ts",
36
+ "**/*.test.ts"
37
+ ]
38
+ }