Compare commits
17 Commits
ee13556c5c
...
v1.0.119
| Author | SHA1 | Date | |
|---|---|---|---|
| 4264026bbe | |||
| 24b4a314a9 | |||
| ba825823a0 | |||
| fb16b7bbb8 | |||
| 8404125ff0 | |||
| 61ad2d61c1 | |||
| 9fd6b44487 | |||
| 9fe10bcce2 | |||
| f2abb40987 | |||
| 3697344cd0 | |||
| 4aa0ff705f | |||
| dc482e614a | |||
| 448882cfef | |||
| 7f9cb33a40 | |||
| 798f6211e0 | |||
| b992b151d3 | |||
| 87b8414e44 |
+9
-9
@@ -8,7 +8,7 @@ This guide provides easy installation instructions for PicPeak on Linux servers
|
||||
|
||||
```bash
|
||||
# Download and run the unified setup script
|
||||
curl -fsSL https://raw.githubusercontent.com/yourusername/wedding-photo-sharing/main/scripts/setup.sh -o setup.sh && \
|
||||
curl -fsSL https://raw.githubusercontent.com/the-luap/picpeak/main/scripts/setup.sh -o setup.sh && \
|
||||
chmod +x setup.sh && \
|
||||
sudo ./setup.sh
|
||||
```
|
||||
@@ -305,9 +305,9 @@ docker compose restart
|
||||
```
|
||||
|
||||
### Native Configuration
|
||||
Edit `/opt/picpeak/backend/.env`:
|
||||
Edit `/opt/picpeak/app/backend/.env`:
|
||||
```bash
|
||||
sudo nano /opt/picpeak/backend/.env
|
||||
sudo nano /opt/picpeak/app/backend/.env
|
||||
sudo systemctl restart picpeak-backend
|
||||
```
|
||||
|
||||
@@ -369,7 +369,7 @@ tar -czf photos-backup.tar.gz storage/events/
|
||||
#### Native:
|
||||
```bash
|
||||
# Database backup
|
||||
sudo cp /opt/picpeak/backend/database.sqlite /backup/database-$(date +%Y%m%d).sqlite
|
||||
sudo cp /opt/picpeak/app/backend/data/photo_sharing.db /backup/database-$(date +%Y%m%d).sqlite
|
||||
|
||||
# Photos backup
|
||||
sudo tar -czf /backup/photos-$(date +%Y%m%d).tar.gz /opt/picpeak/events/
|
||||
@@ -446,7 +446,7 @@ ls -la ~/picpeak/storage/events/
|
||||
docker exec picpeak-backend node scripts/reset-admin-password.js
|
||||
|
||||
# Native
|
||||
cd /opt/picpeak/backend
|
||||
cd /opt/picpeak/app/backend
|
||||
sudo -u picpeak node scripts/reset-admin-password.js
|
||||
```
|
||||
|
||||
@@ -458,11 +458,11 @@ sudo -u picpeak node scripts/reset-admin-password.js
|
||||
- Installation: `/tmp/picpeak-setup-*.log`
|
||||
|
||||
2. **Documentation:**
|
||||
- [Full Documentation](https://github.com/yourusername/wedding-photo-sharing)
|
||||
- [Full Documentation](https://github.com/the-luap/picpeak)
|
||||
- [Deployment Guide](./DEPLOYMENT_GUIDE.md)
|
||||
|
||||
3. **Support:**
|
||||
- [GitHub Issues](https://github.com/yourusername/wedding-photo-sharing/issues)
|
||||
- [GitHub Issues](https://github.com/the-luap/picpeak/issues)
|
||||
- Include: Error messages, system info (`uname -a`), installation method
|
||||
|
||||
## 🔒 Security Best Practices
|
||||
@@ -498,7 +498,7 @@ services:
|
||||
### Native Optimization
|
||||
```bash
|
||||
# Increase Node.js memory
|
||||
echo "NODE_OPTIONS=--max-old-space-size=2048" >> /opt/picpeak/backend/.env
|
||||
echo "NODE_OPTIONS=--max-old-space-size=2048" >> /opt/picpeak/app/backend/.env
|
||||
sudo systemctl restart picpeak-backend
|
||||
```
|
||||
|
||||
@@ -540,4 +540,4 @@ sudo ./setup.sh --native \
|
||||
|
||||
---
|
||||
|
||||
**PicPeak Setup v1.0** | [Documentation](https://github.com/yourusername/wedding-photo-sharing) | [Support](https://github.com/yourusername/wedding-photo-sharing/issues)
|
||||
**PicPeak Setup v1.0** | [Documentation](https://github.com/the-luap/picpeak) | [Support](https://github.com/the-luap/picpeak/issues)
|
||||
|
||||
+32
-24
@@ -26,29 +26,37 @@ const config = {
|
||||
|
||||
production: {
|
||||
client: process.env.DATABASE_CLIENT || 'pg',
|
||||
connection: {
|
||||
host: process.env.DB_HOST || 'db',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
user: process.env.DB_USER || 'picpeak',
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME || 'picpeak',
|
||||
ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
|
||||
// Connection stability settings
|
||||
connectionTimeoutMillis: 30000,
|
||||
idleTimeoutMillis: 30000,
|
||||
keepAlive: true,
|
||||
keepAliveInitialDelayMillis: 0
|
||||
},
|
||||
pool: {
|
||||
min: 5,
|
||||
max: 25,
|
||||
acquireTimeoutMillis: 60000,
|
||||
createTimeoutMillis: 60000,
|
||||
idleTimeoutMillis: 30000,
|
||||
reapIntervalMillis: 1000,
|
||||
createRetryIntervalMillis: 200,
|
||||
propagateCreateError: false
|
||||
},
|
||||
// Support both Postgres and SQLite in production based on DATABASE_CLIENT
|
||||
connection: (process.env.DATABASE_CLIENT || 'pg') === 'pg'
|
||||
? {
|
||||
host: process.env.DB_HOST || 'db',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
user: process.env.DB_USER || 'picpeak',
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME || 'picpeak',
|
||||
ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
|
||||
// Connection stability settings
|
||||
connectionTimeoutMillis: 30000,
|
||||
idleTimeoutMillis: 30000,
|
||||
keepAlive: true,
|
||||
keepAliveInitialDelayMillis: 0
|
||||
}
|
||||
: {
|
||||
filename: path.join(__dirname, process.env.DATABASE_PATH || './data/photo_sharing.db')
|
||||
},
|
||||
useNullAsDefault: (process.env.DATABASE_CLIENT || 'pg') !== 'pg',
|
||||
pool: (process.env.DATABASE_CLIENT || 'pg') === 'pg'
|
||||
? {
|
||||
min: 5,
|
||||
max: 25,
|
||||
acquireTimeoutMillis: 60000,
|
||||
createTimeoutMillis: 60000,
|
||||
idleTimeoutMillis: 30000,
|
||||
reapIntervalMillis: 1000,
|
||||
createRetryIntervalMillis: 200,
|
||||
propagateCreateError: false
|
||||
}
|
||||
: undefined,
|
||||
migrations: {
|
||||
directory: './migrations'
|
||||
},
|
||||
@@ -56,4 +64,4 @@ const config = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config[process.env.NODE_ENV || 'development'];
|
||||
module.exports = config[process.env.NODE_ENV || 'development'];
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "picpeak-backend",
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.119",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "picpeak-backend",
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.119",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.850.0",
|
||||
"@aws-sdk/lib-storage": "^3.850.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picpeak-backend",
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.119",
|
||||
"description": "Backend for PicPeak event photo sharing platform",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
||||
+46
-13
@@ -12,6 +12,7 @@ logger.info('Server starting up', {
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const fs = require('fs');
|
||||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const cors = require('cors');
|
||||
@@ -42,25 +43,36 @@ const PORT = process.env.PORT || 3000;
|
||||
app.set('trust proxy', 'loopback, linklocal, uniquelocal');
|
||||
|
||||
// Security middleware with custom CSP
|
||||
// In native HTTP installs, do NOT force HTTPS for subresources.
|
||||
const enableHsts = process.env.ENABLE_HSTS === 'true';
|
||||
const cspDirectives = {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", "'unsafe-inline'"], // Required for React
|
||||
styleSrc: ["'self'", "'unsafe-inline'", "https:"], // Required for styled components
|
||||
imgSrc: ["'self'", "data:", "https:", "blob:"], // Allow data URLs and external images
|
||||
connectSrc: ["'self'"], // API connections
|
||||
fontSrc: ["'self'", "https:", "data:"], // Web fonts
|
||||
objectSrc: ["'none'"], // Disable plugins
|
||||
mediaSrc: ["'self'"], // Audio/video
|
||||
frameSrc: ["'none'"], // Disable iframes
|
||||
};
|
||||
// Only upgrade insecure requests when HSTS explicitly enabled (HTTPS deployment)
|
||||
if (enableHsts) {
|
||||
// In helmet, an empty array enables the directive
|
||||
cspDirectives.upgradeInsecureRequests = [];
|
||||
}
|
||||
|
||||
app.use(helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", "'unsafe-inline'"], // Required for React
|
||||
styleSrc: ["'self'", "'unsafe-inline'", "https:"], // Required for styled components
|
||||
imgSrc: ["'self'", "data:", "https:", "blob:"], // Allow data URLs and external images
|
||||
connectSrc: ["'self'"], // API connections
|
||||
fontSrc: ["'self'", "https:", "data:"], // Web fonts
|
||||
objectSrc: ["'none'"], // Disable plugins
|
||||
mediaSrc: ["'self'"], // Audio/video
|
||||
frameSrc: ["'none'"], // Disable iframes
|
||||
},
|
||||
// Avoid helmet adding defaults like upgrade-insecure-requests when not desired
|
||||
useDefaults: false,
|
||||
directives: cspDirectives,
|
||||
},
|
||||
hsts: {
|
||||
hsts: enableHsts ? {
|
||||
maxAge: 31536000, // 1 year
|
||||
includeSubDomains: true,
|
||||
preload: true
|
||||
},
|
||||
} : false,
|
||||
permittedCrossDomainPolicies: false,
|
||||
referrerPolicy: { policy: "strict-origin-when-cross-origin" }
|
||||
}));
|
||||
@@ -219,6 +231,27 @@ app.use('/api/public', require('./src/routes/publicCMS'));
|
||||
app.use('/api/images', require('./src/routes/protectedImages'));
|
||||
app.use('/api/secure-images', secureImagesRoutes);
|
||||
|
||||
// Optional: Serve built frontend (native installs)
|
||||
try {
|
||||
const serveFrontendEnv = process.env.SERVE_FRONTEND; // 'true' | 'false' | undefined
|
||||
const frontendDir = process.env.FRONTEND_DIR || path.join(__dirname, '../frontend/dist');
|
||||
const indexPath = path.join(frontendDir, 'index.html');
|
||||
// Auto-serve when dist exists unless explicitly disabled
|
||||
const shouldServe = (serveFrontendEnv === 'true') || ((serveFrontendEnv === undefined || serveFrontendEnv === 'auto') && fs.existsSync(indexPath));
|
||||
if (shouldServe) {
|
||||
logger.info(`Serving frontend from ${frontendDir}`);
|
||||
app.use(express.static(frontendDir));
|
||||
// SPA fallback for non-API routes
|
||||
app.get([ '/', '/admin', '/admin/*', '/gallery/*' ], (req, res) => {
|
||||
res.sendFile(indexPath);
|
||||
});
|
||||
} else {
|
||||
logger.info('Frontend static serving disabled or dist not found', { serveFrontendEnv, frontendDir });
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn('Failed to enable frontend static serving', { error: e.message });
|
||||
}
|
||||
|
||||
// Error handling middleware
|
||||
app.use((err, req, res, next) => {
|
||||
console.error('EXPRESS ERROR HANDLER:', err);
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const knex = require('knex');
|
||||
const knexConfig = require('../../knexfile');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// Ensure SQLite directory exists when using file-based DB (native installs)
|
||||
try {
|
||||
const isPostgres = knexConfig && knexConfig.client === 'pg';
|
||||
if (!isPostgres && knexConfig && knexConfig.connection) {
|
||||
const filename = typeof knexConfig.connection === 'object'
|
||||
? knexConfig.connection.filename
|
||||
: (typeof knexConfig.connection === 'string' ? knexConfig.connection : null);
|
||||
if (filename && typeof filename === 'string') {
|
||||
const dir = path.dirname(filename);
|
||||
if (dir && dir !== '.') {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Non-fatal: log and continue; SQLite will fail later if still missing
|
||||
try { logger.warn('SQLite directory ensure failed', { error: e.message }); } catch (_) {}
|
||||
}
|
||||
|
||||
// Create database connection with built-in retry logic
|
||||
const db = knex(knexConfig);
|
||||
|
||||
@@ -312,4 +333,4 @@ async function logActivity(activityType, metadata = {}, eventId = null, actor =
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { db, initializeDatabase, logActivity, withRetry };
|
||||
module.exports = { db, initializeDatabase, logActivity, withRetry };
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.117",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "picpeak-frontend",
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.117",
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"@tiptap/extension-character-count": "^2.26.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"private": true,
|
||||
"version": "1.0.111",
|
||||
"version": "1.0.117",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
+110
-31
@@ -13,7 +13,7 @@ IFS=$'\n\t'
|
||||
# Script configuration
|
||||
readonly SCRIPT_VERSION="2.0.0"
|
||||
readonly APP_NAME="PicPeak"
|
||||
readonly REPO_URL="https://github.com/yourusername/wedding-photo-sharing"
|
||||
readonly REPO_URL="https://github.com/the-luap/picpeak.git"
|
||||
readonly NODE_VERSION="20"
|
||||
readonly MIN_RAM_DOCKER=2048
|
||||
readonly MIN_RAM_NATIVE=1024
|
||||
@@ -61,6 +61,23 @@ UNINSTALL_MODE=false
|
||||
# Helper Functions
|
||||
################################################################################
|
||||
|
||||
# Run a command as the application user, even if sudo is not available
|
||||
run_as_user() {
|
||||
local cmd="$*"
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
# Already non-root; just run
|
||||
bash -lc "$cmd"
|
||||
return $?
|
||||
fi
|
||||
if command_exists sudo; then
|
||||
sudo -H -u "$NATIVE_APP_USER" bash -lc "$cmd"
|
||||
elif command_exists runuser; then
|
||||
runuser -u "$NATIVE_APP_USER" -- bash -lc "$cmd"
|
||||
else
|
||||
su -s /bin/bash - "$NATIVE_APP_USER" -c "$cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
print_banner() {
|
||||
echo -e "${PURPLE}"
|
||||
echo "╔════════════════════════════════════════════════════════════════════════╗"
|
||||
@@ -110,11 +127,16 @@ generate_jwt_secret() {
|
||||
}
|
||||
|
||||
get_available_ram_mb() {
|
||||
if command_exists free; then
|
||||
free -m | awk '/^Mem:/{print $2}'
|
||||
else
|
||||
echo "0"
|
||||
# Prefer /proc/meminfo (always available on Linux), fallback to free(1)
|
||||
if [[ -r /proc/meminfo ]]; then
|
||||
awk '/^MemTotal:/ { printf "%d\n", $2/1024 }' /proc/meminfo
|
||||
return
|
||||
fi
|
||||
if command_exists free; then
|
||||
free -m | awk '/^Mem:/ {print $2}'
|
||||
return
|
||||
fi
|
||||
echo "0"
|
||||
}
|
||||
|
||||
get_available_disk_gb() {
|
||||
@@ -551,21 +573,48 @@ setup_native_installation() {
|
||||
|
||||
# Create application directory
|
||||
log_step "Creating application directory..."
|
||||
mkdir -p "$NATIVE_APP_DIR"/{backend,events/{active,archived},logs,config}
|
||||
mkdir -p "$NATIVE_APP_DIR"/{app,events/{active,archived},logs,config}
|
||||
chown -R $NATIVE_APP_USER:$NATIVE_APP_USER "$NATIVE_APP_DIR"
|
||||
|
||||
# Clone repository
|
||||
log_step "Downloading PicPeak..."
|
||||
if [[ -d "$NATIVE_APP_DIR/backend/.git" ]]; then
|
||||
cd "$NATIVE_APP_DIR/backend"
|
||||
git pull
|
||||
if [[ -d "$NATIVE_APP_DIR/app/.git" ]]; then
|
||||
cd "$NATIVE_APP_DIR/app"
|
||||
# Ensure correct remote and update even if history was rewritten
|
||||
run_as_user "git config --global --add safe.directory $NATIVE_APP_DIR/app" || true
|
||||
run_as_user "git remote set-url origin $REPO_URL" || true
|
||||
run_as_user "git fetch --all --prune" || true
|
||||
# Prefer checking out remote main and hard resetting to avoid merge prompts
|
||||
if ! run_as_user "git checkout -B main origin/main"; then
|
||||
run_as_user "git checkout main" || true
|
||||
run_as_user "git reset --hard origin/main"
|
||||
fi
|
||||
else
|
||||
git clone "$REPO_URL" "$NATIVE_APP_DIR/backend"
|
||||
run_as_user "git clone $REPO_URL $NATIVE_APP_DIR/app" || {
|
||||
run_as_user "git config --global --add safe.directory $NATIVE_APP_DIR/app"
|
||||
run_as_user "git clone $REPO_URL $NATIVE_APP_DIR/app"
|
||||
}
|
||||
fi
|
||||
|
||||
# Install dependencies
|
||||
log_step "Installing dependencies..."
|
||||
cd "$NATIVE_APP_DIR/backend"
|
||||
# The repository root contains both backend/ and frontend/
|
||||
# Install backend production dependencies
|
||||
cd "$NATIVE_APP_DIR/app/backend"
|
||||
npm install --production
|
||||
# Ensure SQLite data directory exists for native installs
|
||||
mkdir -p "$NATIVE_APP_DIR/app/backend/data"
|
||||
|
||||
# Build frontend for native serving
|
||||
log_step "Building frontend..."
|
||||
if [[ -d "$NATIVE_APP_DIR/app/frontend" ]]; then
|
||||
cd "$NATIVE_APP_DIR/app/frontend"
|
||||
# Try ci (faster/clean) then fallback to install
|
||||
run_as_user "npm ci --include=dev" || run_as_user "npm install"
|
||||
run_as_user "npm run build"
|
||||
else
|
||||
log_warn "Frontend directory not found; admin UI will not be served by backend"
|
||||
fi
|
||||
|
||||
# Generate secrets
|
||||
local jwt_secret=$(generate_jwt_secret)
|
||||
@@ -573,7 +622,7 @@ setup_native_installation() {
|
||||
|
||||
# Create .env file
|
||||
log_step "Creating configuration..."
|
||||
cat > "$NATIVE_APP_DIR/backend/.env" <<EOF
|
||||
cat > "$NATIVE_APP_DIR/app/backend/.env" <<EOF
|
||||
# PicPeak Native Configuration
|
||||
# Generated: $(date)
|
||||
|
||||
@@ -587,11 +636,12 @@ ADMIN_USERNAME=admin
|
||||
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
||||
ADMIN_EMAIL=$ADMIN_EMAIL
|
||||
|
||||
# Database
|
||||
DATABASE_PATH=$NATIVE_APP_DIR/backend/database.sqlite
|
||||
# Database (native uses SQLite by default)
|
||||
DATABASE_CLIENT=sqlite3
|
||||
DATABASE_PATH=$NATIVE_APP_DIR/app/backend/data/photo_sharing.db
|
||||
|
||||
# Storage
|
||||
PHOTOS_DIR=$NATIVE_APP_DIR/events
|
||||
# Storage root (thumbnails/uploads live under this path)
|
||||
STORAGE_PATH=$NATIVE_APP_DIR
|
||||
|
||||
# Email
|
||||
SMTP_ENABLED=${SMTP_HOST:+true}
|
||||
@@ -614,16 +664,20 @@ DEFAULT_EXPIRY_DAYS=30
|
||||
# Logging
|
||||
LOG_DIR=$NATIVE_APP_DIR/logs
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Frontend serving (native installs)
|
||||
SERVE_FRONTEND=true
|
||||
FRONTEND_DIR=$NATIVE_APP_DIR/app/frontend/dist
|
||||
EOF
|
||||
|
||||
# Set permissions
|
||||
chown -R $NATIVE_APP_USER:$NATIVE_APP_USER "$NATIVE_APP_DIR"
|
||||
chmod 600 "$NATIVE_APP_DIR/backend/.env"
|
||||
chmod 600 "$NATIVE_APP_DIR/app/backend/.env"
|
||||
|
||||
# Run database migrations
|
||||
log_step "Initializing database..."
|
||||
cd "$NATIVE_APP_DIR/backend"
|
||||
sudo -u $NATIVE_APP_USER npm run migrate
|
||||
cd "$NATIVE_APP_DIR/app/backend"
|
||||
run_as_user "npm run migrate"
|
||||
|
||||
# Create systemd services
|
||||
create_systemd_services
|
||||
@@ -654,7 +708,7 @@ After=network.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$NATIVE_APP_USER
|
||||
WorkingDirectory=$NATIVE_APP_DIR/backend
|
||||
WorkingDirectory=$NATIVE_APP_DIR/app/backend
|
||||
Environment="NODE_ENV=production"
|
||||
ExecStart=/usr/bin/node server.js
|
||||
Restart=always
|
||||
@@ -675,7 +729,7 @@ After=network.target picpeak-backend.service
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$NATIVE_APP_USER
|
||||
WorkingDirectory=$NATIVE_APP_DIR/backend
|
||||
WorkingDirectory=$NATIVE_APP_DIR/app/backend
|
||||
Environment="NODE_ENV=production"
|
||||
ExecStart=/usr/bin/node src/services/workerManager.js
|
||||
Restart=always
|
||||
@@ -878,8 +932,8 @@ print_success_message() {
|
||||
echo
|
||||
echo "📚 Documentation:"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Setup Guide: https://github.com/yourusername/wedding-photo-sharing/blob/main/SIMPLE_SETUP.md"
|
||||
echo "Full Docs: https://github.com/yourusername/wedding-photo-sharing"
|
||||
echo "Setup Guide: https://github.com/the-luap/picpeak/blob/main/SIMPLE_SETUP.md"
|
||||
echo "Full Docs: https://github.com/the-luap/picpeak"
|
||||
echo
|
||||
echo -e "${GREEN}✨ Setup complete! Visit the admin panel to start creating galleries.${NC}"
|
||||
}
|
||||
@@ -935,20 +989,45 @@ update_native_installation() {
|
||||
systemctl stop picpeak-backend picpeak-workers
|
||||
|
||||
# Backup current configuration
|
||||
cp "$NATIVE_APP_DIR/backend/.env" "$NATIVE_APP_DIR/backend/.env.backup-$(date +%Y%m%d-%H%M%S)"
|
||||
if [[ -f "$NATIVE_APP_DIR/app/backend/.env" ]]; then
|
||||
cp "$NATIVE_APP_DIR/app/backend/.env" "$NATIVE_APP_DIR/app/backend/.env.backup-$(date +%Y%m%d-%H%M%S)"
|
||||
fi
|
||||
|
||||
# Pull latest code
|
||||
cd "$NATIVE_APP_DIR/backend"
|
||||
sudo -u $NATIVE_APP_USER git pull
|
||||
cd "$NATIVE_APP_DIR/app"
|
||||
run_as_user "git config --global --add safe.directory $NATIVE_APP_DIR/app" || true
|
||||
run_as_user "git remote set-url origin $REPO_URL" || true
|
||||
run_as_user "git fetch --all --prune"
|
||||
if ! run_as_user "git checkout -B main origin/main"; then
|
||||
run_as_user "git checkout main" || true
|
||||
run_as_user "git reset --hard origin/main"
|
||||
fi
|
||||
|
||||
# Update dependencies
|
||||
sudo -u $NATIVE_APP_USER npm install --production
|
||||
# Update backend dependencies
|
||||
cd "$NATIVE_APP_DIR/app/backend"
|
||||
run_as_user "npm install --production"
|
||||
|
||||
# Run migrations
|
||||
sudo -u $NATIVE_APP_USER npm run migrate
|
||||
run_as_user "npm run migrate"
|
||||
|
||||
# Rebuild frontend (ensure admin UI for native installs)
|
||||
if [[ -d "$NATIVE_APP_DIR/app/frontend" ]]; then
|
||||
log_step "Rebuilding frontend..."
|
||||
cd "$NATIVE_APP_DIR/app/frontend"
|
||||
run_as_user "npm ci --include=dev" || run_as_user "npm install"
|
||||
run_as_user "npm run build"
|
||||
fi
|
||||
|
||||
# Ensure env has frontend serving flags
|
||||
if ! grep -q '^SERVE_FRONTEND=' "$NATIVE_APP_DIR/app/backend/.env"; then
|
||||
echo "SERVE_FRONTEND=true" >> "$NATIVE_APP_DIR/app/backend/.env"
|
||||
fi
|
||||
if ! grep -q '^FRONTEND_DIR=' "$NATIVE_APP_DIR/app/backend/.env"; then
|
||||
echo "FRONTEND_DIR=$NATIVE_APP_DIR/app/frontend/dist" >> "$NATIVE_APP_DIR/app/backend/.env"
|
||||
fi
|
||||
|
||||
# Restart services
|
||||
systemctl start picpeak-backend picpeak-workers
|
||||
systemctl restart picpeak-backend picpeak-workers
|
||||
|
||||
log_success "Native installation updated successfully!"
|
||||
}
|
||||
@@ -1181,4 +1260,4 @@ main() {
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user