Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 448882cfef | |||
| 7f9cb33a40 | |||
| 798f6211e0 | |||
| b992b151d3 | |||
| 87b8414e44 | |||
| ee13556c5c | |||
| afeb35a446 | |||
| ab324f1928 |
@@ -28,6 +28,7 @@ Unlike expensive SaaS solutions, PicPeak gives you:
|
|||||||
|
|
||||||
### For Photographers
|
### For Photographers
|
||||||
- 📁 **Drag & Drop Upload** - Simply drop photos into folders
|
- 📁 **Drag & Drop Upload** - Simply drop photos into folders
|
||||||
|
- 🔗 **External Media (Reference Mode)** - Browse and import from a read‑only external folder library without copying originals
|
||||||
- ⏰ **Auto-Expiring Galleries** - Set expiration dates (default: 30 days)
|
- ⏰ **Auto-Expiring Galleries** - Set expiration dates (default: 30 days)
|
||||||
- 🔐 **Password Protection** - Secure client galleries
|
- 🔐 **Password Protection** - Secure client galleries
|
||||||
- 📧 **Automated Emails** - Creation confirmations and expiration warnings
|
- 📧 **Automated Emails** - Creation confirmations and expiration warnings
|
||||||
@@ -45,6 +46,7 @@ Unlike expensive SaaS solutions, PicPeak gives you:
|
|||||||
### Technical Excellence
|
### Technical Excellence
|
||||||
- 🐳 **Docker Ready** - Deploy in minutes
|
- 🐳 **Docker Ready** - Deploy in minutes
|
||||||
- 🔄 **Auto-Processing** - Automatic thumbnail generation
|
- 🔄 **Auto-Processing** - Automatic thumbnail generation
|
||||||
|
- 🗂️ **Reference Library Support** - Point PicPeak at `EXTERNAL_MEDIA_ROOT` to reference existing originals, index quickly, and generate thumbnails on demand
|
||||||
- 💾 **Smart Storage** - Automatic archiving of expired galleries
|
- 💾 **Smart Storage** - Automatic archiving of expired galleries
|
||||||
- 🛡️ **Security First** - JWT auth, rate limiting, CORS protection
|
- 🛡️ **Security First** - JWT auth, rate limiting, CORS protection
|
||||||
- 📈 **Scalable** - From small studios to large agencies
|
- 📈 **Scalable** - From small studios to large agencies
|
||||||
@@ -73,6 +75,7 @@ docker-compose up -d
|
|||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
- 📘 [**Deployment Guide**](DEPLOYMENT_GUIDE.md) - Detailed installation instructions
|
- 📘 [**Deployment Guide**](DEPLOYMENT_GUIDE.md) - Detailed installation instructions
|
||||||
|
- Includes the new [External Media Library](DEPLOYMENT_GUIDE.md#external-media-library) reference mode
|
||||||
- 🤝 [**Contributing**](CONTRIBUTING.md) - How to contribute
|
- 🤝 [**Contributing**](CONTRIBUTING.md) - How to contribute
|
||||||
- 📜 [**License**](LICENSE) - MIT License
|
- 📜 [**License**](LICENSE) - MIT License
|
||||||
- 🔒 [**Security**](SECURITY.md) - Security policies
|
- 🔒 [**Security**](SECURITY.md) - Security policies
|
||||||
@@ -192,9 +195,10 @@ These features are currently in beta testing and may have limited functionality
|
|||||||
| Feature | Description | Priority | Status |
|
| Feature | Description | Priority | Status |
|
||||||
|---------|-------------|----------|---------|
|
|---------|-------------|----------|---------|
|
||||||
| **Backup & Restore** | Comprehensive backup system with S3/MinIO support, automated scheduling, and safe restore functionality | High | ✅ Implemented |
|
| **Backup & Restore** | Comprehensive backup system with S3/MinIO support, automated scheduling, and safe restore functionality | High | ✅ Implemented |
|
||||||
|
| **External Media Library (Reference Mode)** | Use an external folder library as a read‑only source with import and on‑demand thumbnail generation | High | ✅ Implemented |
|
||||||
| **Gallery Templates** | Additional gallery layouts and themes (masonry, slideshow, story-style) for different event types | Medium | 🔄 Open |
|
| **Gallery Templates** | Additional gallery layouts and themes (masonry, slideshow, story-style) for different event types | Medium | 🔄 Open |
|
||||||
| **Face Recognition** | AI-powered face detection to help guests find their photos and create automatic person-based albums | Low | 🔄 Open |
|
| **Face Recognition** | AI-powered face detection to help guests find their photos and create automatic person-based albums | Low | 🔄 Open |
|
||||||
| **Gallery Feedback** | Allow guests to like, rate, and comment on photos with admin notifications and moderation | Medium | ✅ Implemented (not tested) |
|
| **Gallery Feedback** | Allow guests to like, rate, and comment on photos with admin notifications and moderation | Medium | ✅ Implemented |
|
||||||
| **Video Support** | Upload and display videos alongside photos in galleries with streaming support | Low | 🔄 Open |
|
| **Video Support** | Upload and display videos alongside photos in galleries with streaming support | Low | 🔄 Open |
|
||||||
| **Multiple Administrators** | Support for multiple admin accounts with role-based permissions and activity tracking | Low | 📋 Planned |
|
| **Multiple Administrators** | Support for multiple admin accounts with role-based permissions and activity tracking | Low | 📋 Planned |
|
||||||
|
|
||||||
@@ -233,4 +237,4 @@ PicPeak is released under the [MIT License](LICENSE). Use it freely for personal
|
|||||||
<a href="https://github.com/the-luap/picpeak">GitHub</a> •
|
<a href="https://github.com/the-luap/picpeak">GitHub</a> •
|
||||||
<a href="DEPLOYMENT_GUIDE.md">Documentation</a> •
|
<a href="DEPLOYMENT_GUIDE.md">Documentation</a> •
|
||||||
<a href="https://github.com/the-luap/picpeak/issues">Support</a>
|
<a href="https://github.com/the-luap/picpeak/issues">Support</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
+9
-9
@@ -8,7 +8,7 @@ This guide provides easy installation instructions for PicPeak on Linux servers
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Download and run the unified setup script
|
# 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 && \
|
chmod +x setup.sh && \
|
||||||
sudo ./setup.sh
|
sudo ./setup.sh
|
||||||
```
|
```
|
||||||
@@ -305,9 +305,9 @@ docker compose restart
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Native Configuration
|
### Native Configuration
|
||||||
Edit `/opt/picpeak/backend/.env`:
|
Edit `/opt/picpeak/app/backend/.env`:
|
||||||
```bash
|
```bash
|
||||||
sudo nano /opt/picpeak/backend/.env
|
sudo nano /opt/picpeak/app/backend/.env
|
||||||
sudo systemctl restart picpeak-backend
|
sudo systemctl restart picpeak-backend
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -369,7 +369,7 @@ tar -czf photos-backup.tar.gz storage/events/
|
|||||||
#### Native:
|
#### Native:
|
||||||
```bash
|
```bash
|
||||||
# Database backup
|
# 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
|
# Photos backup
|
||||||
sudo tar -czf /backup/photos-$(date +%Y%m%d).tar.gz /opt/picpeak/events/
|
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
|
docker exec picpeak-backend node scripts/reset-admin-password.js
|
||||||
|
|
||||||
# Native
|
# Native
|
||||||
cd /opt/picpeak/backend
|
cd /opt/picpeak/app/backend
|
||||||
sudo -u picpeak node scripts/reset-admin-password.js
|
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`
|
- Installation: `/tmp/picpeak-setup-*.log`
|
||||||
|
|
||||||
2. **Documentation:**
|
2. **Documentation:**
|
||||||
- [Full Documentation](https://github.com/yourusername/wedding-photo-sharing)
|
- [Full Documentation](https://github.com/the-luap/picpeak)
|
||||||
- [Deployment Guide](./DEPLOYMENT_GUIDE.md)
|
- [Deployment Guide](./DEPLOYMENT_GUIDE.md)
|
||||||
|
|
||||||
3. **Support:**
|
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
|
- Include: Error messages, system info (`uname -a`), installation method
|
||||||
|
|
||||||
## 🔒 Security Best Practices
|
## 🔒 Security Best Practices
|
||||||
@@ -498,7 +498,7 @@ services:
|
|||||||
### Native Optimization
|
### Native Optimization
|
||||||
```bash
|
```bash
|
||||||
# Increase Node.js memory
|
# 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
|
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: {
|
production: {
|
||||||
client: process.env.DATABASE_CLIENT || 'pg',
|
client: process.env.DATABASE_CLIENT || 'pg',
|
||||||
connection: {
|
// Support both Postgres and SQLite in production based on DATABASE_CLIENT
|
||||||
host: process.env.DB_HOST || 'db',
|
connection: (process.env.DATABASE_CLIENT || 'pg') === 'pg'
|
||||||
port: process.env.DB_PORT || 5432,
|
? {
|
||||||
user: process.env.DB_USER || 'picpeak',
|
host: process.env.DB_HOST || 'db',
|
||||||
password: process.env.DB_PASSWORD,
|
port: process.env.DB_PORT || 5432,
|
||||||
database: process.env.DB_NAME || 'picpeak',
|
user: process.env.DB_USER || 'picpeak',
|
||||||
ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
|
password: process.env.DB_PASSWORD,
|
||||||
// Connection stability settings
|
database: process.env.DB_NAME || 'picpeak',
|
||||||
connectionTimeoutMillis: 30000,
|
ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
|
||||||
idleTimeoutMillis: 30000,
|
// Connection stability settings
|
||||||
keepAlive: true,
|
connectionTimeoutMillis: 30000,
|
||||||
keepAliveInitialDelayMillis: 0
|
idleTimeoutMillis: 30000,
|
||||||
},
|
keepAlive: true,
|
||||||
pool: {
|
keepAliveInitialDelayMillis: 0
|
||||||
min: 5,
|
}
|
||||||
max: 25,
|
: {
|
||||||
acquireTimeoutMillis: 60000,
|
filename: path.join(__dirname, process.env.DATABASE_PATH || './data/photo_sharing.db')
|
||||||
createTimeoutMillis: 60000,
|
},
|
||||||
idleTimeoutMillis: 30000,
|
useNullAsDefault: (process.env.DATABASE_CLIENT || 'pg') !== 'pg',
|
||||||
reapIntervalMillis: 1000,
|
pool: (process.env.DATABASE_CLIENT || 'pg') === 'pg'
|
||||||
createRetryIntervalMillis: 200,
|
? {
|
||||||
propagateCreateError: false
|
min: 5,
|
||||||
},
|
max: 25,
|
||||||
|
acquireTimeoutMillis: 60000,
|
||||||
|
createTimeoutMillis: 60000,
|
||||||
|
idleTimeoutMillis: 30000,
|
||||||
|
reapIntervalMillis: 1000,
|
||||||
|
createRetryIntervalMillis: 200,
|
||||||
|
propagateCreateError: false
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
migrations: {
|
migrations: {
|
||||||
directory: './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",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.850.0",
|
"@aws-sdk/client-s3": "^3.850.0",
|
||||||
"@aws-sdk/lib-storage": "^3.850.0",
|
"@aws-sdk/lib-storage": "^3.850.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"description": "Backend for PicPeak event photo sharing platform",
|
"description": "Backend for PicPeak event photo sharing platform",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+3
-1
@@ -143,6 +143,7 @@ const secureStatic = require('./src/middleware/secureStatic');
|
|||||||
|
|
||||||
// Get storage path from environment or use default
|
// Get storage path from environment or use default
|
||||||
const storagePath = process.env.STORAGE_PATH || path.join(__dirname, '../storage');
|
const storagePath = process.env.STORAGE_PATH || path.join(__dirname, '../storage');
|
||||||
|
process.env.EXTERNAL_MEDIA_ROOT = process.env.EXTERNAL_MEDIA_ROOT || '/external-media';
|
||||||
|
|
||||||
// Static file serving for photos (protected)
|
// Static file serving for photos (protected)
|
||||||
app.use('/photos', require('./src/middleware/photoAuth'), setCorsHeaders, secureStatic(path.join(storagePath, 'events/active')));
|
app.use('/photos', require('./src/middleware/photoAuth'), setCorsHeaders, secureStatic(path.join(storagePath, 'events/active')));
|
||||||
@@ -199,7 +200,8 @@ app.get('/health', async (req, res) => {
|
|||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.use('/api/auth', authRoutes);
|
app.use('/api/auth', authRoutes);
|
||||||
app.use('/api/events', eventRoutes);
|
app.use('/api/events', eventRoutes);
|
||||||
|
app.use('/api/admin/external-media', require('./src/routes/adminExternalMedia'));
|
||||||
// Gallery routes - main routes first, then feedback routes
|
// Gallery routes - main routes first, then feedback routes
|
||||||
app.use('/api/gallery', galleryRoutes);
|
app.use('/api/gallery', galleryRoutes);
|
||||||
app.use('/api/gallery', require('./src/routes/galleryFeedback'));
|
app.use('/api/gallery', require('./src/routes/galleryFeedback'));
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
const knex = require('knex');
|
const knex = require('knex');
|
||||||
const knexConfig = require('../../knexfile');
|
const knexConfig = require('../../knexfile');
|
||||||
const logger = require('../utils/logger');
|
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
|
// Create database connection with built-in retry logic
|
||||||
const db = knex(knexConfig);
|
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",
|
"name": "picpeak-frontend",
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/react-query": "^5.0.0",
|
"@tanstack/react-query": "^5.0.0",
|
||||||
"@tiptap/extension-character-count": "^2.26.1",
|
"@tiptap/extension-character-count": "^2.26.1",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.110",
|
"version": "1.0.113",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { api } from '../config/api';
|
||||||
|
|
||||||
|
export interface ExternalEntry { name: string; type: 'dir' | 'file'; size?: number; mtime?: string }
|
||||||
|
|
||||||
|
export const externalMediaService = {
|
||||||
|
async list(pathRel: string = ''): Promise<{ path: string; entries: ExternalEntry[]; canNavigateUp: boolean }> {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (pathRel) params.set('path', pathRel);
|
||||||
|
const res = await api.get(`/admin/external-media/list?${params.toString()}`);
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async importEvent(eventId: number, externalPath: string, options?: { recursive?: boolean; map?: { individual?: string; collages?: string } }): Promise<{ imported: number; skipped: number; thumbnailsQueued: number }> {
|
||||||
|
const res = await api.post(`/admin/external-media/events/${eventId}/import-external`, {
|
||||||
|
external_path: externalPath,
|
||||||
|
recursive: options?.recursive ?? true,
|
||||||
|
map: options?.map
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+30
-21
@@ -13,7 +13,7 @@ IFS=$'\n\t'
|
|||||||
# Script configuration
|
# Script configuration
|
||||||
readonly SCRIPT_VERSION="2.0.0"
|
readonly SCRIPT_VERSION="2.0.0"
|
||||||
readonly APP_NAME="PicPeak"
|
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 NODE_VERSION="20"
|
||||||
readonly MIN_RAM_DOCKER=2048
|
readonly MIN_RAM_DOCKER=2048
|
||||||
readonly MIN_RAM_NATIVE=1024
|
readonly MIN_RAM_NATIVE=1024
|
||||||
@@ -551,29 +551,34 @@ setup_native_installation() {
|
|||||||
|
|
||||||
# Create application directory
|
# Create application directory
|
||||||
log_step "Creating 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}
|
||||||
|
|
||||||
# Clone repository
|
# Clone repository
|
||||||
log_step "Downloading PicPeak..."
|
log_step "Downloading PicPeak..."
|
||||||
if [[ -d "$NATIVE_APP_DIR/backend/.git" ]]; then
|
if [[ -d "$NATIVE_APP_DIR/app/.git" ]]; then
|
||||||
cd "$NATIVE_APP_DIR/backend"
|
cd "$NATIVE_APP_DIR/app"
|
||||||
git pull
|
git pull
|
||||||
else
|
else
|
||||||
git clone "$REPO_URL" "$NATIVE_APP_DIR/backend"
|
git clone "$REPO_URL" "$NATIVE_APP_DIR/app"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
log_step "Installing 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
|
npm install --production
|
||||||
|
|
||||||
|
# Ensure SQLite data directory exists for native installs
|
||||||
|
mkdir -p "$NATIVE_APP_DIR/app/backend/data"
|
||||||
|
|
||||||
# Generate secrets
|
# Generate secrets
|
||||||
local jwt_secret=$(generate_jwt_secret)
|
local jwt_secret=$(generate_jwt_secret)
|
||||||
[[ -z "$ADMIN_PASSWORD" ]] && ADMIN_PASSWORD=$(generate_password)
|
[[ -z "$ADMIN_PASSWORD" ]] && ADMIN_PASSWORD=$(generate_password)
|
||||||
|
|
||||||
# Create .env file
|
# Create .env file
|
||||||
log_step "Creating configuration..."
|
log_step "Creating configuration..."
|
||||||
cat > "$NATIVE_APP_DIR/backend/.env" <<EOF
|
cat > "$NATIVE_APP_DIR/app/backend/.env" <<EOF
|
||||||
# PicPeak Native Configuration
|
# PicPeak Native Configuration
|
||||||
# Generated: $(date)
|
# Generated: $(date)
|
||||||
|
|
||||||
@@ -587,11 +592,12 @@ ADMIN_USERNAME=admin
|
|||||||
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
||||||
ADMIN_EMAIL=$ADMIN_EMAIL
|
ADMIN_EMAIL=$ADMIN_EMAIL
|
||||||
|
|
||||||
# Database
|
# Database (native uses SQLite by default)
|
||||||
DATABASE_PATH=$NATIVE_APP_DIR/backend/database.sqlite
|
DATABASE_CLIENT=sqlite3
|
||||||
|
DATABASE_PATH=$NATIVE_APP_DIR/app/backend/data/photo_sharing.db
|
||||||
|
|
||||||
# Storage
|
# Storage root (thumbnails/uploads live under this path)
|
||||||
PHOTOS_DIR=$NATIVE_APP_DIR/events
|
STORAGE_PATH=$NATIVE_APP_DIR
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
SMTP_ENABLED=${SMTP_HOST:+true}
|
SMTP_ENABLED=${SMTP_HOST:+true}
|
||||||
@@ -618,11 +624,11 @@ EOF
|
|||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
chown -R $NATIVE_APP_USER:$NATIVE_APP_USER "$NATIVE_APP_DIR"
|
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
|
# Run database migrations
|
||||||
log_step "Initializing database..."
|
log_step "Initializing database..."
|
||||||
cd "$NATIVE_APP_DIR/backend"
|
cd "$NATIVE_APP_DIR/app/backend"
|
||||||
sudo -u $NATIVE_APP_USER npm run migrate
|
sudo -u $NATIVE_APP_USER npm run migrate
|
||||||
|
|
||||||
# Create systemd services
|
# Create systemd services
|
||||||
@@ -654,7 +660,7 @@ After=network.target
|
|||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=$NATIVE_APP_USER
|
User=$NATIVE_APP_USER
|
||||||
WorkingDirectory=$NATIVE_APP_DIR/backend
|
WorkingDirectory=$NATIVE_APP_DIR/app/backend
|
||||||
Environment="NODE_ENV=production"
|
Environment="NODE_ENV=production"
|
||||||
ExecStart=/usr/bin/node server.js
|
ExecStart=/usr/bin/node server.js
|
||||||
Restart=always
|
Restart=always
|
||||||
@@ -675,7 +681,7 @@ After=network.target picpeak-backend.service
|
|||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=$NATIVE_APP_USER
|
User=$NATIVE_APP_USER
|
||||||
WorkingDirectory=$NATIVE_APP_DIR/backend
|
WorkingDirectory=$NATIVE_APP_DIR/app/backend
|
||||||
Environment="NODE_ENV=production"
|
Environment="NODE_ENV=production"
|
||||||
ExecStart=/usr/bin/node src/services/workerManager.js
|
ExecStart=/usr/bin/node src/services/workerManager.js
|
||||||
Restart=always
|
Restart=always
|
||||||
@@ -878,8 +884,8 @@ print_success_message() {
|
|||||||
echo
|
echo
|
||||||
echo "📚 Documentation:"
|
echo "📚 Documentation:"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo "Setup Guide: https://github.com/yourusername/wedding-photo-sharing/blob/main/SIMPLE_SETUP.md"
|
echo "Setup Guide: https://github.com/the-luap/picpeak/blob/main/SIMPLE_SETUP.md"
|
||||||
echo "Full Docs: https://github.com/yourusername/wedding-photo-sharing"
|
echo "Full Docs: https://github.com/the-luap/picpeak"
|
||||||
echo
|
echo
|
||||||
echo -e "${GREEN}✨ Setup complete! Visit the admin panel to start creating galleries.${NC}"
|
echo -e "${GREEN}✨ Setup complete! Visit the admin panel to start creating galleries.${NC}"
|
||||||
}
|
}
|
||||||
@@ -935,13 +941,16 @@ update_native_installation() {
|
|||||||
systemctl stop picpeak-backend picpeak-workers
|
systemctl stop picpeak-backend picpeak-workers
|
||||||
|
|
||||||
# Backup current configuration
|
# 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
|
# Pull latest code
|
||||||
cd "$NATIVE_APP_DIR/backend"
|
cd "$NATIVE_APP_DIR/app"
|
||||||
sudo -u $NATIVE_APP_USER git pull
|
sudo -u $NATIVE_APP_USER git pull
|
||||||
|
|
||||||
# Update dependencies
|
# Update backend dependencies
|
||||||
|
cd "$NATIVE_APP_DIR/app/backend"
|
||||||
sudo -u $NATIVE_APP_USER npm install --production
|
sudo -u $NATIVE_APP_USER npm install --production
|
||||||
|
|
||||||
# Run migrations
|
# Run migrations
|
||||||
@@ -1181,4 +1190,4 @@ main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Run main function
|
# Run main function
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user