@quanticjs/create-app 0.1.1
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/dist/deps.d.ts +4 -0
- package/dist/deps.js +97 -0
- package/dist/deps.js.map +1 -0
- package/dist/generators/backend.d.ts +2 -0
- package/dist/generators/backend.js +20 -0
- package/dist/generators/backend.js.map +1 -0
- package/dist/generators/bff.d.ts +2 -0
- package/dist/generators/bff.js +9 -0
- package/dist/generators/bff.js.map +1 -0
- package/dist/generators/claude.d.ts +2 -0
- package/dist/generators/claude.js +45 -0
- package/dist/generators/claude.js.map +1 -0
- package/dist/generators/docker.d.ts +2 -0
- package/dist/generators/docker.js +10 -0
- package/dist/generators/docker.js.map +1 -0
- package/dist/generators/e2e.d.ts +2 -0
- package/dist/generators/e2e.js +8 -0
- package/dist/generators/e2e.js.map +1 -0
- package/dist/generators/frontend.d.ts +2 -0
- package/dist/generators/frontend.js +28 -0
- package/dist/generators/frontend.js.map +1 -0
- package/dist/generators/module.d.ts +2 -0
- package/dist/generators/module.js +35 -0
- package/dist/generators/module.js.map +1 -0
- package/dist/generators/root.d.ts +2 -0
- package/dist/generators/root.js +7 -0
- package/dist/generators/root.js.map +1 -0
- package/dist/generators/scripts.d.ts +2 -0
- package/dist/generators/scripts.js +10 -0
- package/dist/generators/scripts.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +8 -0
- package/dist/prompts.js +53 -0
- package/dist/prompts.js.map +1 -0
- package/dist/scaffold.d.ts +2 -0
- package/dist/scaffold.js +79 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/utils/exec.d.ts +2 -0
- package/dist/utils/exec.js +14 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/template.d.ts +10 -0
- package/dist/utils/template.js +20 -0
- package/dist/utils/template.js.map +1 -0
- package/dist/utils/validate.d.ts +4 -0
- package/dist/utils/validate.js +27 -0
- package/dist/utils/validate.js.map +1 -0
- package/package.json +50 -0
- package/templates/backend/app.module.ts.ejs +61 -0
- package/templates/backend/bff.controller.ts.ejs +60 -0
- package/templates/backend/bff.module.ts.ejs +10 -0
- package/templates/backend/bff.service.ts.ejs +6 -0
- package/templates/backend/create-schema.migration.ts.ejs +15 -0
- package/templates/backend/data-source.ts.ejs +13 -0
- package/templates/backend/env.example.ejs +30 -0
- package/templates/backend/main.ts.ejs +43 -0
- package/templates/backend/module.ts.ejs +14 -0
- package/templates/backend/nest-cli.json.ejs +8 -0
- package/templates/backend/package.json.ejs +23 -0
- package/templates/backend/tsconfig.build.json.ejs +4 -0
- package/templates/backend/tsconfig.json.ejs +24 -0
- package/templates/claude/CLAUDE.md.ejs +86 -0
- package/templates/claude/hooks/auto-format.sh +22 -0
- package/templates/claude/hooks/check-secrets.sh +49 -0
- package/templates/claude/hooks/guard-destructive.sh +42 -0
- package/templates/claude/hooks/on-compaction.sh +29 -0
- package/templates/claude/mcp.json +10 -0
- package/templates/claude/rules/api-patterns.md +86 -0
- package/templates/claude/rules/auth-patterns.md +109 -0
- package/templates/claude/rules/backend-patterns.md +421 -0
- package/templates/claude/rules/database-patterns.md +96 -0
- package/templates/claude/rules/docker-patterns.md +86 -0
- package/templates/claude/rules/frontend-patterns.md +262 -0
- package/templates/claude/rules/observability-backend.md +132 -0
- package/templates/claude/rules/observability-frontend.md +49 -0
- package/templates/claude/rules/playwright-mcp.md +80 -0
- package/templates/claude/rules/resilience-ops.md +103 -0
- package/templates/claude/rules/testing-e2e-ui.md +190 -0
- package/templates/claude/rules/testing-patterns.md +94 -0
- package/templates/claude/rules/workflow-backend.md +64 -0
- package/templates/claude/rules/workflow-frontend.md +60 -0
- package/templates/claude/settings.json +68 -0
- package/templates/claude/skills/add-api-endpoint/SKILL.md +59 -0
- package/templates/claude/skills/add-auth-endpoint/SKILL.md +68 -0
- package/templates/claude/skills/add-entity/SKILL.md +56 -0
- package/templates/claude/skills/add-event/SKILL.md +127 -0
- package/templates/claude/skills/add-feature/SKILL.md +20 -0
- package/templates/claude/skills/add-frontend-page/SKILL.md +75 -0
- package/templates/claude/skills/add-handler/SKILL.md +105 -0
- package/templates/claude/skills/add-integration/SKILL.md +176 -0
- package/templates/claude/skills/add-migration/SKILL.md +20 -0
- package/templates/claude/skills/add-module/SKILL.md +89 -0
- package/templates/claude/skills/add-realtime/SKILL.md +119 -0
- package/templates/claude/skills/audit-rules/SKILL.md +120 -0
- package/templates/claude/skills/debugging/SKILL.md +105 -0
- package/templates/claude/skills/docker-dev/SKILL.md +86 -0
- package/templates/claude/skills/e2e-audit/SKILL.md +85 -0
- package/templates/claude/skills/e2e-full/SKILL.md +132 -0
- package/templates/claude/skills/e2e-scan/SKILL.md +171 -0
- package/templates/claude/skills/e2e-verify/SKILL.md +145 -0
- package/templates/claude/skills/fix-bug/SKILL.md +33 -0
- package/templates/claude/skills/implement-spec/SKILL.md +98 -0
- package/templates/claude/skills/review-code/SKILL.md +109 -0
- package/templates/claude/skills/review-spec/SKILL.md +216 -0
- package/templates/claude/skills/run-tests/SKILL.md +37 -0
- package/templates/claude/skills/specify/SKILL.md +87 -0
- package/templates/claude/skills/write-backend-tests/SKILL.md +182 -0
- package/templates/claude/skills/write-ui-tests/SKILL.md +118 -0
- package/templates/docker/Dockerfile.client.ejs +14 -0
- package/templates/docker/Dockerfile.ejs +28 -0
- package/templates/docker/docker-compose.test.yml.ejs +54 -0
- package/templates/docker/docker-compose.yml.ejs +76 -0
- package/templates/docker/nginx.conf.ejs +21 -0
- package/templates/frontend/App.tsx.ejs +64 -0
- package/templates/frontend/DashboardPage.tsx.ejs +37 -0
- package/templates/frontend/LoginPage.tsx.ejs +20 -0
- package/templates/frontend/NotFoundPage.tsx.ejs +15 -0
- package/templates/frontend/api-client.ts.ejs +15 -0
- package/templates/frontend/index.css.ejs +57 -0
- package/templates/frontend/index.html.ejs +13 -0
- package/templates/frontend/main.tsx.ejs +10 -0
- package/templates/frontend/package.json.ejs +16 -0
- package/templates/frontend/playwright.config.ts.ejs +20 -0
- package/templates/frontend/postcss.config.js.ejs +3 -0
- package/templates/frontend/smoke.spec.ts.ejs +37 -0
- package/templates/frontend/tailwind.config.ts.ejs +56 -0
- package/templates/frontend/tsconfig.json.ejs +25 -0
- package/templates/frontend/tsconfig.node.json.ejs +15 -0
- package/templates/frontend/utils.ts.ejs +6 -0
- package/templates/frontend/vite-env.d.ts.ejs +1 -0
- package/templates/frontend/vite.config.ts.ejs +20 -0
- package/templates/root/gitignore.ejs +9 -0
- package/templates/root/prettierrc.ejs +7 -0
- package/templates/scripts/init-db.sh.ejs +8 -0
- package/templates/scripts/save-auth-state.ts.ejs +24 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
@layer base {
|
|
4
|
+
:root {
|
|
5
|
+
--background: 0 0% 100%;
|
|
6
|
+
--foreground: 222.2 84% 4.9%;
|
|
7
|
+
--card: 0 0% 100%;
|
|
8
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
9
|
+
--popover: 0 0% 100%;
|
|
10
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
11
|
+
--primary: 222.2 47.4% 11.2%;
|
|
12
|
+
--primary-foreground: 210 40% 98%;
|
|
13
|
+
--secondary: 210 40% 96.1%;
|
|
14
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
15
|
+
--muted: 210 40% 96.1%;
|
|
16
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
17
|
+
--accent: 210 40% 96.1%;
|
|
18
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
19
|
+
--destructive: 0 84.2% 60.2%;
|
|
20
|
+
--destructive-foreground: 210 40% 98%;
|
|
21
|
+
--border: 214.3 31.8% 91.4%;
|
|
22
|
+
--input: 214.3 31.8% 91.4%;
|
|
23
|
+
--ring: 222.2 84% 4.9%;
|
|
24
|
+
--radius: 0.5rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.dark {
|
|
28
|
+
--background: 222.2 84% 4.9%;
|
|
29
|
+
--foreground: 210 40% 98%;
|
|
30
|
+
--card: 222.2 84% 4.9%;
|
|
31
|
+
--card-foreground: 210 40% 98%;
|
|
32
|
+
--popover: 222.2 84% 4.9%;
|
|
33
|
+
--popover-foreground: 210 40% 98%;
|
|
34
|
+
--primary: 210 40% 98%;
|
|
35
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
36
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
37
|
+
--secondary-foreground: 210 40% 98%;
|
|
38
|
+
--muted: 217.2 32.6% 17.5%;
|
|
39
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
40
|
+
--accent: 217.2 32.6% 17.5%;
|
|
41
|
+
--accent-foreground: 210 40% 98%;
|
|
42
|
+
--destructive: 0 62.8% 30.6%;
|
|
43
|
+
--destructive-foreground: 210 40% 98%;
|
|
44
|
+
--border: 217.2 32.6% 17.5%;
|
|
45
|
+
--input: 217.2 32.6% 17.5%;
|
|
46
|
+
--ring: 212.7 26.8% 83.9%;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@layer base {
|
|
51
|
+
* {
|
|
52
|
+
@apply border-border;
|
|
53
|
+
}
|
|
54
|
+
body {
|
|
55
|
+
@apply bg-background text-foreground;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" dir="ltr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title><%= projectNamePascal %></title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= projectName %>-client",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc -b && vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"test:e2e": "playwright test",
|
|
14
|
+
"test:e2e:ui": "playwright test --ui"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: './e2e',
|
|
5
|
+
fullyParallel: true,
|
|
6
|
+
forbidOnly: !!process.env.CI,
|
|
7
|
+
retries: process.env.CI ? 2 : 0,
|
|
8
|
+
workers: process.env.CI ? 1 : undefined,
|
|
9
|
+
reporter: 'html',
|
|
10
|
+
use: {
|
|
11
|
+
baseURL: 'http://localhost:5173',
|
|
12
|
+
trace: 'on-first-retry',
|
|
13
|
+
},
|
|
14
|
+
projects: [
|
|
15
|
+
{
|
|
16
|
+
name: 'chromium',
|
|
17
|
+
use: { ...devices['Desktop Chrome'] },
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
test.describe('Smoke Test', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.route('**/auth/me', (route) =>
|
|
6
|
+
route.fulfill({
|
|
7
|
+
status: 200,
|
|
8
|
+
contentType: 'application/json',
|
|
9
|
+
body: JSON.stringify({
|
|
10
|
+
id: 'user-1',
|
|
11
|
+
keycloakId: 'kc-1',
|
|
12
|
+
email: 'test@test.com',
|
|
13
|
+
displayName: 'Test User',
|
|
14
|
+
role: 'user',
|
|
15
|
+
roles: ['user'],
|
|
16
|
+
permissions: [],
|
|
17
|
+
}),
|
|
18
|
+
}),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('dashboard loads with user name', async ({ page }) => {
|
|
23
|
+
await page.goto('/');
|
|
24
|
+
await expect(page.getByRole('heading', { name: /welcome/i })).toBeVisible();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('shows login page when unauthenticated', async ({ page }) => {
|
|
28
|
+
await page.route('**/auth/me', (route) => route.fulfill({ status: 401 }));
|
|
29
|
+
await page.goto('/login');
|
|
30
|
+
await expect(page.getByRole('button', { name: /sign in/i })).toBeVisible();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('shows 404 for unknown routes', async ({ page }) => {
|
|
34
|
+
await page.goto('/nonexistent');
|
|
35
|
+
await expect(page.getByText('404')).toBeVisible();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Config } from 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
darkMode: 'class',
|
|
5
|
+
content: [
|
|
6
|
+
'./index.html',
|
|
7
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
8
|
+
'./node_modules/@quanticjs/react-ui/dist/**/*.{js,cjs}',
|
|
9
|
+
'./node_modules/@quanticjs/workflow-ui/dist/**/*.{js,cjs}',
|
|
10
|
+
],
|
|
11
|
+
theme: {
|
|
12
|
+
extend: {
|
|
13
|
+
colors: {
|
|
14
|
+
border: 'hsl(var(--border))',
|
|
15
|
+
input: 'hsl(var(--input))',
|
|
16
|
+
ring: 'hsl(var(--ring))',
|
|
17
|
+
background: 'hsl(var(--background))',
|
|
18
|
+
foreground: 'hsl(var(--foreground))',
|
|
19
|
+
primary: {
|
|
20
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
21
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
22
|
+
},
|
|
23
|
+
secondary: {
|
|
24
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
25
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
26
|
+
},
|
|
27
|
+
destructive: {
|
|
28
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
29
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
30
|
+
},
|
|
31
|
+
muted: {
|
|
32
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
33
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
34
|
+
},
|
|
35
|
+
accent: {
|
|
36
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
37
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
38
|
+
},
|
|
39
|
+
popover: {
|
|
40
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
41
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
42
|
+
},
|
|
43
|
+
card: {
|
|
44
|
+
DEFAULT: 'hsl(var(--card))',
|
|
45
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
borderRadius: {
|
|
49
|
+
lg: 'var(--radius)',
|
|
50
|
+
md: 'calc(var(--radius) - 2px)',
|
|
51
|
+
sm: 'calc(var(--radius) - 4px)',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
plugins: [],
|
|
56
|
+
} satisfies Config;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUncheckedIndexedAccess": true,
|
|
16
|
+
"noImplicitOverride": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"baseUrl": ".",
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["src/*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"]
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2023"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"allowImportingTsExtensions": true,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"moduleDetection": "force",
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"strict": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["vite.config.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react(), tailwindcss()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
'@': path.resolve(__dirname, './src'),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
server: {
|
|
14
|
+
port: 5173,
|
|
15
|
+
proxy: {
|
|
16
|
+
'/api': { target: 'http://localhost:3000', changeOrigin: true },
|
|
17
|
+
'/auth': { target: 'http://localhost:3000', changeOrigin: true },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { chromium } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
const KEYCLOAK_URL = process.env.KEYCLOAK_URL ?? 'http://localhost:8080';
|
|
4
|
+
const APP_URL = process.env.APP_URL ?? 'http://localhost:5173';
|
|
5
|
+
const STORAGE_PATH = 'client/e2e/auth/storage-state.json';
|
|
6
|
+
|
|
7
|
+
async function saveAuthState() {
|
|
8
|
+
const browser = await chromium.launch();
|
|
9
|
+
const context = await browser.newContext();
|
|
10
|
+
const page = await context.newPage();
|
|
11
|
+
|
|
12
|
+
await page.goto(`${APP_URL}/auth/login?provider=keycloak`);
|
|
13
|
+
await page.fill('#username', 'testuser');
|
|
14
|
+
await page.fill('#password', 'testpassword');
|
|
15
|
+
await page.click('#kc-login');
|
|
16
|
+
await page.waitForURL(`${APP_URL}/**`);
|
|
17
|
+
|
|
18
|
+
await context.storageState({ path: STORAGE_PATH });
|
|
19
|
+
await browser.close();
|
|
20
|
+
|
|
21
|
+
console.log(`Auth state saved to ${STORAGE_PATH}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
saveAuthState().catch(console.error);
|