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 |