leedstack 3.1.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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +364 -0
  3. package/bin/create-stack.js +277 -0
  4. package/package.json +60 -0
  5. package/tools/templates/backend/go-echo/backend/.env.example +10 -0
  6. package/tools/templates/backend/go-echo/backend/cmd/server/main.go.ejs +57 -0
  7. package/tools/templates/backend/go-echo/backend/go.mod.ejs +10 -0
  8. package/tools/templates/backend/go-echo/backend/internal/handlers/example.go +15 -0
  9. package/tools/templates/backend/go-echo/backend/internal/handlers/health.go +13 -0
  10. package/tools/templates/backend/java-spring/backend/.env.example +10 -0
  11. package/tools/templates/backend/java-spring/backend/pom.xml.ejs +64 -0
  12. package/tools/templates/backend/java-spring/backend/src/main/java/com/app/Application.java.ejs +11 -0
  13. package/tools/templates/backend/java-spring/backend/src/main/java/com/app/config/SecurityConfig.java.ejs +64 -0
  14. package/tools/templates/backend/java-spring/backend/src/main/java/com/app/controller/ExampleController.java +19 -0
  15. package/tools/templates/backend/java-spring/backend/src/main/java/com/app/controller/HealthController.java +15 -0
  16. package/tools/templates/backend/java-spring/backend/src/main/resources/application.yml.ejs +20 -0
  17. package/tools/templates/backend/node-express/backend/.env.example +10 -0
  18. package/tools/templates/backend/node-express/backend/.eslintrc.json +21 -0
  19. package/tools/templates/backend/node-express/backend/.prettierrc +10 -0
  20. package/tools/templates/backend/node-express/backend/Dockerfile +52 -0
  21. package/tools/templates/backend/node-express/backend/README.md +68 -0
  22. package/tools/templates/backend/node-express/backend/package.json.ejs +37 -0
  23. package/tools/templates/backend/node-express/backend/src/index.ts.ejs +75 -0
  24. package/tools/templates/backend/node-express/backend/src/routes/health.ts +54 -0
  25. package/tools/templates/backend/node-express/backend/tsconfig.json +17 -0
  26. package/tools/templates/backend/python-fastapi/backend/.env.example +18 -0
  27. package/tools/templates/backend/python-fastapi/backend/README.md +73 -0
  28. package/tools/templates/backend/python-fastapi/backend/app/__init__.py +1 -0
  29. package/tools/templates/backend/python-fastapi/backend/app/main.py.ejs +68 -0
  30. package/tools/templates/backend/python-fastapi/backend/requirements.txt.ejs +22 -0
  31. package/tools/templates/base/.dockerignore +16 -0
  32. package/tools/templates/base/.env.example +31 -0
  33. package/tools/templates/base/.github/workflows/ci.yml.ejs +124 -0
  34. package/tools/templates/base/.github/workflows/deploy-separate.yml.example +144 -0
  35. package/tools/templates/base/.vscode/extensions.json +17 -0
  36. package/tools/templates/base/.vscode/settings.json +49 -0
  37. package/tools/templates/base/Makefile +98 -0
  38. package/tools/templates/base/README.md.ejs +118 -0
  39. package/tools/templates/base/docker-compose.yml.ejs +49 -0
  40. package/tools/templates/base/package.json.ejs +30 -0
  41. package/tools/templates/base/scripts/split-repos.sh +189 -0
  42. package/tools/templates/db/postgres/backend/java-spring/backend/pom.xml.ejs +81 -0
  43. package/tools/templates/db/postgres/backend/java-spring/backend/src/main/resources/application.yml.ejs +39 -0
  44. package/tools/templates/db/postgres/backend/java-spring/backend/src/main/resources/db/migration/V1__init.sql +17 -0
  45. package/tools/templates/db/postgres/backend/node-express/backend/.env.example +10 -0
  46. package/tools/templates/db/postgres/backend/node-express/backend/package.json.ejs +32 -0
  47. package/tools/templates/db/postgres/backend/node-express/backend/prisma/schema.prisma.ejs +39 -0
  48. package/tools/templates/frontend/angular/frontend/.env.example +9 -0
  49. package/tools/templates/frontend/angular/frontend/angular.json +66 -0
  50. package/tools/templates/frontend/angular/frontend/package.json.ejs +31 -0
  51. package/tools/templates/frontend/angular/frontend/src/app/app.component.ts +30 -0
  52. package/tools/templates/frontend/angular/frontend/src/app/app.routes.ts +18 -0
  53. package/tools/templates/frontend/angular/frontend/src/app/components/home.component.ts +24 -0
  54. package/tools/templates/frontend/angular/frontend/src/app/services/api.service.ts +48 -0
  55. package/tools/templates/frontend/angular/frontend/src/favicon.ico +1 -0
  56. package/tools/templates/frontend/angular/frontend/src/index.html +13 -0
  57. package/tools/templates/frontend/angular/frontend/src/main.ts +10 -0
  58. package/tools/templates/frontend/angular/frontend/src/styles.css +31 -0
  59. package/tools/templates/frontend/angular/frontend/tsconfig.app.json +9 -0
  60. package/tools/templates/frontend/angular/frontend/tsconfig.json +27 -0
  61. package/tools/templates/frontend/nextjs/frontend/.env.example +9 -0
  62. package/tools/templates/frontend/nextjs/frontend/next.config.js +37 -0
  63. package/tools/templates/frontend/nextjs/frontend/package.json.ejs +25 -0
  64. package/tools/templates/frontend/nextjs/frontend/src/app/globals.css +31 -0
  65. package/tools/templates/frontend/nextjs/frontend/src/app/layout.tsx +36 -0
  66. package/tools/templates/frontend/nextjs/frontend/src/app/page.tsx +19 -0
  67. package/tools/templates/frontend/nextjs/frontend/src/lib/api.ts +45 -0
  68. package/tools/templates/frontend/nextjs/frontend/tsconfig.json +27 -0
  69. package/tools/templates/frontend/react/frontend/.env.example +9 -0
  70. package/tools/templates/frontend/react/frontend/.eslintrc.json +32 -0
  71. package/tools/templates/frontend/react/frontend/.prettierrc +10 -0
  72. package/tools/templates/frontend/react/frontend/Dockerfile +37 -0
  73. package/tools/templates/frontend/react/frontend/README.md +54 -0
  74. package/tools/templates/frontend/react/frontend/index.html +13 -0
  75. package/tools/templates/frontend/react/frontend/nginx.conf +35 -0
  76. package/tools/templates/frontend/react/frontend/package.json.ejs +41 -0
  77. package/tools/templates/frontend/react/frontend/public/vite.svg +4 -0
  78. package/tools/templates/frontend/react/frontend/src/App.css +65 -0
  79. package/tools/templates/frontend/react/frontend/src/App.jsx +41 -0
  80. package/tools/templates/frontend/react/frontend/src/assets/react.svg +7 -0
  81. package/tools/templates/frontend/react/frontend/src/components/ErrorBoundary.jsx +62 -0
  82. package/tools/templates/frontend/react/frontend/src/components/Home.jsx +58 -0
  83. package/tools/templates/frontend/react/frontend/src/components/__tests__/Home.test.jsx +74 -0
  84. package/tools/templates/frontend/react/frontend/src/index.css +31 -0
  85. package/tools/templates/frontend/react/frontend/src/lib/api.js +42 -0
  86. package/tools/templates/frontend/react/frontend/src/lib/env.js +58 -0
  87. package/tools/templates/frontend/react/frontend/src/main.jsx +16 -0
  88. package/tools/templates/frontend/react/frontend/src/setupTests.js +8 -0
  89. package/tools/templates/frontend/react/frontend/vite.config.js +30 -0
  90. package/tools/templates/frontend/react/frontend/vitest.config.js +20 -0
  91. package/tools/templates/frontend/svelte/frontend/.env.example +9 -0
  92. package/tools/templates/frontend/svelte/frontend/package.json.ejs +21 -0
  93. package/tools/templates/frontend/svelte/frontend/src/app.html +12 -0
  94. package/tools/templates/frontend/svelte/frontend/src/lib/api.ts +45 -0
  95. package/tools/templates/frontend/svelte/frontend/src/routes/+layout.svelte +56 -0
  96. package/tools/templates/frontend/svelte/frontend/src/routes/+page.svelte +20 -0
  97. package/tools/templates/frontend/svelte/frontend/static/favicon.png +1 -0
  98. package/tools/templates/frontend/svelte/frontend/svelte.config.js +10 -0
  99. package/tools/templates/frontend/svelte/frontend/vite.config.js +9 -0
  100. package/tools/templates/frontend/vue/frontend/.env.example +9 -0
  101. package/tools/templates/frontend/vue/frontend/index.html +13 -0
  102. package/tools/templates/frontend/vue/frontend/package.json.ejs +20 -0
  103. package/tools/templates/frontend/vue/frontend/src/App.vue +60 -0
  104. package/tools/templates/frontend/vue/frontend/src/lib/api.js +42 -0
  105. package/tools/templates/frontend/vue/frontend/src/main.js +33 -0
  106. package/tools/templates/frontend/vue/frontend/src/views/ApiTest.vue +39 -0
  107. package/tools/templates/frontend/vue/frontend/src/views/Home.vue +30 -0
  108. package/tools/templates/frontend/vue/frontend/vite.config.js +9 -0
  109. package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/controller/AdminController.java +41 -0
  110. package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/entity/User.java +55 -0
  111. package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/repository/UserRepository.java +8 -0
  112. package/tools/templates/modules/admin/frontend/svelte/frontend/src/routes/dashboard/+page.svelte +93 -0
  113. package/tools/templates/modules/auth/backend/node-express/backend/src/middleware/auth.ts +42 -0
  114. package/tools/templates/modules/auth/frontend/svelte/frontend/src/hooks.client.ts +3 -0
  115. package/tools/templates/modules/auth/frontend/svelte/frontend/src/lib/auth.ts +104 -0
  116. package/tools/templates/modules/auth/frontend/svelte/frontend/src/routes/callback/+page.svelte +18 -0
  117. package/tools/templates/modules/auth/frontend/svelte/frontend/src/routes/login/+page.svelte +12 -0
  118. package/tools/templates/modules/chatbot/backend/node-express/backend/src/index.ts.ejs +69 -0
  119. package/tools/templates/modules/chatbot/backend/node-express/backend/src/routes/chatbot.ts.ejs +37 -0
  120. package/tools/templates/modules/chatbot/backend/node-express/backend/src/services/chatbotService.ts +124 -0
  121. package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/main.py.ejs +69 -0
  122. package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/routes/chatbot.py +38 -0
  123. package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/services/chatbot_service.py +123 -0
  124. package/tools/templates/modules/chatbot/backend/python-fastapi/backend/requirements.txt +1 -0
  125. package/tools/templates/modules/chatbot/frontend/react/frontend/src/App.jsx.ejs +74 -0
  126. package/tools/templates/modules/chatbot/frontend/react/frontend/src/components/Chatbot.css +198 -0
  127. package/tools/templates/modules/chatbot/frontend/react/frontend/src/components/Chatbot.jsx +113 -0
  128. package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/controller/ContactController.java +29 -0
  129. package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/entity/ContactMessage.java +66 -0
  130. package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/repository/ContactMessageRepository.java +8 -0
  131. package/tools/templates/modules/contact/backend/java-spring/backend/src/main/resources/db/migration/V2__contact.sql +7 -0
  132. package/tools/templates/modules/contact/frontend/svelte/frontend/src/routes/contact/+page.svelte +80 -0
  133. package/tools/templates/modules/payments/backend/java-spring/backend/src/main/java/com/app/controller/PaymentController.java +69 -0
  134. package/tools/templates/modules/payments/backend/node-express/backend/src/routes/payments.ts +30 -0
  135. package/tools/templates/modules/payments/backend/node-express/backend/src/routes/webhook.ts +36 -0
  136. package/tools/templates/modules/payments/frontend/svelte/frontend/src/lib/payments.ts +28 -0
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "leedstack",
3
+ "version": "3.1.0",
4
+ "description": "One-command scaffolder for full-stack web applications with 60+ stack combinations (React/Vue/Next.js/Svelte/Angular + Python/Node/Java/Go + Postgres/MySQL/MongoDB)",
5
+ "type": "module",
6
+ "bin": {
7
+ "leedstack": "./bin/create-stack.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "tools"
12
+ ],
13
+ "engines": {
14
+ "node": ">=20.0.0"
15
+ },
16
+ "keywords": [
17
+ "scaffolder",
18
+ "scaffold",
19
+ "generator",
20
+ "full-stack",
21
+ "cli",
22
+ "template",
23
+ "boilerplate",
24
+ "react",
25
+ "vue",
26
+ "vuejs",
27
+ "nextjs",
28
+ "next.js",
29
+ "svelte",
30
+ "angular",
31
+ "python",
32
+ "fastapi",
33
+ "spring-boot",
34
+ "express",
35
+ "nodejs",
36
+ "go",
37
+ "postgres",
38
+ "postgresql",
39
+ "mysql",
40
+ "mongodb",
41
+ "auth0",
42
+ "stripe",
43
+ "typescript"
44
+ ],
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/CTLeed/leedstack.git"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/CTLeed/leedstack/issues"
51
+ },
52
+ "homepage": "https://github.com/CTLeed/leedstack#readme",
53
+ "author": "Colby Leed",
54
+ "license": "MIT",
55
+ "dependencies": {
56
+ "commander": "^12.0.0",
57
+ "fs-extra": "^11.2.0",
58
+ "ejs": "^3.1.9"
59
+ }
60
+ }
@@ -0,0 +1,10 @@
1
+ APP_PORT=8080
2
+ FRONTEND_URL=http://localhost:<%= frontendPort %>
3
+ <% if (modules.auth) { -%>
4
+ AUTH0_DOMAIN=your-tenant.us.auth0.com
5
+ AUTH0_AUDIENCE=https://api.<%= appSlug %>
6
+ <% } -%>
7
+ <% if (modules.payments) { -%>
8
+ STRIPE_SECRET_KEY=sk_test_xxx
9
+ STRIPE_WEBHOOK_SECRET=whsec_xxx
10
+ <% } -%>
@@ -0,0 +1,57 @@
1
+ package main
2
+
3
+ import (
4
+ "<%= appSlug %>-backend/internal/handlers"
5
+ "os"
6
+
7
+ "github.com/joho/godotenv"
8
+ "github.com/labstack/echo/v4"
9
+ "github.com/labstack/echo/v4/middleware"
10
+ )
11
+
12
+ func main() {
13
+ godotenv.Load()
14
+
15
+ e := echo.New()
16
+
17
+ // Middleware
18
+ e.Use(middleware.Logger())
19
+ e.Use(middleware.Recover())
20
+ // CORS configuration - allow only the configured frontend URL
21
+ allowedOrigins := []string{}
22
+ if frontendURL := os.Getenv("FRONTEND_URL"); frontendURL != "" {
23
+ allowedOrigins = append(allowedOrigins, frontendURL)
24
+ }
25
+
26
+ e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
27
+ AllowOrigins: allowedOrigins,
28
+ AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
29
+ AllowHeaders: []string{"*"},
30
+ AllowCredentials: true,
31
+ }))
32
+
33
+ // Health endpoint
34
+ e.GET("/health", handlers.Health)
35
+ e.GET("/actuator/health", handlers.Health)
36
+
37
+ // Example API route
38
+ e.GET("/api/example", handlers.Example)
39
+
40
+ // Protected API routes
41
+ <% if (modules.auth) { -%>
42
+ // TODO: Add auth middleware
43
+ <% } -%>
44
+ api := e.Group("/api")
45
+ _ = api // Will be used for API routes
46
+
47
+ port := os.Getenv("APP_PORT")
48
+ if port == "" {
49
+ port = "8080"
50
+ }
51
+
52
+ e.Logger.Printf("✅ Server running on http://localhost:%s", port)
53
+ e.Logger.Printf("📍 API available at http://localhost:%s/api", port)
54
+ e.Logger.Printf("🏥 Health check at http://localhost:%s/health", port)
55
+
56
+ e.Logger.Fatal(e.Start(":" + port))
57
+ }
@@ -0,0 +1,10 @@
1
+ module <%= appSlug %>-backend
2
+
3
+ go 1.22
4
+
5
+ require (
6
+ github.com/labstack/echo/v4 v4.12.0
7
+ github.com/joho/godotenv v1.5.1<% if (modules.auth) { %>
8
+ github.com/lestrrat-go/jwx/v2 v2.1.3<% } %><% if (modules.payments) { %>
9
+ github.com/stripe/stripe-go/v76 v76.25.0<% } %>
10
+ )
@@ -0,0 +1,15 @@
1
+ package handlers
2
+
3
+ import (
4
+ "net/http"
5
+ "time"
6
+
7
+ "github.com/labstack/echo/v4"
8
+ )
9
+
10
+ func Example(c echo.Context) error {
11
+ return c.JSON(http.StatusOK, map[string]interface{}{
12
+ "message": "Hello from go-echo backend!",
13
+ "timestamp": time.Now().Format(time.RFC3339),
14
+ })
15
+ }
@@ -0,0 +1,13 @@
1
+ package handlers
2
+
3
+ import (
4
+ "net/http"
5
+
6
+ "github.com/labstack/echo/v4"
7
+ )
8
+
9
+ func Health(c echo.Context) error {
10
+ return c.JSON(http.StatusOK, map[string]string{
11
+ "status": "UP",
12
+ })
13
+ }
@@ -0,0 +1,10 @@
1
+ APP_PORT=8080
2
+ FRONTEND_URL=http://localhost:<%= frontendPort %>
3
+ <% if (modules.auth) { -%>
4
+ AUTH0_DOMAIN=your-tenant.us.auth0.com
5
+ AUTH0_AUDIENCE=https://api.<%= appSlug %>
6
+ <% } -%>
7
+ <% if (modules.payments) { -%>
8
+ STRIPE_SECRET_KEY=sk_test_xxx
9
+ STRIPE_WEBHOOK_SECRET=whsec_xxx
10
+ <% } -%>
@@ -0,0 +1,64 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+ <modelVersion>4.0.0</modelVersion>
6
+
7
+ <parent>
8
+ <groupId>org.springframework.boot</groupId>
9
+ <artifactId>spring-boot-starter-parent</artifactId>
10
+ <version>3.3.4</version>
11
+ <relativePath/>
12
+ </parent>
13
+
14
+ <groupId>com.app</groupId>
15
+ <artifactId><%= appSlug %>-backend</artifactId>
16
+ <version>0.0.1-SNAPSHOT</version>
17
+ <name><%= appName %> Backend</name>
18
+
19
+ <properties>
20
+ <java.version>21</java.version>
21
+ </properties>
22
+
23
+ <dependencies>
24
+ <dependency>
25
+ <groupId>org.springframework.boot</groupId>
26
+ <artifactId>spring-boot-starter-web</artifactId>
27
+ </dependency>
28
+ <% if (modules.auth) { -%>
29
+ <dependency>
30
+ <groupId>org.springframework.boot</groupId>
31
+ <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
32
+ </dependency>
33
+ <dependency>
34
+ <groupId>org.springframework.boot</groupId>
35
+ <artifactId>spring-boot-starter-security</artifactId>
36
+ </dependency>
37
+ <% } -%>
38
+ <% if (modules.payments) { -%>
39
+ <dependency>
40
+ <groupId>com.stripe</groupId>
41
+ <artifactId>stripe-java</artifactId>
42
+ <version>26.0.0</version>
43
+ </dependency>
44
+ <% } -%>
45
+ <dependency>
46
+ <groupId>org.springframework.boot</groupId>
47
+ <artifactId>spring-boot-starter-actuator</artifactId>
48
+ </dependency>
49
+ <dependency>
50
+ <groupId>org.springframework.boot</groupId>
51
+ <artifactId>spring-boot-starter-test</artifactId>
52
+ <scope>test</scope>
53
+ </dependency>
54
+ </dependencies>
55
+
56
+ <build>
57
+ <plugins>
58
+ <plugin>
59
+ <groupId>org.springframework.boot</groupId>
60
+ <artifactId>spring-boot-maven-plugin</artifactId>
61
+ </plugin>
62
+ </plugins>
63
+ </build>
64
+ </project>
@@ -0,0 +1,11 @@
1
+ package com.app;
2
+
3
+ import org.springframework.boot.SpringApplication;
4
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+
6
+ @SpringBootApplication
7
+ public class Application {
8
+ public static void main(String[] args) {
9
+ SpringApplication.run(Application.class, args);
10
+ }
11
+ }
@@ -0,0 +1,64 @@
1
+ package com.app.config;
2
+
3
+ import org.springframework.context.annotation.Bean;
4
+ import org.springframework.context.annotation.Configuration;
5
+ <% if (modules.auth) { -%>
6
+ import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
7
+ <% } -%>
8
+ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9
+ import org.springframework.security.web.SecurityFilterChain;
10
+ import org.springframework.web.cors.*;
11
+
12
+ import java.util.List;
13
+
14
+ @Configuration
15
+ <% if (modules.auth && modules.admin) { -%>
16
+ @EnableMethodSecurity
17
+ <% } -%>
18
+ public class SecurityConfig {
19
+
20
+ @Bean
21
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
22
+ http.csrf(csrf -> csrf.disable());
23
+ http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
24
+
25
+ http.authorizeHttpRequests(auth -> auth
26
+ .requestMatchers("/actuator/health"<% if (modules.payments) { %>, "/stripe/webhook"<% } %>).permitAll()
27
+ <% if (modules.admin) { -%>
28
+ .requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin")
29
+ <% } -%>
30
+ <% if (modules.auth) { -%>
31
+ .anyRequest().authenticated()
32
+ <% } else { -%>
33
+ .anyRequest().permitAll()
34
+ <% } -%>
35
+ );
36
+
37
+ <% if (modules.auth) { -%>
38
+ http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> {}));
39
+ <% } -%>
40
+
41
+ return http.build();
42
+ }
43
+
44
+ @Bean
45
+ public CorsConfigurationSource corsConfigurationSource() {
46
+ CorsConfiguration configuration = new CorsConfiguration();
47
+
48
+ // Allow only the configured frontend URL
49
+ String frontendUrl = System.getenv("FRONTEND_URL");
50
+ if (frontendUrl != null && !frontendUrl.isEmpty()) {
51
+ configuration.setAllowedOrigins(List.of(frontendUrl));
52
+ } else {
53
+ configuration.setAllowedOrigins(List.of());
54
+ }
55
+
56
+ configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
57
+ configuration.setAllowedHeaders(Arrays.asList("*"));
58
+ configuration.setAllowCredentials(true);
59
+
60
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
61
+ source.registerCorsConfiguration("/**", configuration);
62
+ return source;
63
+ }
64
+ }
@@ -0,0 +1,19 @@
1
+ package com.app.controller;
2
+
3
+ import org.springframework.web.bind.annotation.GetMapping;
4
+ import org.springframework.web.bind.annotation.RestController;
5
+
6
+ import java.time.Instant;
7
+ import java.util.Map;
8
+
9
+ @RestController
10
+ public class ExampleController {
11
+
12
+ @GetMapping("/api/example")
13
+ public Map<String, Object> example() {
14
+ return Map.of(
15
+ "message", "Hello from java-spring backend!",
16
+ "timestamp", Instant.now().toString()
17
+ );
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ package com.app.controller;
2
+
3
+ import org.springframework.web.bind.annotation.GetMapping;
4
+ import org.springframework.web.bind.annotation.RestController;
5
+
6
+ import java.util.Map;
7
+
8
+ @RestController
9
+ public class HealthController {
10
+
11
+ @GetMapping("/health")
12
+ public Map<String, String> health() {
13
+ return Map.of("status", "UP");
14
+ }
15
+ }
@@ -0,0 +1,20 @@
1
+ server:
2
+ port: ${APP_PORT:8080}
3
+
4
+ spring:
5
+ application:
6
+ name: <%= appSlug %>-backend
7
+ <% if (modules.auth) { -%>
8
+ security:
9
+ oauth2:
10
+ resourceserver:
11
+ jwt:
12
+ issuer-uri: https://${AUTH0_DOMAIN}/
13
+ audiences: ${AUTH0_AUDIENCE}
14
+ <% } -%>
15
+
16
+ management:
17
+ endpoints:
18
+ web:
19
+ exposure:
20
+ include: health
@@ -0,0 +1,10 @@
1
+ APP_PORT=8080
2
+ FRONTEND_URL=http://localhost:<%= frontendPort %>
3
+ <% if (modules.auth) { -%>
4
+ AUTH0_DOMAIN=your-tenant.us.auth0.com
5
+ AUTH0_AUDIENCE=https://api.<%= appSlug %>
6
+ <% } -%>
7
+ <% if (modules.payments) { -%>
8
+ STRIPE_SECRET_KEY=sk_test_xxx
9
+ STRIPE_WEBHOOK_SECRET=whsec_xxx
10
+ <% } -%>
@@ -0,0 +1,21 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/recommended"
6
+ ],
7
+ "parserOptions": {
8
+ "ecmaVersion": "latest",
9
+ "sourceType": "module"
10
+ },
11
+ "rules": {
12
+ "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
13
+ "@typescript-eslint/no-explicit-any": "warn",
14
+ "no-console": "off",
15
+ "@typescript-eslint/explicit-module-boundary-types": "off"
16
+ },
17
+ "env": {
18
+ "node": true,
19
+ "es2021": true
20
+ }
21
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "semi": true,
3
+ "trailingComma": "es5",
4
+ "singleQuote": true,
5
+ "printWidth": 100,
6
+ "tabWidth": 2,
7
+ "useTabs": false,
8
+ "arrowParens": "avoid",
9
+ "endOfLine": "lf"
10
+ }
@@ -0,0 +1,52 @@
1
+ # Multi-stage build for production
2
+
3
+ # Stage 1: Build
4
+ FROM node:20-alpine AS builder
5
+
6
+ WORKDIR /app
7
+
8
+ # Copy package files
9
+ COPY package*.json ./
10
+
11
+ # Install dependencies
12
+ RUN npm ci
13
+
14
+ # Copy source code
15
+ COPY . .
16
+
17
+ # Build TypeScript
18
+ RUN npm run build
19
+
20
+ # Stage 2: Production
21
+ FROM node:20-alpine
22
+
23
+ WORKDIR /app
24
+
25
+ # Copy package files
26
+ COPY package*.json ./
27
+
28
+ # Install production dependencies only
29
+ RUN npm ci --only=production
30
+
31
+ # Copy built application from builder
32
+ COPY --from=builder /app/dist ./dist
33
+
34
+ # Create non-root user
35
+ RUN addgroup -g 1001 -S nodejs && \
36
+ adduser -S nodejs -u 1001
37
+
38
+ # Change ownership
39
+ RUN chown -R nodejs:nodejs /app
40
+
41
+ # Switch to non-root user
42
+ USER nodejs
43
+
44
+ # Expose port
45
+ EXPOSE 8080
46
+
47
+ # Health check
48
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
49
+ CMD node -e "require('http').get('http://localhost:8080/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
50
+
51
+ # Start application
52
+ CMD ["node", "dist/index.js"]
@@ -0,0 +1,68 @@
1
+ # <%= AppName %> - Backend
2
+
3
+ Node.js + Express + TypeScript backend.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ npm install
10
+
11
+ # Set up environment
12
+ cp .env.example .env
13
+
14
+ # Start development server
15
+ npm run dev
16
+ ```
17
+
18
+ Server runs on http://localhost:8080
19
+
20
+ ## Available Scripts
21
+
22
+ - `npm run dev` - Start development server with hot reload
23
+ - `npm run build` - Compile TypeScript to JavaScript
24
+ - `npm start` - Run production build
25
+
26
+ ## Environment Variables
27
+
28
+ See `.env.example` for required variables:
29
+
30
+ - `APP_PORT` - Server port (default: 8080)
31
+ <% if (db === 'postgres' || db === 'mysql') { -%>
32
+ - `DATABASE_URL` - Database connection string
33
+ <% } else if (db === 'mongodb') { -%>
34
+ - `DATABASE_URL` - MongoDB connection string
35
+ <% } -%>
36
+ <% if (modules.auth) { -%>
37
+ - `AUTH0_DOMAIN` - Auth0 domain
38
+ - `AUTH0_AUDIENCE` - Auth0 API audience
39
+ <% } -%>
40
+
41
+ ## API Routes
42
+
43
+ - `GET /health` - Health check endpoint
44
+ - `GET /api/example` - Example API route
45
+ <% if (modules.contact) { -%>
46
+ - `POST /api/contact` - Submit contact form
47
+ <% } -%>
48
+ <% if (modules.admin) { -%>
49
+ - `GET /api/admin/stats` - Admin statistics (requires auth)
50
+ <% } -%>
51
+ <% if (modules.payments) { -%>
52
+ - `POST /api/payments/create-checkout-session` - Create Stripe checkout
53
+ - `POST /stripe/webhook` - Stripe webhook handler
54
+ <% } -%>
55
+
56
+ ## Tech Stack
57
+
58
+ - **Node.js ≥20** - Runtime
59
+ - **Express 5** - Web framework
60
+ - **TypeScript** - Type safety
61
+ <% if (db === 'postgres' || db === 'mysql') { -%>
62
+ - **Prisma** - Database ORM
63
+ <% } else if (db === 'mongodb') { -%>
64
+ - **Mongoose** - MongoDB ODM
65
+ <% } -%>
66
+ <% if (modules.auth) { -%>
67
+ - **jose** - JWT validation
68
+ <% } -%>
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "<%= appSlug %>-backend",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=20.0.0"
8
+ },
9
+ "scripts": {
10
+ "dev": "tsx watch src/index.ts",
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "lint": "eslint . --ext .ts --report-unused-disable-directives --max-warnings 0",
14
+ "lint:fix": "eslint . --ext .ts --fix",
15
+ "format": "prettier --write \"src/**/*.{ts,json}\"",
16
+ "format:check": "prettier --check \"src/**/*.{ts,json}\"",
17
+ "type-check": "tsc --noEmit"
18
+ },
19
+ "dependencies": {
20
+ "express": "^5.0.0",
21
+ "cors": "^2.8.5",
22
+ "dotenv": "^16.4.5"<% if (modules.auth) { %>,
23
+ "jose": "^5.9.6"<% } %><% if (modules.payments) { %>,
24
+ "stripe": "^16.0.0"<% } %>
25
+ },
26
+ "devDependencies": {
27
+ "@types/express": "^5.0.0",
28
+ "@types/cors": "^2.8.17",
29
+ "@types/node": "^22.0.0",
30
+ "tsx": "^4.19.2",
31
+ "typescript": "^5.6.3",
32
+ "@typescript-eslint/parser": "^6.19.0",
33
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
34
+ "eslint": "^8.57.0",
35
+ "prettier": "^3.2.4"
36
+ }
37
+ }
@@ -0,0 +1,75 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import dotenv from 'dotenv';
4
+ <% if (modules.auth) { -%>
5
+ import { authMiddleware } from './middleware/auth.js';
6
+ <% } -%>
7
+
8
+ dotenv.config();
9
+
10
+ const app = express();
11
+ const PORT = process.env.APP_PORT || 8080;
12
+
13
+ // CORS configuration - allow only the configured frontend URL
14
+ const allowedOrigins = [
15
+ process.env.FRONTEND_URL
16
+ ].filter(Boolean);
17
+
18
+ app.use(cors({
19
+ origin: (origin, callback) => {
20
+ // Allow requests with no origin (like mobile apps or curl)
21
+ if (!origin) return callback(null, true);
22
+ if (allowedOrigins.indexOf(origin) !== -1) {
23
+ callback(null, true);
24
+ } else {
25
+ callback(new Error('Not allowed by CORS'));
26
+ }
27
+ },
28
+ credentials: true
29
+ }));
30
+
31
+ app.use(express.json());
32
+
33
+ // Health endpoint
34
+ app.get('/health', (req, res) => {
35
+ res.json({ status: 'UP' });
36
+ });
37
+
38
+ app.get('/actuator/health', (req, res) => {
39
+ res.json({ status: 'UP' });
40
+ });
41
+
42
+ // Example API route
43
+ app.get('/api/example', (req, res) => {
44
+ res.json({
45
+ message: 'Hello from <%= backend %> backend!',
46
+ timestamp: new Date().toISOString()
47
+ });
48
+ });
49
+
50
+ // Apply auth middleware to protected routes
51
+ <% if (modules.auth) { -%>
52
+ app.use('/api', authMiddleware);
53
+ <% } -%>
54
+
55
+ const server = app.listen(PORT, () => {
56
+ console.log(`✅ Server running on http://localhost:${PORT}`);
57
+ console.log(`📍 API available at http://localhost:${PORT}/api`);
58
+ console.log(`🏥 Health check at http://localhost:${PORT}/health`);
59
+ });
60
+
61
+ // Graceful shutdown
62
+ process.on('SIGTERM', () => {
63
+ console.log('SIGTERM signal received: closing HTTP server');
64
+ server.close(() => {
65
+ console.log('HTTP server closed');
66
+ });
67
+ });
68
+
69
+ process.on('SIGINT', () => {
70
+ console.log('SIGINT signal received: closing HTTP server');
71
+ server.close(() => {
72
+ console.log('HTTP server closed');
73
+ process.exit(0);
74
+ });
75
+ });