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.
- package/LICENSE +21 -0
- package/README.md +364 -0
- package/bin/create-stack.js +277 -0
- package/package.json +60 -0
- package/tools/templates/backend/go-echo/backend/.env.example +10 -0
- package/tools/templates/backend/go-echo/backend/cmd/server/main.go.ejs +57 -0
- package/tools/templates/backend/go-echo/backend/go.mod.ejs +10 -0
- package/tools/templates/backend/go-echo/backend/internal/handlers/example.go +15 -0
- package/tools/templates/backend/go-echo/backend/internal/handlers/health.go +13 -0
- package/tools/templates/backend/java-spring/backend/.env.example +10 -0
- package/tools/templates/backend/java-spring/backend/pom.xml.ejs +64 -0
- package/tools/templates/backend/java-spring/backend/src/main/java/com/app/Application.java.ejs +11 -0
- package/tools/templates/backend/java-spring/backend/src/main/java/com/app/config/SecurityConfig.java.ejs +64 -0
- package/tools/templates/backend/java-spring/backend/src/main/java/com/app/controller/ExampleController.java +19 -0
- package/tools/templates/backend/java-spring/backend/src/main/java/com/app/controller/HealthController.java +15 -0
- package/tools/templates/backend/java-spring/backend/src/main/resources/application.yml.ejs +20 -0
- package/tools/templates/backend/node-express/backend/.env.example +10 -0
- package/tools/templates/backend/node-express/backend/.eslintrc.json +21 -0
- package/tools/templates/backend/node-express/backend/.prettierrc +10 -0
- package/tools/templates/backend/node-express/backend/Dockerfile +52 -0
- package/tools/templates/backend/node-express/backend/README.md +68 -0
- package/tools/templates/backend/node-express/backend/package.json.ejs +37 -0
- package/tools/templates/backend/node-express/backend/src/index.ts.ejs +75 -0
- package/tools/templates/backend/node-express/backend/src/routes/health.ts +54 -0
- package/tools/templates/backend/node-express/backend/tsconfig.json +17 -0
- package/tools/templates/backend/python-fastapi/backend/.env.example +18 -0
- package/tools/templates/backend/python-fastapi/backend/README.md +73 -0
- package/tools/templates/backend/python-fastapi/backend/app/__init__.py +1 -0
- package/tools/templates/backend/python-fastapi/backend/app/main.py.ejs +68 -0
- package/tools/templates/backend/python-fastapi/backend/requirements.txt.ejs +22 -0
- package/tools/templates/base/.dockerignore +16 -0
- package/tools/templates/base/.env.example +31 -0
- package/tools/templates/base/.github/workflows/ci.yml.ejs +124 -0
- package/tools/templates/base/.github/workflows/deploy-separate.yml.example +144 -0
- package/tools/templates/base/.vscode/extensions.json +17 -0
- package/tools/templates/base/.vscode/settings.json +49 -0
- package/tools/templates/base/Makefile +98 -0
- package/tools/templates/base/README.md.ejs +118 -0
- package/tools/templates/base/docker-compose.yml.ejs +49 -0
- package/tools/templates/base/package.json.ejs +30 -0
- package/tools/templates/base/scripts/split-repos.sh +189 -0
- package/tools/templates/db/postgres/backend/java-spring/backend/pom.xml.ejs +81 -0
- package/tools/templates/db/postgres/backend/java-spring/backend/src/main/resources/application.yml.ejs +39 -0
- package/tools/templates/db/postgres/backend/java-spring/backend/src/main/resources/db/migration/V1__init.sql +17 -0
- package/tools/templates/db/postgres/backend/node-express/backend/.env.example +10 -0
- package/tools/templates/db/postgres/backend/node-express/backend/package.json.ejs +32 -0
- package/tools/templates/db/postgres/backend/node-express/backend/prisma/schema.prisma.ejs +39 -0
- package/tools/templates/frontend/angular/frontend/.env.example +9 -0
- package/tools/templates/frontend/angular/frontend/angular.json +66 -0
- package/tools/templates/frontend/angular/frontend/package.json.ejs +31 -0
- package/tools/templates/frontend/angular/frontend/src/app/app.component.ts +30 -0
- package/tools/templates/frontend/angular/frontend/src/app/app.routes.ts +18 -0
- package/tools/templates/frontend/angular/frontend/src/app/components/home.component.ts +24 -0
- package/tools/templates/frontend/angular/frontend/src/app/services/api.service.ts +48 -0
- package/tools/templates/frontend/angular/frontend/src/favicon.ico +1 -0
- package/tools/templates/frontend/angular/frontend/src/index.html +13 -0
- package/tools/templates/frontend/angular/frontend/src/main.ts +10 -0
- package/tools/templates/frontend/angular/frontend/src/styles.css +31 -0
- package/tools/templates/frontend/angular/frontend/tsconfig.app.json +9 -0
- package/tools/templates/frontend/angular/frontend/tsconfig.json +27 -0
- package/tools/templates/frontend/nextjs/frontend/.env.example +9 -0
- package/tools/templates/frontend/nextjs/frontend/next.config.js +37 -0
- package/tools/templates/frontend/nextjs/frontend/package.json.ejs +25 -0
- package/tools/templates/frontend/nextjs/frontend/src/app/globals.css +31 -0
- package/tools/templates/frontend/nextjs/frontend/src/app/layout.tsx +36 -0
- package/tools/templates/frontend/nextjs/frontend/src/app/page.tsx +19 -0
- package/tools/templates/frontend/nextjs/frontend/src/lib/api.ts +45 -0
- package/tools/templates/frontend/nextjs/frontend/tsconfig.json +27 -0
- package/tools/templates/frontend/react/frontend/.env.example +9 -0
- package/tools/templates/frontend/react/frontend/.eslintrc.json +32 -0
- package/tools/templates/frontend/react/frontend/.prettierrc +10 -0
- package/tools/templates/frontend/react/frontend/Dockerfile +37 -0
- package/tools/templates/frontend/react/frontend/README.md +54 -0
- package/tools/templates/frontend/react/frontend/index.html +13 -0
- package/tools/templates/frontend/react/frontend/nginx.conf +35 -0
- package/tools/templates/frontend/react/frontend/package.json.ejs +41 -0
- package/tools/templates/frontend/react/frontend/public/vite.svg +4 -0
- package/tools/templates/frontend/react/frontend/src/App.css +65 -0
- package/tools/templates/frontend/react/frontend/src/App.jsx +41 -0
- package/tools/templates/frontend/react/frontend/src/assets/react.svg +7 -0
- package/tools/templates/frontend/react/frontend/src/components/ErrorBoundary.jsx +62 -0
- package/tools/templates/frontend/react/frontend/src/components/Home.jsx +58 -0
- package/tools/templates/frontend/react/frontend/src/components/__tests__/Home.test.jsx +74 -0
- package/tools/templates/frontend/react/frontend/src/index.css +31 -0
- package/tools/templates/frontend/react/frontend/src/lib/api.js +42 -0
- package/tools/templates/frontend/react/frontend/src/lib/env.js +58 -0
- package/tools/templates/frontend/react/frontend/src/main.jsx +16 -0
- package/tools/templates/frontend/react/frontend/src/setupTests.js +8 -0
- package/tools/templates/frontend/react/frontend/vite.config.js +30 -0
- package/tools/templates/frontend/react/frontend/vitest.config.js +20 -0
- package/tools/templates/frontend/svelte/frontend/.env.example +9 -0
- package/tools/templates/frontend/svelte/frontend/package.json.ejs +21 -0
- package/tools/templates/frontend/svelte/frontend/src/app.html +12 -0
- package/tools/templates/frontend/svelte/frontend/src/lib/api.ts +45 -0
- package/tools/templates/frontend/svelte/frontend/src/routes/+layout.svelte +56 -0
- package/tools/templates/frontend/svelte/frontend/src/routes/+page.svelte +20 -0
- package/tools/templates/frontend/svelte/frontend/static/favicon.png +1 -0
- package/tools/templates/frontend/svelte/frontend/svelte.config.js +10 -0
- package/tools/templates/frontend/svelte/frontend/vite.config.js +9 -0
- package/tools/templates/frontend/vue/frontend/.env.example +9 -0
- package/tools/templates/frontend/vue/frontend/index.html +13 -0
- package/tools/templates/frontend/vue/frontend/package.json.ejs +20 -0
- package/tools/templates/frontend/vue/frontend/src/App.vue +60 -0
- package/tools/templates/frontend/vue/frontend/src/lib/api.js +42 -0
- package/tools/templates/frontend/vue/frontend/src/main.js +33 -0
- package/tools/templates/frontend/vue/frontend/src/views/ApiTest.vue +39 -0
- package/tools/templates/frontend/vue/frontend/src/views/Home.vue +30 -0
- package/tools/templates/frontend/vue/frontend/vite.config.js +9 -0
- package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/controller/AdminController.java +41 -0
- package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/entity/User.java +55 -0
- package/tools/templates/modules/admin/backend/java-spring/backend/src/main/java/com/app/repository/UserRepository.java +8 -0
- package/tools/templates/modules/admin/frontend/svelte/frontend/src/routes/dashboard/+page.svelte +93 -0
- package/tools/templates/modules/auth/backend/node-express/backend/src/middleware/auth.ts +42 -0
- package/tools/templates/modules/auth/frontend/svelte/frontend/src/hooks.client.ts +3 -0
- package/tools/templates/modules/auth/frontend/svelte/frontend/src/lib/auth.ts +104 -0
- package/tools/templates/modules/auth/frontend/svelte/frontend/src/routes/callback/+page.svelte +18 -0
- package/tools/templates/modules/auth/frontend/svelte/frontend/src/routes/login/+page.svelte +12 -0
- package/tools/templates/modules/chatbot/backend/node-express/backend/src/index.ts.ejs +69 -0
- package/tools/templates/modules/chatbot/backend/node-express/backend/src/routes/chatbot.ts.ejs +37 -0
- package/tools/templates/modules/chatbot/backend/node-express/backend/src/services/chatbotService.ts +124 -0
- package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/main.py.ejs +69 -0
- package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/routes/chatbot.py +38 -0
- package/tools/templates/modules/chatbot/backend/python-fastapi/backend/app/services/chatbot_service.py +123 -0
- package/tools/templates/modules/chatbot/backend/python-fastapi/backend/requirements.txt +1 -0
- package/tools/templates/modules/chatbot/frontend/react/frontend/src/App.jsx.ejs +74 -0
- package/tools/templates/modules/chatbot/frontend/react/frontend/src/components/Chatbot.css +198 -0
- package/tools/templates/modules/chatbot/frontend/react/frontend/src/components/Chatbot.jsx +113 -0
- package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/controller/ContactController.java +29 -0
- package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/entity/ContactMessage.java +66 -0
- package/tools/templates/modules/contact/backend/java-spring/backend/src/main/java/com/app/repository/ContactMessageRepository.java +8 -0
- package/tools/templates/modules/contact/backend/java-spring/backend/src/main/resources/db/migration/V2__contact.sql +7 -0
- package/tools/templates/modules/contact/frontend/svelte/frontend/src/routes/contact/+page.svelte +80 -0
- package/tools/templates/modules/payments/backend/java-spring/backend/src/main/java/com/app/controller/PaymentController.java +69 -0
- package/tools/templates/modules/payments/backend/node-express/backend/src/routes/payments.ts +30 -0
- package/tools/templates/modules/payments/backend/node-express/backend/src/routes/webhook.ts +36 -0
- package/tools/templates/modules/payments/frontend/svelte/frontend/src/lib/payments.ts +28 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
model User {
|
|
11
|
+
id BigInt @id @default(autoincrement())
|
|
12
|
+
email String @unique @db.VarChar(255)
|
|
13
|
+
name String? @db.VarChar(120)
|
|
14
|
+
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
15
|
+
|
|
16
|
+
roles UserRole[]
|
|
17
|
+
|
|
18
|
+
@@map("users")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
model Role {
|
|
22
|
+
id Int @id @default(autoincrement())
|
|
23
|
+
name String @unique @db.VarChar(30)
|
|
24
|
+
|
|
25
|
+
users UserRole[]
|
|
26
|
+
|
|
27
|
+
@@map("roles")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
model UserRole {
|
|
31
|
+
userId BigInt @map("user_id")
|
|
32
|
+
roleId Int @map("role_id")
|
|
33
|
+
|
|
34
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
35
|
+
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
36
|
+
|
|
37
|
+
@@id([userId, roleId])
|
|
38
|
+
@@map("user_roles")
|
|
39
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
NG_APP_API_BASE=http://localhost:8080
|
|
2
|
+
<% if (modules.auth) { -%>
|
|
3
|
+
NG_APP_AUTH0_DOMAIN=your-tenant.us.auth0.com
|
|
4
|
+
NG_APP_AUTH0_CLIENT_ID=your_spa_client_id
|
|
5
|
+
NG_APP_AUTH0_AUDIENCE=https://api.<%= appSlug %>
|
|
6
|
+
<% } -%>
|
|
7
|
+
<% if (modules.payments) { -%>
|
|
8
|
+
NG_APP_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
|
9
|
+
<% } -%>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"<%= appSlug %>-frontend": {
|
|
7
|
+
"projectType": "application",
|
|
8
|
+
"schematics": {
|
|
9
|
+
"@schematics/angular:component": {
|
|
10
|
+
"standalone": true
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"root": "",
|
|
14
|
+
"sourceRoot": "src",
|
|
15
|
+
"prefix": "app",
|
|
16
|
+
"architect": {
|
|
17
|
+
"build": {
|
|
18
|
+
"builder": "@angular-devkit/build-angular:application",
|
|
19
|
+
"options": {
|
|
20
|
+
"outputPath": "dist",
|
|
21
|
+
"index": "src/index.html",
|
|
22
|
+
"browser": "src/main.ts",
|
|
23
|
+
"polyfills": ["zone.js"],
|
|
24
|
+
"tsConfig": "tsconfig.app.json",
|
|
25
|
+
"assets": ["src/favicon.ico", "src/assets"],
|
|
26
|
+
"styles": ["src/styles.css"],
|
|
27
|
+
"scripts": []
|
|
28
|
+
},
|
|
29
|
+
"configurations": {
|
|
30
|
+
"production": {
|
|
31
|
+
"budgets": [
|
|
32
|
+
{
|
|
33
|
+
"type": "initial",
|
|
34
|
+
"maximumWarning": "500kb",
|
|
35
|
+
"maximumError": "1mb"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"outputHashing": "all"
|
|
39
|
+
},
|
|
40
|
+
"development": {
|
|
41
|
+
"optimization": false,
|
|
42
|
+
"extractLicenses": false,
|
|
43
|
+
"sourceMap": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"defaultConfiguration": "production"
|
|
47
|
+
},
|
|
48
|
+
"serve": {
|
|
49
|
+
"builder": "@angular-devkit/build-angular:dev-server",
|
|
50
|
+
"configurations": {
|
|
51
|
+
"production": {
|
|
52
|
+
"buildTarget": "<%= appSlug %>-frontend:build:production"
|
|
53
|
+
},
|
|
54
|
+
"development": {
|
|
55
|
+
"buildTarget": "<%= appSlug %>-frontend:build:development"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"defaultConfiguration": "development",
|
|
59
|
+
"options": {
|
|
60
|
+
"port": 5173
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= appSlug %>-frontend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "ng serve",
|
|
7
|
+
"build": "ng build",
|
|
8
|
+
"watch": "ng build --watch --configuration development",
|
|
9
|
+
"test": "ng test"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@angular/animations": "^19.0.0",
|
|
13
|
+
"@angular/common": "^19.0.0",
|
|
14
|
+
"@angular/compiler": "^19.0.0",
|
|
15
|
+
"@angular/core": "^19.0.0",
|
|
16
|
+
"@angular/forms": "^19.0.0",
|
|
17
|
+
"@angular/platform-browser": "^19.0.0",
|
|
18
|
+
"@angular/platform-browser-dynamic": "^19.0.0",
|
|
19
|
+
"@angular/router": "^19.0.0",
|
|
20
|
+
"@auth0/auth0-spa-js": "^2.1.3",
|
|
21
|
+
"rxjs": "^7.8.1",
|
|
22
|
+
"tslib": "^2.7.0",
|
|
23
|
+
"zone.js": "^0.15.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@angular-devkit/build-angular": "^19.0.0",
|
|
27
|
+
"@angular/cli": "^19.0.0",
|
|
28
|
+
"@angular/compiler-cli": "^19.0.0",
|
|
29
|
+
"typescript": "~5.6.3"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { RouterOutlet, RouterLink } from '@angular/router';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-root',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [RouterOutlet, RouterLink],
|
|
8
|
+
template: `
|
|
9
|
+
<div class="app">
|
|
10
|
+
<nav>
|
|
11
|
+
<a routerLink="/">Home</a>
|
|
12
|
+
<% if (modules.contact) { -%>
|
|
13
|
+
<a routerLink="/contact">Contact</a>
|
|
14
|
+
<% } -%>
|
|
15
|
+
<% if (modules.auth) { -%>
|
|
16
|
+
<a routerLink="/login">Login</a>
|
|
17
|
+
<% } -%>
|
|
18
|
+
<% if (modules.admin) { -%>
|
|
19
|
+
<a routerLink="/dashboard">Dashboard</a>
|
|
20
|
+
<% } -%>
|
|
21
|
+
</nav>
|
|
22
|
+
<main>
|
|
23
|
+
<router-outlet />
|
|
24
|
+
</main>
|
|
25
|
+
</div>
|
|
26
|
+
`
|
|
27
|
+
})
|
|
28
|
+
export class AppComponent {
|
|
29
|
+
title = '<%= appName %>';
|
|
30
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { HomeComponent } from './components/home.component';
|
|
3
|
+
<% if (modules.contact) { -%>
|
|
4
|
+
import { ContactComponent } from './components/contact.component';
|
|
5
|
+
<% } -%>
|
|
6
|
+
<% if (modules.admin) { -%>
|
|
7
|
+
import { DashboardComponent } from './components/dashboard.component';
|
|
8
|
+
<% } -%>
|
|
9
|
+
|
|
10
|
+
export const routes: Routes = [
|
|
11
|
+
{ path: '', component: HomeComponent },
|
|
12
|
+
<% if (modules.contact) { -%>
|
|
13
|
+
{ path: 'contact', component: ContactComponent },
|
|
14
|
+
<% } -%>
|
|
15
|
+
<% if (modules.admin) { -%>
|
|
16
|
+
{ path: 'dashboard', component: DashboardComponent },
|
|
17
|
+
<% } -%>
|
|
18
|
+
];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'app-home',
|
|
5
|
+
standalone: true,
|
|
6
|
+
template: `
|
|
7
|
+
<div>
|
|
8
|
+
<h1>Welcome to <%= AppName %></h1>
|
|
9
|
+
<p>This is a full-stack application built with:</p>
|
|
10
|
+
<ul>
|
|
11
|
+
<li>Frontend: <%= frontend %></li>
|
|
12
|
+
<li>Backend: <%= backend %></li>
|
|
13
|
+
<li>Database: <%= db %></li>
|
|
14
|
+
<% if (modules.auth) { -%>
|
|
15
|
+
<li>Auth: <%= auth %></li>
|
|
16
|
+
<% } -%>
|
|
17
|
+
<% if (modules.payments) { -%>
|
|
18
|
+
<li>Payments: <%= payments %></li>
|
|
19
|
+
<% } -%>
|
|
20
|
+
</ul>
|
|
21
|
+
</div>
|
|
22
|
+
`
|
|
23
|
+
})
|
|
24
|
+
export class HomeComponent {}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Injectable({
|
|
4
|
+
providedIn: 'root'
|
|
5
|
+
})
|
|
6
|
+
export class ApiService {
|
|
7
|
+
private readonly apiBase = 'http://localhost:8080'; // Configure via environment
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Fetch wrapper that automatically adds API base URL
|
|
11
|
+
*/
|
|
12
|
+
async fetch<T = any>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
13
|
+
const url = `${this.apiBase}${endpoint}`;
|
|
14
|
+
|
|
15
|
+
const config: RequestInit = {
|
|
16
|
+
...options,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...options.headers,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const response = await fetch(url, config);
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`API Error: ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return response.json();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Example usage in components:
|
|
34
|
+
*
|
|
35
|
+
* constructor(private api: ApiService) {}
|
|
36
|
+
*
|
|
37
|
+
* async ngOnInit() {
|
|
38
|
+
* // GET request
|
|
39
|
+
* const data = await this.api.fetch('/api/example');
|
|
40
|
+
*
|
|
41
|
+
* // POST request
|
|
42
|
+
* const result = await this.api.fetch('/api/contact', {
|
|
43
|
+
* method: 'POST',
|
|
44
|
+
* body: JSON.stringify({ name: 'John', email: 'john@example.com' })
|
|
45
|
+
* });
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- Placeholder favicon -->
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title><%= AppName %></title>
|
|
6
|
+
<base href="/">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<app-root></app-root>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
2
|
+
import { provideRouter } from '@angular/router';
|
|
3
|
+
import { AppComponent } from './app/app.component';
|
|
4
|
+
import { routes } from './app/app.routes';
|
|
5
|
+
|
|
6
|
+
bootstrapApplication(AppComponent, {
|
|
7
|
+
providers: [
|
|
8
|
+
provideRouter(routes)
|
|
9
|
+
]
|
|
10
|
+
}).catch(err => console.error(err));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.app {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
min-height: 100vh;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
nav {
|
|
13
|
+
display: flex;
|
|
14
|
+
gap: 1rem;
|
|
15
|
+
padding: 1rem;
|
|
16
|
+
background: #f0f0f0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
nav a {
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
color: #333;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
nav a:hover {
|
|
25
|
+
text-decoration: underline;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main {
|
|
29
|
+
flex: 1;
|
|
30
|
+
padding: 2rem;
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compileOnSave": false,
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist/out-tsc",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"noImplicitOverride": true,
|
|
7
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
8
|
+
"noImplicitReturns": true,
|
|
9
|
+
"noFallthroughCasesInSwitch": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"sourceMap": true,
|
|
13
|
+
"declaration": false,
|
|
14
|
+
"experimentalDecorators": true,
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"importHelpers": true,
|
|
17
|
+
"target": "ES2022",
|
|
18
|
+
"module": "ES2022",
|
|
19
|
+
"lib": ["ES2022", "dom"]
|
|
20
|
+
},
|
|
21
|
+
"angularCompilerOptions": {
|
|
22
|
+
"enableI18nLegacyMessageIdFormat": false,
|
|
23
|
+
"strictInjectionParameters": true,
|
|
24
|
+
"strictInputAccessModifiers": true,
|
|
25
|
+
"strictTemplates": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
NEXT_PUBLIC_API_BASE=http://localhost:8080
|
|
2
|
+
<% if (modules.auth) { -%>
|
|
3
|
+
NEXT_PUBLIC_AUTH0_DOMAIN=your-tenant.us.auth0.com
|
|
4
|
+
NEXT_PUBLIC_AUTH0_CLIENT_ID=your_spa_client_id
|
|
5
|
+
NEXT_PUBLIC_AUTH0_AUDIENCE=https://api.<%= appSlug %>
|
|
6
|
+
<% } -%>
|
|
7
|
+
<% if (modules.payments) { -%>
|
|
8
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
|
9
|
+
<% } -%>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
reactStrictMode: true,
|
|
4
|
+
swcMinify: true,
|
|
5
|
+
compiler: {
|
|
6
|
+
removeConsole: process.env.NODE_ENV === 'production'
|
|
7
|
+
},
|
|
8
|
+
poweredByHeader: false,
|
|
9
|
+
compress: true,
|
|
10
|
+
images: {
|
|
11
|
+
formats: ['image/avif', 'image/webp'],
|
|
12
|
+
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
|
13
|
+
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
14
|
+
},
|
|
15
|
+
webpack: (config, { isServer }) => {
|
|
16
|
+
// Performance optimizations
|
|
17
|
+
config.optimization.minimize = true;
|
|
18
|
+
|
|
19
|
+
return config;
|
|
20
|
+
},
|
|
21
|
+
experimental: {
|
|
22
|
+
optimizeCss: true,
|
|
23
|
+
optimizePackageImports: ['react', 'react-dom'],
|
|
24
|
+
},
|
|
25
|
+
// Enable faster builds in development
|
|
26
|
+
...(process.env.NODE_ENV === 'development' && {
|
|
27
|
+
webpack: (config) => {
|
|
28
|
+
config.watchOptions = {
|
|
29
|
+
poll: 1000,
|
|
30
|
+
aggregateTimeout: 300,
|
|
31
|
+
};
|
|
32
|
+
return config;
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = nextConfig
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= appSlug %>-frontend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev -p 5173",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start -p 5173",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^19.0.0",
|
|
13
|
+
"react-dom": "^19.0.0",
|
|
14
|
+
"next": "^15.1.0",
|
|
15
|
+
"@auth0/auth0-spa-js": "^2.1.3"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.6.3",
|
|
19
|
+
"@types/node": "^22.0.0",
|
|
20
|
+
"@types/react": "^19.0.0",
|
|
21
|
+
"@types/react-dom": "^19.0.0",
|
|
22
|
+
"eslint": "^9.0.0",
|
|
23
|
+
"eslint-config-next": "^15.1.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.app {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
min-height: 100vh;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
nav {
|
|
13
|
+
display: flex;
|
|
14
|
+
gap: 1rem;
|
|
15
|
+
padding: 1rem;
|
|
16
|
+
background: #f0f0f0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
nav a {
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
color: #333;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
nav a:hover {
|
|
25
|
+
text-decoration: underline;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main {
|
|
29
|
+
flex: 1;
|
|
30
|
+
padding: 2rem;
|
|
31
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import Link from 'next/link';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: '<%= AppName %>',
|
|
7
|
+
description: 'Generated by create-stack',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function RootLayout({
|
|
11
|
+
children,
|
|
12
|
+
}: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<body>
|
|
18
|
+
<div className="app">
|
|
19
|
+
<nav>
|
|
20
|
+
<Link href="/">Home</Link>
|
|
21
|
+
<% if (modules.contact) { -%>
|
|
22
|
+
<Link href="/contact">Contact</Link>
|
|
23
|
+
<% } -%>
|
|
24
|
+
<% if (modules.auth) { -%>
|
|
25
|
+
<Link href="/login">Login</Link>
|
|
26
|
+
<% } -%>
|
|
27
|
+
<% if (modules.admin) { -%>
|
|
28
|
+
<Link href="/dashboard">Dashboard</Link>
|
|
29
|
+
<% } -%>
|
|
30
|
+
</nav>
|
|
31
|
+
<main>{children}</main>
|
|
32
|
+
</div>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function Home() {
|
|
2
|
+
return (
|
|
3
|
+
<div>
|
|
4
|
+
<h1>Welcome to <%= AppName %></h1>
|
|
5
|
+
<p>This is a full-stack application built with:</p>
|
|
6
|
+
<ul>
|
|
7
|
+
<li>Frontend: <%= frontend %></li>
|
|
8
|
+
<li>Backend: <%= backend %></li>
|
|
9
|
+
<li>Database: <%= db %></li>
|
|
10
|
+
<% if (modules.auth) { -%>
|
|
11
|
+
<li>Auth: <%= auth %></li>
|
|
12
|
+
<% } -%>
|
|
13
|
+
<% if (modules.payments) { -%>
|
|
14
|
+
<li>Payments: <%= payments %></li>
|
|
15
|
+
<% } -%>
|
|
16
|
+
</ul>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// API base URL from environment
|
|
2
|
+
const API_BASE = process.env.NEXT_PUBLIC_API_BASE || 'http://localhost:8080';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch wrapper that automatically adds API base URL
|
|
6
|
+
* @param endpoint - API endpoint (e.g., '/api/example')
|
|
7
|
+
* @param options - Fetch options
|
|
8
|
+
*/
|
|
9
|
+
export async function apiFetch<T = any>(
|
|
10
|
+
endpoint: string,
|
|
11
|
+
options: RequestInit = {}
|
|
12
|
+
): Promise<T> {
|
|
13
|
+
const url = `${API_BASE}${endpoint}`;
|
|
14
|
+
|
|
15
|
+
const config: RequestInit = {
|
|
16
|
+
...options,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...options.headers,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const response = await fetch(url, config);
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`API Error: ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return response.json();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Example usage in components:
|
|
34
|
+
*
|
|
35
|
+
* import { apiFetch } from '@/lib/api';
|
|
36
|
+
*
|
|
37
|
+
* // GET request
|
|
38
|
+
* const data = await apiFetch('/api/example');
|
|
39
|
+
*
|
|
40
|
+
* // POST request
|
|
41
|
+
* const result = await apiFetch('/api/contact', {
|
|
42
|
+
* method: 'POST',
|
|
43
|
+
* body: JSON.stringify({ name: 'John', email: 'john@example.com' })
|
|
44
|
+
* });
|
|
45
|
+
*/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
26
|
+
"exclude": ["node_modules"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
VITE_API_BASE=http://localhost:8080
|
|
2
|
+
<% if (modules.auth) { -%>
|
|
3
|
+
VITE_AUTH0_DOMAIN=your-tenant.us.auth0.com
|
|
4
|
+
VITE_AUTH0_CLIENT_ID=your_spa_client_id
|
|
5
|
+
VITE_AUTH0_AUDIENCE=https://api.<%= appSlug %>
|
|
6
|
+
<% } -%>
|
|
7
|
+
<% if (modules.payments) { -%>
|
|
8
|
+
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
|
9
|
+
<% } -%>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"eslint:recommended",
|
|
4
|
+
"plugin:react/recommended",
|
|
5
|
+
"plugin:react/jsx-runtime",
|
|
6
|
+
"plugin:react-hooks/recommended"
|
|
7
|
+
],
|
|
8
|
+
"parserOptions": {
|
|
9
|
+
"ecmaVersion": "latest",
|
|
10
|
+
"sourceType": "module",
|
|
11
|
+
"ecmaFeatures": {
|
|
12
|
+
"jsx": true
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"settings": {
|
|
16
|
+
"react": {
|
|
17
|
+
"version": "detect"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"rules": {
|
|
21
|
+
"react-hooks/rules-of-hooks": "error",
|
|
22
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
23
|
+
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
|
24
|
+
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
|
25
|
+
"react/prop-types": "off"
|
|
26
|
+
},
|
|
27
|
+
"env": {
|
|
28
|
+
"browser": true,
|
|
29
|
+
"es2021": true,
|
|
30
|
+
"node": true
|
|
31
|
+
}
|
|
32
|
+
}
|