6c82958c79
- Implement React frontend with TypeScript and Tailwind CSS - Add scrappbook.de-inspired UI design with photo galleries - Implement authentication, photo viewing, and download features - Add Docker Swarm configuration with Traefik reverse proxy - Set up Drone CI/CD pipeline for automated deployments - Add monitoring stack with Prometheus and Grafana - Create comprehensive deployment documentation - Add simple local development setup with docker-compose.local.yml Features: - Password-protected galleries with expiration warnings - Responsive photo grid with lightbox viewer - Bulk download functionality - Hot reload development environment - Email testing with Mailhog - Production-ready deployment scripts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
311 lines
7.0 KiB
YAML
311 lines
7.0 KiB
YAML
kind: pipeline
|
|
type: docker
|
|
name: default
|
|
|
|
trigger:
|
|
branch:
|
|
- main
|
|
- develop
|
|
- feature/*
|
|
event:
|
|
- push
|
|
- pull_request
|
|
- tag
|
|
|
|
volumes:
|
|
- name: docker
|
|
host:
|
|
path: /var/run/docker.sock
|
|
|
|
steps:
|
|
# Frontend Tests
|
|
- name: frontend-test
|
|
image: node:18-alpine
|
|
commands:
|
|
- cd frontend
|
|
- npm ci --legacy-peer-deps
|
|
- npm run lint
|
|
- npm run build
|
|
when:
|
|
event:
|
|
- push
|
|
- pull_request
|
|
|
|
# Backend Tests
|
|
- name: backend-test
|
|
image: node:18-alpine
|
|
commands:
|
|
- cd backend
|
|
- npm ci
|
|
- npm run lint
|
|
- npm test
|
|
environment:
|
|
NODE_ENV: test
|
|
JWT_SECRET: test-secret
|
|
when:
|
|
event:
|
|
- push
|
|
- pull_request
|
|
|
|
# Build Frontend Docker Image
|
|
- name: build-frontend
|
|
image: plugins/docker
|
|
settings:
|
|
repo: ${DRONE_REPO_NAMESPACE}/photo-sharing-frontend
|
|
tags:
|
|
- latest
|
|
- ${DRONE_COMMIT_SHA:0:8}
|
|
- ${DRONE_TAG}
|
|
dockerfile: frontend/Dockerfile
|
|
context: frontend
|
|
username:
|
|
from_secret: docker_username
|
|
password:
|
|
from_secret: docker_password
|
|
registry:
|
|
from_secret: docker_registry
|
|
when:
|
|
branch:
|
|
- main
|
|
event:
|
|
- push
|
|
- tag
|
|
|
|
# Build Backend Docker Image
|
|
- name: build-backend
|
|
image: plugins/docker
|
|
settings:
|
|
repo: ${DRONE_REPO_NAMESPACE}/photo-sharing-backend
|
|
tags:
|
|
- latest
|
|
- ${DRONE_COMMIT_SHA:0:8}
|
|
- ${DRONE_TAG}
|
|
dockerfile: backend/Dockerfile
|
|
context: backend
|
|
username:
|
|
from_secret: docker_username
|
|
password:
|
|
from_secret: docker_password
|
|
registry:
|
|
from_secret: docker_registry
|
|
when:
|
|
branch:
|
|
- main
|
|
event:
|
|
- push
|
|
- tag
|
|
|
|
# Security Scan
|
|
- name: security-scan
|
|
image: aquasec/trivy:latest
|
|
commands:
|
|
- trivy image --exit-code 0 --no-progress ${DRONE_REPO_NAMESPACE}/photo-sharing-frontend:${DRONE_COMMIT_SHA:0:8}
|
|
- trivy image --exit-code 0 --no-progress ${DRONE_REPO_NAMESPACE}/photo-sharing-backend:${DRONE_COMMIT_SHA:0:8}
|
|
environment:
|
|
DOCKER_HOST: tcp://docker:2375
|
|
volumes:
|
|
- name: docker
|
|
path: /var/run/docker.sock
|
|
when:
|
|
branch:
|
|
- main
|
|
event:
|
|
- push
|
|
|
|
# Deploy to Staging
|
|
- name: deploy-staging
|
|
image: alpine:latest
|
|
environment:
|
|
SWARM_HOST:
|
|
from_secret: staging_swarm_host
|
|
SWARM_USER:
|
|
from_secret: staging_swarm_user
|
|
SWARM_KEY:
|
|
from_secret: staging_swarm_key
|
|
REGISTRY_URL:
|
|
from_secret: docker_registry
|
|
VERSION: ${DRONE_COMMIT_SHA:0:8}
|
|
commands:
|
|
- apk add --no-cache openssh-client
|
|
- mkdir -p ~/.ssh
|
|
- echo "$SWARM_KEY" > ~/.ssh/id_rsa
|
|
- chmod 600 ~/.ssh/id_rsa
|
|
- ssh-keyscan -H $SWARM_HOST >> ~/.ssh/known_hosts
|
|
- |
|
|
ssh $SWARM_USER@$SWARM_HOST << EOF
|
|
cd /opt/photo-sharing
|
|
export REGISTRY_URL=$REGISTRY_URL
|
|
export VERSION=$VERSION
|
|
docker stack deploy -c deploy/docker-stack.yml photo-sharing
|
|
EOF
|
|
when:
|
|
branch:
|
|
- develop
|
|
event:
|
|
- push
|
|
|
|
# Deploy to Production
|
|
- name: deploy-production
|
|
image: alpine:latest
|
|
environment:
|
|
SWARM_HOST:
|
|
from_secret: prod_swarm_host
|
|
SWARM_USER:
|
|
from_secret: prod_swarm_user
|
|
SWARM_KEY:
|
|
from_secret: prod_swarm_key
|
|
REGISTRY_URL:
|
|
from_secret: docker_registry
|
|
VERSION: ${DRONE_TAG:-latest}
|
|
commands:
|
|
- apk add --no-cache openssh-client
|
|
- mkdir -p ~/.ssh
|
|
- echo "$SWARM_KEY" > ~/.ssh/id_rsa
|
|
- chmod 600 ~/.ssh/id_rsa
|
|
- ssh-keyscan -H $SWARM_HOST >> ~/.ssh/known_hosts
|
|
- |
|
|
ssh $SWARM_USER@$SWARM_HOST << EOF
|
|
cd /opt/photo-sharing
|
|
export REGISTRY_URL=$REGISTRY_URL
|
|
export VERSION=$VERSION
|
|
|
|
# Backup database before deployment
|
|
docker exec \$(docker ps -q -f name=photo-sharing_db) pg_dump -U postgres photo_sharing > /backup/db-backup-\$(date +%Y%m%d-%H%M%S).sql
|
|
|
|
# Deploy stack
|
|
docker stack deploy -c deploy/docker-stack.yml photo-sharing --with-registry-auth
|
|
|
|
# Wait for services to be ready
|
|
sleep 30
|
|
|
|
# Run migrations if needed
|
|
docker exec \$(docker ps -q -f name=photo-sharing_backend) npm run migrate
|
|
EOF
|
|
when:
|
|
event:
|
|
- tag
|
|
|
|
# Health Check
|
|
- name: health-check
|
|
image: alpine:latest
|
|
commands:
|
|
- apk add --no-cache curl
|
|
- sleep 30
|
|
- curl -f https://${FRONTEND_HOST}/health || exit 1
|
|
- curl -f https://${BACKEND_HOST}/api/health || exit 1
|
|
when:
|
|
branch:
|
|
- main
|
|
event:
|
|
- push
|
|
- tag
|
|
|
|
# Notification - Success
|
|
- name: notify-success
|
|
image: plugins/slack
|
|
settings:
|
|
webhook:
|
|
from_secret: slack_webhook
|
|
channel: deployments
|
|
template: |
|
|
✅ *Build {{build.number}} succeeded* for {{repo.name}}
|
|
|
|
Branch: {{build.branch}}
|
|
Commit: {{build.commit}}
|
|
Author: {{build.author}}
|
|
|
|
{{#if build.tag}}
|
|
🏷️ Tag: {{build.tag}}
|
|
🚀 Deployed to *PRODUCTION*
|
|
{{else}}
|
|
📦 Deployed to *{{build.branch}}*
|
|
{{/if}}
|
|
|
|
🔗 {{build.link}}
|
|
when:
|
|
status:
|
|
- success
|
|
|
|
# Notification - Failure
|
|
- name: notify-failure
|
|
image: plugins/slack
|
|
settings:
|
|
webhook:
|
|
from_secret: slack_webhook
|
|
channel: deployments
|
|
template: |
|
|
❌ *Build {{build.number}} failed* for {{repo.name}}
|
|
|
|
Branch: {{build.branch}}
|
|
Commit: {{build.commit}}
|
|
Author: {{build.author}}
|
|
|
|
🔗 {{build.link}}
|
|
when:
|
|
status:
|
|
- failure
|
|
|
|
---
|
|
kind: pipeline
|
|
type: docker
|
|
name: rollback
|
|
|
|
trigger:
|
|
event:
|
|
- rollback
|
|
|
|
steps:
|
|
- name: rollback-production
|
|
image: alpine:latest
|
|
environment:
|
|
SWARM_HOST:
|
|
from_secret: prod_swarm_host
|
|
SWARM_USER:
|
|
from_secret: prod_swarm_user
|
|
SWARM_KEY:
|
|
from_secret: prod_swarm_key
|
|
REGISTRY_URL:
|
|
from_secret: docker_registry
|
|
commands:
|
|
- apk add --no-cache openssh-client
|
|
- mkdir -p ~/.ssh
|
|
- echo "$SWARM_KEY" > ~/.ssh/id_rsa
|
|
- chmod 600 ~/.ssh/id_rsa
|
|
- ssh-keyscan -H $SWARM_HOST >> ~/.ssh/known_hosts
|
|
- |
|
|
ssh $SWARM_USER@$SWARM_HOST << EOF
|
|
cd /opt/photo-sharing
|
|
export REGISTRY_URL=$REGISTRY_URL
|
|
export VERSION=${DRONE_ROLLBACK_TO}
|
|
|
|
# Deploy previous version
|
|
docker stack deploy -c deploy/docker-stack.yml photo-sharing --with-registry-auth
|
|
EOF
|
|
|
|
---
|
|
kind: secret
|
|
name: docker_username
|
|
get:
|
|
path: drone/docker
|
|
name: username
|
|
|
|
---
|
|
kind: secret
|
|
name: docker_password
|
|
get:
|
|
path: drone/docker
|
|
name: password
|
|
|
|
---
|
|
kind: secret
|
|
name: docker_registry
|
|
get:
|
|
path: drone/docker
|
|
name: registry
|
|
|
|
---
|
|
kind: secret
|
|
name: slack_webhook
|
|
get:
|
|
path: drone/slack
|
|
name: webhook |