sojorn/sojorn_docs/DEPLOYMENT_COMPREHENSIVE.md
Patrick Britton 38653f5854 Sojorn Backend Finalization & Cleanup - Complete Migration from Supabase
##  Phase 1: Critical Feature Completion (Beacon Voting)
- Add VouchBeacon, ReportBeacon, RemoveBeaconVote methods to PostRepository
- Implement beacon voting HTTP handlers with confidence score calculations
- Register new beacon routes: /beacons/:id/vouch, /beacons/:id/report, /beacons/:id/vouch (DELETE)
- Auto-flag beacons at 5+ reports, confidence scoring (0.5 base + 0.1 per vouch)

##  Phase 2: Feed Logic & Post Distribution Integrity
- Verify unified feed logic supports all content types (Standard, Quips, Beacons)
- Ensure proper distribution: Profile Feed + Main/Home Feed for followers
- Beacon Map integration for location-based content
- Video content filtering for Quips feed

##  Phase 3: The Notification System
- Create comprehensive NotificationService with FCM integration
- Add CreateNotification method to NotificationRepository
- Implement smart deep linking: beacon_map, quip_feed, main_feed
- Trigger notifications for beacon interactions and cross-post comments
- Push notification logic with proper content type detection

##  Phase 4: The Great Supabase Purge
- Delete function_proxy.go and remove /functions/:name route
- Remove SupabaseURL, SupabaseKey from config.go
- Remove SupabaseID field from User model
- Clean all Supabase imports and dependencies
- Sanitize codebase of legacy Supabase references

##  Phase 5: Flutter Frontend Integration
- Implement vouchBeacon(), reportBeacon(), removeBeaconVote() in ApiService
- Replace TODO delay in video_comments_sheet.dart with actual publishComment call
- Fix compilation errors (named parameters, orphaned child properties)
- Complete frontend integration with Go API endpoints

##  Additional Improvements
- Fix compilation errors in threaded_comment_widget.dart (orphaned child property)
- Update video_comments_sheet.dart to use proper named parameters
- Comprehensive error handling and validation
- Production-ready notification system with deep linking

##  Migration Status: 100% Complete
- Backend: Fully migrated from Supabase to custom Go/Gin API
- Frontend: Integrated with new Go endpoints
- Notifications: Complete FCM integration with smart routing
- Database: Clean of all Supabase dependencies
- Features: All functionality preserved and enhanced

Ready for VPS deployment and production testing!
2026-01-30 09:24:31 -06:00

1036 lines
21 KiB
Markdown

