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,30 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
server: {
|
|
7
|
+
port: 5173,
|
|
8
|
+
hmr: {
|
|
9
|
+
overlay: true
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
build: {
|
|
13
|
+
target: 'esnext',
|
|
14
|
+
minify: 'esbuild',
|
|
15
|
+
cssMinify: true,
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
output: {
|
|
18
|
+
manualChunks: {
|
|
19
|
+
'react-vendor': ['react', 'react-dom'],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
chunkSizeWarningLimit: 1000,
|
|
24
|
+
sourcemap: false
|
|
25
|
+
},
|
|
26
|
+
optimizeDeps: {
|
|
27
|
+
include: ['react', 'react-dom'],
|
|
28
|
+
force: false
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
test: {
|
|
7
|
+
globals: true,
|
|
8
|
+
environment: 'jsdom',
|
|
9
|
+
setupFiles: './src/setupTests.js',
|
|
10
|
+
css: true,
|
|
11
|
+
coverage: {
|
|
12
|
+
provider: 'v8',
|
|
13
|
+
reporter: ['text', 'json', 'html'],
|
|
14
|
+
exclude: [
|
|
15
|
+
'node_modules/',
|
|
16
|
+
'src/setupTests.js',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
PUBLIC_API_BASE=http://localhost:8080
|
|
2
|
+
<% if (modules.auth) { -%>
|
|
3
|
+
PUBLIC_AUTH0_DOMAIN=your-tenant.us.auth0.com
|
|
4
|
+
PUBLIC_AUTH0_CLIENT_ID=your_spa_client_id
|
|
5
|
+
PUBLIC_AUTH0_AUDIENCE=https://api.<%= appSlug %>
|
|
6
|
+
<% } -%>
|
|
7
|
+
<% if (modules.payments) { -%>
|
|
8
|
+
PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
|
9
|
+
<% } -%>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= appSlug %>-frontend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite dev",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@sveltejs/adapter-auto": "^3.0.0",
|
|
13
|
+
"@sveltejs/kit": "^2.0.0",
|
|
14
|
+
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
|
15
|
+
"svelte": "^5.0.0",
|
|
16
|
+
"vite": "^6.0.0"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@auth0/auth0-spa-js": "^2.1.3"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
%sveltekit.head%
|
|
8
|
+
</head>
|
|
9
|
+
<body data-sveltekit-preload-data="hover">
|
|
10
|
+
<div style="display: contents">%sveltekit.body%</div>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// API base URL from environment
|
|
2
|
+
const API_BASE = import.meta.env.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,56 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { page } from '$app/stores';
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div class="app">
|
|
6
|
+
<nav>
|
|
7
|
+
<a href="/">Home</a>
|
|
8
|
+
<% if (modules.contact) { -%>
|
|
9
|
+
<a href="/contact">Contact</a>
|
|
10
|
+
<% } -%>
|
|
11
|
+
<% if (modules.auth) { -%>
|
|
12
|
+
<a href="/login">Login</a>
|
|
13
|
+
<% } -%>
|
|
14
|
+
<% if (modules.admin) { -%>
|
|
15
|
+
<a href="/dashboard">Dashboard</a>
|
|
16
|
+
<% } -%>
|
|
17
|
+
</nav>
|
|
18
|
+
|
|
19
|
+
<main>
|
|
20
|
+
<slot />
|
|
21
|
+
</main>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
.app {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
min-height: 100vh;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
nav {
|
|
32
|
+
display: flex;
|
|
33
|
+
gap: 1rem;
|
|
34
|
+
padding: 1rem;
|
|
35
|
+
background: #f0f0f0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
nav a {
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
color: #333;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
nav a:hover {
|
|
44
|
+
text-decoration: underline;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
main {
|
|
48
|
+
flex: 1;
|
|
49
|
+
padding: 2rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:global(body) {
|
|
53
|
+
margin: 0;
|
|
54
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<h1>Welcome to <%= AppName %></h1>
|
|
2
|
+
|
|
3
|
+
<p>This is a full-stack application built with:</p>
|
|
4
|
+
<ul>
|
|
5
|
+
<li>Frontend: <%= frontend %></li>
|
|
6
|
+
<li>Backend: <%= backend %></li>
|
|
7
|
+
<li>Database: <%= db %></li>
|
|
8
|
+
<% if (modules.auth) { -%>
|
|
9
|
+
<li>Auth: <%= auth %></li>
|
|
10
|
+
<% } -%>
|
|
11
|
+
<% if (modules.payments) { -%>
|
|
12
|
+
<li>Payments: <%= payments %></li>
|
|
13
|
+
<% } -%>
|
|
14
|
+
</ul>
|
|
15
|
+
|
|
16
|
+
<style>
|
|
17
|
+
h1 {
|
|
18
|
+
color: #333;
|
|
19
|
+
}
|
|
20
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- Placeholder favicon file -->
|
|
@@ -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,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<link rel="icon" href="/favicon.ico">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title><%= AppName %></title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= appSlug %>-frontend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"vue": "^3.5.0",
|
|
13
|
+
"vue-router": "^4.4.0",
|
|
14
|
+
"@auth0/auth0-spa-js": "^2.1.3"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@vitejs/plugin-vue": "^5.2.1",
|
|
18
|
+
"vite": "^6.0.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<nav>
|
|
4
|
+
<router-link to="/">Home</router-link>
|
|
5
|
+
<% if (modules.contact) { -%>
|
|
6
|
+
<router-link to="/contact">Contact</router-link>
|
|
7
|
+
<% } -%>
|
|
8
|
+
<% if (modules.auth) { -%>
|
|
9
|
+
<router-link to="/login">Login</router-link>
|
|
10
|
+
<% } -%>
|
|
11
|
+
<% if (modules.admin) { -%>
|
|
12
|
+
<router-link to="/dashboard">Dashboard</router-link>
|
|
13
|
+
<% } -%>
|
|
14
|
+
</nav>
|
|
15
|
+
<main>
|
|
16
|
+
<router-view />
|
|
17
|
+
</main>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
export default {
|
|
23
|
+
name: 'App'
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<style>
|
|
28
|
+
body {
|
|
29
|
+
margin: 0;
|
|
30
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#app {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
min-height: 100vh;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
nav {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 1rem;
|
|
42
|
+
padding: 1rem;
|
|
43
|
+
background: #f0f0f0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
nav a {
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
color: #333;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
nav a:hover,
|
|
52
|
+
nav a.router-link-active {
|
|
53
|
+
text-decoration: underline;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
main {
|
|
57
|
+
flex: 1;
|
|
58
|
+
padding: 2rem;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// API base URL from environment
|
|
2
|
+
const API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:8080';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch wrapper that automatically adds API base URL
|
|
6
|
+
* @param {string} endpoint - API endpoint (e.g., '/api/example')
|
|
7
|
+
* @param {RequestInit} options - Fetch options
|
|
8
|
+
*/
|
|
9
|
+
export async function apiFetch(endpoint, options = {}) {
|
|
10
|
+
const url = `${API_BASE}${endpoint}`;
|
|
11
|
+
|
|
12
|
+
const config = {
|
|
13
|
+
...options,
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
...options.headers,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const response = await fetch(url, config);
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`API Error: ${response.statusText}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return response.json();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Example usage in components:
|
|
31
|
+
*
|
|
32
|
+
* import { apiFetch } from '@/lib/api';
|
|
33
|
+
*
|
|
34
|
+
* // GET request
|
|
35
|
+
* const data = await apiFetch('/api/example');
|
|
36
|
+
*
|
|
37
|
+
* // POST request
|
|
38
|
+
* const result = await apiFetch('/api/contact', {
|
|
39
|
+
* method: 'POST',
|
|
40
|
+
* body: JSON.stringify({ name: 'John', email: 'john@example.com' })
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createApp } from 'vue';
|
|
2
|
+
import { createRouter, createWebHistory } from 'vue-router';
|
|
3
|
+
import App from './App.vue';
|
|
4
|
+
import Home from './views/Home.vue';
|
|
5
|
+
<% if (modules.contact) { -%>
|
|
6
|
+
import Contact from './views/Contact.vue';
|
|
7
|
+
<% } -%>
|
|
8
|
+
<% if (modules.admin) { -%>
|
|
9
|
+
import Dashboard from './views/Dashboard.vue';
|
|
10
|
+
<% } -%>
|
|
11
|
+
|
|
12
|
+
const routes = [
|
|
13
|
+
{ path: '/', component: Home },
|
|
14
|
+
<% if (modules.contact) { -%>
|
|
15
|
+
{ path: '/contact', component: Contact },
|
|
16
|
+
<% } -%>
|
|
17
|
+
<% if (modules.auth) { -%>
|
|
18
|
+
{ path: '/login', component: () => import('./views/Login.vue') },
|
|
19
|
+
{ path: '/callback', component: () => import('./views/Callback.vue') },
|
|
20
|
+
<% } -%>
|
|
21
|
+
<% if (modules.admin) { -%>
|
|
22
|
+
{ path: '/dashboard', component: Dashboard },
|
|
23
|
+
<% } -%>
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const router = createRouter({
|
|
27
|
+
history: createWebHistory(),
|
|
28
|
+
routes
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const app = createApp(App);
|
|
32
|
+
app.use(router);
|
|
33
|
+
app.mount('#app');
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="margin-top: 2rem; padding: 1rem; background: #f5f5f5; border-radius: 8px;">
|
|
3
|
+
<h3>API Connection Test</h3>
|
|
4
|
+
<p v-if="loading">Testing backend connection...</p>
|
|
5
|
+
<p v-if="error" style="color: red;">❌ Error: {{ error }}</p>
|
|
6
|
+
<p v-if="apiMessage" style="color: green;">✅ {{ apiMessage }}</p>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
import { ref, onMounted } from 'vue';
|
|
12
|
+
import { apiFetch } from '@/lib/api';
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
name: 'ApiTest',
|
|
16
|
+
setup() {
|
|
17
|
+
const apiMessage = ref('');
|
|
18
|
+
const loading = ref(true);
|
|
19
|
+
const error = ref('');
|
|
20
|
+
|
|
21
|
+
onMounted(async () => {
|
|
22
|
+
try {
|
|
23
|
+
const data = await apiFetch('/api/example');
|
|
24
|
+
apiMessage.value = data.message;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
error.value = err.message;
|
|
27
|
+
} finally {
|
|
28
|
+
loading.value = false;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
apiMessage,
|
|
34
|
+
loading,
|
|
35
|
+
error
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>Welcome to <%= AppName %></h1>
|
|
4
|
+
<p>This is a full-stack application built with:</p>
|
|
5
|
+
<ul>
|
|
6
|
+
<li>Frontend: <%= frontend %></li>
|
|
7
|
+
<li>Backend: <%= backend %></li>
|
|
8
|
+
<li>Database: <%= db %></li>
|
|
9
|
+
<% if (modules.auth) { -%>
|
|
10
|
+
<li>Auth: <%= auth %></li>
|
|
11
|
+
<% } -%>
|
|
12
|
+
<% if (modules.payments) { -%>
|
|
13
|
+
<li>Payments: <%= payments %></li>
|
|
14
|
+
<% } -%>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
<ApiTest />
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
import ApiTest from './ApiTest.vue';
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: 'Home',
|
|
26
|
+
components: {
|
|
27
|
+
ApiTest
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package com.app.controller;
|
|
2
|
+
|
|
3
|
+
import com.app.repository.UserRepository;
|
|
4
|
+
<% if (modules.contact) { -%>
|
|
5
|
+
import com.app.repository.ContactMessageRepository;
|
|
6
|
+
<% } -%>
|
|
7
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
8
|
+
import org.springframework.http.ResponseEntity;
|
|
9
|
+
import org.springframework.security.access.prepost.PreAuthorize;
|
|
10
|
+
import org.springframework.web.bind.annotation.*;
|
|
11
|
+
|
|
12
|
+
import java.util.Map;
|
|
13
|
+
|
|
14
|
+
@RestController
|
|
15
|
+
@RequestMapping("/api/admin")
|
|
16
|
+
public class AdminController {
|
|
17
|
+
|
|
18
|
+
@Autowired
|
|
19
|
+
private UserRepository userRepository;
|
|
20
|
+
|
|
21
|
+
<% if (modules.contact) { -%>
|
|
22
|
+
@Autowired
|
|
23
|
+
private ContactMessageRepository contactMessageRepository;
|
|
24
|
+
|
|
25
|
+
<% } -%>
|
|
26
|
+
@GetMapping("/stats")
|
|
27
|
+
@PreAuthorize("hasAuthority('SCOPE_admin')")
|
|
28
|
+
public ResponseEntity<?> getStats() {
|
|
29
|
+
long userCount = userRepository.count();
|
|
30
|
+
<% if (modules.contact) { -%>
|
|
31
|
+
long contactCount = contactMessageRepository.count();
|
|
32
|
+
|
|
33
|
+
return ResponseEntity.ok(Map.of(
|
|
34
|
+
"users", userCount,
|
|
35
|
+
"contacts", contactCount
|
|
36
|
+
));
|
|
37
|
+
<% } else { -%>
|
|
38
|
+
return ResponseEntity.ok(Map.of("users", userCount));
|
|
39
|
+
<% } -%>
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.app.entity;
|
|
2
|
+
|
|
3
|
+
import jakarta.persistence.*;
|
|
4
|
+
import java.time.Instant;
|
|
5
|
+
|
|
6
|
+
@Entity
|
|
7
|
+
@Table(name = "users")
|
|
8
|
+
public class User {
|
|
9
|
+
|
|
10
|
+
@Id
|
|
11
|
+
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
12
|
+
private Long id;
|
|
13
|
+
|
|
14
|
+
@Column(unique = true, nullable = false, length = 255)
|
|
15
|
+
private String email;
|
|
16
|
+
|
|
17
|
+
@Column(length = 120)
|
|
18
|
+
private String name;
|
|
19
|
+
|
|
20
|
+
@Column(name = "created_at", nullable = false, updatable = false)
|
|
21
|
+
private Instant createdAt = Instant.now();
|
|
22
|
+
|
|
23
|
+
// Getters and setters
|
|
24
|
+
public Long getId() {
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void setId(Long id) {
|
|
29
|
+
this.id = id;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public String getEmail() {
|
|
33
|
+
return email;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public void setEmail(String email) {
|
|
37
|
+
this.email = email;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public String getName() {
|
|
41
|
+
return name;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public void setName(String name) {
|
|
45
|
+
this.name = name;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public Instant getCreatedAt() {
|
|
49
|
+
return createdAt;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public void setCreatedAt(Instant createdAt) {
|
|
53
|
+
this.createdAt = createdAt;
|
|
54
|
+
}
|
|
55
|
+
}
|