@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.30

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 (199) hide show
  1. package/frigg-cli/.eslintrc.js +141 -0
  2. package/frigg-cli/__tests__/jest.config.js +102 -0
  3. package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
  4. package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
  5. package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
  6. package/frigg-cli/__tests__/utils/command-tester.js +170 -0
  7. package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
  8. package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
  9. package/frigg-cli/__tests__/utils/test-setup.js +286 -0
  10. package/frigg-cli/build-command/index.js +54 -0
  11. package/frigg-cli/deploy-command/index.js +36 -0
  12. package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
  13. package/frigg-cli/generate-command/azure-generator.js +43 -0
  14. package/frigg-cli/generate-command/gcp-generator.js +47 -0
  15. package/frigg-cli/generate-command/index.js +332 -0
  16. package/frigg-cli/generate-command/terraform-generator.js +555 -0
  17. package/frigg-cli/generate-iam-command.js +115 -0
  18. package/frigg-cli/index.js +47 -1
  19. package/frigg-cli/index.test.js +1 -4
  20. package/frigg-cli/init-command/backend-first-handler.js +756 -0
  21. package/frigg-cli/init-command/index.js +93 -0
  22. package/frigg-cli/init-command/template-handler.js +143 -0
  23. package/frigg-cli/install-command/index.js +1 -4
  24. package/frigg-cli/package.json +51 -0
  25. package/frigg-cli/start-command/index.js +24 -4
  26. package/frigg-cli/test/init-command.test.js +180 -0
  27. package/frigg-cli/test/npm-registry.test.js +319 -0
  28. package/frigg-cli/ui-command/index.js +154 -0
  29. package/frigg-cli/utils/app-resolver.js +319 -0
  30. package/frigg-cli/utils/backend-path.js +16 -17
  31. package/frigg-cli/utils/npm-registry.js +167 -0
  32. package/frigg-cli/utils/process-manager.js +199 -0
  33. package/frigg-cli/utils/repo-detection.js +405 -0
  34. package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +245 -0
  35. package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +596 -0
  36. package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
  37. package/infrastructure/GENERATE-IAM-DOCS.md +253 -0
  38. package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
  39. package/infrastructure/README-TESTING.md +332 -0
  40. package/infrastructure/README.md +421 -0
  41. package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
  42. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
  43. package/infrastructure/__tests__/helpers/test-utils.js +277 -0
  44. package/infrastructure/aws-discovery.js +568 -0
  45. package/infrastructure/aws-discovery.test.js +373 -0
  46. package/infrastructure/build-time-discovery.js +206 -0
  47. package/infrastructure/build-time-discovery.test.js +375 -0
  48. package/infrastructure/create-frigg-infrastructure.js +3 -5
  49. package/infrastructure/frigg-deployment-iam-stack.yaml +379 -0
  50. package/infrastructure/iam-generator.js +687 -0
  51. package/infrastructure/iam-generator.test.js +169 -0
  52. package/infrastructure/iam-policy-basic.json +212 -0
  53. package/infrastructure/iam-policy-full.json +282 -0
  54. package/infrastructure/integration.test.js +383 -0
  55. package/infrastructure/run-discovery.js +110 -0
  56. package/infrastructure/serverless-template.js +923 -113
  57. package/infrastructure/serverless-template.test.js +541 -0
  58. package/management-ui/.eslintrc.js +22 -0
  59. package/management-ui/README.md +203 -0
  60. package/management-ui/components.json +21 -0
  61. package/management-ui/docs/phase2-integration-guide.md +320 -0
  62. package/management-ui/index.html +13 -0
  63. package/management-ui/package-lock.json +16517 -0
  64. package/management-ui/package.json +76 -0
  65. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  66. package/management-ui/postcss.config.js +6 -0
  67. package/management-ui/server/api/backend.js +256 -0
  68. package/management-ui/server/api/cli.js +315 -0
  69. package/management-ui/server/api/codegen.js +663 -0
  70. package/management-ui/server/api/connections.js +857 -0
  71. package/management-ui/server/api/discovery.js +185 -0
  72. package/management-ui/server/api/environment/index.js +1 -0
  73. package/management-ui/server/api/environment/router.js +378 -0
  74. package/management-ui/server/api/environment.js +328 -0
  75. package/management-ui/server/api/integrations.js +876 -0
  76. package/management-ui/server/api/logs.js +248 -0
  77. package/management-ui/server/api/monitoring.js +282 -0
  78. package/management-ui/server/api/open-ide.js +31 -0
  79. package/management-ui/server/api/project.js +1029 -0
  80. package/management-ui/server/api/users/sessions.js +371 -0
  81. package/management-ui/server/api/users/simulation.js +254 -0
  82. package/management-ui/server/api/users.js +362 -0
  83. package/management-ui/server/api-contract.md +275 -0
  84. package/management-ui/server/index.js +873 -0
  85. package/management-ui/server/middleware/errorHandler.js +93 -0
  86. package/management-ui/server/middleware/security.js +32 -0
  87. package/management-ui/server/processManager.js +296 -0
  88. package/management-ui/server/server.js +346 -0
  89. package/management-ui/server/services/aws-monitor.js +413 -0
  90. package/management-ui/server/services/npm-registry.js +347 -0
  91. package/management-ui/server/services/template-engine.js +538 -0
  92. package/management-ui/server/utils/cliIntegration.js +220 -0
  93. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  94. package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
  95. package/management-ui/server/utils/environment/encryption.js +278 -0
  96. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  97. package/management-ui/server/utils/import-commonjs.js +28 -0
  98. package/management-ui/server/utils/response.js +83 -0
  99. package/management-ui/server/websocket/handler.js +325 -0
  100. package/management-ui/src/App.jsx +109 -0
  101. package/management-ui/src/assets/FriggLogo.svg +1 -0
  102. package/management-ui/src/components/AppRouter.jsx +65 -0
  103. package/management-ui/src/components/Button.jsx +70 -0
  104. package/management-ui/src/components/Card.jsx +97 -0
  105. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  106. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  107. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  108. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  109. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  110. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  111. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  112. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  113. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  114. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  115. package/management-ui/src/components/Layout.jsx +716 -0
  116. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  117. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  118. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  119. package/management-ui/src/components/StatusBadge.jsx +208 -0
  120. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  121. package/management-ui/src/components/UserSimulation.jsx +327 -0
  122. package/management-ui/src/components/Welcome.jsx +434 -0
  123. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  124. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  125. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  126. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  127. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  128. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  129. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  130. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  131. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  132. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  133. package/management-ui/src/components/codegen/index.js +10 -0
  134. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  135. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  136. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  137. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  138. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  139. package/management-ui/src/components/connections/index.js +5 -0
  140. package/management-ui/src/components/index.js +21 -0
  141. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  142. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  143. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  144. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  145. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  146. package/management-ui/src/components/monitoring/index.js +6 -0
  147. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  148. package/management-ui/src/components/theme-provider.jsx +52 -0
  149. package/management-ui/src/components/theme-toggle.jsx +39 -0
  150. package/management-ui/src/components/ui/badge.tsx +36 -0
  151. package/management-ui/src/components/ui/button.test.jsx +56 -0
  152. package/management-ui/src/components/ui/button.tsx +57 -0
  153. package/management-ui/src/components/ui/card.tsx +76 -0
  154. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  155. package/management-ui/src/components/ui/select.tsx +157 -0
  156. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  157. package/management-ui/src/hooks/useFrigg.jsx +601 -0
  158. package/management-ui/src/hooks/useSocket.jsx +58 -0
  159. package/management-ui/src/index.css +193 -0
  160. package/management-ui/src/lib/utils.ts +6 -0
  161. package/management-ui/src/main.jsx +10 -0
  162. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  163. package/management-ui/src/pages/Connections.jsx +252 -0
  164. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  165. package/management-ui/src/pages/Dashboard.jsx +311 -0
  166. package/management-ui/src/pages/Environment.jsx +314 -0
  167. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  168. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  169. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  170. package/management-ui/src/pages/Integrations.jsx +253 -0
  171. package/management-ui/src/pages/Monitoring.jsx +17 -0
  172. package/management-ui/src/pages/Simulation.jsx +155 -0
  173. package/management-ui/src/pages/Users.jsx +492 -0
  174. package/management-ui/src/services/api.js +41 -0
  175. package/management-ui/src/services/apiModuleService.js +193 -0
  176. package/management-ui/src/services/websocket-handlers.js +120 -0
  177. package/management-ui/src/test/api/project.test.js +273 -0
  178. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  179. package/management-ui/src/test/mocks/server.js +178 -0
  180. package/management-ui/src/test/setup.js +61 -0
  181. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  182. package/management-ui/src/utils/repository.js +98 -0
  183. package/management-ui/src/utils/repository.test.js +118 -0
  184. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  185. package/management-ui/tailwind.config.js +63 -0
  186. package/management-ui/tsconfig.json +37 -0
  187. package/management-ui/tsconfig.node.json +10 -0
  188. package/management-ui/vite.config.js +26 -0
  189. package/management-ui/vitest.config.js +38 -0
  190. package/package.json +16 -9
  191. package/infrastructure/app-handler-helpers.js +0 -57
  192. package/infrastructure/backend-utils.js +0 -90
  193. package/infrastructure/routers/auth.js +0 -26
  194. package/infrastructure/routers/integration-defined-routers.js +0 -37
  195. package/infrastructure/routers/middleware/loadUser.js +0 -15
  196. package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
  197. package/infrastructure/routers/user.js +0 -41
  198. package/infrastructure/routers/websocket.js +0 -55
  199. package/infrastructure/workers/integration-defined-workers.js +0 -24
