popeye-cli 1.7.0 → 1.8.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.
Files changed (132) hide show
  1. package/README.md +102 -5
  2. package/cheatsheet.md +407 -0
  3. package/dist/cli/commands/db.d.ts +10 -0
  4. package/dist/cli/commands/db.d.ts.map +1 -0
  5. package/dist/cli/commands/db.js +240 -0
  6. package/dist/cli/commands/db.js.map +1 -0
  7. package/dist/cli/commands/doctor.d.ts +18 -0
  8. package/dist/cli/commands/doctor.d.ts.map +1 -0
  9. package/dist/cli/commands/doctor.js +255 -0
  10. package/dist/cli/commands/doctor.js.map +1 -0
  11. package/dist/cli/commands/index.d.ts +2 -0
  12. package/dist/cli/commands/index.d.ts.map +1 -1
  13. package/dist/cli/commands/index.js +2 -0
  14. package/dist/cli/commands/index.js.map +1 -1
  15. package/dist/cli/index.d.ts.map +1 -1
  16. package/dist/cli/index.js +3 -1
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/interactive.d.ts.map +1 -1
  19. package/dist/cli/interactive.js +96 -0
  20. package/dist/cli/interactive.js.map +1 -1
  21. package/dist/generators/admin-wizard.d.ts +25 -0
  22. package/dist/generators/admin-wizard.d.ts.map +1 -0
  23. package/dist/generators/admin-wizard.js +123 -0
  24. package/dist/generators/admin-wizard.js.map +1 -0
  25. package/dist/generators/all.d.ts.map +1 -1
  26. package/dist/generators/all.js +10 -3
  27. package/dist/generators/all.js.map +1 -1
  28. package/dist/generators/database.d.ts +58 -0
  29. package/dist/generators/database.d.ts.map +1 -0
  30. package/dist/generators/database.js +229 -0
  31. package/dist/generators/database.js.map +1 -0
  32. package/dist/generators/fullstack.d.ts.map +1 -1
  33. package/dist/generators/fullstack.js +23 -7
  34. package/dist/generators/fullstack.js.map +1 -1
  35. package/dist/generators/index.d.ts +2 -0
  36. package/dist/generators/index.d.ts.map +1 -1
  37. package/dist/generators/index.js +2 -0
  38. package/dist/generators/index.js.map +1 -1
  39. package/dist/generators/templates/admin-wizard-python.d.ts +32 -0
  40. package/dist/generators/templates/admin-wizard-python.d.ts.map +1 -0
  41. package/dist/generators/templates/admin-wizard-python.js +425 -0
  42. package/dist/generators/templates/admin-wizard-python.js.map +1 -0
  43. package/dist/generators/templates/admin-wizard-react.d.ts +48 -0
  44. package/dist/generators/templates/admin-wizard-react.d.ts.map +1 -0
  45. package/dist/generators/templates/admin-wizard-react.js +554 -0
  46. package/dist/generators/templates/admin-wizard-react.js.map +1 -0
  47. package/dist/generators/templates/database-docker.d.ts +23 -0
  48. package/dist/generators/templates/database-docker.d.ts.map +1 -0
  49. package/dist/generators/templates/database-docker.js +221 -0
  50. package/dist/generators/templates/database-docker.js.map +1 -0
  51. package/dist/generators/templates/database-python.d.ts +54 -0
  52. package/dist/generators/templates/database-python.d.ts.map +1 -0
  53. package/dist/generators/templates/database-python.js +723 -0
  54. package/dist/generators/templates/database-python.js.map +1 -0
  55. package/dist/generators/templates/database-typescript.d.ts +34 -0
  56. package/dist/generators/templates/database-typescript.d.ts.map +1 -0
  57. package/dist/generators/templates/database-typescript.js +232 -0
  58. package/dist/generators/templates/database-typescript.js.map +1 -0
  59. package/dist/generators/templates/fullstack.d.ts.map +1 -1
  60. package/dist/generators/templates/fullstack.js +29 -0
  61. package/dist/generators/templates/fullstack.js.map +1 -1
  62. package/dist/generators/templates/index.d.ts +5 -0
  63. package/dist/generators/templates/index.d.ts.map +1 -1
  64. package/dist/generators/templates/index.js +5 -0
  65. package/dist/generators/templates/index.js.map +1 -1
  66. package/dist/state/index.d.ts +10 -0
  67. package/dist/state/index.d.ts.map +1 -1
  68. package/dist/state/index.js +21 -0
  69. package/dist/state/index.js.map +1 -1
  70. package/dist/types/database-runtime.d.ts +86 -0
  71. package/dist/types/database-runtime.d.ts.map +1 -0
  72. package/dist/types/database-runtime.js +61 -0
  73. package/dist/types/database-runtime.js.map +1 -0
  74. package/dist/types/database.d.ts +85 -0
  75. package/dist/types/database.d.ts.map +1 -0
  76. package/dist/types/database.js +71 -0
  77. package/dist/types/database.js.map +1 -0
  78. package/dist/types/index.d.ts +2 -0
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/dist/types/index.js +4 -0
  81. package/dist/types/index.js.map +1 -1
  82. package/dist/types/workflow.d.ts +21 -0
  83. package/dist/types/workflow.d.ts.map +1 -1
  84. package/dist/types/workflow.js +2 -0
  85. package/dist/types/workflow.js.map +1 -1
  86. package/dist/workflow/db-setup-runner.d.ts +63 -0
  87. package/dist/workflow/db-setup-runner.d.ts.map +1 -0
  88. package/dist/workflow/db-setup-runner.js +336 -0
  89. package/dist/workflow/db-setup-runner.js.map +1 -0
  90. package/dist/workflow/db-state-machine.d.ts +30 -0
  91. package/dist/workflow/db-state-machine.d.ts.map +1 -0
  92. package/dist/workflow/db-state-machine.js +51 -0
  93. package/dist/workflow/db-state-machine.js.map +1 -0
  94. package/dist/workflow/index.d.ts +2 -0
  95. package/dist/workflow/index.d.ts.map +1 -1
  96. package/dist/workflow/index.js +2 -0
  97. package/dist/workflow/index.js.map +1 -1
  98. package/package.json +1 -1
  99. package/src/cli/commands/db.ts +281 -0
  100. package/src/cli/commands/doctor.ts +273 -0
  101. package/src/cli/commands/index.ts +2 -0
  102. package/src/cli/index.ts +4 -0
  103. package/src/cli/interactive.ts +102 -0
  104. package/src/generators/admin-wizard.ts +146 -0
  105. package/src/generators/all.ts +10 -3
  106. package/src/generators/database.ts +286 -0
  107. package/src/generators/fullstack.ts +26 -9
  108. package/src/generators/index.ts +12 -0
  109. package/src/generators/templates/admin-wizard-python.ts +431 -0
  110. package/src/generators/templates/admin-wizard-react.ts +560 -0
  111. package/src/generators/templates/database-docker.ts +227 -0
  112. package/src/generators/templates/database-python.ts +734 -0
  113. package/src/generators/templates/database-typescript.ts +238 -0
  114. package/src/generators/templates/fullstack.ts +29 -0
  115. package/src/generators/templates/index.ts +5 -0
  116. package/src/state/index.ts +28 -0
  117. package/src/types/database-runtime.ts +69 -0
  118. package/src/types/database.ts +84 -0
  119. package/src/types/index.ts +29 -0
  120. package/src/types/workflow.ts +5 -0
  121. package/src/workflow/db-setup-runner.ts +391 -0
  122. package/src/workflow/db-state-machine.ts +58 -0
  123. package/src/workflow/index.ts +2 -0
  124. package/tests/generators/admin-wizard-orchestrator.test.ts +64 -0
  125. package/tests/generators/admin-wizard-templates.test.ts +366 -0
  126. package/tests/generators/cross-phase-integration.test.ts +383 -0
  127. package/tests/generators/database.test.ts +456 -0
  128. package/tests/generators/fe-be-db-integration.test.ts +613 -0
  129. package/tests/types/database-runtime.test.ts +158 -0
  130. package/tests/types/database.test.ts +187 -0
  131. package/tests/workflow/db-setup-runner.test.ts +211 -0
  132. package/tests/workflow/db-state-machine.test.ts +117 -0
