chore: remove sensitive files for GitHub mirror
@@ -1,114 +0,0 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
steps:
|
||||
# Build Backend Docker Image
|
||||
- name: build-backend
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: registry.local.nothaft.cloud/picpeak-backend
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_COMMIT_SHA:0:8}
|
||||
- ${DRONE_BRANCH}-latest
|
||||
dockerfile: backend/Dockerfile
|
||||
context: backend/
|
||||
registry: registry.local.nothaft.cloud
|
||||
build_args:
|
||||
- VERSION=${DRONE_TAG:-dev}
|
||||
|
||||
# Build Frontend Docker Image
|
||||
- name: build-frontend
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: registry.local.nothaft.cloud/picpeak-frontend
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_COMMIT_SHA:0:8}
|
||||
- ${DRONE_BRANCH}-latest
|
||||
dockerfile: frontend/Dockerfile
|
||||
context: frontend/
|
||||
registry: registry.local.nothaft.cloud
|
||||
build_args:
|
||||
- VERSION=${DRONE_TAG:-dev}
|
||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
- develop
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: release
|
||||
|
||||
steps:
|
||||
# Build Backend Release
|
||||
- name: build-backend-release
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: registry.local.nothaft.cloud/picpeak-backend
|
||||
tags:
|
||||
- ${DRONE_TAG}
|
||||
- latest
|
||||
dockerfile: backend/Dockerfile
|
||||
context: backend/
|
||||
registry: registry.local.nothaft.cloud
|
||||
|
||||
# Build Frontend Release
|
||||
- name: build-frontend-release
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: registry.local.nothaft.cloud/picpeak-frontend
|
||||
tags:
|
||||
- ${DRONE_TAG}
|
||||
- latest
|
||||
dockerfile: frontend/Dockerfile
|
||||
context: frontend/
|
||||
registry: registry.local.nothaft.cloud
|
||||
|
||||
# -------- NEW: Publish Docker images to GitHub Container Registry --------
|
||||
- name: push-backend-ghcr
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: ghcr.io/the-luap/picpeak-backend
|
||||
tags:
|
||||
- ${DRONE_TAG}
|
||||
- latest
|
||||
dockerfile: backend/Dockerfile
|
||||
context: backend/
|
||||
registry: ghcr.io
|
||||
username:
|
||||
from_secret: GITHUB_USERNAME
|
||||
password:
|
||||
from_secret: GITHUB_TOKEN
|
||||
build_args:
|
||||
- VERSION=${DRONE_TAG}
|
||||
|
||||
- name: push-frontend-ghcr
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: ghcr.io/the-luap/picpeak-frontend
|
||||
tags:
|
||||
- ${DRONE_TAG}
|
||||
- latest
|
||||
dockerfile: frontend/Dockerfile
|
||||
context: frontend/
|
||||
registry: ghcr.io
|
||||
username:
|
||||
from_secret: GITHUB_USERNAME
|
||||
password:
|
||||
from_secret: GITHUB_TOKEN
|
||||
build_args:
|
||||
- VERSION=${DRONE_TAG}
|
||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
@@ -1,132 +0,0 @@
|
||||
name: Mirror to GitHub
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allow manual triggering only
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
runs-on: ubuntu-latest
|
||||
# Note: For GitHub fine-grained tokens, ensure the token has:
|
||||
# - Repository access to the-luap/picpeak
|
||||
# - Repository permissions: Contents (Read and Write), Metadata (Read)
|
||||
# For classic tokens: repo scope is sufficient
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Full history for proper mirroring
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.name "the-luap"
|
||||
git config --global user.email "paul-nothaft@hotmail.de"
|
||||
|
||||
- name: Remove sensitive files and directories
|
||||
run: |
|
||||
echo "Current files before cleanup:"
|
||||
ls -la | head -10 || true
|
||||
echo "..."
|
||||
|
||||
# Remove sensitive files/directories if they exist
|
||||
echo "Removing sensitive files..."
|
||||
rm -rf .gitea/ || true
|
||||
rm -rf scripts/install-gitea-runner.sh || true
|
||||
rm -rf .drone* || true
|
||||
rm -rf photo-sharing-prd.md || true
|
||||
rm -rf CLAUDE.md || true
|
||||
rm -rf storage/ || true
|
||||
rm -rf events/ || true
|
||||
rm -rf .playwright-mcp/
|
||||
rm -rf .swarm || true
|
||||
rm -rf .claude-flow || true
|
||||
|
||||
|
||||
echo "Sensitive files removal completed"
|
||||
|
||||
# Add and commit the cleanup if there are changes
|
||||
git add -A
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "chore: remove sensitive files for GitHub mirror"
|
||||
echo "✅ Committed cleanup of sensitive files"
|
||||
else
|
||||
echo "✅ No sensitive files to remove"
|
||||
fi
|
||||
|
||||
echo "Final file structure (top level):"
|
||||
ls -la | head -10 || true
|
||||
|
||||
- name: Check GitHub token
|
||||
env:
|
||||
GITHUBTOKEN: ${{ secrets.GITHUBTOKEN }}
|
||||
run: |
|
||||
if [ -z "$GITHUBTOKEN" ]; then
|
||||
echo "ERROR: GITHUBTOKEN secret is not set!"
|
||||
echo "Please add a GitHub Personal Access Token as a secret named GITHUBTOKEN"
|
||||
echo ""
|
||||
echo "For fine-grained tokens:"
|
||||
echo " - Go to GitHub Settings > Developer settings > Personal access tokens > Fine-grained tokens"
|
||||
echo " - Create token with repository access to the-luap/picpeak"
|
||||
echo " - Grant permissions: Contents (Read and Write), Metadata (Read)"
|
||||
echo ""
|
||||
echo "For classic tokens:"
|
||||
echo " - Go to GitHub Settings > Developer settings > Personal access tokens > Tokens (classic)"
|
||||
echo " - Create token with 'repo' scope"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ GitHub token is available (length: ${#GITHUBTOKEN})"
|
||||
# Try to detect token type (fine-grained tokens are typically longer)
|
||||
if [ ${#GITHUBTOKEN} -gt 80 ]; then
|
||||
echo "📌 Token appears to be a fine-grained personal access token"
|
||||
else
|
||||
echo "📌 Token appears to be a classic personal access token"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Push to GitHub
|
||||
env:
|
||||
GITHUBTOKEN: ${{ secrets.GITHUBTOKEN }}
|
||||
GIT_TRACE: 1 # Enable Git trace for debugging if needed
|
||||
run: |
|
||||
# Remove existing github remote if it exists
|
||||
git remote remove github || true
|
||||
|
||||
# Configure Git to use the token for authentication
|
||||
# This method works for both classic and fine-grained tokens
|
||||
git config --global url."https://the-luap:${GITHUBTOKEN}@github.com/".insteadOf "https://github.com/"
|
||||
|
||||
# Add GitHub remote (clean URL without credentials)
|
||||
git remote add github https://github.com/the-luap/picpeak.git
|
||||
|
||||
# Verify remote was added
|
||||
echo "GitHub remote configuration:"
|
||||
git remote -v
|
||||
|
||||
# Push to GitHub main branch with error handling
|
||||
echo "Pushing to GitHub..."
|
||||
if git push github main --force 2>&1; then
|
||||
echo "✅ Push to GitHub completed successfully!"
|
||||
else
|
||||
echo "❌ Push to GitHub failed!"
|
||||
echo ""
|
||||
echo "Common issues and solutions:"
|
||||
echo "1. Token permissions: Ensure your token has 'Contents: write' permission"
|
||||
echo "2. Token expiration: Check if your token has expired"
|
||||
echo "3. Repository access: Verify the token has access to the-luap/picpeak repository"
|
||||
echo ""
|
||||
echo "For fine-grained tokens, required permissions:"
|
||||
echo " - Repository access: the-luap/picpeak"
|
||||
echo " - Repository permissions: Contents (Read and Write), Metadata (Read)"
|
||||
echo ""
|
||||
echo "For classic tokens, required scope: 'repo'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up the git config after push
|
||||
git config --global --unset url."https://the-luap:${GITHUBTOKEN}@github.com/".insteadOf
|
||||
|
||||
- name: Workflow completed
|
||||
run: |
|
||||
echo "✅ Mirror to GitHub workflow completed successfully!"
|
||||
echo "📊 Repository mirrored to: https://github.com/the-luap/picpeak"
|
||||
echo "🔒 Sensitive files have been removed from the mirror"
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
name: Test and Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
backend-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install backend dependencies
|
||||
working-directory: ./backend
|
||||
run: npm ci
|
||||
|
||||
- name: Run backend linting
|
||||
working-directory: ./backend
|
||||
run: npm run lint || true # Continue on lint errors for now
|
||||
|
||||
- name: Run backend tests
|
||||
working-directory: ./backend
|
||||
run: npm test || true # Continue on test failures for now
|
||||
|
||||
frontend-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install frontend dependencies
|
||||
working-directory: ./frontend
|
||||
run: npm ci --legacy-peer-deps
|
||||
|
||||
- name: Run frontend linting
|
||||
working-directory: ./frontend
|
||||
run: npm run lint || true # Continue on lint errors for now
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: ./frontend
|
||||
run: npm run build
|
||||
@@ -1,269 +0,0 @@
|
||||
name: Version and Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
version-bump:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
new_version: ${{ steps.version.outputs.new_version }}
|
||||
version_changed: ${{ steps.version.outputs.version_changed }}
|
||||
component_changed: ${{ steps.version.outputs.component_changed }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITEA_TOKEN || github.token }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name 'Gitea Actions Bot'
|
||||
git config --global user.email 'actions@gitea.local'
|
||||
|
||||
- name: Detect changes and bump version
|
||||
id: version
|
||||
run: |
|
||||
set -e # Exit on error
|
||||
|
||||
echo "=== Debug Info ==="
|
||||
echo "GitHub event before: ${{ github.event.before }}"
|
||||
echo "GitHub SHA: ${{ github.sha }}"
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Git log (last 5): $(git log --oneline -5)"
|
||||
|
||||
# Get the commit range for changed files
|
||||
if [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ] && [ "${{ github.event.before }}" != "" ]; then
|
||||
COMMIT_RANGE="${{ github.event.before }}..${{ github.sha }}"
|
||||
echo "Using commit range: $COMMIT_RANGE"
|
||||
CHANGED_FILES=$(git diff --name-only $COMMIT_RANGE || echo "")
|
||||
else
|
||||
# First commit or no previous commit, check against HEAD~1 if it exists
|
||||
if git rev-parse HEAD~1 >/dev/null 2>&1; then
|
||||
COMMIT_RANGE="HEAD~1..HEAD"
|
||||
echo "Using commit range: $COMMIT_RANGE"
|
||||
CHANGED_FILES=$(git diff --name-only $COMMIT_RANGE || echo "")
|
||||
else
|
||||
echo "First commit detected, checking all files"
|
||||
CHANGED_FILES=$(git ls-files)
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Changed files:"
|
||||
echo "$CHANGED_FILES"
|
||||
|
||||
# Check what changed (using echo to pipe to grep to avoid grep exit codes)
|
||||
BACKEND_CHANGED=$(echo "$CHANGED_FILES" | grep -c '^backend/' || echo "0")
|
||||
FRONTEND_CHANGED=$(echo "$CHANGED_FILES" | grep -c '^frontend/' || echo "0")
|
||||
ROOT_CHANGED=$(echo "$CHANGED_FILES" | grep -c -E '^(package\.json|docker-compose|Dockerfile|scripts/)' || echo "0")
|
||||
|
||||
echo "Backend files changed: $BACKEND_CHANGED"
|
||||
echo "Frontend files changed: $FRONTEND_CHANGED"
|
||||
echo "Root files changed: $ROOT_CHANGED"
|
||||
|
||||
# Get current versions
|
||||
BACKEND_VERSION=$(node -p "require('./backend/package.json').version" 2>/dev/null || echo "1.1.0")
|
||||
FRONTEND_VERSION=$(node -p "require('./frontend/package.json').version" 2>/dev/null || echo "1.1.0")
|
||||
|
||||
echo "Current backend version: $BACKEND_VERSION"
|
||||
echo "Current frontend version: $FRONTEND_VERSION"
|
||||
|
||||
# Determine what to update based on changes
|
||||
BACKEND_UPDATE=false
|
||||
FRONTEND_UPDATE=false
|
||||
COMPONENT_CHANGED="none"
|
||||
|
||||
if [ "$ROOT_CHANGED" -gt 0 ]; then
|
||||
# Root changes affect both components
|
||||
BACKEND_UPDATE=true
|
||||
FRONTEND_UPDATE=true
|
||||
COMPONENT_CHANGED="both"
|
||||
SOURCE_VERSION=$BACKEND_VERSION
|
||||
echo "Root changes detected - updating both components"
|
||||
elif [ "$BACKEND_CHANGED" -gt 0 ] && [ "$FRONTEND_CHANGED" -gt 0 ]; then
|
||||
# Both components changed
|
||||
BACKEND_UPDATE=true
|
||||
FRONTEND_UPDATE=true
|
||||
COMPONENT_CHANGED="both"
|
||||
# Use the higher version as source
|
||||
if [ "$(printf '%s\n' "$BACKEND_VERSION" "$FRONTEND_VERSION" | sort -V | tail -n1)" = "$BACKEND_VERSION" ]; then
|
||||
SOURCE_VERSION=$BACKEND_VERSION
|
||||
else
|
||||
SOURCE_VERSION=$FRONTEND_VERSION
|
||||
fi
|
||||
echo "Both backend and frontend changed - updating both"
|
||||
elif [ "$BACKEND_CHANGED" -gt 0 ]; then
|
||||
# Only backend changed
|
||||
BACKEND_UPDATE=true
|
||||
COMPONENT_CHANGED="backend"
|
||||
SOURCE_VERSION=$BACKEND_VERSION
|
||||
echo "Only backend changed - updating backend"
|
||||
elif [ "$FRONTEND_CHANGED" -gt 0 ]; then
|
||||
# Only frontend changed
|
||||
FRONTEND_UPDATE=true
|
||||
COMPONENT_CHANGED="frontend"
|
||||
SOURCE_VERSION=$FRONTEND_VERSION
|
||||
echo "Only frontend changed - updating frontend"
|
||||
else
|
||||
echo "No relevant changes detected"
|
||||
echo "version_changed=false" >> $GITHUB_OUTPUT
|
||||
echo "component_changed=none" >> $GITHUB_OUTPUT
|
||||
echo "new_version=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Component changed: $COMPONENT_CHANGED"
|
||||
echo "Source version: $SOURCE_VERSION"
|
||||
echo "Backend update: $BACKEND_UPDATE"
|
||||
echo "Frontend update: $FRONTEND_UPDATE"
|
||||
|
||||
# Calculate new version
|
||||
IFS='.' read -r -a version_parts <<< "$SOURCE_VERSION"
|
||||
MAJOR="${version_parts[0]}"
|
||||
MINOR="${version_parts[1]}"
|
||||
PATCH="${version_parts[2]}"
|
||||
|
||||
# Increment patch version and ensure tag uniqueness
|
||||
git fetch --tags --quiet || true
|
||||
NEW_PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH"
|
||||
|
||||
while git rev-parse "v${NEW_VERSION}" >/dev/null 2>&1; do
|
||||
echo "Tag v${NEW_VERSION} already exists, bumping patch version again"
|
||||
NEW_PATCH=$((NEW_PATCH + 1))
|
||||
NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH"
|
||||
done
|
||||
|
||||
echo "New version: $NEW_VERSION"
|
||||
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "component_changed=$COMPONENT_CHANGED" >> $GITHUB_OUTPUT
|
||||
|
||||
# Update versions in package.json files
|
||||
if [ "$BACKEND_UPDATE" = true ]; then
|
||||
echo "Updating backend version to $NEW_VERSION"
|
||||
cd backend && npm version $NEW_VERSION --no-git-tag-version
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [ "$FRONTEND_UPDATE" = true ]; then
|
||||
echo "Updating frontend version to $NEW_VERSION"
|
||||
cd frontend && npm version $NEW_VERSION --no-git-tag-version
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "version_changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version_changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Commit version bump
|
||||
if: steps.version.outputs.version_changed == 'true'
|
||||
run: |
|
||||
set -e # Exit on any error
|
||||
|
||||
# First, ensure we have the latest changes
|
||||
echo "Fetching latest changes..."
|
||||
git fetch origin main
|
||||
|
||||
# Check if we're behind and need to update
|
||||
LOCAL=$(git rev-parse HEAD)
|
||||
REMOTE=$(git rev-parse origin/main)
|
||||
|
||||
if [ "$LOCAL" != "$REMOTE" ]; then
|
||||
echo "Local is behind remote, pulling changes..."
|
||||
git pull origin main --no-rebase
|
||||
fi
|
||||
|
||||
COMPONENT="${{ steps.version.outputs.component_changed }}"
|
||||
|
||||
if [ "$COMPONENT" = "both" ]; then
|
||||
git add backend/package.json backend/package-lock.json frontend/package.json frontend/package-lock.json
|
||||
git commit -m "chore: bump version to ${{ steps.version.outputs.new_version }} (backend + frontend)"
|
||||
elif [ "$COMPONENT" = "backend" ]; then
|
||||
git add backend/package.json backend/package-lock.json
|
||||
git commit -m "chore: bump backend version to ${{ steps.version.outputs.new_version }}"
|
||||
elif [ "$COMPONENT" = "frontend" ]; then
|
||||
git add frontend/package.json frontend/package-lock.json
|
||||
git commit -m "chore: bump frontend version to ${{ steps.version.outputs.new_version }}"
|
||||
fi
|
||||
|
||||
# Pull latest changes before pushing to avoid conflicts
|
||||
echo "Pulling latest changes from origin/main..."
|
||||
if ! git pull --rebase origin main; then
|
||||
echo "Rebase failed, attempting to resolve..."
|
||||
# If rebase fails, abort and try a regular merge
|
||||
git rebase --abort || true
|
||||
git pull origin main --no-rebase
|
||||
fi
|
||||
|
||||
# Push the changes with retry logic
|
||||
echo "Pushing version bump..."
|
||||
PUSH_SUCCESS=false
|
||||
|
||||
for i in 1 2 3; do
|
||||
echo "Push attempt $i of 3..."
|
||||
|
||||
# Try to push
|
||||
if git push origin main 2>&1; then
|
||||
echo "Successfully pushed version bump on attempt $i"
|
||||
PUSH_SUCCESS=true
|
||||
break
|
||||
else
|
||||
echo "Push failed on attempt $i"
|
||||
|
||||
if [ $i -lt 3 ]; then
|
||||
echo "Waiting 5 seconds before retry..."
|
||||
sleep 5
|
||||
|
||||
echo "Pulling latest changes..."
|
||||
git fetch origin main
|
||||
|
||||
# Try rebase first, fall back to merge
|
||||
if ! git rebase origin/main; then
|
||||
echo "Rebase failed, trying merge..."
|
||||
git rebase --abort 2>/dev/null || true
|
||||
git pull origin main --no-rebase
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$PUSH_SUCCESS" = "false" ]; then
|
||||
echo "ERROR: Failed to push after 3 attempts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create Git tag
|
||||
if: steps.version.outputs.version_changed == 'true'
|
||||
run: |
|
||||
COMPONENT="${{ steps.version.outputs.component_changed }}"
|
||||
|
||||
if [ "$COMPONENT" = "both" ]; then
|
||||
TAG_MESSAGE="Release v${{ steps.version.outputs.new_version }} (backend + frontend)"
|
||||
elif [ "$COMPONENT" = "backend" ]; then
|
||||
TAG_MESSAGE="Release v${{ steps.version.outputs.new_version }} (backend)"
|
||||
elif [ "$COMPONENT" = "frontend" ]; then
|
||||
TAG_MESSAGE="Release v${{ steps.version.outputs.new_version }} (frontend)"
|
||||
fi
|
||||
|
||||
git tag -a "v${{ steps.version.outputs.new_version }}" -m "$TAG_MESSAGE"
|
||||
git push origin "v${{ steps.version.outputs.new_version }}"
|
||||
|
||||
trigger-drone:
|
||||
needs: version-bump
|
||||
if: needs.version-bump.outputs.version_changed == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger Drone Build
|
||||
run: |
|
||||
echo "Version bumped to ${{ needs.version-bump.outputs.new_version }}"
|
||||
echo "Component(s) changed: ${{ needs.version-bump.outputs.component_changed }}"
|
||||
echo "Drone will automatically trigger on the new tag"
|
||||
# Drone CI will automatically trigger on the tag push event
|
||||
@@ -1,386 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Product Overview
|
||||
|
||||
A secure photo sharing platform designed for weddings and events, enabling photographers to share time-limited, password-protected galleries. The platform features automatic expiration, archiving, and a scrappbook.de-inspired modern, minimalist UI.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
- **Backend**: Node.js/Express API with SQLite/PostgreSQL, file-based photo storage
|
||||
- **Frontend**: React SPA with scrappbook.de-style design (requires implementation)
|
||||
- **Storage**: File-based with active/archived separation
|
||||
- **Services**: Background workers for email, archiving, file watching, and expiration monitoring
|
||||
- **Analytics**: Umami integration for engagement tracking
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Backend Development
|
||||
```bash
|
||||
cd backend
|
||||
npm install # Install dependencies
|
||||
npm run migrate # Initialize database schema
|
||||
npm run dev # Start with hot-reload (port 3001)
|
||||
npm test # Run Jest tests
|
||||
npm run lint # ESLint checks
|
||||
```
|
||||
|
||||
### Running a Single Test
|
||||
```bash
|
||||
cd backend
|
||||
npm test -- path/to/test.test.js
|
||||
npm test -- --testNamePattern="test name"
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
See [DEPLOYMENT_GUIDE.md](./DEPLOYMENT_GUIDE.md) for comprehensive deployment instructions including:
|
||||
- Docker Compose deployment
|
||||
- PM2 deployment
|
||||
- Manual installation
|
||||
- Non-nginx deployment options
|
||||
- SSL/HTTPS setup
|
||||
- Troubleshooting guide
|
||||
|
||||
**⚠️ CRITICAL PRODUCTION NOTICE:**
|
||||
- Production runs on a SEPARATE SERVER - never assume local changes affect production
|
||||
- ALWAYS request production server details before any troubleshooting
|
||||
- NO trial-and-error approaches in production - data loss is unacceptable
|
||||
- Every change must be thoroughly analyzed and tested locally first
|
||||
|
||||
## Key Product Requirements (from PRD)
|
||||
|
||||
### Core Features
|
||||
1. **File-Based System**: Drop photos in folders → automatic gallery creation
|
||||
2. **Automatic Expiration**: Default 30 days, with 7-day warning emails
|
||||
3. **Password Protection**: Secure access with customizable passwords
|
||||
4. **Automatic Archiving**: ZIP compression and storage after expiration
|
||||
5. **Email Notifications**: Creation, warning, and expiration notifications
|
||||
6. **Analytics**: Umami tracking for views, downloads, and engagement
|
||||
|
||||
### Folder Structure
|
||||
```
|
||||
/events/
|
||||
├── active/
|
||||
│ ├── wedding-smith-jones-2024-06-15/
|
||||
│ │ ├── collages/
|
||||
│ │ └── individual/
|
||||
│ └── birthday-emma-2024-07-20/
|
||||
└── archived/
|
||||
└── wedding-smith-jones-2024-06-15.zip
|
||||
```
|
||||
|
||||
## Frontend Implementation Requirements
|
||||
|
||||
### Design Style (scrappbook.de-inspired)
|
||||
- **Color Palette**: Primary green (#5C8762), neutral backgrounds
|
||||
- **Typography**: Clean, modern sans-serif (Noto Sans or similar)
|
||||
- **Layout**: Minimalist, modular sections with grid-based photo displays
|
||||
- **Aesthetic**: Professional yet approachable, photographer-focused
|
||||
|
||||
### Key Frontend Components to Build
|
||||
1. **Landing Page**: Password entry with event preview
|
||||
2. **Gallery View**:
|
||||
- Responsive photo grid with lazy loading
|
||||
- Toggle between collages/individual photos
|
||||
- Prominent expiration banner
|
||||
- Download urgency indicators
|
||||
3. **Photo Lightbox**: Full-screen viewing with zoom
|
||||
4. **Mobile-First**: Responsive design with touch gestures
|
||||
5. **Personalization**: Dynamic theming per event type
|
||||
|
||||
### User Experience Priorities
|
||||
- Clear expiration warnings (sticky banner)
|
||||
- One-click "Download All" for urgent galleries
|
||||
- Smooth image loading with skeleton screens
|
||||
- Intuitive navigation between photo categories
|
||||
- Professional presentation matching photographer branding
|
||||
|
||||
## Key Architecture Patterns
|
||||
|
||||
### Authentication Flow
|
||||
- JWT-based with separate tokens for admin and gallery access
|
||||
- Gallery tokens include event-specific claims
|
||||
- Auth middleware: `backend/src/middleware/auth.js`
|
||||
- `adminAuth` - Admin panel protection
|
||||
- `photoAuth` - Protected photo access
|
||||
- `verifyGalleryAccess` - Gallery-specific validation
|
||||
|
||||
### Database Schema (Knex/SQLite)
|
||||
Main tables:
|
||||
- `events` - Gallery metadata with expiration, custom messages, themes
|
||||
- `photos` - Photo records linked to events
|
||||
- `access_logs` - IP-based usage tracking
|
||||
- `email_queue` - Async email processing
|
||||
- `admin_users` - Admin authentication
|
||||
|
||||
### Service Architecture
|
||||
Background services run as separate processes:
|
||||
- **emailService**: Processes email queue with retry logic
|
||||
- **archiveService**: Creates ZIP archives of expired events
|
||||
- **expirationChecker**: Cron job for expiration warnings
|
||||
- **fileWatcher**: Monitors for new photo uploads
|
||||
- **backupService**: Scheduled backups with checksum-based change detection
|
||||
|
||||
### API Structure
|
||||
- `/api/admin/*` - Admin panel endpoints (requires adminAuth)
|
||||
- `/api/gallery/*` - Public gallery endpoints
|
||||
- `/api/auth/*` - Authentication endpoints
|
||||
- Rate limiting: 100 req/15min (general), 5 req/15min (auth)
|
||||
|
||||
## Critical Implementation Notes
|
||||
|
||||
1. **Security**: All gallery access requires valid JWT with event-specific claims
|
||||
2. **Expiration**: Events auto-expire based on `expires_at`, with 7-day email warnings
|
||||
3. **Email Queue**: Async processing with retry logic, check `email_queue` table
|
||||
4. **File Processing**: Sharp library for thumbnail generation (300x300)
|
||||
5. **Frontend Status**: Only skeleton exists - requires full implementation based on PRD
|
||||
6. **Umami Analytics**: Track password entries, downloads, views, expiration warnings
|
||||
|
||||
## Troubleshooting Guidelines
|
||||
|
||||
### Before ANY Production Troubleshooting:
|
||||
1. **ALWAYS request specific details**:
|
||||
- Production server URL/IP
|
||||
- Current error messages/logs
|
||||
- Recent changes or deployments
|
||||
- Affected users/galleries
|
||||
- Time of issue occurrence
|
||||
|
||||
2. **Thorough Analysis Required**:
|
||||
- Use detailed thinking/analysis for EVERY troubleshooting task
|
||||
- Review all related code before suggesting changes
|
||||
- Consider all potential side effects
|
||||
- Never make assumptions about production environment
|
||||
|
||||
3. **Safe Troubleshooting Steps**:
|
||||
- First, reproduce issue in local/dev environment
|
||||
- Analyze logs without modifying production
|
||||
- Create detailed action plan before any changes
|
||||
- Always have rollback strategy ready
|
||||
- Document every step taken
|
||||
|
||||
### Common Issues & Safe Approaches:
|
||||
- **Email not sending**: Check email_queue table, SMTP settings, service status
|
||||
- **Photos not loading**: Verify file permissions, storage paths, nginx config
|
||||
- **Gallery access issues**: Check JWT tokens, expiration dates, access_logs
|
||||
- **Performance problems**: Analyze with monitoring tools first, never experiment
|
||||
|
||||
### Data Safety Rules:
|
||||
- NEVER delete or modify production data without explicit backup confirmation
|
||||
- ALWAYS verify backups exist before any data operations
|
||||
- NO direct database modifications without transaction safety
|
||||
- Log all actions for audit trail
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Backend (.env)
|
||||
- `JWT_SECRET` - Token signing
|
||||
- `ADMIN_URL`, `FRONTEND_URL` - CORS origins
|
||||
- `SMTP_*` - Email configuration
|
||||
- `DB_*` - PostgreSQL credentials (production)
|
||||
- `UMAMI_URL` - Umami instance URL (for server-side tracking)
|
||||
- `UMAMI_WEBSITE_ID` - Website ID from Umami
|
||||
|
||||
### Frontend (.env)
|
||||
- `VITE_API_URL` - Backend API URL
|
||||
- `VITE_UMAMI_URL` - Umami analytics URL
|
||||
- `VITE_UMAMI_WEBSITE_ID` - Website ID from Umami
|
||||
- `VITE_UMAMI_SHARE_URL` - (Optional) Public share URL for embedded dashboard
|
||||
|
||||
## Testing Approach
|
||||
- Jest with Supertest for API testing
|
||||
- Test files in `__tests__` directories
|
||||
- Database migrations run before tests
|
||||
- Mock email sending in tests
|
||||
|
||||
## Umami Analytics Integration
|
||||
|
||||
The frontend includes comprehensive Umami analytics integration for tracking user behavior and gallery performance.
|
||||
|
||||
### Tracked Events:
|
||||
- **Gallery Events**:
|
||||
- `gallery_password_entry` - Password attempts (success/failure)
|
||||
- `gallery_photo_view` - Individual photo views
|
||||
- `gallery_photo_download` - Single photo downloads
|
||||
- `gallery_bulk_download` - Bulk/all photo downloads
|
||||
- `gallery_expired` - Expired gallery access attempts
|
||||
- **Admin Events**:
|
||||
- `admin_login` - Admin authentication
|
||||
- `admin_event_created` - New event creation
|
||||
- `admin_event_archived` - Event archiving
|
||||
- `admin_event_deleted` - Event deletion
|
||||
- `admin_settings_updated` - Settings changes
|
||||
- **User Behavior**:
|
||||
- Search queries (with debouncing)
|
||||
- Expiration warning views
|
||||
- Page views with automatic tracking
|
||||
|
||||
### Setup:
|
||||
1. Install Umami (self-hosted or cloud)
|
||||
2. Create a website in Umami dashboard
|
||||
3. Set environment variables:
|
||||
```
|
||||
VITE_UMAMI_URL=https://your-umami-instance.com
|
||||
VITE_UMAMI_WEBSITE_ID=your-website-id
|
||||
VITE_UMAMI_SHARE_URL=https://your-umami-instance.com/share/...
|
||||
```
|
||||
|
||||
### Analytics Dashboard:
|
||||
- Admin panel includes analytics page at `/admin/analytics`
|
||||
- Summary view with key metrics
|
||||
- Option to embed full Umami dashboard
|
||||
- Real-time event tracking
|
||||
|
||||
## Accessibility & Performance Features
|
||||
|
||||
### Accessibility (WCAG 2.1 AA Compliance)
|
||||
- **Error Boundaries**: Graceful error handling with recovery options
|
||||
- **Skip Links**: Skip to main content for keyboard navigation
|
||||
- **ARIA Labels**: Proper labeling for screen readers
|
||||
- **Focus Management**: Focus trap in modals, visible focus indicators
|
||||
- **Keyboard Navigation**: Full keyboard support in gallery lightbox (arrows, escape, +/-, d for download)
|
||||
- **Loading States**: Skeleton screens instead of spinners for better UX
|
||||
- **Offline Support**: Visual indicator when offline
|
||||
- **Form Validation**: Accessible error messages with aria-describedby
|
||||
|
||||
### Performance Optimizations
|
||||
- **Lazy Loading**: Images load on scroll with Intersection Observer
|
||||
- **Skeleton Screens**: Instant visual feedback during loading
|
||||
- **Error Recovery**: Component-level error boundaries prevent full page crashes
|
||||
- **Optimistic Updates**: Immediate UI updates with background sync
|
||||
- **Debounced Search**: Prevents excessive API calls
|
||||
- **Analytics**: Non-blocking Umami integration
|
||||
|
||||
### Component Library Enhancements
|
||||
- `<ErrorBoundary>` - Catches and displays errors gracefully
|
||||
- `<PageErrorBoundary>` - Full-page error recovery
|
||||
- `<Skeleton>` - Flexible skeleton loader with variants
|
||||
- `<OfflineIndicator>` - Network status monitoring
|
||||
- `<SkipLink>` - Accessibility navigation
|
||||
- `useFocusTrap` - Modal focus management hook
|
||||
- `useOnlineStatus` - Network status hook
|
||||
|
||||
## Theme System & Branding
|
||||
|
||||
### Theme Features
|
||||
- **Dynamic Theming**: CSS variables for runtime theme switching
|
||||
- **Preset Themes**: Default, Wedding, Birthday, Corporate, Minimal
|
||||
- **Customization Options**:
|
||||
- Primary/Accent/Background/Text colors
|
||||
- Font family selection
|
||||
- Border radius (none, sm, md, lg)
|
||||
- Custom logo upload
|
||||
- Custom CSS injection
|
||||
- **Event-Specific Themes**: Override global theme per gallery
|
||||
- **Live Preview**: Real-time theme changes in admin panel
|
||||
|
||||
### Theme Context API
|
||||
```typescript
|
||||
const { theme, setTheme, setThemeByName } = useTheme();
|
||||
```
|
||||
|
||||
### Branding Settings
|
||||
- Company name, tagline, and support email
|
||||
- Custom footer text
|
||||
- Optional watermarking on downloads
|
||||
- Logo upload for gallery header
|
||||
|
||||
### CSS Variables
|
||||
```css
|
||||
--color-primary: #5C8762;
|
||||
--color-primary-light: #7aa583;
|
||||
--color-primary-dark: #4a6f4f;
|
||||
--color-accent: #22c55e;
|
||||
--color-background: #fafafa;
|
||||
--color-text: #171717;
|
||||
--font-family: 'Inter', sans-serif;
|
||||
--border-radius: 0.5rem;
|
||||
```
|
||||
|
||||
## Backup Service
|
||||
|
||||
### Overview
|
||||
The backup service provides automated, scheduled backups of all photo data with checksum-based change detection to minimize transfer overhead.
|
||||
|
||||
### Features
|
||||
- **Multiple Destinations**: Local directory, remote server (rsync), S3-compatible storage
|
||||
- **Change Detection**: SHA256 checksums track file changes, only modified files are backed up
|
||||
- **Scheduled Execution**: Configurable cron-based scheduling (default: 2 AM daily)
|
||||
- **Email Notifications**: Alerts on backup failure, optional success notifications
|
||||
- **Retention Management**: Automatic cleanup of old backup runs based on retention policy
|
||||
- **Progress Tracking**: Database storage of backup history, file states, and statistics
|
||||
|
||||
### Configuration
|
||||
Backup settings are stored in `app_settings` table with `backup_` prefix:
|
||||
- `backup_enabled`: Enable/disable the service
|
||||
- `backup_schedule`: Cron expression (e.g., '0 2 * * *')
|
||||
- `backup_destination_type`: 'local', 'rsync', or 's3'
|
||||
- `backup_retention_days`: How long to keep backup history
|
||||
- `backup_include_archived`: Whether to backup archived events
|
||||
- `backup_exclude_patterns`: File patterns to exclude
|
||||
|
||||
### API Endpoints
|
||||
- `GET /api/admin/backup/config` - Get current configuration
|
||||
- `PUT /api/admin/backup/config` - Update configuration
|
||||
- `GET /api/admin/backup/status` - Get backup status and history
|
||||
- `POST /api/admin/backup/run` - Trigger manual backup
|
||||
- `POST /api/admin/backup/test-connection` - Test destination connectivity
|
||||
|
||||
### Testing
|
||||
Run backup service test: `npm run test-backup`
|
||||
|
||||
### Database Tables
|
||||
- `backup_runs`: Tracks each backup execution with statistics
|
||||
- `backup_file_states`: Stores file checksums for change detection
|
||||
|
||||
## Thumbnail Generation
|
||||
|
||||
### Square Thumbnail Implementation (Issue #12 Fix)
|
||||
The system now generates **square 300x300px thumbnails** to prevent blurry/stretched images in the gallery grid:
|
||||
|
||||
- **Problem**: Previously generated 300px width with proportional height (e.g., 300x200 for 3:2 photos), but CSS forced square display causing distortion
|
||||
- **Solution**: Thumbnails now use `cover` fit mode to crop to exact 300x300px dimensions with center positioning
|
||||
- **Configuration**: Settings stored in `app_settings` table with keys: `thumbnail_width`, `thumbnail_height`, `thumbnail_fit`, `thumbnail_quality`, `thumbnail_format`
|
||||
- **Migration**: Run `040_add_thumbnail_settings.js` to add default square thumbnail settings
|
||||
- **Regeneration Script**: Use `scripts/regenerate-square-thumbnails.js` to update existing thumbnails
|
||||
|
||||
### Thumbnail Settings API
|
||||
- `GET /api/admin/thumbnails/settings` - Get current thumbnail configuration
|
||||
- `PUT /api/admin/thumbnails/settings` - Update thumbnail settings (requires regeneration)
|
||||
- `POST /api/admin/thumbnails/regenerate` - Regenerate all thumbnails with new settings
|
||||
- `GET /api/admin/thumbnails/regenerate/status` - Check regeneration progress
|
||||
|
||||
## Success Metrics (from PRD)
|
||||
- Time to generate gallery: <2 minutes
|
||||
- Guest satisfaction: >90%
|
||||
- System uptime: 99.9%
|
||||
- Email delivery rate: >98%
|
||||
- Successful archiving: 100%
|
||||
|
||||
## Documentation & Development Practices
|
||||
|
||||
### Documentation Guidelines:
|
||||
- **NEVER create new documentation files for simple tasks**
|
||||
- **ALWAYS update existing documentation (like this CLAUDE.md)**
|
||||
- Only create new .md files when explicitly requested
|
||||
- Avoid creating temporary scripts for one-off tasks
|
||||
|
||||
### Development Best Practices:
|
||||
- Test all changes thoroughly in local environment first
|
||||
- Use version control for all changes
|
||||
- Keep commits atomic and well-described
|
||||
- Review impact on all integrated services
|
||||
- Consider backward compatibility
|
||||
- Update tests when changing functionality
|
||||
|
||||
### Production Deployment Checklist:
|
||||
- [ ] All tests passing locally
|
||||
- [ ] Linting and type checks pass
|
||||
- [ ] Database migrations tested with rollback plan
|
||||
- [ ] Environment variables documented
|
||||
- [ ] Backup strategy confirmed
|
||||
- [ ] Monitoring alerts configured
|
||||
- [ ] Rollback procedure documented
|
||||
- [ ] Stakeholders notified of maintenance window
|
||||
- always use docker deployment for testing
|
||||
@@ -1,372 +0,0 @@
|
||||
# Product Requirements Document: Event Photo Sharing Platform
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
### 1.1 Product Overview
|
||||
A secure, customizable photo sharing platform designed primarily for wedding photo booths but adaptable for any event type. The platform enables event organizers to easily share photos with guests through password-protected, time-limited links while maintaining a simple file-based backend system with automatic archiving.
|
||||
|
||||
### 1.2 Key Value Propositions
|
||||
- **Simple Backend Management**: Drop photos in folders, generate links instantly
|
||||
- **Secure Sharing**: Password-protected access with expiration dates
|
||||
- **Automated Lifecycle**: Automatic archiving and storage optimization
|
||||
- **Proactive Communication**: Email notifications for key events
|
||||
- **Personalized Experience**: Custom branding for each event
|
||||
- **Analytics Integration**: Track engagement through Umami
|
||||
- **Versatile Use Cases**: Optimized for weddings but suitable for any event
|
||||
|
||||
## 2. Product Goals & Objectives
|
||||
|
||||
### 2.1 Primary Goals
|
||||
- Provide a seamless, time-limited photo sharing experience for event guests
|
||||
- Minimize technical complexity for administrators
|
||||
- Ensure photo privacy through password protection and link expiration
|
||||
- Automate storage management through intelligent archiving
|
||||
- Enable detailed analytics on photo access and engagement
|
||||
- Keep stakeholders informed through automated notifications
|
||||
|
||||
### 2.2 Success Metrics
|
||||
- Time to generate new event gallery (<2 minutes)
|
||||
- Guest satisfaction score (>90%)
|
||||
- Photo view/download rates
|
||||
- System uptime (99.9%)
|
||||
- Successful automatic archiving rate (100%)
|
||||
- Email delivery rate (>98%)
|
||||
|
||||
## 3. User Personas
|
||||
|
||||
### 3.1 Administrator (Event Organizer/Photographer)
|
||||
- **Background**: Professional photographer or event organizer
|
||||
- **Technical Skills**: Basic to intermediate
|
||||
- **Needs**: Quick photo upload, easy link generation, access analytics, automated cleanup
|
||||
- **Pain Points**: Complex upload processes, managing multiple events, storage management
|
||||
|
||||
### 3.2 End User (Event Guest)
|
||||
- **Background**: Wedding guest or event attendee
|
||||
- **Technical Skills**: Varies widely
|
||||
- **Needs**: Easy photo viewing, downloading, sharing within timeframe
|
||||
- **Pain Points**: Complicated interfaces, slow loading, expired links
|
||||
|
||||
### 3.3 Event Host (Bride/Groom/Celebrant)
|
||||
- **Background**: Person celebrating the event
|
||||
- **Technical Skills**: Basic
|
||||
- **Needs**: Notification of gallery availability, awareness of expiration
|
||||
- **Pain Points**: Missing the opportunity to save photos, not knowing when gallery is ready
|
||||
|
||||
## 4. Functional Requirements
|
||||
|
||||
### 4.1 Backend Administration
|
||||
|
||||
#### 4.1.1 File Management System
|
||||
- **Photo Upload**: Direct file system access via designated folders
|
||||
- **Folder Structure**:
|
||||
```
|
||||
/events/
|
||||
├── active/
|
||||
│ ├── wedding-smith-jones-2024-06-15/
|
||||
│ │ ├── collages/
|
||||
│ │ │ ├── collage_001.jpg
|
||||
│ │ │ └── collage_002.jpg
|
||||
│ │ └── individual/
|
||||
│ │ ├── photo_001.jpg
|
||||
│ │ └── photo_002.jpg
|
||||
│ └── birthday-emma-2024-07-20/
|
||||
│ └── photos/
|
||||
└── archived/
|
||||
└── wedding-smith-jones-2024-06-15.zip
|
||||
```
|
||||
- **Supported Formats**: JPEG, PNG, WebP
|
||||
- **Auto-detection**: System monitors folders for new photos
|
||||
- **Automatic Archiving**: Upon expiration, compress folder to ZIP and move to archive
|
||||
|
||||
#### 4.1.2 Link Generation
|
||||
- **Unique URL Generation**: Automatic creation of shareable links
|
||||
- **Password Setting**: Admin sets password during link creation
|
||||
- **Expiration Date**: Mandatory expiration date selection (default: 30 days)
|
||||
- **Event Metadata**:
|
||||
- Event type (wedding, birthday, corporate, etc.)
|
||||
- Names (couple names for weddings, celebrant for others)
|
||||
- Event date
|
||||
- Host email address (for notifications)
|
||||
- Admin notification email
|
||||
- Custom welcome message
|
||||
- Color theme selection
|
||||
- Link validity period
|
||||
|
||||
#### 4.1.3 Email Notification System
|
||||
- **Trigger Events**:
|
||||
- Link creation: Notify host with access details
|
||||
- Link expiration warning: 7 days before expiration
|
||||
- Link expiration: Notify both host and admin
|
||||
- Archive completion: Confirm to admin
|
||||
- **Email Templates**: Customizable, branded email templates
|
||||
- **Configuration**: SMTP settings, from address, reply-to address
|
||||
|
||||
#### 4.1.4 Admin Dashboard
|
||||
- **Event Management**: List all events, active/inactive/archived status
|
||||
- **Expiration Overview**: Timeline view of upcoming expirations
|
||||
- **Analytics Overview**: Quick stats per event
|
||||
- **Link Management**: Copy links, reset passwords, extend expiration, deactivate events
|
||||
- **Bulk Operations**: Archive old events, batch photo operations
|
||||
- **Email Configuration**: Template management, SMTP settings
|
||||
- **Archive Management**: View and download archived ZIPs
|
||||
|
||||
### 4.2 Frontend Guest Experience
|
||||
|
||||
#### 4.2.1 Landing Page
|
||||
- **Password Entry**: Clean, intuitive password input
|
||||
- **Event Preview**: Show event name, date, and expiration notice
|
||||
- **Expiration Warning**: Prominent display if <7 days remaining
|
||||
- **Expired State**: Clear message with contact information if expired
|
||||
- **Responsive Design**: Mobile-first approach
|
||||
|
||||
#### 4.2.2 Gallery View
|
||||
- **Expiration Banner**: Sticky banner showing days remaining
|
||||
- **Grid Layout**: Responsive photo grid with lazy loading
|
||||
- **View Toggle**: Switch between collages and individual photos
|
||||
- **Sorting Options**: By date, name, or custom order
|
||||
- **Search**: Basic filename or date search
|
||||
- **Download Urgency**: Prominent "Download All" for soon-to-expire galleries
|
||||
|
||||
#### 4.2.3 Photo Interactions
|
||||
- **Lightbox View**: Full-screen photo viewing with navigation
|
||||
- **Zoom**: Pinch-to-zoom on mobile, mouse wheel on desktop
|
||||
- **Download Options**:
|
||||
- Single photo download
|
||||
- Bulk download (selected photos)
|
||||
- Download all (ZIP file)
|
||||
- **Sharing**: Direct link to specific photos (respects expiration)
|
||||
|
||||
#### 4.2.4 Personalization
|
||||
- **Dynamic Theming**: Based on event type and admin preferences
|
||||
- **Custom Headers**: Event names, dates, and messages
|
||||
- **Branded Elements**: Optional logo upload
|
||||
- **Expiration Messaging**: Customizable expiration notices
|
||||
|
||||
### 4.3 Analytics Integration
|
||||
|
||||
#### 4.3.1 Umami Analytics
|
||||
- **Page Views**: Track gallery visits
|
||||
- **User Actions**: Photo views, downloads, time spent
|
||||
- **Device/Browser Stats**: Understand user base
|
||||
- **Geographic Data**: Guest locations
|
||||
- **Custom Events**:
|
||||
- Password entries (successful/failed)
|
||||
- Photo downloads
|
||||
- Share button clicks
|
||||
- Expiration warning views
|
||||
- Last-minute download spikes
|
||||
|
||||
### 4.4 Archiving System
|
||||
|
||||
#### 4.4.1 Automatic Archiving Process
|
||||
- **Trigger**: Activated upon link expiration
|
||||
- **Process**:
|
||||
1. Create ZIP file with folder structure preserved
|
||||
2. Verify ZIP integrity
|
||||
3. Move ZIP to archive location
|
||||
4. Delete original files
|
||||
5. Update database with archive location
|
||||
6. Send confirmation emails
|
||||
|
||||
#### 4.4.2 Archive Management
|
||||
- **Storage Optimization**: Compression settings for long-term storage
|
||||
- **Retrieval System**: Admin can restore archives if needed
|
||||
- **Retention Policy**: Configurable long-term retention rules
|
||||
|
||||
## 5. Technical Requirements
|
||||
|
||||
### 5.1 Architecture
|
||||
|
||||
#### 5.1.1 Infrastructure
|
||||
- **Backend Access**: Dedicated FQDN (e.g., admin.photos.domain.com)
|
||||
- **Frontend Access**: Public FQDN (e.g., photos.domain.com)
|
||||
- **File Storage**: Local file system or network-attached storage
|
||||
- **Archive Storage**: Separate location for long-term ZIP storage
|
||||
- **Database**: Lightweight database for metadata (SQLite or PostgreSQL)
|
||||
- **Email Service**: SMTP integration or email service provider
|
||||
|
||||
#### 5.1.2 Security
|
||||
- **HTTPS**: Required for both frontend and backend
|
||||
- **Password Hashing**: Bcrypt or similar for stored passwords
|
||||
- **Rate Limiting**: Prevent brute force attacks
|
||||
- **Access Logs**: Track all access attempts
|
||||
- **Expiration Enforcement**: Server-side validation of link validity
|
||||
|
||||
### 5.2 Performance Requirements
|
||||
- **Page Load Time**: <3 seconds on 4G connection
|
||||
- **Image Optimization**: Automatic thumbnail generation
|
||||
- **Caching**: CDN integration for static assets
|
||||
- **Concurrent Users**: Support 100+ simultaneous users per event
|
||||
- **Archive Generation**: Complete within 10 minutes for 1000 photos
|
||||
|
||||
### 5.3 Technology Stack (Recommended)
|
||||
- **Backend**: Node.js with Express or Python with FastAPI
|
||||
- **Frontend**: React or Vue.js for dynamic interactions
|
||||
- **Image Processing**: Sharp (Node.js) or Pillow (Python)
|
||||
- **File Monitoring**: Chokidar or Watchdog
|
||||
- **Analytics**: Umami self-hosted or cloud
|
||||
- **Email Service**: Nodemailer or SendGrid
|
||||
- **Job Queue**: Bull (Node.js) or Celery (Python) for archiving tasks
|
||||
- **Scheduler**: Node-cron or APScheduler for expiration checks
|
||||
|
||||
## 6. User Interface Requirements
|
||||
|
||||
### 6.1 Design Principles
|
||||
- **Modern Aesthetic**: Clean, minimalist design
|
||||
- **Wedding-Optimized**: Elegant typography, romantic color options
|
||||
- **Urgency Communication**: Clear expiration indicators
|
||||
- **Accessibility**: WCAG 2.1 AA compliant
|
||||
- **Responsive**: Mobile, tablet, and desktop optimized
|
||||
|
||||
### 6.2 UI Components
|
||||
- **Photo Grid**: Masonry or uniform grid layout
|
||||
- **Navigation**: Sticky header with view toggles
|
||||
- **Expiration Timer**: Countdown display for urgent galleries
|
||||
- **Loading States**: Skeleton screens for better UX
|
||||
- **Error Handling**: Friendly error messages
|
||||
- **Email Status**: Indicators for sent notifications
|
||||
|
||||
### 6.3 Branding Options
|
||||
- **Color Schemes**: Pre-defined themes plus custom colors
|
||||
- **Font Selection**: Google Fonts integration
|
||||
- **Layout Templates**: Multiple gallery layout options
|
||||
- **Email Templates**: Matching email designs
|
||||
|
||||
## 7. Non-Functional Requirements
|
||||
|
||||
### 7.1 Scalability
|
||||
- Horizontal scaling capability
|
||||
- Support for 10,000+ photos per event
|
||||
- Efficient handling of high-resolution images
|
||||
- Queue system for archiving operations
|
||||
|
||||
### 7.2 Reliability
|
||||
- 99.9% uptime SLA
|
||||
- Automated backups (including archives)
|
||||
- Graceful error handling
|
||||
- Failed job retry mechanisms
|
||||
|
||||
### 7.3 Maintainability
|
||||
- Clear code documentation
|
||||
- Modular architecture
|
||||
- Automated testing suite
|
||||
- Monitoring for failed archiving jobs
|
||||
|
||||
### 7.4 Compliance
|
||||
- GDPR compliance for EU users
|
||||
- Copyright considerations
|
||||
- Privacy policy and terms of service
|
||||
- Data retention policies
|
||||
|
||||
## 8. Email Templates
|
||||
|
||||
### 8.1 Link Creation Email (to Host)
|
||||
- Subject: "Your [Event Name] Photos Are Ready!"
|
||||
- Content: Access details, password, expiration date
|
||||
- Call-to-action: View gallery button
|
||||
|
||||
### 8.2 Expiration Warning Email
|
||||
- Subject: "Your [Event Name] Photos Expire in 7 Days"
|
||||
- Content: Urgency message, download instructions
|
||||
- Call-to-action: Download all photos button
|
||||
|
||||
### 8.3 Expiration Notification Email
|
||||
- To Host: "Your [Event Name] Photo Gallery Has Expired"
|
||||
- To Admin: "[Event Name] Gallery Archived Successfully"
|
||||
- Content: Confirmation of archiving, contact for retrieval
|
||||
|
||||
## 9. Future Enhancements
|
||||
|
||||
### 9.1 Phase 2 Features
|
||||
- **Flexible Expiration**: Extend expiration for individual users
|
||||
- **Partial Downloads**: Resume interrupted downloads
|
||||
- **AI-Powered Features**: Face recognition for automatic grouping
|
||||
- **Social Integration**: Direct sharing to social media
|
||||
- **Guest Uploads**: Allow guests to add their photos
|
||||
- **Video Support**: Basic video playback
|
||||
|
||||
### 9.2 Phase 3 Features
|
||||
- **Mobile Apps**: Native iOS/Android applications
|
||||
- **Print Integration**: Direct ordering of prints
|
||||
- **Event Packages**: Bundled services with photographers
|
||||
- **Multi-language Support**: Internationalization
|
||||
- **Cloud Archive**: Optional cloud storage for archives
|
||||
|
||||
## 10. Success Criteria
|
||||
|
||||
### 10.1 Launch Criteria
|
||||
- Successfully handle 10 concurrent events
|
||||
- Process 1,000 photos in <5 minutes
|
||||
- 100% successful archiving rate
|
||||
- Achieve 95% positive user feedback in beta
|
||||
- Email delivery rate >98%
|
||||
|
||||
### 10.2 Post-Launch Metrics
|
||||
- Monthly active events: 100+
|
||||
- Average photos per event: 200+
|
||||
- Guest engagement rate: 70%+
|
||||
- Download rate: 50%+ of guests
|
||||
- On-time archiving: 99%+
|
||||
|
||||
## 11. Risks & Mitigation
|
||||
|
||||
### 11.1 Technical Risks
|
||||
- **Storage Limitations**: Implement automated archiving and cloud storage
|
||||
- **Performance Issues**: Progressive loading and CDN usage
|
||||
- **Security Breaches**: Regular security audits
|
||||
- **Archive Failures**: Redundant archiving with verification
|
||||
- **Email Delivery**: Multiple SMTP providers, delivery monitoring
|
||||
|
||||
### 11.2 Business Risks
|
||||
- **Low Adoption**: Marketing partnerships with photographers
|
||||
- **Feature Creep**: Strict MVP scope adherence
|
||||
- **Support Burden**: Comprehensive documentation and FAQs
|
||||
- **Expired Link Complaints**: Clear communication, grace period
|
||||
|
||||
## 12. Timeline & Milestones
|
||||
|
||||
### 12.1 Development Phases
|
||||
- **Phase 1 (MVP)**: 10-12 weeks
|
||||
- Core functionality
|
||||
- Basic UI
|
||||
- Expiration system
|
||||
- Email notifications
|
||||
- Archiving system
|
||||
- Umami integration
|
||||
- **Phase 2 (Enhancement)**: 4-6 weeks
|
||||
- Advanced features
|
||||
- Performance optimization
|
||||
- **Phase 3 (Polish)**: 2-4 weeks
|
||||
- UI refinements
|
||||
- Beta testing
|
||||
|
||||
### 12.2 Key Milestones
|
||||
- Week 2: Technical architecture finalized
|
||||
- Week 4: Backend functionality complete
|
||||
- Week 6: Frontend gallery functional
|
||||
- Week 7: Email system integrated
|
||||
- Week 8: Archiving system complete
|
||||
- Week 9: Analytics integrated
|
||||
- Week 12: Beta launch
|
||||
|
||||
## 13. Appendices
|
||||
|
||||
### 13.1 Technical Specifications
|
||||
- Detailed API documentation
|
||||
- Database schema (including expiration tracking)
|
||||
- File naming conventions
|
||||
- Archive format specifications
|
||||
|
||||
### 13.2 Design Mockups
|
||||
- UI wireframes
|
||||
- Email template designs
|
||||
- Expiration state displays
|
||||
- Style guide
|
||||
- Component library
|
||||
|
||||
### 13.3 Testing Plan
|
||||
- Unit test coverage
|
||||
- Integration testing
|
||||
- Archiving system testing
|
||||
- Email delivery testing
|
||||
- User acceptance criteria
|
||||
@@ -1,176 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Gitea Act Runner Installation Script
|
||||
set -e
|
||||
|
||||
echo "==================================="
|
||||
echo "Gitea Act Runner Installation"
|
||||
echo "==================================="
|
||||
|
||||
# Configuration
|
||||
GITEA_URL="https://gitea.nothaft.cloud"
|
||||
RUNNER_NAME="picpeak-runner-$(hostname)"
|
||||
RUNNER_VERSION="0.2.10" # Latest stable version
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${YELLOW}This script will help you install and register a Gitea Act Runner${NC}"
|
||||
echo ""
|
||||
|
||||
# Step 1: Get registration token
|
||||
echo -e "${GREEN}Step 1: Get Registration Token${NC}"
|
||||
echo "1. Go to: $GITEA_URL/admin/runners"
|
||||
echo "2. Click 'Create new Runner'"
|
||||
echo "3. Copy the registration token"
|
||||
echo ""
|
||||
read -p "Enter your registration token: " REGISTRATION_TOKEN
|
||||
|
||||
if [ -z "$REGISTRATION_TOKEN" ]; then
|
||||
echo -e "${RED}Error: Registration token is required${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 2: Choose installation method
|
||||
echo ""
|
||||
echo -e "${GREEN}Step 2: Choose Installation Method${NC}"
|
||||
echo "1. Docker (Recommended)"
|
||||
echo "2. Binary installation"
|
||||
read -p "Choose method (1 or 2): " METHOD
|
||||
|
||||
if [ "$METHOD" == "1" ]; then
|
||||
# Docker installation
|
||||
echo ""
|
||||
echo -e "${GREEN}Installing with Docker...${NC}"
|
||||
|
||||
# Check if Docker is installed
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo -e "${RED}Error: Docker is not installed${NC}"
|
||||
echo "Please install Docker first: https://docs.docker.com/get-docker/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create docker-compose file for runner
|
||||
cat > docker-compose.runner.yml << EOF
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
gitea-runner:
|
||||
image: gitea/act_runner:latest
|
||||
container_name: gitea-runner
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- GITEA_INSTANCE_URL=$GITEA_URL
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=$REGISTRATION_TOKEN
|
||||
- GITEA_RUNNER_NAME=$RUNNER_NAME
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./runner-data:/data
|
||||
networks:
|
||||
- picpeak
|
||||
|
||||
networks:
|
||||
picpeak:
|
||||
external: true
|
||||
EOF
|
||||
|
||||
echo "Starting Gitea Runner with Docker..."
|
||||
docker-compose -f docker-compose.runner.yml up -d
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ Runner installed and started with Docker${NC}"
|
||||
echo "Check logs with: docker logs gitea-runner"
|
||||
|
||||
elif [ "$METHOD" == "2" ]; then
|
||||
# Binary installation
|
||||
echo ""
|
||||
echo -e "${GREEN}Installing binary...${NC}"
|
||||
|
||||
# Detect OS and architecture
|
||||
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
ARCH=$(uname -m)
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
ARCH="amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
ARCH="arm64"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unsupported architecture: $ARCH${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Download act_runner
|
||||
DOWNLOAD_URL="https://gitea.com/gitea/act_runner/releases/download/v${RUNNER_VERSION}/act_runner-${RUNNER_VERSION}-${OS}-${ARCH}"
|
||||
|
||||
echo "Downloading from: $DOWNLOAD_URL"
|
||||
curl -L -o act_runner "$DOWNLOAD_URL"
|
||||
chmod +x act_runner
|
||||
|
||||
# Create config directory
|
||||
mkdir -p ~/.config/act_runner
|
||||
|
||||
# Register the runner
|
||||
echo ""
|
||||
echo -e "${GREEN}Registering runner...${NC}"
|
||||
./act_runner register \
|
||||
--no-interactive \
|
||||
--instance "$GITEA_URL" \
|
||||
--token "$REGISTRATION_TOKEN" \
|
||||
--name "$RUNNER_NAME" \
|
||||
--labels "ubuntu-latest:docker://node:16-bullseye,ubuntu-22.04:docker://node:16-bullseye,ubuntu-20.04:docker://node:16-bullseye"
|
||||
|
||||
# Create systemd service
|
||||
if [ "$OS" == "linux" ]; then
|
||||
echo ""
|
||||
echo -e "${GREEN}Creating systemd service...${NC}"
|
||||
|
||||
sudo tee /etc/systemd/system/gitea-runner.service > /dev/null << EOF
|
||||
[Unit]
|
||||
Description=Gitea Act Runner
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$USER
|
||||
WorkingDirectory=$PWD
|
||||
ExecStart=$PWD/act_runner daemon
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable gitea-runner
|
||||
sudo systemctl start gitea-runner
|
||||
|
||||
echo -e "${GREEN}✓ Runner installed as systemd service${NC}"
|
||||
echo "Check status with: sudo systemctl status gitea-runner"
|
||||
echo "Check logs with: sudo journalctl -u gitea-runner -f"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ Runner installed${NC}"
|
||||
echo "Start runner with: ./act_runner daemon"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}==================================="
|
||||
echo "Installation Complete!"
|
||||
echo "===================================${NC}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Go to: $GITEA_URL/paul/picpeak/settings/actions/runners"
|
||||
echo "2. Verify your runner appears in the list"
|
||||
echo "3. Push a commit to trigger the test workflow"
|
||||
echo ""
|
||||
echo "If the runner doesn't appear, check the logs for errors."
|
||||
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 1014 B |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 853 KiB |