@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.
Files changed (136) hide show
  1. package/dist/deps.d.ts +4 -0
  2. package/dist/deps.js +97 -0
  3. package/dist/deps.js.map +1 -0
  4. package/dist/generators/backend.d.ts +2 -0
  5. package/dist/generators/backend.js +20 -0
  6. package/dist/generators/backend.js.map +1 -0
  7. package/dist/generators/bff.d.ts +2 -0
  8. package/dist/generators/bff.js +9 -0
  9. package/dist/generators/bff.js.map +1 -0
  10. package/dist/generators/claude.d.ts +2 -0
  11. package/dist/generators/claude.js +45 -0
  12. package/dist/generators/claude.js.map +1 -0
  13. package/dist/generators/docker.d.ts +2 -0
  14. package/dist/generators/docker.js +10 -0
  15. package/dist/generators/docker.js.map +1 -0
  16. package/dist/generators/e2e.d.ts +2 -0
  17. package/dist/generators/e2e.js +8 -0
  18. package/dist/generators/e2e.js.map +1 -0
  19. package/dist/generators/frontend.d.ts +2 -0
  20. package/dist/generators/frontend.js +28 -0
  21. package/dist/generators/frontend.js.map +1 -0
  22. package/dist/generators/module.d.ts +2 -0
  23. package/dist/generators/module.js +35 -0
  24. package/dist/generators/module.js.map +1 -0
  25. package/dist/generators/root.d.ts +2 -0
  26. package/dist/generators/root.js +7 -0
  27. package/dist/generators/root.js.map +1 -0
  28. package/dist/generators/scripts.d.ts +2 -0
  29. package/dist/generators/scripts.js +10 -0
  30. package/dist/generators/scripts.js.map +1 -0
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.js +40 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/prompts.d.ts +8 -0
  35. package/dist/prompts.js +53 -0
  36. package/dist/prompts.js.map +1 -0
  37. package/dist/scaffold.d.ts +2 -0
  38. package/dist/scaffold.js +79 -0
  39. package/dist/scaffold.js.map +1 -0
  40. package/dist/utils/exec.d.ts +2 -0
  41. package/dist/utils/exec.js +14 -0
  42. package/dist/utils/exec.js.map +1 -0
  43. package/dist/utils/template.d.ts +10 -0
  44. package/dist/utils/template.js +20 -0
  45. package/dist/utils/template.js.map +1 -0
  46. package/dist/utils/validate.d.ts +4 -0
  47. package/dist/utils/validate.js +27 -0
  48. package/dist/utils/validate.js.map +1 -0
  49. package/package.json +50 -0
  50. package/templates/backend/app.module.ts.ejs +61 -0
  51. package/templates/backend/bff.controller.ts.ejs +60 -0
  52. package/templates/backend/bff.module.ts.ejs +10 -0
  53. package/templates/backend/bff.service.ts.ejs +6 -0
  54. package/templates/backend/create-schema.migration.ts.ejs +15 -0
  55. package/templates/backend/data-source.ts.ejs +13 -0
  56. package/templates/backend/env.example.ejs +30 -0
  57. package/templates/backend/main.ts.ejs +43 -0
  58. package/templates/backend/module.ts.ejs +14 -0
  59. package/templates/backend/nest-cli.json.ejs +8 -0
  60. package/templates/backend/package.json.ejs +23 -0
  61. package/templates/backend/tsconfig.build.json.ejs +4 -0
  62. package/templates/backend/tsconfig.json.ejs +24 -0
  63. package/templates/claude/CLAUDE.md.ejs +86 -0
  64. package/templates/claude/hooks/auto-format.sh +22 -0
  65. package/templates/claude/hooks/check-secrets.sh +49 -0
  66. package/templates/claude/hooks/guard-destructive.sh +42 -0
  67. package/templates/claude/hooks/on-compaction.sh +29 -0
  68. package/templates/claude/mcp.json +10 -0
  69. package/templates/claude/rules/api-patterns.md +86 -0
  70. package/templates/claude/rules/auth-patterns.md +109 -0
  71. package/templates/claude/rules/backend-patterns.md +421 -0
  72. package/templates/claude/rules/database-patterns.md +96 -0
  73. package/templates/claude/rules/docker-patterns.md +86 -0
  74. package/templates/claude/rules/frontend-patterns.md +262 -0
  75. package/templates/claude/rules/observability-backend.md +132 -0
  76. package/templates/claude/rules/observability-frontend.md +49 -0
  77. package/templates/claude/rules/playwright-mcp.md +80 -0
  78. package/templates/claude/rules/resilience-ops.md +103 -0
  79. package/templates/claude/rules/testing-e2e-ui.md +190 -0
  80. package/templates/claude/rules/testing-patterns.md +94 -0
  81. package/templates/claude/rules/workflow-backend.md +64 -0
  82. package/templates/claude/rules/workflow-frontend.md +60 -0
  83. package/templates/claude/settings.json +68 -0
  84. package/templates/claude/skills/add-api-endpoint/SKILL.md +59 -0
  85. package/templates/claude/skills/add-auth-endpoint/SKILL.md +68 -0
  86. package/templates/claude/skills/add-entity/SKILL.md +56 -0
  87. package/templates/claude/skills/add-event/SKILL.md +127 -0
  88. package/templates/claude/skills/add-feature/SKILL.md +20 -0
  89. package/templates/claude/skills/add-frontend-page/SKILL.md +75 -0
  90. package/templates/claude/skills/add-handler/SKILL.md +105 -0
  91. package/templates/claude/skills/add-integration/SKILL.md +176 -0
  92. package/templates/claude/skills/add-migration/SKILL.md +20 -0
  93. package/templates/claude/skills/add-module/SKILL.md +89 -0
  94. package/templates/claude/skills/add-realtime/SKILL.md +119 -0
  95. package/templates/claude/skills/audit-rules/SKILL.md +120 -0
  96. package/templates/claude/skills/debugging/SKILL.md +105 -0
  97. package/templates/claude/skills/docker-dev/SKILL.md +86 -0
  98. package/templates/claude/skills/e2e-audit/SKILL.md +85 -0
  99. package/templates/claude/skills/e2e-full/SKILL.md +132 -0
  100. package/templates/claude/skills/e2e-scan/SKILL.md +171 -0
  101. package/templates/claude/skills/e2e-verify/SKILL.md +145 -0
  102. package/templates/claude/skills/fix-bug/SKILL.md +33 -0
  103. package/templates/claude/skills/implement-spec/SKILL.md +98 -0
  104. package/templates/claude/skills/review-code/SKILL.md +109 -0
  105. package/templates/claude/skills/review-spec/SKILL.md +216 -0
  106. package/templates/claude/skills/run-tests/SKILL.md +37 -0
  107. package/templates/claude/skills/specify/SKILL.md +87 -0
  108. package/templates/claude/skills/write-backend-tests/SKILL.md +182 -0
  109. package/templates/claude/skills/write-ui-tests/SKILL.md +118 -0
  110. package/templates/docker/Dockerfile.client.ejs +14 -0
  111. package/templates/docker/Dockerfile.ejs +28 -0
  112. package/templates/docker/docker-compose.test.yml.ejs +54 -0
  113. package/templates/docker/docker-compose.yml.ejs +76 -0
  114. package/templates/docker/nginx.conf.ejs +21 -0
  115. package/templates/frontend/App.tsx.ejs +64 -0
  116. package/templates/frontend/DashboardPage.tsx.ejs +37 -0
  117. package/templates/frontend/LoginPage.tsx.ejs +20 -0
  118. package/templates/frontend/NotFoundPage.tsx.ejs +15 -0
  119. package/templates/frontend/api-client.ts.ejs +15 -0
  120. package/templates/frontend/index.css.ejs +57 -0
  121. package/templates/frontend/index.html.ejs +13 -0
  122. package/templates/frontend/main.tsx.ejs +10 -0
  123. package/templates/frontend/package.json.ejs +16 -0
  124. package/templates/frontend/playwright.config.ts.ejs +20 -0
  125. package/templates/frontend/postcss.config.js.ejs +3 -0
  126. package/templates/frontend/smoke.spec.ts.ejs +37 -0
  127. package/templates/frontend/tailwind.config.ts.ejs +56 -0
  128. package/templates/frontend/tsconfig.json.ejs +25 -0
  129. package/templates/frontend/tsconfig.node.json.ejs +15 -0
  130. package/templates/frontend/utils.ts.ejs +6 -0
  131. package/templates/frontend/vite-env.d.ts.ejs +1 -0
  132. package/templates/frontend/vite.config.ts.ejs +20 -0
  133. package/templates/root/gitignore.ejs +9 -0
  134. package/templates/root/prettierrc.ejs +7 -0
  135. package/templates/scripts/init-db.sh.ejs +8 -0
  136. 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,10 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { App } from './App';
4
+ import './index.css';
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ );
@@ -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,3 @@
1
+ export default {
2
+ plugins: {},
3
+ };
@@ -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,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -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,9 @@
1
+ node_modules/
2
+ dist/
3
+ .env
4
+ *.log
5
+ coverage/
6
+ .DS_Store
7
+ client/node_modules/
8
+ client/dist/
9
+ client/e2e/auth/storage-state.json
@@ -0,0 +1,7 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all",
4
+ "printWidth": 100,
5
+ "tabWidth": 2,
6
+ "semi": true
7
+ }
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
5
+ <% modules.forEach(function(mod) { -%>
6
+ CREATE SCHEMA IF NOT EXISTS <%= mod.replace(/-/g, '_') %>;
7
+ <% }); -%>
8
+ EOSQL
@@ -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);