@gv-sh/specgen-app 0.6.4 โ 0.6.6
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/README.md +1 -1
- package/package.json +1 -1
- package/scripts/deploy.sh +253 -27
package/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# SpecGen App - Complete Platform
|
2
2
|
|
3
|
-
[](https://github.com/gv-sh/specgen-app)
|
4
4
|
|
5
5
|
A unified deployment package for the SpecGen speculative fiction generator platform. **Optimized for port 8080 deployment with low memory usage.**
|
6
6
|
|
package/package.json
CHANGED
package/scripts/deploy.sh
CHANGED
@@ -11,10 +11,9 @@ if [ "$1" = "--dry-run" ] || [ "$1" = "-d" ]; then
|
|
11
11
|
echo "๐ฅ๏ธ Platform: $(uname -s) $(uname -m)"
|
12
12
|
else
|
13
13
|
echo "๐ Deploying SpecGen to production on port 8080..."
|
14
|
+
echo "๐ฆ This is a complete deployment - no separate setup needed!"
|
14
15
|
fi
|
15
16
|
|
16
|
-
echo "๐ฆ This is a complete deployment - no separate setup needed!"
|
17
|
-
|
18
17
|
# Function to check if port is available
|
19
18
|
check_port() {
|
20
19
|
local port=$1
|
@@ -26,7 +25,13 @@ check_port() {
|
|
26
25
|
}
|
27
26
|
|
28
27
|
# Get absolute path of current working directory
|
29
|
-
|
28
|
+
# In dry-run, use the actual working directory, not NPX cache
|
29
|
+
if [ "$DRY_RUN" = true ]; then
|
30
|
+
PROJECT_DIR=$(pwd)
|
31
|
+
else
|
32
|
+
PROJECT_DIR=$(pwd)
|
33
|
+
fi
|
34
|
+
|
30
35
|
echo "๐ Project directory: $PROJECT_DIR"
|
31
36
|
|
32
37
|
# ========================================
|
@@ -74,6 +79,7 @@ if [ "$DRY_RUN" = false ]; then
|
|
74
79
|
rm -rf logs/* 2>/dev/null || true
|
75
80
|
else
|
76
81
|
echo "๐งช DRY RUN: Skipping cleanup (existing processes will remain)"
|
82
|
+
echo " This is a safe test that won't affect your system"
|
77
83
|
fi
|
78
84
|
|
79
85
|
# ========================================
|
@@ -82,18 +88,35 @@ fi
|
|
82
88
|
|
83
89
|
echo "๐ Checking prerequisites..."
|
84
90
|
|
85
|
-
# Check Node.js version
|
91
|
+
# Check Node.js version (more lenient for dry-run)
|
86
92
|
NODE_VERSION=$(node --version | sed 's/v//' | cut -d. -f1)
|
87
|
-
if [ "$
|
88
|
-
|
89
|
-
if [ "$
|
90
|
-
echo "
|
93
|
+
if [ "$DRY_RUN" = true ]; then
|
94
|
+
# More lenient for dry-run testing
|
95
|
+
if [ "$NODE_VERSION" -lt 18 ]; then
|
96
|
+
echo "โ Node.js 18+ required for testing. Current version: $(node --version)"
|
97
|
+
if [ "$PLATFORM" = "Darwin" ]; then
|
98
|
+
echo "Install with: brew install node"
|
99
|
+
fi
|
100
|
+
exit 1
|
91
101
|
else
|
92
|
-
echo "
|
102
|
+
echo "โ
Node.js version: $(node --version) (sufficient for testing)"
|
103
|
+
if [ "$NODE_VERSION" -lt 20 ]; then
|
104
|
+
echo " โ ๏ธ Note: Production deployment requires Node.js 20+"
|
105
|
+
fi
|
93
106
|
fi
|
94
|
-
exit 1
|
95
107
|
else
|
96
|
-
|
108
|
+
# Strict for production
|
109
|
+
if [ "$NODE_VERSION" -lt 20 ]; then
|
110
|
+
echo "โ Node.js 20+ required for production. Current version: $(node --version)"
|
111
|
+
if [ "$PLATFORM" = "Darwin" ]; then
|
112
|
+
echo "Install with: brew install node@20"
|
113
|
+
else
|
114
|
+
echo "Install with: curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs"
|
115
|
+
fi
|
116
|
+
exit 1
|
117
|
+
else
|
118
|
+
echo "โ
Node.js version: $(node --version)"
|
119
|
+
fi
|
97
120
|
fi
|
98
121
|
|
99
122
|
# Check npm
|
@@ -114,13 +137,19 @@ elif [ "$PLATFORM" = "Linux" ]; then
|
|
114
137
|
fi
|
115
138
|
fi
|
116
139
|
|
140
|
+
# Check if we have required tools
|
141
|
+
echo "โ
Platform tools:"
|
142
|
+
echo " curl: $(which curl >/dev/null && echo "available" || echo "missing")"
|
143
|
+
echo " tar: $(which tar >/dev/null && echo "available" || echo "missing")"
|
144
|
+
echo " lsof: $(which lsof >/dev/null && echo "available" || echo "missing")"
|
145
|
+
|
117
146
|
# ========================================
|
118
147
|
# SETUP OPENAI API KEY
|
119
148
|
# ========================================
|
120
149
|
|
121
150
|
echo "๐ Setting up OpenAI API key..."
|
122
151
|
|
123
|
-
# In dry-run mode, use a test key
|
152
|
+
# In dry-run mode, always use a test key
|
124
153
|
if [ "$DRY_RUN" = true ]; then
|
125
154
|
echo "๐งช DRY RUN: Using test API key"
|
126
155
|
mkdir -p "$PROJECT_DIR/server"
|
@@ -136,7 +165,7 @@ elif [ ! -f "$PROJECT_DIR/server/.env" ] || grep -q "your_openai_api_key_here" "
|
|
136
165
|
echo "PORT=8080" >> "$PROJECT_DIR/server/.env"
|
137
166
|
else
|
138
167
|
echo "โ ๏ธ OpenAI API key required for SpecGen to work."
|
139
|
-
echo "Enter your OpenAI API key (or press Enter to use test key
|
168
|
+
echo "Enter your OpenAI API key (or press Enter to use test key): "
|
140
169
|
read -r OPENAI_KEY
|
141
170
|
|
142
171
|
if [ -z "$OPENAI_KEY" ]; then
|
@@ -203,6 +232,170 @@ if [ ! -f "server/index.js" ]; then
|
|
203
232
|
fi
|
204
233
|
|
205
234
|
cd "$PROJECT_DIR"
|
235
|
+
|
236
|
+
# Replace with unified server that serves static files
|
237
|
+
echo " ๐ง Installing unified server for port 8080..."
|
238
|
+
cat > server/index.js << 'EOF'
|
239
|
+
// index.js - Unified server for port 8080 with proper routing
|
240
|
+
/* global process */
|
241
|
+
require('dotenv').config();
|
242
|
+
const express = require('express');
|
243
|
+
const cors = require('cors');
|
244
|
+
const path = require('path');
|
245
|
+
const errorHandler = require('./middleware/errorHandler');
|
246
|
+
|
247
|
+
// Initialize Express app
|
248
|
+
const app = express();
|
249
|
+
let PORT = process.env.PORT || 8080;
|
250
|
+
|
251
|
+
// Middleware
|
252
|
+
app.use(cors());
|
253
|
+
app.use(express.json());
|
254
|
+
app.use(express.urlencoded({ extended: true }));
|
255
|
+
|
256
|
+
// Serve static files for admin interface at /admin
|
257
|
+
const adminBuildPath = path.join(__dirname, '../admin/build');
|
258
|
+
const fs = require('fs');
|
259
|
+
if (fs.existsSync(adminBuildPath)) {
|
260
|
+
app.use('/admin', express.static(adminBuildPath));
|
261
|
+
// Handle React Router for admin (catch all admin routes)
|
262
|
+
app.get('/admin/*', (req, res) => {
|
263
|
+
res.sendFile(path.join(adminBuildPath, 'index.html'));
|
264
|
+
});
|
265
|
+
console.log('โ
Admin interface available at /admin');
|
266
|
+
} else {
|
267
|
+
console.log('โ ๏ธ Admin build not found at', adminBuildPath);
|
268
|
+
}
|
269
|
+
|
270
|
+
// Serve static files for user interface at /app
|
271
|
+
const userBuildPath = path.join(__dirname, '../user/build');
|
272
|
+
if (fs.existsSync(userBuildPath)) {
|
273
|
+
app.use('/app', express.static(userBuildPath));
|
274
|
+
// Handle React Router for user app (catch all app routes)
|
275
|
+
app.get('/app/*', (req, res) => {
|
276
|
+
res.sendFile(path.join(userBuildPath, 'index.html'));
|
277
|
+
});
|
278
|
+
console.log('โ
User interface available at /app');
|
279
|
+
} else {
|
280
|
+
console.log('โ ๏ธ User build not found at', userBuildPath);
|
281
|
+
}
|
282
|
+
|
283
|
+
// Serve user interface as default at root (/) as well
|
284
|
+
if (fs.existsSync(userBuildPath)) {
|
285
|
+
app.use('/', express.static(userBuildPath, { index: false }));
|
286
|
+
}
|
287
|
+
|
288
|
+
// Routes
|
289
|
+
const categoryRoutes = require('./routes/categories');
|
290
|
+
const parameterRoutes = require('./routes/parameters');
|
291
|
+
const generateRoutes = require('./routes/generate');
|
292
|
+
const databaseRoutes = require('./routes/database');
|
293
|
+
const contentRoutes = require('./routes/content');
|
294
|
+
const settingsRoutes = require('./routes/settings');
|
295
|
+
|
296
|
+
// API Routes
|
297
|
+
app.use('/api/categories', categoryRoutes);
|
298
|
+
app.use('/api/parameters', parameterRoutes);
|
299
|
+
app.use('/api/generate', generateRoutes);
|
300
|
+
app.use('/api/database', databaseRoutes);
|
301
|
+
app.use('/api/content', contentRoutes);
|
302
|
+
app.use('/api/settings', settingsRoutes);
|
303
|
+
|
304
|
+
// Only add Swagger in non-test environment
|
305
|
+
if (process.env.NODE_ENV !== 'test') {
|
306
|
+
const swaggerRoutes = require('./routes/swagger');
|
307
|
+
app.use('/api-docs', swaggerRoutes);
|
308
|
+
}
|
309
|
+
|
310
|
+
// Health check routes
|
311
|
+
const healthRoutes = require('./routes/health');
|
312
|
+
app.use('/api/health', healthRoutes);
|
313
|
+
|
314
|
+
// Root route - serve user app or provide navigation
|
315
|
+
app.get('/', (req, res) => {
|
316
|
+
// If user build exists, serve it
|
317
|
+
if (fs.existsSync(userBuildPath)) {
|
318
|
+
res.sendFile(path.join(userBuildPath, 'index.html'));
|
319
|
+
} else {
|
320
|
+
// Fallback navigation page
|
321
|
+
const html = `
|
322
|
+
<!DOCTYPE html>
|
323
|
+
<html>
|
324
|
+
<head>
|
325
|
+
<title>SpecGen - API & Applications</title>
|
326
|
+
<style>
|
327
|
+
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; background: #f8f9fa; }
|
328
|
+
.nav-card { border: 1px solid #dee2e6; border-radius: 8px; padding: 20px; margin: 15px 0; background: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
329
|
+
.nav-card:hover { background-color: #f8f9fa; transform: translateY(-2px); transition: all 0.2s; }
|
330
|
+
a { text-decoration: none; color: #007bff; }
|
331
|
+
h1 { color: #343a40; text-align: center; }
|
332
|
+
.status { color: #28a745; font-weight: bold; text-align: center; background: #d4edda; padding: 10px; border-radius: 5px; margin: 20px 0; }
|
333
|
+
.footer { text-align: center; margin-top: 30px; color: #6c757d; font-size: 14px; }
|
334
|
+
.warning { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
335
|
+
</style>
|
336
|
+
</head>
|
337
|
+
<body>
|
338
|
+
<h1>๐ SpecGen Platform</h1>
|
339
|
+
<div class="status">โ
All services running on port ${PORT}</div>
|
340
|
+
|
341
|
+
<div class="warning">
|
342
|
+
<strong>๐ AWS Security Group Note:</strong> If you can't access this from outside,
|
343
|
+
add port ${PORT} to your AWS Security Group inbound rules.
|
344
|
+
</div>
|
345
|
+
|
346
|
+
<div class="nav-card">
|
347
|
+
<h3><a href="/app">๐ฑ User Application</a></h3>
|
348
|
+
<p>Main SpecGen user interface for creating and managing specifications</p>
|
349
|
+
</div>
|
350
|
+
|
351
|
+
<div class="nav-card">
|
352
|
+
<h3><a href="/admin">โ๏ธ Admin Panel</a></h3>
|
353
|
+
<p>Administrative interface for system management and configuration</p>
|
354
|
+
</div>
|
355
|
+
|
356
|
+
<div class="nav-card">
|
357
|
+
<h3><a href="/api-docs">๐ API Documentation</a></h3>
|
358
|
+
<p>Interactive API documentation and testing interface</p>
|
359
|
+
</div>
|
360
|
+
|
361
|
+
<div class="nav-card">
|
362
|
+
<h3><a href="/api/health">โค๏ธ Health Check</a></h3>
|
363
|
+
<p>System health and status monitoring endpoint</p>
|
364
|
+
</div>
|
365
|
+
|
366
|
+
<div class="footer">
|
367
|
+
<p><strong>API Base URL:</strong> <code>http://your-server:${PORT}/api</code></p>
|
368
|
+
<p><strong>Environment:</strong> ${process.env.NODE_ENV || 'development'}</p>
|
369
|
+
<p><strong>Server Time:</strong> ${new Date().toISOString()}</p>
|
370
|
+
</div>
|
371
|
+
</body>
|
372
|
+
</html>`;
|
373
|
+
res.send(html);
|
374
|
+
}
|
375
|
+
});
|
376
|
+
|
377
|
+
// Error handling middleware
|
378
|
+
app.use(errorHandler);
|
379
|
+
|
380
|
+
if (require.main === module) {
|
381
|
+
app.listen(PORT, () => {
|
382
|
+
console.log(`๐ SpecGen unified server running on port ${PORT}`);
|
383
|
+
console.log(`๐ฑ User App: http://localhost:${PORT}/app`);
|
384
|
+
console.log(`โ๏ธ Admin Panel: http://localhost:${PORT}/admin`);
|
385
|
+
console.log(`๐ API Docs: http://localhost:${PORT}/api-docs`);
|
386
|
+
console.log(`โค๏ธ Health Check: http://localhost:${PORT}/api/health`);
|
387
|
+
console.log(`๐ Main Page: http://localhost:${PORT}/`);
|
388
|
+
console.log(`๐ AWS Note: Ensure port ${PORT} is open in Security Groups`);
|
389
|
+
if (process.env.NODE_ENV !== 'test') {
|
390
|
+
console.log(`- API Documentation: http://localhost:${PORT}/api-docs`);
|
391
|
+
}
|
392
|
+
console.log(`- API is ready for use`);
|
393
|
+
});
|
394
|
+
}
|
395
|
+
|
396
|
+
module.exports = app;
|
397
|
+
EOF
|
398
|
+
echo "โ
Unified server installed"
|
206
399
|
fi
|
207
400
|
|
208
401
|
# Install and build admin
|
@@ -327,32 +520,42 @@ if [ "$DRY_RUN" = true ]; then
|
|
327
520
|
# Copy environment
|
328
521
|
cp "$PROJECT_DIR/server/.env" "$PROJECT_DIR/.env" 2>/dev/null || true
|
329
522
|
|
330
|
-
|
523
|
+
# Check if port 8080 is available for testing
|
524
|
+
if ! check_port 8080; then
|
525
|
+
echo " โ ๏ธ Port 8080 is in use, testing on port 8081 instead"
|
526
|
+
TEST_PORT=8081
|
527
|
+
sed -i.bak 's/PORT=8080/PORT=8081/' "$PROJECT_DIR/server/.env"
|
528
|
+
else
|
529
|
+
TEST_PORT=8080
|
530
|
+
fi
|
531
|
+
|
532
|
+
echo " Starting test server on port $TEST_PORT for 10 seconds..."
|
331
533
|
|
332
534
|
# Start server in background
|
333
|
-
(cd server && NODE_ENV=production PORT
|
535
|
+
(cd server && NODE_ENV=production PORT=$TEST_PORT node index.js) &
|
334
536
|
SERVER_PID=$!
|
335
537
|
|
336
538
|
# Wait a bit for server to start
|
337
539
|
sleep 3
|
338
540
|
|
339
541
|
# Test the endpoints
|
340
|
-
echo " Testing endpoints:"
|
542
|
+
echo " Testing endpoints on port $TEST_PORT:"
|
341
543
|
|
342
|
-
if curl -s http://localhost
|
544
|
+
if curl -s http://localhost:$TEST_PORT/api/health >/dev/null 2>&1; then
|
343
545
|
echo " โ
Health endpoint: OK"
|
344
|
-
|
546
|
+
HEALTH_RESPONSE=$(curl -s http://localhost:$TEST_PORT/api/health)
|
547
|
+
echo " Status: $(echo $HEALTH_RESPONSE | grep -o '"status":"[^"]*"' | cut -d'"' -f4)"
|
345
548
|
else
|
346
549
|
echo " โ Health endpoint: FAILED"
|
347
550
|
fi
|
348
551
|
|
349
|
-
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost
|
552
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$TEST_PORT/ 2>/dev/null || echo "000")
|
350
553
|
echo " ๐ Main page: HTTP $HTTP_CODE"
|
351
554
|
|
352
|
-
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost
|
555
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$TEST_PORT/admin/ 2>/dev/null || echo "000")
|
353
556
|
echo " โ๏ธ Admin page: HTTP $HTTP_CODE"
|
354
557
|
|
355
|
-
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost
|
558
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$TEST_PORT/app/ 2>/dev/null || echo "000")
|
356
559
|
echo " ๐ค User page: HTTP $HTTP_CODE"
|
357
560
|
|
358
561
|
# Stop test server
|
@@ -360,6 +563,11 @@ if [ "$DRY_RUN" = true ]; then
|
|
360
563
|
kill $SERVER_PID 2>/dev/null || true
|
361
564
|
wait $SERVER_PID 2>/dev/null || true
|
362
565
|
|
566
|
+
# Restore original .env if we changed it
|
567
|
+
if [ -f "$PROJECT_DIR/server/.env.bak" ]; then
|
568
|
+
mv "$PROJECT_DIR/server/.env.bak" "$PROJECT_DIR/server/.env"
|
569
|
+
fi
|
570
|
+
|
363
571
|
echo ""
|
364
572
|
echo "๐ DRY RUN COMPLETED!"
|
365
573
|
echo ""
|
@@ -367,12 +575,25 @@ if [ "$DRY_RUN" = true ]; then
|
|
367
575
|
echo " โ
All packages downloaded and extracted"
|
368
576
|
echo " โ
All dependencies installed"
|
369
577
|
echo " โ
React apps built successfully"
|
578
|
+
echo " โ
Unified server installed"
|
370
579
|
echo " โ
Server can start and respond"
|
371
580
|
echo ""
|
581
|
+
if [ "$NODE_VERSION" -lt 20 ]; then
|
582
|
+
echo "โ ๏ธ Note for AWS deployment:"
|
583
|
+
echo " Your Mac has Node.js $(node --version)"
|
584
|
+
echo " AWS deployment requires Node.js 20+"
|
585
|
+
echo " Make sure your AWS server has the right version"
|
586
|
+
echo ""
|
587
|
+
fi
|
372
588
|
echo "๐ Ready for production deployment!"
|
373
|
-
echo "
|
589
|
+
echo " Deploy to AWS with: npx @gv-sh/specgen-app deploy"
|
374
590
|
echo ""
|
375
|
-
echo "
|
591
|
+
echo "๐ AWS Deployment Notes:"
|
592
|
+
echo " 1. Ensure Node.js 20+ on your AWS instance"
|
593
|
+
echo " 2. Add port 8080 to Security Group inbound rules"
|
594
|
+
echo " 3. Run: npx @gv-sh/specgen-app deploy"
|
595
|
+
echo ""
|
596
|
+
echo "๐ง To test locally right now:"
|
376
597
|
echo " cd server && npm start"
|
377
598
|
echo " Open http://localhost:8080/"
|
378
599
|
|
@@ -444,10 +665,10 @@ EOF
|
|
444
665
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/ 2>/dev/null)
|
445
666
|
echo "๐ Main page: HTTP $HTTP_CODE"
|
446
667
|
|
447
|
-
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/admin 2>/dev/null)
|
668
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/admin/ 2>/dev/null)
|
448
669
|
echo "โ๏ธ Admin page: HTTP $HTTP_CODE"
|
449
670
|
|
450
|
-
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/app 2>/dev/null)
|
671
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/app/ 2>/dev/null)
|
451
672
|
echo "๐ค User page: HTTP $HTTP_CODE"
|
452
673
|
|
453
674
|
PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || curl -s ipecho.net/plain 2>/dev/null || echo 'your-server')
|
@@ -457,11 +678,16 @@ EOF
|
|
457
678
|
echo ""
|
458
679
|
echo "๐ Access your application at:"
|
459
680
|
echo " - Main page: http://$PUBLIC_IP:8080/"
|
460
|
-
echo " - User app: http://$PUBLIC_IP:8080/app"
|
461
|
-
echo " - Admin panel: http://$PUBLIC_IP:8080/admin"
|
681
|
+
echo " - User app: http://$PUBLIC_IP:8080/app/"
|
682
|
+
echo " - Admin panel: http://$PUBLIC_IP:8080/admin/"
|
462
683
|
echo " - API docs: http://$PUBLIC_IP:8080/api-docs"
|
463
684
|
echo " - Health check: http://$PUBLIC_IP:8080/api/health"
|
464
685
|
echo ""
|
686
|
+
echo "๐ AWS Security Group:"
|
687
|
+
echo " If you can't access from outside, add port 8080 to inbound rules:"
|
688
|
+
echo " EC2 Console โ Security Groups โ Edit Inbound Rules โ Add Rule"
|
689
|
+
echo " Type: Custom TCP, Port: 8080, Source: 0.0.0.0/0"
|
690
|
+
echo ""
|
465
691
|
echo "๐ Management commands:"
|
466
692
|
echo " $PM2_CMD status # Check status"
|
467
693
|
echo " $PM2_CMD logs specgen # View logs"
|