# Deployment & Operations Comprehensive Guide
## Overview
This guide consolidates all deployment, operations, and maintenance documentation for the Sojorn platform, covering infrastructure setup, deployment procedures, monitoring, and operational best practices.
---
## Infrastructure Setup
### Server Requirements
#### Minimum Specifications
- **CPU**: 2 vCPU
- **Memory**: 4GB RAM
- **Storage**: 50GB SSD
- **OS**: Ubuntu 22.04 LTS
- **Network**: Public IP with domain pointing
#### Recommended Specifications
- **CPU**: 4 vCPU
- **Memory**: 8GB RAM
- **Storage**: 100GB SSD
- **OS**: Ubuntu 22.04 LTS
- **Network**: Public IP with SSL certificate
### System Dependencies
#### Core Packages
```bash
sudo apt update && sudo apt install -y \
postgresql \
postgresql-contrib \
postgis \
nginx \
certbot \
python3-certbot-nginx \
git \
curl \
wget \
htop
```
#### Go Environment
```bash
# Install Go 1.21+
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
```
### Database Setup
#### PostgreSQL Configuration
```bash
# Create database
sudo -u postgres createdb sojorn
# Create user
sudo -u postgres createuser --interactive sojorn_user
# Grant privileges
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE sojorn TO sojorn_user;"
# Enable extensions
sudo -u postgres psql sojorn -c "
CREATE EXTENSION IF NOT EXISTS uuid-ossp;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS postgis;
"
```
#### PostgreSQL Performance Tuning
```bash
# Edit postgresql.conf
sudo nano /etc/postgresql/15/main/postgresql.conf
```
Key settings:
```ini
# Memory settings
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
maintenance_work_mem = 64MB
# Connection settings
max_connections = 100
listen_addresses = 'localhost'
# Logging settings
log_statement = 'all'
log_duration = on
log_min_duration_statement = 1000
```
---
## Application Deployment
### Deployment Structure
```
/opt/sojorn/
├── .env # Environment variables
├── firebase-service-account.json # FCM credentials
├── uploads/ # User uploaded files
├── logs/ # Application logs
└── go-backend/
├── bin/
│ └── api # Compiled binary
├── migrations/ # Database migrations
└── scripts/ # Deployment scripts
```
### Environment Configuration
#### .env File Template
```bash
# Database
DATABASE_URL=postgres://sojorn_user:password@localhost:5432/sojorn?sslmode=disable
# Server
PORT=8080
HOST=localhost
ENVIRONMENT=production
# JWT
JWT_SECRET=your-super-secret-jwt-key-here
JWT_EXPIRY=24h
REFRESH_TOKEN_EXPIRY=168h
# Firebase/FCM
FIREBASE_CREDENTIALS_FILE=/opt/sojorn/firebase-service-account.json
FIREBASE_WEB_VAPID_KEY=BNxS7_your_vapid_key_here
# Storage
R2_ACCOUNT_ID=your-r2-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_BUCKET_NAME=sojorn-uploads
R2_PUBLIC_BASE_URL=https://pub-xxxxx.r2.dev
R2_IMG_DOMAIN=img.sojorn.com
R2_VID_DOMAIN=vid.sojorn.com
# Email (Optional)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=noreply@sojorn.com
SMTP_PASS=your-app-password
# Logging
LOG_LEVEL=info
LOG_FORMAT=json
```
### Build Process
#### Compile Go Backend
```bash
cd /opt/sojorn/go-backend
# Build for production
go build -ldflags="-s -w" -o bin/api ./cmd/api/main.go
# Make executable
chmod +x bin/api
```
#### Database Migrations
```bash
cd /opt/sojorn/go-backend
# Run migrations
make migrate-up
# Or manually
go run ./cmd/migrate/main.go up
```
### Systemd Service
#### Service Configuration
Create `/etc/systemd/system/sojorn-api.service`:
```ini
[Unit]
Description=Sojorn API Server
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=patrick
Group=patrick
WorkingDirectory=/opt/sojorn/go-backend
Environment=GO_ENV=production
EnvironmentFile=/opt/sojorn/.env
ExecStart=/opt/sojorn/go-backend/bin/api
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=sojorn-api
# Security
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/sojorn/uploads /opt/sojorn/logs
[Install]
WantedBy=multi-user.target
```
#### Service Management
```bash
# Reload systemd
sudo systemctl daemon-reload
# Enable service
sudo systemctl enable sojorn-api
# Start service
sudo systemctl start sojorn-api
# Check status
sudo systemctl status sojorn-api
# View logs
sudo journalctl -u sojorn-api -f
```
---
## Web Server Configuration
### Nginx Setup
#### Main Configuration
Create `/etc/nginx/sites-available/sojorn-api`:
```nginx
server {
listen 80;
server_name api.gosojorn.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.gosojorn.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/api.gosojorn.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.gosojorn.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Logging
access_log /var/log/nginx/sojorn-api.access.log;
error_log /var/log/nginx/sojorn-api.error.log;
# Rate Limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
# API Proxy
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400;
}
# File Uploads
location /uploads/ {
alias /opt/sojorn/uploads/;
expires 1y;
add_header Cache-Control "public, immutable";
# Security for uploads
location ~* \.(php|jsp|asp|sh|py)$ {
deny all;
}
}
# Health Check
location /health {
access_log off;
proxy_pass http://localhost:8080/health;
}
# WebSocket Support (for chat)
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
}
```
#### Enable Site
```bash
# Enable site
sudo ln -s /etc/nginx/sites-available/sojorn-api /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx
```
### SSL Certificate Setup
#### Let's Encrypt Certificate
```bash
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d api.gosojorn.com
# Test renewal
sudo certbot renew --dry-run
# Set up auto-renewal
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet
```
---
## Monitoring & Logging
### Application Monitoring
#### Health Check Endpoint
```go
// health_check.go
func (h *HealthHandler) Health(c *gin.Context) {
status := map[string]interface{}{
"status": "healthy",
"timestamp": time.Now(),
"version": os.Getenv("APP_VERSION"),
"environment": os.Getenv("ENVIRONMENT"),
}
// Check database
if err := h.db.Ping(); err != nil {
status["status"] = "unhealthy"
status["database"] = "disconnected"
c.JSON(http.StatusServiceUnavailable, status)
return
}
status["database"] = "connected"
c.JSON(http.StatusOK, status)
}
```
#### Metrics Collection
```go
// metrics.go
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "endpoint", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
},
[]string{"method", "endpoint"},
)
)
func MetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start).Seconds()
status := fmt.Sprintf("%d", c.Writer.Status())
httpRequestsTotal.WithLabelValues(c.Request.Method, c.FullPath(), status).Inc()
httpRequestDuration.WithLabelValues(c.Request.Method, c.FullPath()).Observe(duration)
}
}
```
### System Monitoring
#### Setup Prometheus & Grafana (Optional)
```bash
# Install Prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.40.0/prometheus-2.40.0.linux-amd64.tar.gz
tar xvfz prometheus-2.40.0.linux-amd64.tar.gz
sudo mv prometheus-2.40.0.linux-amd64/prometheus /usr/local/bin/
sudo mv prometheus-2.40.0.linux-amd64/prometheus.yml /etc/prometheus/
# Install Grafana
sudo apt-get install -y adduser libfontconfig1
wget https://dl.grafana.com/oss/release/grafana_9.3.0_amd64.deb
sudo dpkg -i grafana_9.3.0_amd64.deb
```
#### Log Management
```bash
# Configure log rotation
sudo nano /etc/logrotate.d/sojorn-api
```
```
/opt/sojorn/logs/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 patrick patrick
postrotate
systemctl reload sojorn-api
endscript
}
```
### Alerting
#### System Alerts Script
```bash
#!/bin/bash
# monitor.sh - System health monitoring
# Check service status
if ! systemctl is-active --quiet sojorn-api; then
echo "ALERT: sojorn-api service is down" | mail -s "Sojorn Service Alert" admin@sojorn.com
fi
# Check disk space
DISK_USAGE=$(df /opt/sojorn | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $DISK_USAGE -gt 80 ]; then
echo "ALERT: Disk usage is ${DISK_USAGE}%" | mail -s "Sojorn Disk Alert" admin@sojorn.com
fi
# Check memory usage
MEM_USAGE=$(free | awk 'NR==2{printf "%.0f", $3*100/$2}')
if [ $MEM_USAGE -gt 90 ]; then
echo "ALERT: Memory usage is ${MEM_USAGE}%" | mail -s "Sojorn Memory Alert" admin@sojorn.com
fi
```
---
## Backup & Recovery
### Database Backups
#### Automated Backup Script
```bash
#!/bin/bash
# backup.sh - Database backup script
BACKUP_DIR="/opt/sojorn/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/sojorn_backup_$DATE.sql"
# Create backup directory
mkdir -p $BACKUP_DIR
# Create backup
pg_dump -h localhost -U sojorn_user sojorn > $BACKUP_FILE
# Compress backup
gzip $BACKUP_FILE
# Remove old backups (keep 7 days)
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
echo "Backup completed: $BACKUP_FILE.gz"
```
#### Cron Job for Daily Backups
```bash
# Add to crontab
sudo crontab -e
# Daily backup at 2 AM
0 2 * * * /opt/sojorn/scripts/backup.sh
```
### File Backups
#### Upload Directory Backup
```bash
#!/bin/bash
# backup_uploads.sh
BACKUP_DIR="/opt/sojorn/backups"
DATE=$(date +%Y%m%d_%H%M%S)
UPLOAD_DIR="/opt/sojorn/uploads"
# Create compressed backup
tar -czf "$BACKUP_DIR/uploads_backup_$DATE.tar.gz" -C "$UPLOAD_DIR" .
# Remove old backups (keep 7 days)
find $BACKUP_DIR -name "uploads_backup_*.tar.gz" -mtime +7 -delete
```
### Recovery Procedures
#### Database Recovery
```bash
# Stop application
sudo systemctl stop sojorn-api
# Restore database
gunzip -c /opt/sojorn/backups/sojorn_backup_20260130_020000.sql.gz | \
psql -h localhost -U sojorn_user -d sojorn
# Start application
sudo systemctl start sojorn-api
# Verify recovery
curl -f https://api.gosojorn.com/health
```
#### File Recovery
```bash
# Restore uploads
tar -xzf /opt/sojorn/backups/uploads_backup_20260130_020000.tar.gz \
-C /opt/sojorn/uploads
# Fix permissions
sudo chown -R patrick:patrick /opt/sojorn/uploads
sudo chmod -R 755 /opt/sojorn/uploads
```
---
## Security Hardening
### System Security
#### Firewall Configuration
```bash
# Install UFW
sudo apt install ufw
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH
sudo ufw allow ssh
# Allow HTTP/HTTPS
sudo ufw allow 80
sudo ufw allow 443
# Enable firewall
sudo ufw enable
```
#### SSH Security
```bash
# Edit SSH config
sudo nano /etc/ssh/sshd_config
```
Key settings:
```
# Disable root login
PermitRootLogin no
# Use key-based authentication
PasswordAuthentication no
PubkeyAuthentication yes
# Change default port (optional)
Port 2222
# Limit login attempts
MaxAuthTries 3
```
#### Fail2Ban Setup
```bash
# Install Fail2Ban
sudo apt install fail2ban
# Configure for SSH
sudo nano /etc/fail2ban/jail.local
```
```
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
```
### Application Security
#### Environment Variable Protection
```bash
# Secure .env file
sudo chmod 600 /opt/sojorn/.env
sudo chown patrick:patrick /opt/sojorn/.env
# Secure service account file
sudo chmod 600 /opt/sojorn/firebase-service-account.json
sudo chown patrick:patrick /opt/sojorn/firebase-service-account.json
```
#### SSL/TLS Hardening
```nginx
# Add to Nginx config
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Other security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
```
---
## Performance Optimization
### Database Optimization
#### Query Optimization
```sql
-- Add indexes for common queries
CREATE INDEX CONCURRENTLY idx_posts_author_created ON posts(author_id, created_at DESC);
CREATE INDEX CONCURRENTLY idx_posts_category_created ON posts(category_id, created_at DESC) WHERE category_id IS NOT NULL;
CREATE INDEX CONCURRENTLY idx_follows_follower ON follows(follower_id);
CREATE INDEX CONCURRENTLY idx_follows_following ON follows(following_id);
-- Analyze table statistics
ANALYZE posts;
ANALYZE follows;
ANALYZE users;
```
#### Connection Pool Tuning
```go
// In database setup
config, err := pgxpool.ParseConfig(databaseURL)
if err != nil {
return nil, err
}
config.MaxConns = 25
config.MinConns = 5
config.MaxConnLifetime = time.Hour
config.HealthCheckPeriod = time.Minute * 5
config.MaxConnIdleTime = time.Minute * 30
```
### Caching Strategy
#### Redis Integration (Optional)
```bash
# Install Redis
sudo apt install redis-server
# Configure Redis
sudo nano /etc/redis/redis.conf
```
Key settings:
```
# Memory management
maxmemory 256mb
maxmemory-policy allkeys-lru
# Persistence
save 900 1
save 300 10
save 60 10000
```
#### Application Caching
```go
// Cache implementation
type CacheService struct {
redis *redis.Client
}
func (c *CacheService) Set(key string, value interface{}, expiration time.Duration) error {
json, err := json.Marshal(value)
if err != nil {
return err
}
return c.redis.Set(context.Background(), key, json, expiration).Err()
}
func (c *CacheService) Get(key string, dest interface{}) error {
val, err := c.redis.Get(context.Background(), key).Result()
if err != nil {
return err
}
return json.Unmarshal([]byte(val), dest)
}
```
---
## Deployment Automation
### Deployment Script
#### Automated Deploy Script
```bash
#!/bin/bash
# deploy.sh - Automated deployment script
set -e # Exit on any error
# Configuration
REPO_URL="https://github.com/your-org/sojorn.git"
DEPLOY_DIR="/opt/sojorn"
BACKUP_DIR="/opt/sojorn/backups"
SERVICE_NAME="sojorn-api"
echo "Starting deployment..."
# Create backup
echo "Creating backup..."
$DEPLOY_DIR/scripts/backup.sh
# Pull latest code
echo "Pulling latest code..."
cd $DEPLOY_DIR
git pull origin main
# Build application
echo "Building application..."
cd go-backend
go build -ldflags="-s -w" -o bin/api ./cmd/api/main.go
# Run migrations
echo "Running database migrations..."
make migrate-up
# Restart service
echo "Restarting service..."
sudo systemctl restart $SERVICE_NAME
# Wait for service to start
sleep 5
# Health check
echo "Performing health check..."
if curl -f http://localhost:8080/health; then
echo "✅ Deployment successful!"
else
echo "❌ Health check failed!"
echo "Rolling back..."
sudo systemctl restart $SERVICE_NAME
exit 1
fi
echo "Deployment completed successfully!"
```
### CI/CD Pipeline (Optional)
#### GitHub Actions Example
```yaml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.21'
- name: Build application
run: |
cd go-backend
go build -ldflags="-s -w" -o bin/api ./cmd/api/main.go
- 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/sojorn
./scripts/deploy.sh
```
---
## Troubleshooting Common Issues
### Service Startup Issues
#### Problem: Service fails to start
```bash
# Check service status
sudo systemctl status sojorn-api
# Check logs
sudo journalctl -u sojorn-api -n 50
# Common fixes
# 1. Check .env file permissions
sudo chmod 600 /opt/sojorn/.env
# 2. Check database connection
sudo -u postgres psql -c "SELECT 1;"
# 3. Check port availability
sudo netstat -tlnp | grep :8080
```
#### Problem: Database connection errors
```bash
# Check PostgreSQL status
sudo systemctl status postgresql
# Check connection string
sudo cat /opt/sojorn/.env | grep DATABASE_URL
# Test connection manually
psql "postgres://sojorn_user:password@localhost:5432/sojorn"
```
### Performance Issues
#### Problem: Slow API responses
```bash
# Check system resources
top
htop
iostat -x 1
# Check database queries
sudo -u postgres psql -c "
SELECT query, mean_time, calls
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;"
# Check Nginx logs
sudo tail -f /var/log/nginx/sojorn-api.access.log
```
#### Problem: High memory usage
```bash
# Check memory usage
free -h
ps aux --sort=-%mem | head
# Restart service if needed
sudo systemctl restart sojorn-api
# Consider tuning Go memory settings
# In .env: GOMEMLIMIT=256MiB
```
### SSL/TLS Issues
#### Problem: Certificate expired
```bash
# Check certificate expiry
sudo certbot certificates
# Renew certificate
sudo certbot renew
# Reload Nginx
sudo systemctl reload nginx
```
#### Problem: SSL handshake failed
```bash
# Test SSL configuration
openssl s_client -connect api.gosojorn.com:443
# Check Nginx configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx
```
---
## Maintenance Schedule
### Daily Tasks
- [ ] Check service status and logs
- [ ] Monitor system resources
- [ ] Verify backup completion
- [ ] Review error rates
### Weekly Tasks
- [ ] Update security patches
- [ ] Review performance metrics
- [ ] Check disk space usage
- [ ] Test backup restoration
### Monthly Tasks
- [ ] Update application dependencies
- [ ] Review and rotate secrets
- [ ] Audit user access and permissions
- [ ] Performance optimization review
### Quarterly Tasks
- [ ] Security audit and penetration testing
- [ ] Disaster recovery testing
- [ ] Capacity planning review
- [ ] Documentation updates
---
## Emergency Procedures
### Service Outage Response
1. **Immediate Assessment**
```bash
# Check service status
sudo systemctl status sojorn-api
# Check system resources
top
df -h
# Check network connectivity
ping 8.8.8.8
```
2. **Service Recovery**
```bash
# Restart services
sudo systemctl restart sojorn-api
sudo systemctl restart nginx
sudo systemctl restart postgresql
# Verify recovery
curl -f https://api.gosojorn.com/health
```
3. **Communication**
- Notify stakeholders of outage
- Provide ETA for resolution
- Document incident and resolution
### Security Incident Response
1. **Containment**
- Isolate affected systems
- Preserve evidence
- Change credentials
2. **Investigation**
- Review logs and audit trails
- Identify breach scope
- Document findings
3. **Recovery**
- Patch vulnerabilities
- Restore from clean backups
- Monitor for suspicious activity
---
**Last Updated**: January 30, 2026
**Version**: 1.0
**Next Review**: February 15, 2026