@@ -0,0 +1,554 @@
1
+ /**
2
+ * Admin Wizard React frontend templates
3
+ * Generates React components for the database setup wizard UI
4
+ */
5
+ /**
6
+ * Generate useAdminApi custom hook for authenticated API calls
7
+ *
8
+ * @returns TypeScript source for useAdminApi.ts
9
+ */
10
+ export function generateUseAdminApiHook() {
11
+ return `/**
12
+ * Custom hook for admin API calls with token authentication.
13
+ */
14
+
15
+ interface ApiOptions {
16
+ method?: string;
17
+ body?: unknown;
18
+ }
19
+
20
+ interface ApiResult<T = unknown> {
21
+ data: T | null;
22
+ error: string | null;
23
+ }
24
+
25
+ export function useAdminApi() {
26
+ const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
27
+ const adminToken = import.meta.env.VITE_ADMIN_TOKEN || '';
28
+
29
+ async function callApi<T = unknown>(
30
+ path: string,
31
+ options: ApiOptions = {}
32
+ ): Promise<ApiResult<T>> {
33
+ const { method = 'GET', body } = options;
34
+ try {
35
+ const response = await fetch(\`\${apiUrl}\${path}\`, {
36
+ method,
37
+ headers: {
38
+ 'Content-Type': 'application/json',
39
+ 'X-Admin-Token': adminToken,
40
+ },
41
+ body: body ? JSON.stringify(body) : undefined,
42
+ });
43
+
44
+ if (!response.ok) {
45
+ const text = await response.text();
46
+ return { data: null, error: text || \`HTTP \${response.status}\` };
47
+ }
48
+
49
+ const data = (await response.json()) as T;
50
+ return { data, error: null };
51
+ } catch (err) {
52
+ const message = err instanceof Error ? err.message : 'Unknown error';
53
+ return { data: null, error: message };
54
+ }
55
+ }
56
+
57
+ return { callApi };
58
+ }
59
+ `;
60
+ }
61
+ /**
62
+ * Generate DbStatusBanner component that polls DB status and shows setup prompt
63
+ *
64
+ * @returns TypeScript/React source for DbStatusBanner.tsx
65
+ */
66
+ export function generateDbStatusBanner() {
67
+ return `import { useState, useEffect } from 'react';
68
+ import { useAdminApi } from './useAdminApi';
69
+
70
+ interface DbStatus {
71
+ status: string;
72
+ mode: string;
73
+ lastError: string | null;
74
+ migrationsApplied: number;
75
+ dbUrlConfigured: boolean;
76
+ }
77
+
78
+ interface DbStatusBannerProps {
79
+ onSetupClick: () => void;
80
+ }
81
+
82
+ /**
83
+ * Banner that polls the database status on mount.
84
+ * Hidden when status is "ready". Shows an amber bar when
85
+ * the database is unconfigured or in error state.
86
+ */
87
+ export function DbStatusBanner({ onSetupClick }: DbStatusBannerProps) {
88
+ const { callApi } = useAdminApi();
89
+ const [status, setStatus] = useState<DbStatus | null>(null);
90
+ const [loading, setLoading] = useState(true);
91
+
92
+ useEffect(() => {
93
+ let cancelled = false;
94
+
95
+ async function fetchStatus() {
96
+ const result = await callApi<DbStatus>('/api/admin/db/status');
97
+ if (!cancelled) {
98
+ setStatus(result.data);
99
+ setLoading(false);
100
+ }
101
+ }
102
+
103
+ fetchStatus();
104
+ return () => { cancelled = true; };
105
+ }, []);
106
+
107
+ if (loading) return null;
108
+ if (!status) return null;
109
+ if (status.status === 'ready') return null;
110
+
111
+ return (
112
+ <div className="bg-amber-50 border-b border-amber-200 px-4 py-3 flex items-center justify-between">
113
+ <div className="flex items-center gap-2">
114
+ <span className="inline-block w-2 h-2 rounded-full bg-amber-400" />
115
+ <span className="text-amber-800 text-sm font-medium">
116
+ {status.status === 'error'
117
+ ? \`Database error: \${status.lastError || 'Unknown'}\`
118
+ : 'Database is not configured'}
119
+ </span>
120
+ </div>
121
+ <button
122
+ onClick={onSetupClick}
123
+ className="bg-amber-500 hover:bg-amber-600 text-white text-sm font-medium px-4 py-1.5 rounded transition-colors"
124
+ >
125
+ Set up database
126
+ </button>
127
+ </div>
128
+ );
129
+ }
130
+ `;
131
+ }
132
+ /**
133
+ * Generate ConnectionForm component for testing DB URLs
134
+ *
135
+ * @returns TypeScript/React source for ConnectionForm.tsx
136
+ */
137
+ export function generateConnectionForm() {
138
+ return `import { useState } from 'react';
139
+ import { useAdminApi } from './useAdminApi';
140
+
141
+ interface ConnectionFormProps {
142
+ onTestSuccess: (url: string) => void;
143
+ onBack: () => void;
144
+ }
145
+
146
+ /**
147
+ * Form to enter a DATABASE_URL and test the connection.
148
+ * Calls POST /api/admin/db/test and reports success/failure.
149
+ */
150
+ export function ConnectionForm({ onTestSuccess, onBack }: ConnectionFormProps) {
151
+ const { callApi } = useAdminApi();
152
+ const [url, setUrl] = useState('');
153
+ const [testing, setTesting] = useState(false);
154
+ const [result, setResult] = useState<{ success: boolean; message: string } | null>(null);
155
+
156
+ async function handleTest() {
157
+ if (!url.trim()) return;
158
+ setTesting(true);
159
+ setResult(null);
160
+
161
+ const res = await callApi<{ success: boolean; message: string }>(
162
+ '/api/admin/db/test',
163
+ { method: 'POST', body: { database_url: url } }
164
+ );
165
+
166
+ setTesting(false);
167
+
168
+ if (res.data) {
169
+ setResult(res.data);
170
+ if (res.data.success) {
171
+ onTestSuccess(url);
172
+ }
173
+ } else {
174
+ setResult({ success: false, message: res.error || 'Connection failed' });
175
+ }
176
+ }
177
+
178
+ return (
179
+ <div className="space-y-4">
180
+ <div>
181
+ <label htmlFor="db-url" className="block text-sm font-medium text-gray-700 mb-1">
182
+ DATABASE_URL
183
+ </label>
184
+ <input
185
+ id="db-url"
186
+ type="text"
187
+ value={url}
188
+ onChange={(e) => setUrl(e.target.value)}
189
+ placeholder="postgresql://user:pass@host:5432/dbname"
190
+ className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-sm"
191
+ />
192
+ </div>
193
+
194
+ {result && (
195
+ <div className={\`text-sm p-3 rounded \${result.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'}\`}>
196
+ {result.message}
197
+ </div>
198
+ )}
199
+
200
+ <div className="flex gap-3">
201
+ <button
202
+ onClick={onBack}
203
+ className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"
204
+ >
205
+ Back
206
+ </button>
207
+ <button
208
+ onClick={handleTest}
209
+ disabled={testing || !url.trim()}
210
+ className="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
211
+ >
212
+ {testing ? 'Testing...' : 'Test Connection'}
213
+ </button>
214
+ </div>
215
+ </div>
216
+ );
217
+ }
218
+ `;
219
+ }
220
+ /**
221
+ * Generate MigrationProgress component that polls status during apply
222
+ *
223
+ * @returns TypeScript/React source for MigrationProgress.tsx
224
+ */
225
+ export function generateMigrationProgress() {
226
+ return `import { useState, useEffect, useRef } from 'react';
227
+ import { useAdminApi } from './useAdminApi';
228
+
229
+ interface StepResult {
230
+ step: string;
231
+ success: boolean;
232
+ message: string;
233
+ }
234
+
235
+ interface MigrationProgressProps {
236
+ databaseUrl: string;
237
+ onComplete: () => void;
238
+ onError: (msg: string) => void;
239
+ }
240
+
241
+ /**
242
+ * Runs POST /api/admin/db/apply then polls GET /api/admin/db/status
243
+ * every 2 seconds while in "applying" state.
244
+ * Shows a step-by-step progress list.
245
+ */
246
+ export function MigrationProgress({ databaseUrl, onComplete, onError }: MigrationProgressProps) {
247
+ const { callApi } = useAdminApi();
248
+ const [steps, setSteps] = useState<StepResult[]>([]);
249
+ const [applying, setApplying] = useState(true);
250
+ const started = useRef(false);
251
+
252
+ useEffect(() => {
253
+ if (started.current) return;
254
+ started.current = true;
255
+
256
+ async function runApply() {
257
+ const res = await callApi<{ steps: StepResult[]; status: string }>(
258
+ '/api/admin/db/apply',
259
+ { method: 'POST', body: { database_url: databaseUrl } }
260
+ );
261
+
262
+ if (res.data) {
263
+ setSteps(res.data.steps);
264
+ if (res.data.status === 'ready') {
265
+ setApplying(false);
266
+ onComplete();
267
+ } else if (res.data.status === 'error') {
268
+ setApplying(false);
269
+ const failedStep = res.data.steps.find((s) => !s.success);
270
+ onError(failedStep?.message || 'Setup failed');
271
+ }
272
+ } else {
273
+ setApplying(false);
274
+ onError(res.error || 'Failed to apply setup');
275
+ }
276
+ }
277
+
278
+ runApply();
279
+ }, [databaseUrl]);
280
+
281
+ useEffect(() => {
282
+ if (!applying) return;
283
+
284
+ const interval = setInterval(async () => {
285
+ const res = await callApi<{ status: string }>('/api/admin/db/status');
286
+ if (res.data) {
287
+ if (res.data.status === 'ready') {
288
+ setApplying(false);
289
+ onComplete();
290
+ } else if (res.data.status === 'error') {
291
+ setApplying(false);
292
+ }
293
+ }
294
+ }, 2000);
295
+
296
+ return () => clearInterval(interval);
297
+ }, [applying]);
298
+
299
+ return (
300
+ <div className="space-y-3">
301
+ <h3 className="text-sm font-semibold text-gray-700">Applying Setup</h3>
302
+ <ul className="space-y-2">
303
+ {steps.map((step, i) => (
304
+ <li key={i} className="flex items-center gap-2 text-sm">
305
+ <span className={\`inline-block w-4 h-4 rounded-full flex items-center justify-center text-xs \${
306
+ step.success ? 'bg-green-100 text-green-600' : 'bg-red-100 text-red-600'
307
+ }\`}>
308
+ {step.success ? '\\u2713' : '\\u2717'}
309
+ </span>
310
+ <span className={step.success ? 'text-gray-700' : 'text-red-700'}>
311
+ {step.message}
312
+ </span>
313
+ </li>
314
+ ))}
315
+ {applying && (
316
+ <li className="flex items-center gap-2 text-sm text-gray-500">
317
+ <span className="inline-block w-4 h-4 rounded-full bg-blue-100 animate-pulse" />
318
+ Running...
319
+ </li>
320
+ )}
321
+ </ul>
322
+ </div>
323
+ );
324
+ }
325
+ `;
326
+ }
327
+ /**
328
+ * Generate DbSetupStepper component - multi-step wizard overlay
329
+ *
330
+ * @returns TypeScript/React source for DbSetupStepper.tsx
331
+ */
332
+ export function generateDbSetupStepper() {
333
+ return `import { useState } from 'react';
334
+ import { ConnectionForm } from './ConnectionForm';
335
+ import { MigrationProgress } from './MigrationProgress';
336
+
337
+ type WizardStep = 'choose' | 'credentials' | 'apply' | 'ready';
338
+
339
+ interface DbSetupStepperProps {
340
+ onClose: () => void;
341
+ }
342
+
343
+ const STEP_LABELS: Record<WizardStep, string> = {
344
+ choose: 'Setup Mode',
345
+ credentials: 'Connection',
346
+ apply: 'Applying',
347
+ ready: 'Complete',
348
+ };
349
+
350
+ const STEP_ORDER: WizardStep[] = ['choose', 'credentials', 'apply', 'ready'];
351
+
352
+ /**
353
+ * Multi-step database setup wizard rendered as a modal overlay.
354
+ * State machine: choose -> credentials -> apply -> ready
355
+ */
356
+ export function DbSetupStepper({ onClose }: DbSetupStepperProps) {
357
+ const [step, setStep] = useState<WizardStep>('choose');
358
+ const [dbUrl, setDbUrl] = useState('');
359
+ const [errorMsg, setErrorMsg] = useState('');
360
+
361
+ const currentIndex = STEP_ORDER.indexOf(step);
362
+
363
+ return (
364
+ <div className="fixed inset-0 z-50 flex items-center justify-center">
365
+ {/* Backdrop */}
366
+ <div className="absolute inset-0 bg-black/50" onClick={onClose} />
367
+
368
+ {/* Panel */}
369
+ <div className="relative bg-white rounded-xl shadow-2xl w-full max-w-lg mx-4 p-6">
370
+ {/* Close button */}
371
+ <button
372
+ onClick={onClose}
373
+ className="absolute top-3 right-3 text-gray-400 hover:text-gray-600 text-xl leading-none"
374
+ aria-label="Close"
375
+ >
376
+ \\u00d7
377
+ </button>
378
+
379
+ <h2 className="text-lg font-bold text-gray-900 mb-4">Database Setup</h2>
380
+
381
+ {/* Step indicator */}
382
+ <div className="flex gap-1 mb-6">
383
+ {STEP_ORDER.map((s, i) => (
384
+ <div key={s} className="flex-1">
385
+ <div className={\`h-1.5 rounded-full \${
386
+ i <= currentIndex ? 'bg-blue-500' : 'bg-gray-200'
387
+ }\`} />
388
+ <span className={\`block text-xs mt-1 \${
389
+ i === currentIndex ? 'text-blue-600 font-medium' : 'text-gray-400'
390
+ }\`}>
391
+ {STEP_LABELS[s]}
392
+ </span>
393
+ </div>
394
+ ))}
395
+ </div>
396
+
397
+ {/* Step content */}
398
+ {step === 'choose' && (
399
+ <div className="space-y-4">
400
+ <p className="text-sm text-gray-600">
401
+ Configure your PostgreSQL database to enable data persistence.
402
+ </p>
403
+ <button
404
+ onClick={() => setStep('credentials')}
405
+ className="w-full px-4 py-3 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors"
406
+ >
407
+ Enter connection details
408
+ </button>
409
+ </div>
410
+ )}
411
+
412
+ {step === 'credentials' && (
413
+ <ConnectionForm
414
+ onTestSuccess={(url) => {
415
+ setDbUrl(url);
416
+ setStep('apply');
417
+ }}
418
+ onBack={() => setStep('choose')}
419
+ />
420
+ )}
421
+
422
+ {step === 'apply' && (
423
+ <MigrationProgress
424
+ databaseUrl={dbUrl}
425
+ onComplete={() => setStep('ready')}
426
+ onError={(msg) => setErrorMsg(msg)}
427
+ />
428
+ )}
429
+
430
+ {step === 'ready' && (
431
+ <div className="text-center space-y-4">
432
+ <div className="inline-flex items-center justify-center w-12 h-12 rounded-full bg-green-100">
433
+ <span className="text-green-600 text-2xl">\\u2713</span>
434
+ </div>
435
+ <p className="text-gray-700 font-medium">Database is ready!</p>
436
+ <button
437
+ onClick={onClose}
438
+ className="px-6 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700"
439
+ >
440
+ Done
441
+ </button>
442
+ </div>
443
+ )}
444
+
445
+ {errorMsg && step === 'apply' && (
446
+ <div className="mt-4 p-3 bg-red-50 text-red-700 text-sm rounded">
447
+ {errorMsg}
448
+ </div>
449
+ )}
450
+ </div>
451
+ </div>
452
+ );
453
+ }
454
+ `;
455
+ }
456
+ /**
457
+ * Generate admin barrel export index
458
+ *
459
+ * @returns TypeScript source for admin/index.ts
460
+ */
461
+ export function generateAdminIndex() {
462
+ return `/**
463
+ * Admin wizard components barrel export.
464
+ */
465
+
466
+ export { DbStatusBanner } from './DbStatusBanner';
467
+ export { DbSetupStepper } from './DbSetupStepper';
468
+ `;
469
+ }
470
+ /**
471
+ * Generate App.tsx that includes DbStatusBanner and DbSetupStepper
472
+ *
473
+ * @param projectName - Human-readable project name
474
+ * @returns TypeScript/React source for App.tsx
475
+ */
476
+ export function generateAppTsxWithAdmin(projectName) {
477
+ return `import { useState, useEffect } from 'react';
478
+ import { DbStatusBanner } from './admin';
479
+ import { DbSetupStepper } from './admin';
480
+
481
+ interface HealthStatus {
482
+ status: string;
483
+ message: string;
484
+ }
485
+
486
+ function App() {
487
+ const [health, setHealth] = useState<HealthStatus | null>(null);
488
+ const [loading, setLoading] = useState(true);
489
+ const [error, setError] = useState<string | null>(null);
490
+ const [showWizard, setShowWizard] = useState(false);
491
+
492
+ useEffect(() => {
493
+ const checkHealth = async () => {
494
+ try {
495
+ const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
496
+ const response = await fetch(\`\${apiUrl}/health\`);
497
+ if (response.ok) {
498
+ const data = await response.json();
499
+ setHealth(data);
500
+ } else {
501
+ setError('Backend not responding');
502
+ }
503
+ } catch (err) {
504
+ setError('Failed to connect to backend');
505
+ } finally {
506
+ setLoading(false);
507
+ }
508
+ };
509
+
510
+ checkHealth();
511
+ }, []);
512
+
513
+ return (
514
+ <div className="min-h-screen flex flex-col">
515
+ <DbStatusBanner onSetupClick={() => setShowWizard(true)} />
516
+
517
+ <div className="flex-1 flex items-center justify-center">
518
+ <div className="text-center p-8">
519
+ <h1 className="text-4xl font-bold text-primary-600 mb-4">
520
+ ${projectName}
521
+ </h1>
522
+ <p className="text-gray-600 mb-8">
523
+ Fullstack application with React + FastAPI
524
+ </p>
525
+
526
+ <div className="bg-white rounded-lg shadow-md p-6">
527
+ <h2 className="text-lg font-semibold mb-2">Backend Status</h2>
528
+ {loading && (
529
+ <p className="text-gray-500">Checking...</p>
530
+ )}
531
+ {error && (
532
+ <p className="text-red-500">{error}</p>
533
+ )}
534
+ {health && (
535
+ <div className="text-green-500">
536
+ <p>Status: {health.status}</p>
537
+ <p className="text-sm text-gray-500">{health.message}</p>
538
+ </div>
539
+ )}
540
+ </div>
541
+ </div>
542
+ </div>
543
+
544
+ {showWizard && (
545
+ <DbSetupStepper onClose={() => setShowWizard(false)} />
546
+ )}
547
+ </div>
548
+ );
549
+ }
550
+
551
+ export default App;
552
+ `;
553
+ }
554
+ //# sourceMappingURL=admin-wizard-react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-wizard-react.js","sourceRoot":"","sources":["../../../src/generators/templates/admin-wizard-react.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgFR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmGR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyHR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAmB;IACzD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2CK,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCxB,CAAC;AACF,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Docker-related database template functions
3
+ * Generates PostgreSQL service configs and docker-compose files
4
+ */
5
+ /**
6
+ * Generate PostgreSQL service YAML block for docker-compose
7
+ */
8
+ export declare function generatePostgresServiceYaml(projectName: string): string;
9
+ /**
10
+ * Generate full docker-compose.yml for fullstack projects with PostgreSQL
11
+ * Preserves all 4 existing services (frontend, backend, frontend-dev, backend-dev)
12
+ * and adds postgres service with proper depends_on
13
+ */
14
+ export declare function generateDockerComposeWithDb(projectName: string): string;
15
+ /**
16
+ * Generate full docker-compose.yml for "all" projects (FE + BE + Website + Postgres)
17
+ */
18
+ export declare function generateAllDockerComposeWithDb(projectName: string): string;
19
+ /**
20
+ * Generate .env.example content with database variables
21
+ */
22
+ export declare function generateDbEnvExample(projectName: string): string;
23
+ //# sourceMappingURL=database-docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-docker.d.ts","sourceRoot":"","sources":["../../../src/generators/templates/database-docker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAkBvE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAwFvE;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8E1E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAiBhE"}