@@ -0,0 +1,797 @@
1
+ import React, { useState, useCallback } from 'react';
2
+ import { Card } from '../Card';
3
+ import { Button } from '../Button';
4
+
5
+ const PROJECT_TEMPLATES = {
6
+ 'basic-backend': {
7
+ name: 'Basic Backend',
8
+ description: 'Simple Frigg backend with core functionality',
9
+ features: ['Express server', 'MongoDB integration', 'Basic authentication', 'Environment configuration']
10
+ },
11
+ 'microservices': {
12
+ name: 'Microservices',
13
+ description: 'Multi-service architecture with API Gateway',
14
+ features: ['API Gateway', 'Service discovery', 'Load balancing', 'Circuit breakers']
15
+ },
16
+ 'serverless': {
17
+ name: 'Serverless',
18
+ description: 'AWS Lambda-based serverless backend',
19
+ features: ['Lambda functions', 'API Gateway', 'DynamoDB', 'CloudWatch logging']
20
+ },
21
+ 'full-stack': {
22
+ name: 'Full Stack',
23
+ description: 'Complete application with frontend and backend',
24
+ features: ['React frontend', 'Express backend', 'Database integration', 'Authentication']
25
+ }
26
+ };
27
+
28
+ const INTEGRATION_OPTIONS = [
29
+ { id: 'hubspot', name: 'HubSpot', category: 'CRM' },
30
+ { id: 'salesforce', name: 'Salesforce', category: 'CRM' },
31
+ { id: 'slack', name: 'Slack', category: 'Communication' },
32
+ { id: 'mailchimp', name: 'Mailchimp', category: 'Marketing' },
33
+ { id: 'stripe', name: 'Stripe', category: 'Payments' },
34
+ { id: 'twilio', name: 'Twilio', category: 'Communication' },
35
+ { id: 'google-analytics', name: 'Google Analytics', category: 'Analytics' },
36
+ { id: 'microsoft-teams', name: 'Microsoft Teams', category: 'Communication' }
37
+ ];
38
+
39
+ const DATABASE_OPTIONS = [
40
+ { value: 'mongodb', label: 'MongoDB', description: 'Document database' },
41
+ { value: 'postgresql', label: 'PostgreSQL', description: 'Relational database' },
42
+ { value: 'mysql', label: 'MySQL', description: 'Relational database' },
43
+ { value: 'dynamodb', label: 'DynamoDB', description: 'AWS NoSQL database' },
44
+ { value: 'redis', label: 'Redis', description: 'In-memory cache' }
45
+ ];
46
+
47
+ const ProjectScaffoldWizard = ({ onGenerate }) => {
48
+ const [projectData, setProjectData] = useState({
49
+ name: '',
50
+ description: '',
51
+ template: 'basic-backend',
52
+ database: 'mongodb',
53
+ integrations: [],
54
+ features: {
55
+ authentication: true,
56
+ logging: true,
57
+ monitoring: true,
58
+ testing: true,
59
+ docker: true,
60
+ ci: false
61
+ },
62
+ deployment: {
63
+ platform: 'aws',
64
+ environment: 'development'
65
+ }
66
+ });
67
+
68
+ const [currentStep, setCurrentStep] = useState(0);
69
+
70
+ const steps = [
71
+ { title: 'Project Info', description: 'Basic project configuration' },
72
+ { title: 'Template', description: 'Choose project template' },
73
+ { title: 'Database', description: 'Select database options' },
74
+ { title: 'Integrations', description: 'Choose integrations' },
75
+ { title: 'Features', description: 'Enable additional features' },
76
+ { title: 'Deployment', description: 'Deployment configuration' }
77
+ ];
78
+
79
+ const handleInputChange = useCallback((field, value) => {
80
+ setProjectData(prev => ({
81
+ ...prev,
82
+ [field]: value
83
+ }));
84
+ }, []);
85
+
86
+ const handleFeatureToggle = useCallback((feature) => {
87
+ setProjectData(prev => ({
88
+ ...prev,
89
+ features: {
90
+ ...prev.features,
91
+ [feature]: !prev.features[feature]
92
+ }
93
+ }));
94
+ }, []);
95
+
96
+ const handleIntegrationToggle = useCallback((integrationId) => {
97
+ setProjectData(prev => ({
98
+ ...prev,
99
+ integrations: prev.integrations.includes(integrationId)
100
+ ? prev.integrations.filter(id => id !== integrationId)
101
+ : [...prev.integrations, integrationId]
102
+ }));
103
+ }, []);
104
+
105
+ const generateProjectFiles = useCallback(() => {
106
+ const template = PROJECT_TEMPLATES[projectData.template];
107
+
108
+ // Generate package.json
109
+ const packageJson = {
110
+ name: projectData.name,
111
+ version: '1.0.0',
112
+ description: projectData.description,
113
+ main: 'app.js',
114
+ scripts: {
115
+ start: 'node app.js',
116
+ dev: 'nodemon app.js',
117
+ test: projectData.features.testing ? 'jest' : undefined,
118
+ build: projectData.template === 'serverless' ? 'serverless package' : undefined,
119
+ deploy: projectData.template === 'serverless' ? 'serverless deploy' : undefined
120
+ },
121
+ dependencies: {
122
+ '@friggframework/core': '^1.0.0',
123
+ express: '^4.18.0',
124
+ ...(projectData.database === 'mongodb' ? { mongoose: '^7.0.0' } : {}),
125
+ ...(projectData.database === 'postgresql' ? { pg: '^8.8.0', 'pg-hstore': '^2.3.4' } : {}),
126
+ ...(projectData.database === 'mysql' ? { mysql2: '^3.0.0' } : {}),
127
+ ...(projectData.features.authentication ? { passport: '^0.6.0', 'passport-jwt': '^4.0.0' } : {}),
128
+ ...(projectData.features.logging ? { winston: '^3.8.0' } : {}),
129
+ ...(projectData.integrations.map(id => ({ [`@friggframework/api-module-${id}`]: '^1.0.0' })).reduce((acc, obj) => ({ ...acc, ...obj }), {}))
130
+ },
131
+ devDependencies: {
132
+ nodemon: '^2.0.0',
133
+ ...(projectData.features.testing ? { jest: '^29.0.0', supertest: '^6.3.0' } : {})
134
+ }
135
+ };
136
+
137
+ // Generate app.js
138
+ const appJs = generateAppJs();
139
+
140
+ // Generate serverless.yml (if serverless template)
141
+ const serverlessYml = projectData.template === 'serverless' ? generateServerlessYml() : null;
142
+
143
+ // Generate docker files (if docker enabled)
144
+ const dockerfile = projectData.features.docker ? generateDockerfile() : null;
145
+ const dockerCompose = projectData.features.docker ? generateDockerCompose() : null;
146
+
147
+ // Generate README
148
+ const readme = generateReadme();
149
+
150
+ // Generate environment files
151
+ const envExample = generateEnvExample();
152
+
153
+ const files = [
154
+ { name: 'package.json', content: JSON.stringify(packageJson, null, 2) },
155
+ { name: 'app.js', content: appJs },
156
+ { name: 'README.md', content: readme },
157
+ { name: '.env.example', content: envExample },
158
+ ...(serverlessYml ? [{ name: 'serverless.yml', content: serverlessYml }] : []),
159
+ ...(dockerfile ? [{ name: 'Dockerfile', content: dockerfile }] : []),
160
+ ...(dockerCompose ? [{ name: 'docker-compose.yml', content: dockerCompose }] : []),
161
+ ...(projectData.features.ci ? [{ name: '.github/workflows/ci.yml', content: generateCIConfig() }] : [])
162
+ ];
163
+
164
+ const metadata = {
165
+ name: projectData.name,
166
+ template: projectData.template,
167
+ type: 'project-scaffold',
168
+ files
169
+ };
170
+
171
+ onGenerate(projectData, { files }, metadata);
172
+ }, [projectData, onGenerate]);
173
+
174
+ const generateAppJs = () => {
175
+ return `const express = require('express');
176
+ const { FriggManager } = require('@friggframework/core');
177
+ ${projectData.features.logging ? "const winston = require('winston');" : ''}
178
+ ${projectData.database === 'mongodb' ? "const mongoose = require('mongoose');" : ''}
179
+
180
+ const app = express();
181
+ const port = process.env.PORT || 3000;
182
+
183
+ // Middleware
184
+ app.use(express.json());
185
+ app.use(express.urlencoded({ extended: true }));
186
+
187
+ ${projectData.features.logging ? `
188
+ // Logging configuration
189
+ const logger = winston.createLogger({
190
+ level: 'info',
191
+ format: winston.format.combine(
192
+ winston.format.timestamp(),
193
+ winston.format.json()
194
+ ),
195
+ transports: [
196
+ new winston.transports.Console(),
197
+ new winston.transports.File({ filename: 'app.log' })
198
+ ]
199
+ });
200
+ ` : ''}
201
+
202
+ ${projectData.database === 'mongodb' ? `
203
+ // Database connection
204
+ mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/${projectData.name}', {
205
+ useNewUrlParser: true,
206
+ useUnifiedTopology: true
207
+ });
208
+ ` : ''}
209
+
210
+ // Frigg Manager initialization
211
+ const friggManager = new FriggManager({
212
+ database: '${projectData.database}',
213
+ integrations: [
214
+ ${projectData.integrations.map(id => ` require('@friggframework/api-module-${id}')`).join(',\n')}
215
+ ]
216
+ });
217
+
218
+ // Routes
219
+ app.get('/', (req, res) => {
220
+ res.json({
221
+ message: 'Welcome to ${projectData.name}',
222
+ status: 'running',
223
+ integrations: [${projectData.integrations.map(id => `'${id}'`).join(', ')}]
224
+ });
225
+ });
226
+
227
+ app.get('/health', (req, res) => {
228
+ res.json({ status: 'healthy', timestamp: new Date().toISOString() });
229
+ });
230
+
231
+ // Start server
232
+ app.listen(port, () => {
233
+ ${projectData.features.logging ? 'logger.info' : 'console.log'}(\`Server running on port \${port}\`);
234
+ });
235
+
236
+ module.exports = app;`;
237
+ };
238
+
239
+ const generateServerlessYml = () => {
240
+ return `service: ${projectData.name}
241
+
242
+ frameworkVersion: '3'
243
+
244
+ provider:
245
+ name: aws
246
+ runtime: nodejs18.x
247
+ stage: \${opt:stage, 'dev'}
248
+ region: \${opt:region, 'us-east-1'}
249
+ environment:
250
+ NODE_ENV: \${self:provider.stage}
251
+ ${projectData.integrations.map(id => `${id.toUpperCase()}_API_KEY: \${env:${id.toUpperCase()}_API_KEY}`).join('\n ')}
252
+
253
+ functions:
254
+ app:
255
+ handler: app.handler
256
+ events:
257
+ - http:
258
+ path: /{proxy+}
259
+ method: ANY
260
+ cors: true
261
+ - http:
262
+ path: /
263
+ method: ANY
264
+ cors: true
265
+
266
+ ${projectData.database === 'dynamodb' ? `
267
+ resources:
268
+ Resources:
269
+ ${projectData.name}Table:
270
+ Type: AWS::DynamoDB::Table
271
+ Properties:
272
+ TableName: \${self:provider.stage}-${projectData.name}
273
+ AttributeDefinitions:
274
+ - AttributeName: id
275
+ AttributeType: S
276
+ KeySchema:
277
+ - AttributeName: id
278
+ KeyType: HASH
279
+ BillingMode: PAY_PER_REQUEST
280
+ ` : ''}
281
+
282
+ plugins:
283
+ - serverless-offline`;
284
+ };
285
+
286
+ const generateDockerfile = () => {
287
+ return `FROM node:18-alpine
288
+
289
+ WORKDIR /app
290
+
291
+ COPY package*.json ./
292
+ RUN npm ci --only=production
293
+
294
+ COPY . .
295
+
296
+ EXPOSE 3000
297
+
298
+ CMD ["npm", "start"]`;
299
+ };
300
+
301
+ const generateDockerCompose = () => {
302
+ return `version: '3.8'
303
+
304
+ services:
305
+ app:
306
+ build: .
307
+ ports:
308
+ - "3000:3000"
309
+ environment:
310
+ - NODE_ENV=development
311
+ ${projectData.database === 'mongodb' ? '- MONGODB_URI=mongodb://mongo:27017/' + projectData.name : ''}
312
+ depends_on:
313
+ ${projectData.database === 'mongodb' ? '- mongo' : ''}
314
+ volumes:
315
+ - .:/app
316
+ - /app/node_modules
317
+
318
+ ${projectData.database === 'mongodb' ? ` mongo:
319
+ image: mongo:5
320
+ ports:
321
+ - "27017:27017"
322
+ volumes:
323
+ - mongo_data:/data/db
324
+
325
+ volumes:
326
+ mongo_data:` : ''}`;
327
+ };
328
+
329
+ const generateReadme = () => {
330
+ const template = PROJECT_TEMPLATES[projectData.template];
331
+
332
+ return `# ${projectData.name}
333
+
334
+ ${projectData.description}
335
+
336
+ ## Project Template: ${template.name}
337
+
338
+ ${template.description}
339
+
340
+ ### Features
341
+
342
+ ${template.features.map(feature => `- ${feature}`).join('\n')}
343
+
344
+ ### Integrations
345
+
346
+ ${projectData.integrations.length > 0
347
+ ? projectData.integrations.map(id => {
348
+ const integration = INTEGRATION_OPTIONS.find(i => i.id === id);
349
+ return `- ${integration?.name} (${integration?.category})`;
350
+ }).join('\n')
351
+ : 'No integrations configured'
352
+ }
353
+
354
+ ### Database
355
+
356
+ - ${DATABASE_OPTIONS.find(db => db.value === projectData.database)?.label}
357
+
358
+ ### Additional Features
359
+
360
+ ${Object.entries(projectData.features)
361
+ .filter(([, enabled]) => enabled)
362
+ .map(([feature]) => `- ${feature.charAt(0).toUpperCase() + feature.slice(1)}`)
363
+ .join('\n')}
364
+
365
+ ## Getting Started
366
+
367
+ 1. Install dependencies:
368
+ \`\`\`bash
369
+ npm install
370
+ \`\`\`
371
+
372
+ 2. Copy environment variables:
373
+ \`\`\`bash
374
+ cp .env.example .env
375
+ \`\`\`
376
+
377
+ 3. Update environment variables in \`.env\`
378
+
379
+ ${projectData.features.docker ? `4. Start with Docker:
380
+ \`\`\`bash
381
+ docker-compose up
382
+ \`\`\`
383
+
384
+ Or start locally:` : '4. Start the application:'}
385
+ \`\`\`bash
386
+ npm run dev
387
+ \`\`\`
388
+
389
+ ## API Endpoints
390
+
391
+ - \`GET /\` - Welcome message and status
392
+ - \`GET /health\` - Health check
393
+
394
+ ## Deployment
395
+
396
+ ${projectData.template === 'serverless'
397
+ ? `This project uses Serverless Framework for deployment:
398
+
399
+ \`\`\`bash
400
+ npm run deploy
401
+ \`\`\``
402
+ : `Configure your deployment platform (${projectData.deployment.platform}) according to your needs.`
403
+ }
404
+
405
+ ## License
406
+
407
+ MIT`;
408
+ };
409
+
410
+ const generateEnvExample = () => {
411
+ return `# Environment Configuration
412
+ NODE_ENV=development
413
+ PORT=3000
414
+
415
+ # Database
416
+ ${projectData.database === 'mongodb' ? `MONGODB_URI=mongodb://localhost:27017/${projectData.name}` : ''}
417
+ ${projectData.database === 'postgresql' ? `DATABASE_URL=postgresql://user:password@localhost:5432/${projectData.name}` : ''}
418
+ ${projectData.database === 'mysql' ? `DATABASE_URL=mysql://user:password@localhost:3306/${projectData.name}` : ''}
419
+
420
+ # Integration API Keys
421
+ ${projectData.integrations.map(id => `${id.toUpperCase()}_API_KEY=your_${id}_api_key_here`).join('\n')}
422
+
423
+ # Authentication (if enabled)
424
+ ${projectData.features.authentication ? `JWT_SECRET=your_jwt_secret_here
425
+ JWT_EXPIRES_IN=24h` : ''}
426
+
427
+ # AWS Configuration (if using AWS services)
428
+ ${projectData.deployment.platform === 'aws' ? `AWS_ACCESS_KEY_ID=your_access_key
429
+ AWS_SECRET_ACCESS_KEY=your_secret_key
430
+ AWS_REGION=us-east-1` : ''}`;
431
+ };
432
+
433
+ const generateCIConfig = () => {
434
+ return `name: CI/CD Pipeline
435
+
436
+ on:
437
+ push:
438
+ branches: [ main, develop ]
439
+ pull_request:
440
+ branches: [ main ]
441
+
442
+ jobs:
443
+ test:
444
+ runs-on: ubuntu-latest
445
+
446
+ strategy:
447
+ matrix:
448
+ node-version: [16.x, 18.x]
449
+
450
+ steps:
451
+ - uses: actions/checkout@v3
452
+
453
+ - name: Use Node.js \${{ matrix.node-version }}
454
+ uses: actions/setup-node@v3
455
+ with:
456
+ node-version: \${{ matrix.node-version }}
457
+ cache: 'npm'
458
+
459
+ - run: npm ci
460
+
461
+ ${projectData.features.testing ? '- run: npm test' : ''}
462
+
463
+ - run: npm run lint
464
+
465
+ deploy:
466
+ needs: test
467
+ runs-on: ubuntu-latest
468
+ if: github.ref == 'refs/heads/main'
469
+
470
+ steps:
471
+ - uses: actions/checkout@v3
472
+
473
+ - name: Use Node.js 18.x
474
+ uses: actions/setup-node@v3
475
+ with:
476
+ node-version: 18.x
477
+ cache: 'npm'
478
+
479
+ - run: npm ci
480
+
481
+ ${projectData.template === 'serverless' ? '- run: npm run deploy' : '# Add your deployment steps here'}`;
482
+ };
483
+
484
+ const nextStep = () => {
485
+ if (currentStep < steps.length - 1) {
486
+ setCurrentStep(currentStep + 1);
487
+ }
488
+ };
489
+
490
+ const prevStep = () => {
491
+ if (currentStep > 0) {
492
+ setCurrentStep(currentStep - 1);
493
+ }
494
+ };
495
+
496
+ const canProceed = () => {
497
+ switch (currentStep) {
498
+ case 0:
499
+ return projectData.name && projectData.description;
500
+ case 1:
501
+ return projectData.template;
502
+ case 2:
503
+ return projectData.database;
504
+ default:
505
+ return true;
506
+ }
507
+ };
508
+
509
+ const renderStep = () => {
510
+ switch (currentStep) {
511
+ case 0:
512
+ return (
513
+ <div className="space-y-4">
514
+ <h3 className="text-lg font-medium">Project Information</h3>
515
+ <div className="grid grid-cols-1 gap-4">
516
+ <div>
517
+ <label className="block text-sm font-medium text-gray-700 mb-2">
518
+ Project Name *
519
+ </label>
520
+ <input
521
+ type="text"
522
+ value={projectData.name}
523
+ onChange={(e) => handleInputChange('name', e.target.value)}
524
+ placeholder="my-frigg-project"
525
+ className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
526
+ />
527
+ </div>
528
+ <div>
529
+ <label className="block text-sm font-medium text-gray-700 mb-2">
530
+ Description *
531
+ </label>
532
+ <textarea
533
+ value={projectData.description}
534
+ onChange={(e) => handleInputChange('description', e.target.value)}
535
+ placeholder="Brief description of your project"
536
+ rows={3}
537
+ className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
538
+ />
539
+ </div>
540
+ </div>
541
+ </div>
542
+ );
543
+
544
+ case 1:
545
+ return (
546
+ <div className="space-y-4">
547
+ <h3 className="text-lg font-medium">Choose Project Template</h3>
548
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
549
+ {Object.entries(PROJECT_TEMPLATES).map(([key, template]) => (
550
+ <Card
551
+ key={key}
552
+ className={`cursor-pointer transition-all p-4 ${
553
+ projectData.template === key
554
+ ? 'border-blue-500 bg-blue-50'
555
+ : 'hover:border-gray-300'
556
+ }`}
557
+ onClick={() => handleInputChange('template', key)}
558
+ >
559
+ <div className="flex items-start justify-between mb-2">
560
+ <h4 className="font-medium">{template.name}</h4>
561
+ <input
562
+ type="radio"
563
+ checked={projectData.template === key}
564
+ onChange={() => handleInputChange('template', key)}
565
+ className="mt-1"
566
+ />
567
+ </div>
568
+ <p className="text-sm text-gray-600 mb-3">{template.description}</p>
569
+ <div className="space-y-1">
570
+ {template.features.map((feature, index) => (
571
+ <div key={index} className="text-xs text-gray-500 flex items-center">
572
+ <span className="w-1 h-1 bg-gray-400 rounded-full mr-2"></span>
573
+ {feature}
574
+ </div>
575
+ ))}
576
+ </div>
577
+ </Card>
578
+ ))}
579
+ </div>
580
+ </div>
581
+ );
582
+
583
+ case 2:
584
+ return (
585
+ <div className="space-y-4">
586
+ <h3 className="text-lg font-medium">Database Configuration</h3>
587
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
588
+ {DATABASE_OPTIONS.map((db) => (
589
+ <Card
590
+ key={db.value}
591
+ className={`cursor-pointer transition-all p-4 ${
592
+ projectData.database === db.value
593
+ ? 'border-blue-500 bg-blue-50'
594
+ : 'hover:border-gray-300'
595
+ }`}
596
+ onClick={() => handleInputChange('database', db.value)}
597
+ >
598
+ <div className="flex items-start justify-between mb-2">
599
+ <h4 className="font-medium">{db.label}</h4>
600
+ <input
601
+ type="radio"
602
+ checked={projectData.database === db.value}
603
+ onChange={() => handleInputChange('database', db.value)}
604
+ className="mt-1"
605
+ />
606
+ </div>
607
+ <p className="text-sm text-gray-600">{db.description}</p>
608
+ </Card>
609
+ ))}
610
+ </div>
611
+ </div>
612
+ );
613
+
614
+ case 3:
615
+ return (
616
+ <div className="space-y-4">
617
+ <h3 className="text-lg font-medium">Select Integrations</h3>
618
+ <p className="text-sm text-gray-600">Choose the integrations you want to include in your project.</p>
619
+
620
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
621
+ {INTEGRATION_OPTIONS.map((integration) => (
622
+ <div
623
+ key={integration.id}
624
+ className={`border rounded p-3 cursor-pointer transition-all ${
625
+ projectData.integrations.includes(integration.id)
626
+ ? 'border-blue-500 bg-blue-50'
627
+ : 'hover:border-gray-300'
628
+ }`}
629
+ onClick={() => handleIntegrationToggle(integration.id)}
630
+ >
631
+ <div className="flex items-center justify-between">
632
+ <div>
633
+ <h4 className="font-medium text-sm">{integration.name}</h4>
634
+ <p className="text-xs text-gray-500">{integration.category}</p>
635
+ </div>
636
+ <input
637
+ type="checkbox"
638
+ checked={projectData.integrations.includes(integration.id)}
639
+ onChange={() => handleIntegrationToggle(integration.id)}
640
+ />
641
+ </div>
642
+ </div>
643
+ ))}
644
+ </div>
645
+ </div>
646
+ );
647
+
648
+ case 4:
649
+ return (
650
+ <div className="space-y-4">
651
+ <h3 className="text-lg font-medium">Additional Features</h3>
652
+ <p className="text-sm text-gray-600">Enable additional features for your project.</p>
653
+
654
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
655
+ {Object.entries(projectData.features).map(([feature, enabled]) => (
656
+ <div key={feature} className="flex items-center justify-between p-3 border rounded">
657
+ <div>
658
+ <h4 className="font-medium capitalize">{feature.replace(/([A-Z])/g, ' $1')}</h4>
659
+ <p className="text-sm text-gray-500">
660
+ {feature === 'authentication' && 'JWT-based authentication system'}
661
+ {feature === 'logging' && 'Winston logging configuration'}
662
+ {feature === 'monitoring' && 'Health checks and metrics'}
663
+ {feature === 'testing' && 'Jest testing framework'}
664
+ {feature === 'docker' && 'Docker and docker-compose files'}
665
+ {feature === 'ci' && 'GitHub Actions CI/CD pipeline'}
666
+ </p>
667
+ </div>
668
+ <input
669
+ type="checkbox"
670
+ checked={enabled}
671
+ onChange={() => handleFeatureToggle(feature)}
672
+ />
673
+ </div>
674
+ ))}
675
+ </div>
676
+ </div>
677
+ );
678
+
679
+ case 5:
680
+ return (
681
+ <div className="space-y-4">
682
+ <h3 className="text-lg font-medium">Deployment Configuration</h3>
683
+
684
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
685
+ <div>
686
+ <label className="block text-sm font-medium text-gray-700 mb-2">
687
+ Platform
688
+ </label>
689
+ <select
690
+ value={projectData.deployment.platform}
691
+ onChange={(e) => handleInputChange('deployment', { ...projectData.deployment, platform: e.target.value })}
692
+ className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
693
+ >
694
+ <option value="aws">AWS</option>
695
+ <option value="gcp">Google Cloud</option>
696
+ <option value="azure">Microsoft Azure</option>
697
+ <option value="heroku">Heroku</option>
698
+ <option value="vercel">Vercel</option>
699
+ <option value="netlify">Netlify</option>
700
+ </select>
701
+ </div>
702
+ <div>
703
+ <label className="block text-sm font-medium text-gray-700 mb-2">
704
+ Environment
705
+ </label>
706
+ <select
707
+ value={projectData.deployment.environment}
708
+ onChange={(e) => handleInputChange('deployment', { ...projectData.deployment, environment: e.target.value })}
709
+ className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
710
+ >
711
+ <option value="development">Development</option>
712
+ <option value="staging">Staging</option>
713
+ <option value="production">Production</option>
714
+ </select>
715
+ </div>
716
+ </div>
717
+
718
+ <div className="bg-blue-50 p-4 rounded-md">
719
+ <h4 className="font-medium text-blue-900 mb-2">Project Summary</h4>
720
+ <div className="text-sm text-blue-800 space-y-1">
721
+ <p><strong>Name:</strong> {projectData.name}</p>
722
+ <p><strong>Template:</strong> {PROJECT_TEMPLATES[projectData.template].name}</p>
723
+ <p><strong>Database:</strong> {DATABASE_OPTIONS.find(db => db.value === projectData.database)?.label}</p>
724
+ <p><strong>Integrations:</strong> {projectData.integrations.length > 0 ? projectData.integrations.join(', ') : 'None'}</p>
725
+ <p><strong>Features:</strong> {Object.entries(projectData.features).filter(([, enabled]) => enabled).map(([feature]) => feature).join(', ')}</p>
726
+ </div>
727
+ </div>
728
+ </div>
729
+ );
730
+
731
+ default:
732
+ return null;
733
+ }
734
+ };
735
+
736
+ return (
737
+ <div className="space-y-6">
738
+ <h2 className="text-2xl font-bold">Project Scaffold Wizard</h2>
739
+
740
+ {/* Progress indicator */}
741
+ <div className="flex items-center justify-between mb-8">
742
+ {steps.map((step, index) => (
743
+ <div key={index} className="flex items-center">
744
+ <div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium ${
745
+ index <= currentStep
746
+ ? 'bg-blue-600 text-white'
747
+ : 'bg-gray-200 text-gray-500'
748
+ }`}>
749
+ {index + 1}
750
+ </div>
751
+ <div className="ml-2 text-sm">
752
+ <div className={`font-medium ${index <= currentStep ? 'text-blue-600' : 'text-gray-500'}`}>
753
+ {step.title}
754
+ </div>
755
+ <div className="text-gray-400 text-xs">{step.description}</div>
756
+ </div>
757
+ {index < steps.length - 1 && (
758
+ <div className={`w-16 h-px mx-4 ${index < currentStep ? 'bg-blue-600' : 'bg-gray-200'}`} />
759
+ )}
760
+ </div>
761
+ ))}
762
+ </div>
763
+
764
+ <Card className="p-6">
765
+ {renderStep()}
766
+ </Card>
767
+
768
+ <div className="flex justify-between">
769
+ <Button
770
+ variant="outline"
771
+ onClick={prevStep}
772
+ disabled={currentStep === 0}
773
+ >
774
+ Previous
775
+ </Button>
776
+
777
+ {currentStep === steps.length - 1 ? (
778
+ <Button
779
+ onClick={generateProjectFiles}
780
+ className="bg-green-600 hover:bg-green-700"
781
+ >
782
+ Generate Project
783
+ </Button>
784
+ ) : (
785
+ <Button
786
+ onClick={nextStep}
787
+ disabled={!canProceed()}
788
+ >
789
+ Next
790
+ </Button>
791
+ )}
792
+ </div>
793
+ </div>
794
+ );
795
+ };
796
+
797
+ export default ProjectScaffoldWizard;