Implement dynamic daily verse system with rotating Biblical content
- Add daily-verse API endpoint with 7 rotating verses in Romanian and English - Replace static homepage verse with dynamic fetch from API - Ensure consistent daily rotation using day-of-year calculation - Support both ro and en locales for verse content 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
438
temp/git-deployment-strategy.md
Normal file
438
temp/git-deployment-strategy.md
Normal file
@@ -0,0 +1,438 @@
|
||||
# Git-Based Production Deployment Strategy
|
||||
|
||||
## Overview
|
||||
This guide covers how to deploy the latest code from your git repository to production, ensuring your local development changes are properly deployed.
|
||||
|
||||
## Prerequisites
|
||||
- Git repository (GitHub, GitLab, Bitbucket, or self-hosted)
|
||||
- Production server with Docker and Git installed
|
||||
- SSH access to production server
|
||||
|
||||
## Deployment Strategies
|
||||
|
||||
### Option 1: Manual Git Pull Deployment (Simple)
|
||||
|
||||
#### Setup on Production Server
|
||||
```bash
|
||||
# Clone the repository on production server
|
||||
cd /opt
|
||||
git clone https://github.com/yourusername/ghidul-biblic.git
|
||||
cd ghidul-biblic
|
||||
|
||||
# Create production environment file
|
||||
cp .env.example .env.production
|
||||
# Edit .env.production with production values
|
||||
```
|
||||
|
||||
#### Create Deployment Script
|
||||
Create `/opt/ghidul-biblic/deploy.sh`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting deployment..."
|
||||
|
||||
# Navigate to project directory
|
||||
cd /opt/ghidul-biblic
|
||||
|
||||
# Stop current services
|
||||
echo "⏹️ Stopping current services..."
|
||||
docker-compose -f docker-compose.prod.simple.yml down
|
||||
|
||||
# Pull latest code
|
||||
echo "📥 Pulling latest code..."
|
||||
git pull origin main
|
||||
|
||||
# Load environment variables
|
||||
export $(cat .env.production | xargs)
|
||||
|
||||
# Build and start services
|
||||
echo "🔨 Building and starting services..."
|
||||
docker-compose -f docker-compose.prod.simple.yml up -d --build
|
||||
|
||||
# Wait for health check
|
||||
echo "🏥 Waiting for health check..."
|
||||
sleep 30
|
||||
curl -f http://localhost:3010/api/health || {
|
||||
echo "❌ Health check failed!"
|
||||
docker-compose -f docker-compose.prod.simple.yml logs app
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "✅ Deployment successful!"
|
||||
echo "🌐 Application is running at http://localhost:3010"
|
||||
```
|
||||
|
||||
Make it executable:
|
||||
```bash
|
||||
chmod +x /opt/ghidul-biblic/deploy.sh
|
||||
```
|
||||
|
||||
#### Deploy from Local Machine
|
||||
```bash
|
||||
# Push your changes to git
|
||||
git add .
|
||||
git commit -m "Your changes"
|
||||
git push origin main
|
||||
|
||||
# SSH into production and deploy
|
||||
ssh user@your-server "cd /opt/ghidul-biblic && ./deploy.sh"
|
||||
```
|
||||
|
||||
### Option 2: Webhook-Based Auto Deployment (Recommended)
|
||||
|
||||
#### Setup Webhook Server on Production
|
||||
Create `/opt/ghidul-biblic/webhook-server.js`:
|
||||
```javascript
|
||||
const express = require('express');
|
||||
const { execSync } = require('child_process');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const app = express();
|
||||
const PORT = 9000;
|
||||
const SECRET = process.env.WEBHOOK_SECRET || 'your-webhook-secret';
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
function verifySignature(payload, signature) {
|
||||
const hmac = crypto.createHmac('sha256', SECRET);
|
||||
const digest = 'sha256=' + hmac.update(payload).digest('hex');
|
||||
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
|
||||
}
|
||||
|
||||
app.post('/webhook', (req, res) => {
|
||||
const signature = req.headers['x-hub-signature-256'];
|
||||
const payload = JSON.stringify(req.body);
|
||||
|
||||
if (!verifySignature(payload, signature)) {
|
||||
return res.status(401).send('Unauthorized');
|
||||
}
|
||||
|
||||
// Only deploy on push to main branch
|
||||
if (req.body.ref === 'refs/heads/main') {
|
||||
console.log('🚀 Webhook received, starting deployment...');
|
||||
|
||||
try {
|
||||
execSync('/opt/ghidul-biblic/deploy.sh', {
|
||||
stdio: 'inherit',
|
||||
cwd: '/opt/ghidul-biblic'
|
||||
});
|
||||
res.status(200).send('Deployment successful');
|
||||
} catch (error) {
|
||||
console.error('Deployment failed:', error);
|
||||
res.status(500).send('Deployment failed');
|
||||
}
|
||||
} else {
|
||||
res.status(200).send('Not main branch, skipping deployment');
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Webhook server running on port ${PORT}`);
|
||||
});
|
||||
```
|
||||
|
||||
#### Setup Webhook Service
|
||||
Create `/etc/systemd/system/ghidul-webhook.service`:
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Ghidul Biblic Webhook Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/ghidul-biblic
|
||||
ExecStart=/usr/bin/node webhook-server.js
|
||||
Restart=always
|
||||
Environment=WEBHOOK_SECRET=your-webhook-secret-here
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Enable and start the service:
|
||||
```bash
|
||||
systemctl enable ghidul-webhook.service
|
||||
systemctl start ghidul-webhook.service
|
||||
systemctl status ghidul-webhook.service
|
||||
```
|
||||
|
||||
#### Configure Git Repository Webhook
|
||||
**For GitHub:**
|
||||
1. Go to your repository → Settings → Webhooks
|
||||
2. Add webhook:
|
||||
- URL: `http://your-server:9000/webhook`
|
||||
- Content type: `application/json`
|
||||
- Secret: `your-webhook-secret-here`
|
||||
- Events: `Just the push event`
|
||||
|
||||
**For GitLab:**
|
||||
1. Go to your project → Settings → Webhooks
|
||||
2. Add webhook:
|
||||
- URL: `http://your-server:9000/webhook`
|
||||
- Secret token: `your-webhook-secret-here`
|
||||
- Trigger: `Push events`
|
||||
|
||||
### Option 3: GitHub Actions CI/CD (Advanced)
|
||||
|
||||
#### Create GitHub Actions Workflow
|
||||
Create `.github/workflows/deploy.yml`:
|
||||
```yaml
|
||||
name: Deploy to Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Deploy to server
|
||||
uses: appleboy/ssh-action@v0.1.5
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
script: |
|
||||
cd /opt/ghidul-biblic
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
#### Setup GitHub Secrets
|
||||
In your GitHub repository, go to Settings → Secrets and variables → Actions:
|
||||
- `HOST`: Your production server IP
|
||||
- `USERNAME`: SSH username
|
||||
- `SSH_KEY`: Private SSH key content
|
||||
|
||||
### Option 4: Docker Hub Auto-Build (Professional)
|
||||
|
||||
#### Setup Dockerfile for Production
|
||||
Ensure your `docker/Dockerfile.prod` is optimized:
|
||||
```dockerfile
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build application
|
||||
RUN npm run build
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs
|
||||
RUN adduser -S nextjs -u 1001
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT 3000
|
||||
ENV HOSTNAME "0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
#### Create Docker Compose for Auto-Pull
|
||||
Create `docker-compose.prod.autopull.yml`:
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg16
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: bible_chat
|
||||
POSTGRES_USER: bible_admin
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- bible_network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U bible_admin -d bible_chat"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
app:
|
||||
image: yourdockerhub/ghidul-biblic:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "3010:3000"
|
||||
environment:
|
||||
DATABASE_URL: postgresql://bible_admin:${DB_PASSWORD}@postgres:5432/bible_chat
|
||||
AZURE_OPENAI_KEY: ${AZURE_OPENAI_KEY}
|
||||
AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT}
|
||||
AZURE_OPENAI_DEPLOYMENT: ${AZURE_OPENAI_DEPLOYMENT}
|
||||
OLLAMA_API_URL: ${OLLAMA_API_URL}
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||
NODE_ENV: production
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- bible_network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --interval 300 --cleanup app
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
bible_network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
## Recommended Workflow
|
||||
|
||||
### For Development
|
||||
1. **Local Development**:
|
||||
```bash
|
||||
# Work on your local machine
|
||||
npm run dev
|
||||
# Make changes, test locally
|
||||
```
|
||||
|
||||
2. **Commit and Push**:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Feature: Add new functionality"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
3. **Automatic Deployment**:
|
||||
- Webhook triggers deployment
|
||||
- Or manual trigger: `ssh user@server "/opt/ghidul-biblic/deploy.sh"`
|
||||
|
||||
### For Production Server Setup
|
||||
1. **Initial Setup**:
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/yourusername/ghidul-biblic.git /opt/ghidul-biblic
|
||||
cd /opt/ghidul-biblic
|
||||
|
||||
# Setup environment
|
||||
cp .env.example .env.production
|
||||
# Edit .env.production
|
||||
|
||||
# Make deployment script executable
|
||||
chmod +x deploy.sh
|
||||
|
||||
# Setup webhook (optional)
|
||||
npm install express
|
||||
# Setup systemd service
|
||||
```
|
||||
|
||||
2. **Deploy**:
|
||||
```bash
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Git Repository
|
||||
- Use private repositories for production code
|
||||
- Use deploy keys or personal access tokens
|
||||
- Never commit sensitive environment variables
|
||||
|
||||
### Production Server
|
||||
- Use non-root user for deployment when possible
|
||||
- Secure webhook endpoints with proper secrets
|
||||
- Use SSH key authentication
|
||||
- Keep server updated
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
# .env.production should never be in git
|
||||
echo ".env.production" >> .gitignore
|
||||
echo ".env.local" >> .gitignore
|
||||
```
|
||||
|
||||
## Monitoring Deployment
|
||||
|
||||
### Create Health Check Script
|
||||
Create `/opt/ghidul-biblic/health-check.sh`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
HEALTH_URL="http://localhost:3010/api/health"
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)
|
||||
|
||||
if [ $RESPONSE -eq 200 ]; then
|
||||
echo "✅ Application is healthy"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Application is unhealthy (HTTP $RESPONSE)"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Setup Cron for Health Monitoring
|
||||
```bash
|
||||
# Add to crontab
|
||||
*/5 * * * * /opt/ghidul-biblic/health-check.sh >> /var/log/ghidul-health.log 2>&1
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
1. **Git pull fails**: Check SSH keys and repository access
|
||||
2. **Docker build fails**: Check Dockerfile and dependencies
|
||||
3. **Health check fails**: Check application logs
|
||||
4. **Webhook not triggered**: Verify webhook URL and secret
|
||||
|
||||
### Useful Commands
|
||||
```bash
|
||||
# Check deployment logs
|
||||
tail -f /var/log/ghidul-deployment.log
|
||||
|
||||
# Check application logs
|
||||
docker-compose -f docker-compose.prod.simple.yml logs -f app
|
||||
|
||||
# Manual health check
|
||||
curl http://localhost:3010/api/health
|
||||
|
||||
# Restart services
|
||||
docker-compose -f docker-compose.prod.simple.yml restart app
|
||||
```
|
||||
|
||||
This setup ensures your production environment always has the latest code from your git repository while maintaining proper deployment practices.
|
||||
Reference in New Issue
Block a user