popeye-cli 1.0.1 → 1.2.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/.env.example +24 -1
- package/CONTRIBUTING.md +275 -0
- package/OPEN_SOURCE_MANIFESTO.md +172 -0
- package/README.md +832 -123
- package/dist/adapters/claude.d.ts +19 -4
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/claude.js +908 -42
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/gemini.d.ts +55 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +318 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/grok.d.ts +73 -0
- package/dist/adapters/grok.d.ts.map +1 -0
- package/dist/adapters/grok.js +430 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +47 -8
- package/dist/adapters/openai.js.map +1 -1
- package/dist/auth/claude.d.ts +11 -9
- package/dist/auth/claude.d.ts.map +1 -1
- package/dist/auth/claude.js +107 -71
- package/dist/auth/claude.js.map +1 -1
- package/dist/auth/gemini.d.ts +58 -0
- package/dist/auth/gemini.d.ts.map +1 -0
- package/dist/auth/gemini.js +172 -0
- package/dist/auth/gemini.js.map +1 -0
- package/dist/auth/grok.d.ts +73 -0
- package/dist/auth/grok.d.ts.map +1 -0
- package/dist/auth/grok.js +211 -0
- package/dist/auth/grok.js.map +1 -0
- package/dist/auth/index.d.ts +14 -7
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +41 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/keychain.d.ts +20 -7
- package/dist/auth/keychain.d.ts.map +1 -1
- package/dist/auth/keychain.js +85 -29
- package/dist/auth/keychain.js.map +1 -1
- package/dist/auth/openai.d.ts +2 -2
- package/dist/auth/openai.d.ts.map +1 -1
- package/dist/auth/openai.js +30 -32
- package/dist/auth/openai.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +79 -8
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +15 -4
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +1494 -114
- package/dist/cli/interactive.js.map +1 -1
- package/dist/config/defaults.d.ts +9 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +19 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +19 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +33 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +47 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +29 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/generators/fullstack.d.ts +32 -0
- package/dist/generators/fullstack.d.ts.map +1 -0
- package/dist/generators/fullstack.js +497 -0
- package/dist/generators/fullstack.js.map +1 -0
- package/dist/generators/index.d.ts +4 -3
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +15 -1
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/python.d.ts +17 -1
- package/dist/generators/python.d.ts.map +1 -1
- package/dist/generators/python.js +34 -20
- package/dist/generators/python.js.map +1 -1
- package/dist/generators/templates/fullstack.d.ts +113 -0
- package/dist/generators/templates/fullstack.d.ts.map +1 -0
- package/dist/generators/templates/fullstack.js +1004 -0
- package/dist/generators/templates/fullstack.js.map +1 -0
- package/dist/generators/typescript.d.ts +19 -1
- package/dist/generators/typescript.d.ts.map +1 -1
- package/dist/generators/typescript.js +37 -20
- package/dist/generators/typescript.js.map +1 -1
- package/dist/state/index.d.ts +108 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +551 -4
- package/dist/state/index.js.map +1 -1
- package/dist/state/registry.d.ts +52 -0
- package/dist/state/registry.d.ts.map +1 -0
- package/dist/state/registry.js +215 -0
- package/dist/state/registry.js.map +1 -0
- package/dist/types/cli.d.ts +8 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/cli.js.map +1 -1
- package/dist/types/consensus.d.ts +186 -4
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js +35 -3
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/project.d.ts +76 -0
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +1 -1
- package/dist/types/project.js.map +1 -1
- package/dist/types/workflow.d.ts +217 -16
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +40 -1
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/auto-fix.d.ts +45 -0
- package/dist/workflow/auto-fix.d.ts.map +1 -0
- package/dist/workflow/auto-fix.js +274 -0
- package/dist/workflow/auto-fix.js.map +1 -0
- package/dist/workflow/consensus.d.ts +70 -2
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js +872 -17
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/execution-mode.d.ts +10 -4
- package/dist/workflow/execution-mode.d.ts.map +1 -1
- package/dist/workflow/execution-mode.js +547 -58
- package/dist/workflow/execution-mode.js.map +1 -1
- package/dist/workflow/index.d.ts +14 -2
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +69 -6
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/milestone-workflow.d.ts +34 -0
- package/dist/workflow/milestone-workflow.d.ts.map +1 -0
- package/dist/workflow/milestone-workflow.js +414 -0
- package/dist/workflow/milestone-workflow.js.map +1 -0
- package/dist/workflow/plan-mode.d.ts +80 -3
- package/dist/workflow/plan-mode.d.ts.map +1 -1
- package/dist/workflow/plan-mode.js +767 -49
- package/dist/workflow/plan-mode.js.map +1 -1
- package/dist/workflow/plan-storage.d.ts +386 -0
- package/dist/workflow/plan-storage.d.ts.map +1 -0
- package/dist/workflow/plan-storage.js +878 -0
- package/dist/workflow/plan-storage.js.map +1 -0
- package/dist/workflow/project-verification.d.ts +37 -0
- package/dist/workflow/project-verification.d.ts.map +1 -0
- package/dist/workflow/project-verification.js +381 -0
- package/dist/workflow/project-verification.js.map +1 -0
- package/dist/workflow/task-workflow.d.ts +37 -0
- package/dist/workflow/task-workflow.d.ts.map +1 -0
- package/dist/workflow/task-workflow.js +386 -0
- package/dist/workflow/task-workflow.js.map +1 -0
- package/dist/workflow/test-runner.d.ts +9 -0
- package/dist/workflow/test-runner.d.ts.map +1 -1
- package/dist/workflow/test-runner.js +101 -5
- package/dist/workflow/test-runner.js.map +1 -1
- package/dist/workflow/ui-designer.d.ts +82 -0
- package/dist/workflow/ui-designer.d.ts.map +1 -0
- package/dist/workflow/ui-designer.js +234 -0
- package/dist/workflow/ui-designer.js.map +1 -0
- package/dist/workflow/ui-setup.d.ts +58 -0
- package/dist/workflow/ui-setup.d.ts.map +1 -0
- package/dist/workflow/ui-setup.js +685 -0
- package/dist/workflow/ui-setup.js.map +1 -0
- package/dist/workflow/ui-verification.d.ts +114 -0
- package/dist/workflow/ui-verification.d.ts.map +1 -0
- package/dist/workflow/ui-verification.js +258 -0
- package/dist/workflow/ui-verification.js.map +1 -0
- package/dist/workflow/workflow-logger.d.ts +110 -0
- package/dist/workflow/workflow-logger.d.ts.map +1 -0
- package/dist/workflow/workflow-logger.js +267 -0
- package/dist/workflow/workflow-logger.js.map +1 -0
- package/dist/workflow/workspace-manager.d.ts +342 -0
- package/dist/workflow/workspace-manager.d.ts.map +1 -0
- package/dist/workflow/workspace-manager.js +733 -0
- package/dist/workflow/workspace-manager.js.map +1 -0
- package/package.json +2 -2
- package/src/adapters/claude.ts +1067 -47
- package/src/adapters/gemini.ts +373 -0
- package/src/adapters/grok.ts +492 -0
- package/src/adapters/openai.ts +48 -9
- package/src/auth/claude.ts +120 -78
- package/src/auth/gemini.ts +207 -0
- package/src/auth/grok.ts +255 -0
- package/src/auth/index.ts +47 -9
- package/src/auth/keychain.ts +95 -28
- package/src/auth/openai.ts +29 -36
- package/src/cli/commands/auth.ts +89 -10
- package/src/cli/commands/create.ts +13 -4
- package/src/cli/interactive.ts +1774 -142
- package/src/config/defaults.ts +19 -2
- package/src/config/index.ts +36 -1
- package/src/config/schema.ts +30 -1
- package/src/generators/fullstack.ts +551 -0
- package/src/generators/index.ts +25 -1
- package/src/generators/python.ts +65 -20
- package/src/generators/templates/fullstack.ts +1047 -0
- package/src/generators/typescript.ts +69 -20
- package/src/state/index.ts +713 -4
- package/src/state/registry.ts +278 -0
- package/src/types/cli.ts +8 -0
- package/src/types/consensus.ts +197 -6
- package/src/types/project.ts +82 -1
- package/src/types/workflow.ts +90 -1
- package/src/workflow/auto-fix.ts +340 -0
- package/src/workflow/consensus.ts +1180 -16
- package/src/workflow/execution-mode.ts +673 -74
- package/src/workflow/index.ts +95 -6
- package/src/workflow/milestone-workflow.ts +576 -0
- package/src/workflow/plan-mode.ts +924 -50
- package/src/workflow/plan-storage.ts +1282 -0
- package/src/workflow/project-verification.ts +471 -0
- package/src/workflow/task-workflow.ts +528 -0
- package/src/workflow/test-runner.ts +120 -5
- package/src/workflow/ui-designer.ts +337 -0
- package/src/workflow/ui-setup.ts +797 -0
- package/src/workflow/ui-verification.ts +357 -0
- package/src/workflow/workflow-logger.ts +353 -0
- package/src/workflow/workspace-manager.ts +912 -0
- package/tests/config/config.test.ts +1 -1
- package/tests/types/consensus.test.ts +3 -3
- package/tests/workflow/plan-mode.test.ts +213 -0
- package/tests/workflow/test-runner.test.ts +5 -3
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fullstack project templates
|
|
3
|
+
* Provides template files for fullstack monorepo project generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WorkspaceConfig } from '../../types/project.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generate workspace.json content
|
|
10
|
+
*
|
|
11
|
+
* @param projectName - The project name
|
|
12
|
+
* @returns Workspace configuration object
|
|
13
|
+
*/
|
|
14
|
+
export function generateWorkspaceConfig(projectName: string): WorkspaceConfig {
|
|
15
|
+
return {
|
|
16
|
+
version: '1.0',
|
|
17
|
+
apps: {
|
|
18
|
+
frontend: {
|
|
19
|
+
name: 'frontend',
|
|
20
|
+
path: 'apps/frontend',
|
|
21
|
+
language: 'typescript',
|
|
22
|
+
commands: {
|
|
23
|
+
test: 'npm test',
|
|
24
|
+
lint: 'npm run lint',
|
|
25
|
+
build: 'npm run build',
|
|
26
|
+
dev: 'npm run dev',
|
|
27
|
+
typecheck: 'npm run typecheck',
|
|
28
|
+
},
|
|
29
|
+
docker: {
|
|
30
|
+
dockerfile: 'apps/frontend/Dockerfile',
|
|
31
|
+
imageName: `${projectName}-frontend`,
|
|
32
|
+
context: 'apps/frontend',
|
|
33
|
+
},
|
|
34
|
+
uiSpec: '.popeye/ui-spec.json',
|
|
35
|
+
},
|
|
36
|
+
backend: {
|
|
37
|
+
name: 'backend',
|
|
38
|
+
path: 'apps/backend',
|
|
39
|
+
language: 'python',
|
|
40
|
+
commands: {
|
|
41
|
+
test: 'python -m pytest tests/ -v',
|
|
42
|
+
lint: 'ruff check src/ tests/',
|
|
43
|
+
build: 'pip install -e .',
|
|
44
|
+
dev: 'uvicorn src.backend.main:app --reload --port 8000',
|
|
45
|
+
},
|
|
46
|
+
docker: {
|
|
47
|
+
dockerfile: 'apps/backend/Dockerfile',
|
|
48
|
+
imageName: `${projectName}-backend`,
|
|
49
|
+
context: 'apps/backend',
|
|
50
|
+
},
|
|
51
|
+
contextRoots: ['src/backend', 'tests'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
commands: {
|
|
55
|
+
testAll: 'cd apps/backend && pytest && cd ../frontend && npm test',
|
|
56
|
+
lintAll: 'cd apps/backend && ruff check . && cd ../frontend && npm run lint',
|
|
57
|
+
buildAll: 'cd apps/backend && pip install -e . && cd ../frontend && npm run build',
|
|
58
|
+
devAll: 'docker-compose up',
|
|
59
|
+
},
|
|
60
|
+
docker: {
|
|
61
|
+
composePath: 'infra/docker/docker-compose.yml',
|
|
62
|
+
rootComposeSymlink: true,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generate workspace.json file content as string
|
|
69
|
+
*/
|
|
70
|
+
export function generateWorkspaceJson(projectName: string): string {
|
|
71
|
+
const config = generateWorkspaceConfig(projectName);
|
|
72
|
+
return JSON.stringify(config, null, 2);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Generate root docker-compose.yml for fullstack project
|
|
77
|
+
*/
|
|
78
|
+
export function generateRootDockerCompose(projectName: string): string {
|
|
79
|
+
return `version: "3.8"
|
|
80
|
+
|
|
81
|
+
services:
|
|
82
|
+
frontend:
|
|
83
|
+
build:
|
|
84
|
+
context: ./apps/frontend
|
|
85
|
+
target: production
|
|
86
|
+
container_name: ${projectName}-frontend
|
|
87
|
+
restart: unless-stopped
|
|
88
|
+
ports:
|
|
89
|
+
- "3000:80"
|
|
90
|
+
depends_on:
|
|
91
|
+
- backend
|
|
92
|
+
environment:
|
|
93
|
+
- VITE_API_URL=http://backend:8000
|
|
94
|
+
|
|
95
|
+
backend:
|
|
96
|
+
build:
|
|
97
|
+
context: ./apps/backend
|
|
98
|
+
container_name: ${projectName}-backend
|
|
99
|
+
restart: unless-stopped
|
|
100
|
+
ports:
|
|
101
|
+
- "8000:8000"
|
|
102
|
+
env_file:
|
|
103
|
+
- ./apps/backend/.env
|
|
104
|
+
volumes:
|
|
105
|
+
- backend-data:/app/data
|
|
106
|
+
|
|
107
|
+
frontend-dev:
|
|
108
|
+
build:
|
|
109
|
+
context: ./apps/frontend
|
|
110
|
+
target: development
|
|
111
|
+
container_name: ${projectName}-frontend-dev
|
|
112
|
+
ports:
|
|
113
|
+
- "5173:5173"
|
|
114
|
+
volumes:
|
|
115
|
+
- ./apps/frontend/src:/app/src
|
|
116
|
+
environment:
|
|
117
|
+
- VITE_API_URL=http://backend:8000
|
|
118
|
+
depends_on:
|
|
119
|
+
- backend
|
|
120
|
+
|
|
121
|
+
backend-dev:
|
|
122
|
+
build:
|
|
123
|
+
context: ./apps/backend
|
|
124
|
+
container_name: ${projectName}-backend-dev
|
|
125
|
+
ports:
|
|
126
|
+
- "8000:8000"
|
|
127
|
+
volumes:
|
|
128
|
+
- ./apps/backend/src:/app/src
|
|
129
|
+
- ./apps/backend/tests:/app/tests
|
|
130
|
+
command: ["uvicorn", "src.backend.main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]
|
|
131
|
+
|
|
132
|
+
volumes:
|
|
133
|
+
backend-data:
|
|
134
|
+
`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Generate root README.md for fullstack project
|
|
139
|
+
*/
|
|
140
|
+
export function generateRootReadme(projectName: string, description?: string): string {
|
|
141
|
+
return `# ${projectName}
|
|
142
|
+
|
|
143
|
+
${description || 'A fullstack application with React frontend and FastAPI backend.'}
|
|
144
|
+
|
|
145
|
+
## Project Structure
|
|
146
|
+
|
|
147
|
+
\`\`\`
|
|
148
|
+
${projectName}/
|
|
149
|
+
apps/
|
|
150
|
+
frontend/ # React + Vite + Tailwind CSS
|
|
151
|
+
backend/ # FastAPI (Python)
|
|
152
|
+
packages/
|
|
153
|
+
contracts/ # OpenAPI spec (future)
|
|
154
|
+
infra/
|
|
155
|
+
docker/ # Docker configuration
|
|
156
|
+
docs/ # Documentation
|
|
157
|
+
.popeye/ # Popeye CLI configuration
|
|
158
|
+
\`\`\`
|
|
159
|
+
|
|
160
|
+
## Quick Start
|
|
161
|
+
|
|
162
|
+
### Development Mode
|
|
163
|
+
|
|
164
|
+
Run both frontend and backend in development mode:
|
|
165
|
+
|
|
166
|
+
\`\`\`bash
|
|
167
|
+
# Option 1: Using Docker Compose (recommended)
|
|
168
|
+
docker-compose up frontend-dev backend-dev
|
|
169
|
+
|
|
170
|
+
# Option 2: Run separately
|
|
171
|
+
# Terminal 1 - Backend
|
|
172
|
+
cd apps/backend
|
|
173
|
+
pip install -e .
|
|
174
|
+
uvicorn src.backend.main:app --reload --port 8000
|
|
175
|
+
|
|
176
|
+
# Terminal 2 - Frontend
|
|
177
|
+
cd apps/frontend
|
|
178
|
+
npm install
|
|
179
|
+
npm run dev
|
|
180
|
+
\`\`\`
|
|
181
|
+
|
|
182
|
+
### Production Build
|
|
183
|
+
|
|
184
|
+
\`\`\`bash
|
|
185
|
+
# Build and run with Docker Compose
|
|
186
|
+
docker-compose up --build frontend backend
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
## Running Tests
|
|
190
|
+
|
|
191
|
+
\`\`\`bash
|
|
192
|
+
# Run all tests
|
|
193
|
+
cd apps/backend && pytest && cd ../frontend && npm test
|
|
194
|
+
|
|
195
|
+
# Frontend tests only
|
|
196
|
+
cd apps/frontend && npm test
|
|
197
|
+
|
|
198
|
+
# Backend tests only
|
|
199
|
+
cd apps/backend && pytest
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
## Linting
|
|
203
|
+
|
|
204
|
+
\`\`\`bash
|
|
205
|
+
# Lint all
|
|
206
|
+
cd apps/backend && ruff check . && cd ../frontend && npm run lint
|
|
207
|
+
|
|
208
|
+
# Frontend only
|
|
209
|
+
cd apps/frontend && npm run lint
|
|
210
|
+
|
|
211
|
+
# Backend only
|
|
212
|
+
cd apps/backend && ruff check .
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
## Apps
|
|
216
|
+
|
|
217
|
+
### Frontend (apps/frontend)
|
|
218
|
+
|
|
219
|
+
React application built with:
|
|
220
|
+
- **Vite** - Fast build tool
|
|
221
|
+
- **Tailwind CSS** - Utility-first CSS
|
|
222
|
+
- **TypeScript** - Type safety
|
|
223
|
+
- **Vitest** - Unit testing
|
|
224
|
+
|
|
225
|
+
See [apps/frontend/README.md](apps/frontend/README.md) for frontend-specific documentation.
|
|
226
|
+
|
|
227
|
+
### Backend (apps/backend)
|
|
228
|
+
|
|
229
|
+
Python API built with:
|
|
230
|
+
- **FastAPI** - Modern async API framework
|
|
231
|
+
- **Pydantic** - Data validation
|
|
232
|
+
- **pytest** - Testing framework
|
|
233
|
+
|
|
234
|
+
See [apps/backend/README.md](apps/backend/README.md) for backend-specific documentation.
|
|
235
|
+
|
|
236
|
+
## API Communication
|
|
237
|
+
|
|
238
|
+
Frontend connects to backend at:
|
|
239
|
+
- Development: \`http://localhost:8000\`
|
|
240
|
+
- Docker: \`http://backend:8000\`
|
|
241
|
+
|
|
242
|
+
The API URL is configured via \`VITE_API_URL\` environment variable.
|
|
243
|
+
|
|
244
|
+
## Docker
|
|
245
|
+
|
|
246
|
+
### Services
|
|
247
|
+
|
|
248
|
+
| Service | Port | Description |
|
|
249
|
+
|---------|------|-------------|
|
|
250
|
+
| frontend | 3000 | Production frontend (nginx) |
|
|
251
|
+
| backend | 8000 | Production API |
|
|
252
|
+
| frontend-dev | 5173 | Development frontend (HMR) |
|
|
253
|
+
| backend-dev | 8000 | Development API (auto-reload) |
|
|
254
|
+
|
|
255
|
+
### Commands
|
|
256
|
+
|
|
257
|
+
\`\`\`bash
|
|
258
|
+
# Build all
|
|
259
|
+
docker-compose build
|
|
260
|
+
|
|
261
|
+
# Run production
|
|
262
|
+
docker-compose up frontend backend
|
|
263
|
+
|
|
264
|
+
# Run development
|
|
265
|
+
docker-compose up frontend-dev backend-dev
|
|
266
|
+
|
|
267
|
+
# Stop all
|
|
268
|
+
docker-compose down
|
|
269
|
+
\`\`\`
|
|
270
|
+
|
|
271
|
+
## Configuration
|
|
272
|
+
|
|
273
|
+
- Backend environment: \`apps/backend/.env\`
|
|
274
|
+
- Frontend environment: \`apps/frontend/.env\`
|
|
275
|
+
- Workspace config: \`.popeye/workspace.json\`
|
|
276
|
+
|
|
277
|
+
## License
|
|
278
|
+
|
|
279
|
+
MIT
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Generate root .gitignore for fullstack project
|
|
285
|
+
*/
|
|
286
|
+
export function generateRootGitignore(): string {
|
|
287
|
+
return `# Dependencies
|
|
288
|
+
node_modules/
|
|
289
|
+
__pycache__/
|
|
290
|
+
*.py[cod]
|
|
291
|
+
*$py.class
|
|
292
|
+
.Python
|
|
293
|
+
venv/
|
|
294
|
+
.venv/
|
|
295
|
+
env/
|
|
296
|
+
|
|
297
|
+
# Build outputs
|
|
298
|
+
dist/
|
|
299
|
+
build/
|
|
300
|
+
*.egg-info/
|
|
301
|
+
.eggs/
|
|
302
|
+
|
|
303
|
+
# IDE
|
|
304
|
+
.idea/
|
|
305
|
+
.vscode/
|
|
306
|
+
*.swp
|
|
307
|
+
*.swo
|
|
308
|
+
|
|
309
|
+
# Environment files
|
|
310
|
+
.env
|
|
311
|
+
.env.local
|
|
312
|
+
.env.*.local
|
|
313
|
+
!.env.example
|
|
314
|
+
|
|
315
|
+
# Logs
|
|
316
|
+
*.log
|
|
317
|
+
npm-debug.log*
|
|
318
|
+
pip-log.txt
|
|
319
|
+
|
|
320
|
+
# Testing
|
|
321
|
+
coverage/
|
|
322
|
+
.coverage
|
|
323
|
+
htmlcov/
|
|
324
|
+
.pytest_cache/
|
|
325
|
+
.nyc_output/
|
|
326
|
+
|
|
327
|
+
# OS files
|
|
328
|
+
.DS_Store
|
|
329
|
+
Thumbs.db
|
|
330
|
+
|
|
331
|
+
# Project specific
|
|
332
|
+
.popeye/state.json
|
|
333
|
+
data/
|
|
334
|
+
|
|
335
|
+
# Docker
|
|
336
|
+
*.pid
|
|
337
|
+
`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Generate frontend-specific README for fullstack project
|
|
342
|
+
*/
|
|
343
|
+
export function generateFrontendReadme(projectName: string): string {
|
|
344
|
+
return `# ${projectName} - Frontend
|
|
345
|
+
|
|
346
|
+
React frontend application built with Vite, Tailwind CSS, and TypeScript.
|
|
347
|
+
|
|
348
|
+
## Development
|
|
349
|
+
|
|
350
|
+
\`\`\`bash
|
|
351
|
+
npm install
|
|
352
|
+
npm run dev
|
|
353
|
+
\`\`\`
|
|
354
|
+
|
|
355
|
+
## Scripts
|
|
356
|
+
|
|
357
|
+
| Script | Description |
|
|
358
|
+
|--------|-------------|
|
|
359
|
+
| \`npm run dev\` | Start development server |
|
|
360
|
+
| \`npm run build\` | Build for production |
|
|
361
|
+
| \`npm run preview\` | Preview production build |
|
|
362
|
+
| \`npm test\` | Run tests |
|
|
363
|
+
| \`npm run lint\` | Lint code |
|
|
364
|
+
| \`npm run typecheck\` | Type check |
|
|
365
|
+
|
|
366
|
+
## Structure
|
|
367
|
+
|
|
368
|
+
\`\`\`
|
|
369
|
+
src/
|
|
370
|
+
components/ # Reusable components
|
|
371
|
+
pages/ # Page components
|
|
372
|
+
hooks/ # Custom hooks
|
|
373
|
+
utils/ # Utility functions
|
|
374
|
+
api/ # API client
|
|
375
|
+
App.tsx # Root component
|
|
376
|
+
main.tsx # Entry point
|
|
377
|
+
\`\`\`
|
|
378
|
+
|
|
379
|
+
## API Integration
|
|
380
|
+
|
|
381
|
+
The API URL is configured via environment variable:
|
|
382
|
+
|
|
383
|
+
\`\`\`env
|
|
384
|
+
VITE_API_URL=http://localhost:8000
|
|
385
|
+
\`\`\`
|
|
386
|
+
|
|
387
|
+
## Testing
|
|
388
|
+
|
|
389
|
+
\`\`\`bash
|
|
390
|
+
npm test # Run tests
|
|
391
|
+
npm run test:watch # Watch mode
|
|
392
|
+
npm run test:coverage # With coverage
|
|
393
|
+
\`\`\`
|
|
394
|
+
`;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Generate backend-specific README for fullstack project
|
|
399
|
+
*/
|
|
400
|
+
export function generateBackendReadme(projectName: string): string {
|
|
401
|
+
return `# ${projectName} - Backend
|
|
402
|
+
|
|
403
|
+
FastAPI backend application.
|
|
404
|
+
|
|
405
|
+
## Development
|
|
406
|
+
|
|
407
|
+
\`\`\`bash
|
|
408
|
+
# Install dependencies
|
|
409
|
+
pip install -e .
|
|
410
|
+
|
|
411
|
+
# Run development server
|
|
412
|
+
uvicorn src.backend.main:app --reload --port 8000
|
|
413
|
+
\`\`\`
|
|
414
|
+
|
|
415
|
+
## Scripts (Makefile)
|
|
416
|
+
|
|
417
|
+
| Command | Description |
|
|
418
|
+
|---------|-------------|
|
|
419
|
+
| \`make dev\` | Run development server |
|
|
420
|
+
| \`make test\` | Run tests |
|
|
421
|
+
| \`make lint\` | Lint code |
|
|
422
|
+
| \`make format\` | Format code |
|
|
423
|
+
|
|
424
|
+
## Structure
|
|
425
|
+
|
|
426
|
+
\`\`\`
|
|
427
|
+
src/backend/
|
|
428
|
+
main.py # FastAPI app entry point
|
|
429
|
+
routes/ # API routes
|
|
430
|
+
models/ # Pydantic models
|
|
431
|
+
services/ # Business logic
|
|
432
|
+
utils/ # Utility functions
|
|
433
|
+
tests/
|
|
434
|
+
test_main.py # Main tests
|
|
435
|
+
conftest.py # Test fixtures
|
|
436
|
+
\`\`\`
|
|
437
|
+
|
|
438
|
+
## API Documentation
|
|
439
|
+
|
|
440
|
+
Once running, API docs are available at:
|
|
441
|
+
- Swagger UI: http://localhost:8000/docs
|
|
442
|
+
- ReDoc: http://localhost:8000/redoc
|
|
443
|
+
|
|
444
|
+
## Testing
|
|
445
|
+
|
|
446
|
+
\`\`\`bash
|
|
447
|
+
pytest # Run all tests
|
|
448
|
+
pytest -v # Verbose
|
|
449
|
+
pytest --cov=src/backend # With coverage
|
|
450
|
+
\`\`\`
|
|
451
|
+
|
|
452
|
+
## Environment Variables
|
|
453
|
+
|
|
454
|
+
Copy \`.env.example\` to \`.env\` and configure:
|
|
455
|
+
|
|
456
|
+
\`\`\`env
|
|
457
|
+
DEBUG=true
|
|
458
|
+
DATABASE_URL=sqlite:///./data/app.db
|
|
459
|
+
\`\`\`
|
|
460
|
+
`;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Generate UI spec placeholder for fullstack project
|
|
465
|
+
*/
|
|
466
|
+
export function generateUiSpec(projectName: string): string {
|
|
467
|
+
return JSON.stringify(
|
|
468
|
+
{
|
|
469
|
+
name: projectName,
|
|
470
|
+
version: '1.0',
|
|
471
|
+
theme: {
|
|
472
|
+
colors: {
|
|
473
|
+
primary: '#3B82F6',
|
|
474
|
+
secondary: '#6B7280',
|
|
475
|
+
accent: '#10B981',
|
|
476
|
+
},
|
|
477
|
+
fonts: {
|
|
478
|
+
heading: 'Inter',
|
|
479
|
+
body: 'Inter',
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
components: [],
|
|
483
|
+
pages: [
|
|
484
|
+
{
|
|
485
|
+
name: 'Home',
|
|
486
|
+
path: '/',
|
|
487
|
+
layout: 'default',
|
|
488
|
+
},
|
|
489
|
+
],
|
|
490
|
+
},
|
|
491
|
+
null,
|
|
492
|
+
2
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Generate Vite config for React frontend
|
|
498
|
+
*/
|
|
499
|
+
export function generateViteConfigReact(): string {
|
|
500
|
+
return `import { defineConfig } from 'vite';
|
|
501
|
+
import react from '@vitejs/plugin-react';
|
|
502
|
+
import path from 'path';
|
|
503
|
+
|
|
504
|
+
export default defineConfig({
|
|
505
|
+
plugins: [react()],
|
|
506
|
+
resolve: {
|
|
507
|
+
alias: {
|
|
508
|
+
'@': path.resolve(__dirname, './src'),
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
server: {
|
|
512
|
+
port: 5173,
|
|
513
|
+
host: true,
|
|
514
|
+
proxy: {
|
|
515
|
+
'/api': {
|
|
516
|
+
target: process.env.VITE_API_URL || 'http://localhost:8000',
|
|
517
|
+
changeOrigin: true,
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
build: {
|
|
522
|
+
outDir: 'dist',
|
|
523
|
+
sourcemap: true,
|
|
524
|
+
},
|
|
525
|
+
});
|
|
526
|
+
`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Generate Tailwind config for frontend
|
|
531
|
+
*/
|
|
532
|
+
export function generateTailwindConfig(): string {
|
|
533
|
+
return `/** @type {import('tailwindcss').Config} */
|
|
534
|
+
export default {
|
|
535
|
+
content: [
|
|
536
|
+
'./index.html',
|
|
537
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
538
|
+
],
|
|
539
|
+
theme: {
|
|
540
|
+
extend: {
|
|
541
|
+
colors: {
|
|
542
|
+
primary: {
|
|
543
|
+
50: '#eff6ff',
|
|
544
|
+
100: '#dbeafe',
|
|
545
|
+
200: '#bfdbfe',
|
|
546
|
+
300: '#93c5fd',
|
|
547
|
+
400: '#60a5fa',
|
|
548
|
+
500: '#3b82f6',
|
|
549
|
+
600: '#2563eb',
|
|
550
|
+
700: '#1d4ed8',
|
|
551
|
+
800: '#1e40af',
|
|
552
|
+
900: '#1e3a8a',
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
plugins: [],
|
|
558
|
+
};
|
|
559
|
+
`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Generate PostCSS config for frontend
|
|
564
|
+
*/
|
|
565
|
+
export function generatePostcssConfig(): string {
|
|
566
|
+
return `export default {
|
|
567
|
+
plugins: {
|
|
568
|
+
tailwindcss: {},
|
|
569
|
+
autoprefixer: {},
|
|
570
|
+
},
|
|
571
|
+
};
|
|
572
|
+
`;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Generate main CSS with Tailwind directives
|
|
577
|
+
*/
|
|
578
|
+
export function generateMainCss(): string {
|
|
579
|
+
return `@tailwind base;
|
|
580
|
+
@tailwind components;
|
|
581
|
+
@tailwind utilities;
|
|
582
|
+
|
|
583
|
+
/* Custom styles */
|
|
584
|
+
body {
|
|
585
|
+
@apply bg-gray-50 text-gray-900;
|
|
586
|
+
}
|
|
587
|
+
`;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Generate React App.tsx
|
|
592
|
+
*/
|
|
593
|
+
export function generateAppTsx(projectName: string): string {
|
|
594
|
+
return `import { useState, useEffect } from 'react';
|
|
595
|
+
|
|
596
|
+
interface HealthStatus {
|
|
597
|
+
status: string;
|
|
598
|
+
message: string;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function App() {
|
|
602
|
+
const [health, setHealth] = useState<HealthStatus | null>(null);
|
|
603
|
+
const [loading, setLoading] = useState(true);
|
|
604
|
+
const [error, setError] = useState<string | null>(null);
|
|
605
|
+
|
|
606
|
+
useEffect(() => {
|
|
607
|
+
const checkHealth = async () => {
|
|
608
|
+
try {
|
|
609
|
+
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
|
610
|
+
const response = await fetch(\`\${apiUrl}/health\`);
|
|
611
|
+
if (response.ok) {
|
|
612
|
+
const data = await response.json();
|
|
613
|
+
setHealth(data);
|
|
614
|
+
} else {
|
|
615
|
+
setError('Backend not responding');
|
|
616
|
+
}
|
|
617
|
+
} catch (err) {
|
|
618
|
+
setError('Failed to connect to backend');
|
|
619
|
+
} finally {
|
|
620
|
+
setLoading(false);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
checkHealth();
|
|
625
|
+
}, []);
|
|
626
|
+
|
|
627
|
+
return (
|
|
628
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
629
|
+
<div className="text-center p-8">
|
|
630
|
+
<h1 className="text-4xl font-bold text-primary-600 mb-4">
|
|
631
|
+
${projectName}
|
|
632
|
+
</h1>
|
|
633
|
+
<p className="text-gray-600 mb-8">
|
|
634
|
+
Fullstack application with React + FastAPI
|
|
635
|
+
</p>
|
|
636
|
+
|
|
637
|
+
<div className="bg-white rounded-lg shadow-md p-6">
|
|
638
|
+
<h2 className="text-lg font-semibold mb-2">Backend Status</h2>
|
|
639
|
+
{loading && (
|
|
640
|
+
<p className="text-gray-500">Checking...</p>
|
|
641
|
+
)}
|
|
642
|
+
{error && (
|
|
643
|
+
<p className="text-red-500">{error}</p>
|
|
644
|
+
)}
|
|
645
|
+
{health && (
|
|
646
|
+
<div className="text-green-500">
|
|
647
|
+
<p>Status: {health.status}</p>
|
|
648
|
+
<p className="text-sm text-gray-500">{health.message}</p>
|
|
649
|
+
</div>
|
|
650
|
+
)}
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
export default App;
|
|
658
|
+
`;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Generate React main.tsx entry point
|
|
663
|
+
*/
|
|
664
|
+
export function generateMainTsx(): string {
|
|
665
|
+
return `import { StrictMode } from 'react';
|
|
666
|
+
import { createRoot } from 'react-dom/client';
|
|
667
|
+
import App from './App';
|
|
668
|
+
import './index.css';
|
|
669
|
+
|
|
670
|
+
createRoot(document.getElementById('root')!).render(
|
|
671
|
+
<StrictMode>
|
|
672
|
+
<App />
|
|
673
|
+
</StrictMode>
|
|
674
|
+
);
|
|
675
|
+
`;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Generate index.html for React app
|
|
680
|
+
*/
|
|
681
|
+
export function generateIndexHtml(projectName: string): string {
|
|
682
|
+
return `<!DOCTYPE html>
|
|
683
|
+
<html lang="en">
|
|
684
|
+
<head>
|
|
685
|
+
<meta charset="UTF-8" />
|
|
686
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
687
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
688
|
+
<title>${projectName}</title>
|
|
689
|
+
</head>
|
|
690
|
+
<body>
|
|
691
|
+
<div id="root"></div>
|
|
692
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
693
|
+
</body>
|
|
694
|
+
</html>
|
|
695
|
+
`;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Generate frontend package.json for React + Vite
|
|
700
|
+
*/
|
|
701
|
+
export function generateFrontendPackageJson(projectName: string): string {
|
|
702
|
+
return JSON.stringify(
|
|
703
|
+
{
|
|
704
|
+
name: `${projectName}-frontend`,
|
|
705
|
+
private: true,
|
|
706
|
+
version: '1.0.0',
|
|
707
|
+
type: 'module',
|
|
708
|
+
scripts: {
|
|
709
|
+
dev: 'vite',
|
|
710
|
+
build: 'tsc && vite build',
|
|
711
|
+
preview: 'vite preview',
|
|
712
|
+
test: 'vitest run',
|
|
713
|
+
'test:watch': 'vitest',
|
|
714
|
+
'test:coverage': 'vitest run --coverage',
|
|
715
|
+
lint: 'eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0',
|
|
716
|
+
typecheck: 'tsc --noEmit',
|
|
717
|
+
},
|
|
718
|
+
dependencies: {
|
|
719
|
+
react: '^18.2.0',
|
|
720
|
+
'react-dom': '^18.2.0',
|
|
721
|
+
},
|
|
722
|
+
devDependencies: {
|
|
723
|
+
'@types/react': '^18.2.0',
|
|
724
|
+
'@types/react-dom': '^18.2.0',
|
|
725
|
+
'@typescript-eslint/eslint-plugin': '^8.0.0',
|
|
726
|
+
'@typescript-eslint/parser': '^8.0.0',
|
|
727
|
+
'@vitejs/plugin-react': '^4.2.0',
|
|
728
|
+
'@vitest/coverage-v8': '^2.0.0',
|
|
729
|
+
autoprefixer: '^10.4.0',
|
|
730
|
+
eslint: '^9.0.0',
|
|
731
|
+
'eslint-plugin-react-hooks': '^4.6.0',
|
|
732
|
+
'eslint-plugin-react-refresh': '^0.4.0',
|
|
733
|
+
postcss: '^8.4.0',
|
|
734
|
+
tailwindcss: '^3.4.0',
|
|
735
|
+
typescript: '^5.4.0',
|
|
736
|
+
vite: '^5.2.0',
|
|
737
|
+
vitest: '^2.0.0',
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
null,
|
|
741
|
+
2
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Generate frontend tsconfig.json for React
|
|
747
|
+
*/
|
|
748
|
+
export function generateFrontendTsconfig(): string {
|
|
749
|
+
return JSON.stringify(
|
|
750
|
+
{
|
|
751
|
+
compilerOptions: {
|
|
752
|
+
target: 'ES2020',
|
|
753
|
+
useDefineForClassFields: true,
|
|
754
|
+
lib: ['ES2020', 'DOM', 'DOM.Iterable'],
|
|
755
|
+
module: 'ESNext',
|
|
756
|
+
skipLibCheck: true,
|
|
757
|
+
moduleResolution: 'bundler',
|
|
758
|
+
allowImportingTsExtensions: true,
|
|
759
|
+
resolveJsonModule: true,
|
|
760
|
+
isolatedModules: true,
|
|
761
|
+
noEmit: true,
|
|
762
|
+
jsx: 'react-jsx',
|
|
763
|
+
strict: true,
|
|
764
|
+
noUnusedLocals: true,
|
|
765
|
+
noUnusedParameters: true,
|
|
766
|
+
noFallthroughCasesInSwitch: true,
|
|
767
|
+
paths: {
|
|
768
|
+
'@/*': ['./src/*'],
|
|
769
|
+
},
|
|
770
|
+
},
|
|
771
|
+
include: ['src'],
|
|
772
|
+
references: [{ path: './tsconfig.node.json' }],
|
|
773
|
+
},
|
|
774
|
+
null,
|
|
775
|
+
2
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Generate frontend tsconfig.node.json
|
|
781
|
+
*/
|
|
782
|
+
export function generateFrontendTsconfigNode(): string {
|
|
783
|
+
return JSON.stringify(
|
|
784
|
+
{
|
|
785
|
+
compilerOptions: {
|
|
786
|
+
composite: true,
|
|
787
|
+
skipLibCheck: true,
|
|
788
|
+
module: 'ESNext',
|
|
789
|
+
moduleResolution: 'bundler',
|
|
790
|
+
allowSyntheticDefaultImports: true,
|
|
791
|
+
strict: true,
|
|
792
|
+
},
|
|
793
|
+
include: ['vite.config.ts'],
|
|
794
|
+
},
|
|
795
|
+
null,
|
|
796
|
+
2
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Generate frontend Dockerfile for React + nginx
|
|
802
|
+
*/
|
|
803
|
+
export function generateFrontendDockerfile(): string {
|
|
804
|
+
return `# Build stage
|
|
805
|
+
FROM node:20-slim as build
|
|
806
|
+
|
|
807
|
+
WORKDIR /app
|
|
808
|
+
|
|
809
|
+
COPY package*.json ./
|
|
810
|
+
RUN npm ci
|
|
811
|
+
|
|
812
|
+
COPY . .
|
|
813
|
+
RUN npm run build
|
|
814
|
+
|
|
815
|
+
# Production stage
|
|
816
|
+
FROM nginx:alpine as production
|
|
817
|
+
|
|
818
|
+
COPY --from=build /app/dist /usr/share/nginx/html
|
|
819
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
820
|
+
|
|
821
|
+
EXPOSE 80
|
|
822
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
823
|
+
|
|
824
|
+
# Development stage
|
|
825
|
+
FROM node:20-slim as development
|
|
826
|
+
|
|
827
|
+
WORKDIR /app
|
|
828
|
+
|
|
829
|
+
COPY package*.json ./
|
|
830
|
+
RUN npm ci
|
|
831
|
+
|
|
832
|
+
COPY . .
|
|
833
|
+
|
|
834
|
+
EXPOSE 5173
|
|
835
|
+
CMD ["npm", "run", "dev", "--", "--host"]
|
|
836
|
+
`;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Generate nginx config for frontend
|
|
841
|
+
*/
|
|
842
|
+
export function generateNginxConfig(): string {
|
|
843
|
+
return `server {
|
|
844
|
+
listen 80;
|
|
845
|
+
server_name localhost;
|
|
846
|
+
root /usr/share/nginx/html;
|
|
847
|
+
index index.html;
|
|
848
|
+
|
|
849
|
+
# Handle SPA routing
|
|
850
|
+
location / {
|
|
851
|
+
try_files $uri $uri/ /index.html;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
# Proxy API requests to backend
|
|
855
|
+
location /api {
|
|
856
|
+
proxy_pass http://backend:8000;
|
|
857
|
+
proxy_http_version 1.1;
|
|
858
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
859
|
+
proxy_set_header Connection 'upgrade';
|
|
860
|
+
proxy_set_header Host $host;
|
|
861
|
+
proxy_cache_bypass $http_upgrade;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
# Cache static assets
|
|
865
|
+
location ~* \\.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
|
866
|
+
expires 1y;
|
|
867
|
+
add_header Cache-Control "public, immutable";
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
`;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Generate frontend test file
|
|
875
|
+
*/
|
|
876
|
+
export function generateFrontendTest(projectName: string): string {
|
|
877
|
+
return `import { describe, it, expect } from 'vitest';
|
|
878
|
+
import { render, screen } from '@testing-library/react';
|
|
879
|
+
import App from '../src/App';
|
|
880
|
+
|
|
881
|
+
describe('App', () => {
|
|
882
|
+
it('renders the project name', () => {
|
|
883
|
+
render(<App />);
|
|
884
|
+
expect(screen.getByText('${projectName}')).toBeDefined();
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
it('shows loading state initially', () => {
|
|
888
|
+
render(<App />);
|
|
889
|
+
expect(screen.getByText('Checking...')).toBeDefined();
|
|
890
|
+
});
|
|
891
|
+
});
|
|
892
|
+
`;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Generate vitest setup for React
|
|
897
|
+
*/
|
|
898
|
+
export function generateVitestSetup(): string {
|
|
899
|
+
return `import '@testing-library/jest-dom';
|
|
900
|
+
`;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Generate vitest config for React
|
|
905
|
+
*/
|
|
906
|
+
export function generateFrontendVitestConfig(): string {
|
|
907
|
+
return `import { defineConfig } from 'vitest/config';
|
|
908
|
+
import react from '@vitejs/plugin-react';
|
|
909
|
+
|
|
910
|
+
export default defineConfig({
|
|
911
|
+
plugins: [react()],
|
|
912
|
+
test: {
|
|
913
|
+
globals: true,
|
|
914
|
+
environment: 'jsdom',
|
|
915
|
+
setupFiles: './tests/setup.ts',
|
|
916
|
+
coverage: {
|
|
917
|
+
provider: 'v8',
|
|
918
|
+
reporter: ['text', 'json', 'html'],
|
|
919
|
+
exclude: ['node_modules/', 'tests/'],
|
|
920
|
+
},
|
|
921
|
+
},
|
|
922
|
+
});
|
|
923
|
+
`;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Generate backend FastAPI main.py
|
|
928
|
+
*/
|
|
929
|
+
export function generateFastAPIMain(projectName: string): string {
|
|
930
|
+
return `"""
|
|
931
|
+
${projectName} Backend API
|
|
932
|
+
|
|
933
|
+
FastAPI application entry point.
|
|
934
|
+
"""
|
|
935
|
+
|
|
936
|
+
import logging
|
|
937
|
+
from fastapi import FastAPI
|
|
938
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
939
|
+
|
|
940
|
+
# Configure logging
|
|
941
|
+
logging.basicConfig(level=logging.INFO)
|
|
942
|
+
logger = logging.getLogger(__name__)
|
|
943
|
+
|
|
944
|
+
# Create FastAPI app
|
|
945
|
+
app = FastAPI(
|
|
946
|
+
title="${projectName} API",
|
|
947
|
+
description="Backend API for ${projectName}",
|
|
948
|
+
version="1.0.0",
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
# Configure CORS
|
|
952
|
+
app.add_middleware(
|
|
953
|
+
CORSMiddleware,
|
|
954
|
+
allow_origins=["http://localhost:5173", "http://localhost:3000"],
|
|
955
|
+
allow_credentials=True,
|
|
956
|
+
allow_methods=["*"],
|
|
957
|
+
allow_headers=["*"],
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
@app.get("/health")
|
|
962
|
+
async def health_check():
|
|
963
|
+
"""
|
|
964
|
+
Health check endpoint.
|
|
965
|
+
|
|
966
|
+
Returns:
|
|
967
|
+
dict: Health status.
|
|
968
|
+
"""
|
|
969
|
+
return {
|
|
970
|
+
"status": "healthy",
|
|
971
|
+
"message": "Backend is running",
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
@app.get("/")
|
|
976
|
+
async def root():
|
|
977
|
+
"""
|
|
978
|
+
Root endpoint.
|
|
979
|
+
|
|
980
|
+
Returns:
|
|
981
|
+
dict: Welcome message.
|
|
982
|
+
"""
|
|
983
|
+
return {
|
|
984
|
+
"message": "Welcome to ${projectName} API",
|
|
985
|
+
"docs": "/docs",
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
if __name__ == "__main__":
|
|
990
|
+
import uvicorn
|
|
991
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
992
|
+
`;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Generate backend Dockerfile for FastAPI
|
|
997
|
+
*/
|
|
998
|
+
export function generateBackendDockerfile(_projectName: string): string {
|
|
999
|
+
return `# Python base image
|
|
1000
|
+
FROM python:3.11-slim
|
|
1001
|
+
|
|
1002
|
+
WORKDIR /app
|
|
1003
|
+
|
|
1004
|
+
# Install system dependencies
|
|
1005
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \\
|
|
1006
|
+
build-essential \\
|
|
1007
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
1008
|
+
|
|
1009
|
+
# Copy requirements first for caching
|
|
1010
|
+
COPY requirements.txt pyproject.toml ./
|
|
1011
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
1012
|
+
|
|
1013
|
+
# Copy application code
|
|
1014
|
+
COPY src/ ./src/
|
|
1015
|
+
COPY tests/ ./tests/
|
|
1016
|
+
|
|
1017
|
+
# Install the package
|
|
1018
|
+
RUN pip install -e .
|
|
1019
|
+
|
|
1020
|
+
# Create non-root user
|
|
1021
|
+
RUN adduser --disabled-password --gecos '' appuser
|
|
1022
|
+
RUN mkdir -p /app/data && chown -R appuser:appuser /app
|
|
1023
|
+
USER appuser
|
|
1024
|
+
|
|
1025
|
+
EXPOSE 8000
|
|
1026
|
+
|
|
1027
|
+
CMD ["uvicorn", "src.backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
1028
|
+
`;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* Generate backend requirements.txt for FastAPI
|
|
1033
|
+
*/
|
|
1034
|
+
export function generateFastAPIRequirements(): string {
|
|
1035
|
+
return `# FastAPI and dependencies
|
|
1036
|
+
fastapi>=0.109.0
|
|
1037
|
+
uvicorn[standard]>=0.27.0
|
|
1038
|
+
pydantic>=2.5.0
|
|
1039
|
+
pydantic-settings>=2.1.0
|
|
1040
|
+
|
|
1041
|
+
# Development
|
|
1042
|
+
ruff>=0.1.0
|
|
1043
|
+
pytest>=7.4.0
|
|
1044
|
+
pytest-asyncio>=0.23.0
|
|
1045
|
+
httpx>=0.26.0
|
|
1046
|
+
`;
|
|
1047
|
+
}
|