Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d77a3a0a8 | |||
| 0618b78725 | |||
| 0178e71c67 | |||
| aa9b3a0227 | |||
| 410a33fecf | |||
| 05ebaaeedb | |||
| 84d0f63d36 |
@@ -53,6 +53,12 @@ VITE_API_URL=/api
|
|||||||
# Timezone
|
# Timezone
|
||||||
TZ=UTC
|
TZ=UTC
|
||||||
|
|
||||||
|
# Runtime user mapping for Docker (optional)
|
||||||
|
# Set these to your host user's UID/GID to avoid permission issues on bind mounts.
|
||||||
|
# Run `id -u` and `id -g` on host to get values. Defaults to 1001.
|
||||||
|
PUID=1001
|
||||||
|
PGID=1001
|
||||||
|
|
||||||
# Analytics (Optional - Umami)
|
# Analytics (Optional - Umami)
|
||||||
VITE_UMAMI_URL=
|
VITE_UMAMI_URL=
|
||||||
VITE_UMAMI_WEBSITE_ID=
|
VITE_UMAMI_WEBSITE_ID=
|
||||||
|
|||||||
@@ -72,6 +72,14 @@ docker-compose up -d
|
|||||||
# Access at http://localhost:3005
|
# Access at http://localhost:3005
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note on Docker file permissions (PUID/PGID)
|
||||||
|
- When using bind mounts (e.g., `./storage`, `./data`, `./logs`, `./events`), ensure the container user can write to these host folders. The backend runs as a non‑root user by default.
|
||||||
|
- Set `PUID` and `PGID` in your `.env` to match your host user’s UID/GID (run `id -u` and `id -g` on the host). Compose maps the container user to these values.
|
||||||
|
- Example in `.env`:
|
||||||
|
- `PUID=1000`
|
||||||
|
- `PGID=1000`
|
||||||
|
- Without this, creating events, uploads, thumbnails, or logs can fail with “Permission denied”.
|
||||||
|
|
||||||
## 📖 Documentation
|
## 📖 Documentation
|
||||||
|
|
||||||
- 📘 [**Deployment Guide**](DEPLOYMENT_GUIDE.md) - Detailed installation instructions
|
- 📘 [**Deployment Guide**](DEPLOYMENT_GUIDE.md) - Detailed installation instructions
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.121",
|
"version": "1.0.124",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-backend",
|
"name": "picpeak-backend",
|
||||||
"version": "1.0.121",
|
"version": "1.0.124",
|
||||||
"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.121",
|
"version": "1.0.124",
|
||||||
"description": "Backend for PicPeak event photo sharing platform",
|
"description": "Backend for PicPeak event photo sharing platform",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ services:
|
|||||||
- ADMIN_URL=${ADMIN_URL:-http://localhost:3001}
|
- ADMIN_URL=${ADMIN_URL:-http://localhost:3001}
|
||||||
- TZ=${TZ:-UTC}
|
- TZ=${TZ:-UTC}
|
||||||
- STORAGE_PATH=/app/storage
|
- STORAGE_PATH=/app/storage
|
||||||
|
# Optional: run container as matching host user to avoid bind mount permission issues
|
||||||
|
- PUID=${PUID:-1001}
|
||||||
|
- PGID=${PGID:-1001}
|
||||||
|
# Use host-matching user ID/GID so bind-mounted folders are writable
|
||||||
|
user: "${PUID:-1001}:${PGID:-1001}"
|
||||||
volumes:
|
volumes:
|
||||||
- ./events:/app/events
|
- ./events:/app/events
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"version": "1.0.121",
|
"version": "1.0.124",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"version": "1.0.121",
|
"version": "1.0.124",
|
||||||
"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.121",
|
"version": "1.0.124",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+67
-18
@@ -44,7 +44,6 @@ INSTALL_METHOD="" # docker or native
|
|||||||
OS_TYPE=""
|
OS_TYPE=""
|
||||||
OS_VERSION=""
|
OS_VERSION=""
|
||||||
PACKAGE_MANAGER=""
|
PACKAGE_MANAGER=""
|
||||||
ADMIN_PASSWORD=""
|
|
||||||
ADMIN_EMAIL="admin@example.com"
|
ADMIN_EMAIL="admin@example.com"
|
||||||
DOMAIN_NAME=""
|
DOMAIN_NAME=""
|
||||||
SMTP_HOST=""
|
SMTP_HOST=""
|
||||||
@@ -78,6 +77,21 @@ run_as_user() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Prompt for admin email interactively (unless provided or unattended)
|
||||||
|
prompt_admin_email() {
|
||||||
|
if [[ -n "$ADMIN_EMAIL" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ "$UNATTENDED" == "true" ]]; then
|
||||||
|
ADMIN_EMAIL="admin@example.com"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
echo "Please enter the admin email address (used for the initial admin account):"
|
||||||
|
read -p "Admin email [admin@example.com]: " ADMIN_EMAIL
|
||||||
|
ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com}
|
||||||
|
}
|
||||||
|
|
||||||
print_banner() {
|
print_banner() {
|
||||||
echo -e "${PURPLE}"
|
echo -e "${PURPLE}"
|
||||||
echo "╔════════════════════════════════════════════════════════════════════════╗"
|
echo "╔════════════════════════════════════════════════════════════════════════╗"
|
||||||
@@ -338,7 +352,7 @@ setup_docker_installation() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
log_step "Creating application directory at $app_dir"
|
log_step "Creating application directory at $app_dir"
|
||||||
mkdir -p "$app_dir"/{storage/events/{active,archived},logs,backup,config}
|
mkdir -p "$app_dir"/{storage/events/{active,archived},logs,backup,config,data,events}
|
||||||
|
|
||||||
# Clone repository
|
# Clone repository
|
||||||
log_step "Downloading PicPeak..."
|
log_step "Downloading PicPeak..."
|
||||||
@@ -349,11 +363,20 @@ setup_docker_installation() {
|
|||||||
git clone "$REPO_URL" "$app_dir"
|
git clone "$REPO_URL" "$app_dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Determine host user for container mapping (PUID/PGID)
|
||||||
|
local host_uid host_gid
|
||||||
|
if [[ -n "${SUDO_USER:-}" ]]; then
|
||||||
|
host_uid=$(id -u "$SUDO_USER" 2>/dev/null || echo 1000)
|
||||||
|
host_gid=$(id -g "$SUDO_USER" 2>/dev/null || echo 1000)
|
||||||
|
else
|
||||||
|
host_uid=$(id -u 2>/dev/null || echo 1000)
|
||||||
|
host_gid=$(id -g 2>/dev/null || echo 1000)
|
||||||
|
fi
|
||||||
|
|
||||||
# Generate secrets
|
# Generate secrets
|
||||||
local jwt_secret=$(generate_jwt_secret)
|
local jwt_secret=$(generate_jwt_secret)
|
||||||
local db_password=$(generate_password)
|
local db_password=$(generate_password)
|
||||||
local redis_password=$(generate_password)
|
local redis_password=$(generate_password)
|
||||||
[[ -z "$ADMIN_PASSWORD" ]] && ADMIN_PASSWORD=$(generate_password)
|
|
||||||
|
|
||||||
# Create .env file
|
# Create .env file
|
||||||
log_step "Creating configuration..."
|
log_step "Creating configuration..."
|
||||||
@@ -368,7 +391,10 @@ JWT_SECRET=$jwt_secret
|
|||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
ADMIN_EMAIL=$ADMIN_EMAIL
|
ADMIN_EMAIL=$ADMIN_EMAIL
|
||||||
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
|
||||||
|
# Runtime user mapping for Docker bind mounts
|
||||||
|
PUID=$host_uid
|
||||||
|
PGID=$host_gid
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DB_HOST=postgres
|
DB_HOST=postgres
|
||||||
@@ -395,7 +421,7 @@ SMTP_FROM=${SMTP_USER:-noreply@localhost}
|
|||||||
|
|
||||||
# URLs
|
# URLs
|
||||||
FRONTEND_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
FRONTEND_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
||||||
ADMIN_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME/admin}
|
ADMIN_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
ENABLE_FILE_WATCHER=true
|
ENABLE_FILE_WATCHER=true
|
||||||
@@ -404,6 +430,9 @@ ENABLE_EMAIL_SERVICE=true
|
|||||||
DEFAULT_EXPIRY_DAYS=30
|
DEFAULT_EXPIRY_DAYS=30
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Ensure bind mounts are writable by mapped user
|
||||||
|
chown -R "$host_uid":"$host_gid" "$app_dir"/storage "$app_dir"/logs "$app_dir"/backup "$app_dir"/data "$app_dir"/events 2>/dev/null || true
|
||||||
|
|
||||||
# Create docker-compose.yml if it doesn't exist
|
# Create docker-compose.yml if it doesn't exist
|
||||||
if [[ ! -f "$app_dir/docker-compose.yml" ]]; then
|
if [[ ! -f "$app_dir/docker-compose.yml" ]]; then
|
||||||
log_step "Creating Docker Compose configuration..."
|
log_step "Creating Docker Compose configuration..."
|
||||||
@@ -618,7 +647,6 @@ setup_native_installation() {
|
|||||||
|
|
||||||
# Generate secrets
|
# Generate secrets
|
||||||
local jwt_secret=$(generate_jwt_secret)
|
local jwt_secret=$(generate_jwt_secret)
|
||||||
[[ -z "$ADMIN_PASSWORD" ]] && ADMIN_PASSWORD=$(generate_password)
|
|
||||||
|
|
||||||
# Create .env file
|
# Create .env file
|
||||||
log_step "Creating configuration..."
|
log_step "Creating configuration..."
|
||||||
@@ -633,7 +661,6 @@ JWT_SECRET=$jwt_secret
|
|||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
ADMIN_PASSWORD=$ADMIN_PASSWORD
|
|
||||||
ADMIN_EMAIL=$ADMIN_EMAIL
|
ADMIN_EMAIL=$ADMIN_EMAIL
|
||||||
|
|
||||||
# Database (native uses SQLite by default)
|
# Database (native uses SQLite by default)
|
||||||
@@ -653,7 +680,7 @@ SMTP_FROM=${SMTP_USER:-noreply@localhost}
|
|||||||
|
|
||||||
# URLs
|
# URLs
|
||||||
FRONTEND_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
FRONTEND_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
||||||
ADMIN_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME/admin}
|
ADMIN_URL=${DOMAIN_NAME:+https://$DOMAIN_NAME}
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
ENABLE_FILE_WATCHER=true
|
ENABLE_FILE_WATCHER=true
|
||||||
@@ -906,8 +933,32 @@ print_success_message() {
|
|||||||
echo
|
echo
|
||||||
echo "🔐 Admin Credentials:"
|
echo "🔐 Admin Credentials:"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo -e "Email: ${CYAN}$ADMIN_EMAIL${NC}"
|
# Read from ADMIN_CREDENTIALS.txt when available
|
||||||
echo -e "Password: ${CYAN}$ADMIN_PASSWORD${NC}"
|
local cred_file email_line pass_line admin_email_val admin_pass_val
|
||||||
|
if [[ "$INSTALL_METHOD" == "docker" ]]; then
|
||||||
|
cred_file="$app_dir/data/ADMIN_CREDENTIALS.txt"
|
||||||
|
else
|
||||||
|
cred_file="$NATIVE_APP_DIR/app/backend/data/ADMIN_CREDENTIALS.txt"
|
||||||
|
fi
|
||||||
|
if [[ -f "$cred_file" ]]; then
|
||||||
|
email_line=$(grep -m1 '^Email:' "$cred_file" || true)
|
||||||
|
pass_line=$(grep -m1 '^Password:' "$cred_file" || true)
|
||||||
|
admin_email_val=${email_line#Email: }
|
||||||
|
admin_pass_val=${pass_line#Password: }
|
||||||
|
if [[ -n "$admin_email_val" ]]; then
|
||||||
|
echo -e "Email: ${CYAN}$admin_email_val${NC}"
|
||||||
|
else
|
||||||
|
echo -e "Email: ${CYAN}$ADMIN_EMAIL${NC}"
|
||||||
|
fi
|
||||||
|
if [[ -n "$admin_pass_val" ]]; then
|
||||||
|
echo -e "Password: ${CYAN}$admin_pass_val${NC}"
|
||||||
|
else
|
||||||
|
echo -e "Password: ${YELLOW}(see $cred_file)${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "Email: ${CYAN}$ADMIN_EMAIL${NC}"
|
||||||
|
echo -e "Password: ${YELLOW}(credentials file not found)${NC}"
|
||||||
|
fi
|
||||||
echo
|
echo
|
||||||
echo -e "${YELLOW}⚠️ IMPORTANT: Change the admin password on first login!${NC}"
|
echo -e "${YELLOW}⚠️ IMPORTANT: Change the admin password on first login!${NC}"
|
||||||
|
|
||||||
@@ -931,8 +982,8 @@ print_success_message() {
|
|||||||
echo "🔧 Service Commands:"
|
echo "🔧 Service Commands:"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo "View logs: sudo journalctl -u picpeak-backend -f"
|
echo "View logs: sudo journalctl -u picpeak-backend -f"
|
||||||
echo "Stop: sudo systemctl stop picpeak-backend picpeak-workers"
|
echo "Stop: sudo systemctl stop picpeak-backend"
|
||||||
echo "Start: sudo systemctl start picpeak-backend picpeak-workers"
|
echo "Start: sudo systemctl start picpeak-backend"
|
||||||
echo "Status: sudo systemctl status picpeak-backend"
|
echo "Status: sudo systemctl status picpeak-backend"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1146,10 +1197,6 @@ parse_arguments() {
|
|||||||
ADMIN_EMAIL="$2"
|
ADMIN_EMAIL="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
--admin-password)
|
|
||||||
ADMIN_PASSWORD="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--smtp-host)
|
--smtp-host)
|
||||||
SMTP_HOST="$2"
|
SMTP_HOST="$2"
|
||||||
shift 2
|
shift 2
|
||||||
@@ -1207,7 +1254,6 @@ Options:
|
|||||||
--unattended Run without prompts
|
--unattended Run without prompts
|
||||||
--domain DOMAIN Set domain name for HTTPS
|
--domain DOMAIN Set domain name for HTTPS
|
||||||
--email EMAIL Admin email address
|
--email EMAIL Admin email address
|
||||||
--admin-password Admin password (auto-generated if not set)
|
|
||||||
--smtp-host HOST SMTP server hostname
|
--smtp-host HOST SMTP server hostname
|
||||||
--smtp-port PORT SMTP server port
|
--smtp-port PORT SMTP server port
|
||||||
--smtp-user USER SMTP username
|
--smtp-user USER SMTP username
|
||||||
@@ -1230,7 +1276,7 @@ Examples:
|
|||||||
|
|
||||||
# Fully automated Docker setup
|
# Fully automated Docker setup
|
||||||
sudo $0 --docker --unattended --domain photos.example.com \\
|
sudo $0 --docker --unattended --domain photos.example.com \\
|
||||||
--email admin@example.com --admin-password SecurePass123 \\
|
--email admin@example.com \\
|
||||||
--smtp-host smtp.gmail.com --smtp-port 587 \\
|
--smtp-host smtp.gmail.com --smtp-port 587 \\
|
||||||
--smtp-user user@gmail.com --smtp-pass app-password \\
|
--smtp-user user@gmail.com --smtp-pass app-password \\
|
||||||
--enable-ssl
|
--enable-ssl
|
||||||
@@ -1270,6 +1316,9 @@ main() {
|
|||||||
# Check system requirements
|
# Check system requirements
|
||||||
check_system_requirements
|
check_system_requirements
|
||||||
|
|
||||||
|
# Prompt for admin email (design choice: always ask unless provided)
|
||||||
|
prompt_admin_email
|
||||||
|
|
||||||
# Configure email (optional)
|
# Configure email (optional)
|
||||||
configure_email
|
configure_email
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user