Unified email reports
This commit is contained in:
467
README.md
Normal file
467
README.md
Normal file
@@ -0,0 +1,467 @@
|
||||
# Email Reports - Dockerized Container
|
||||
|
||||
Unified Docker container for automated daily order email reports for **both Crew Sportswear and MerchBay**.
|
||||
|
||||
## Overview
|
||||
|
||||
This container runs cron jobs daily at **23:55 CT** to:
|
||||
1. Query orders from both Crew and MerchBay databases
|
||||
2. Generate separate CSV reports for each brand
|
||||
3. Email reports to recipients via SMTP
|
||||
|
||||
**Cron Schedule:**
|
||||
- **23:55** - Crew Sportswear report
|
||||
- **23:56** - MerchBay report
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create `.env` file
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
vim .env
|
||||
```
|
||||
|
||||
Configure your environment variables:
|
||||
```env
|
||||
# Crew Database
|
||||
DB_HOST_CREW=mysql
|
||||
DB_NAME_CREW=custom_design
|
||||
DB_USER_CREW=crew_user
|
||||
DB_PASS_CREW=your_password
|
||||
|
||||
# MerchBay Database
|
||||
DB_HOST_MERCHBAY=mysql
|
||||
DB_NAME_MERCHBAY=merchbay_laravel
|
||||
DB_USER_MERCHBAY=merchbay_user
|
||||
DB_PASS_MERCHBAY=your_password
|
||||
|
||||
# SMTP
|
||||
SMTP_PASS_CREW=crew_gmail_app_password
|
||||
SMTP_PASS_MERCHBAY=merchbay_gmail_app_password
|
||||
```
|
||||
|
||||
### 2. Build and Run
|
||||
|
||||
```bash
|
||||
# Build image
|
||||
docker-compose build
|
||||
|
||||
# Start container
|
||||
docker-compose up -d
|
||||
|
||||
# Check logs
|
||||
docker logs -f email_reports_crew
|
||||
```
|
||||
|
||||
### 3. Test Manually
|
||||
|
||||
```bash
|
||||
# Test Crew report
|
||||
docker exec email_reports_unified BRAND=crew php /app/send_report.php
|
||||
|
||||
# Test MerchBay report
|
||||
docker exec email_reports_unified BRAND=merchbay php /app/send_report.php
|
||||
|
||||
# Check cron log
|
||||
docker exec email_reports_unified tail -f /var/log/cron.log
|
||||
|
||||
# Check email log (shows both brands)
|
||||
docker exec email_reports_unified tail -f /app/email.log
|
||||
```
|
||||
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Email Reports Container (Unified) │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────┐ │
|
||||
│ │ Cron Jobs: │ │
|
||||
│ │ 23:55 → BRAND=crew │ │
|
||||
│ │ 23:56 → BRAND=merchbay │ │
|
||||
│ │ │ │
|
||||
│ │ send_report.php │ │
|
||||
│ │ └─ PHPMailer │ │
|
||||
│ └────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└─────────────┼────────────────────────────┘
|
||||
│
|
||||
├──> MySQL: custom_design (Crew)
|
||||
├──> MySQL: merchbay_laravel (MerchBay)
|
||||
└──> SMTP: Gmail (2 accounts)
|
||||
│
|
||||
├──────> MySQL (crew-app-net)
|
||||
└──────> SMTP (smtp.gmail.com)
|
||||
```
|
||||
|
||||
## Fsend_report.php** - Unified report generator (handles both brands)
|
||||
- **index.php** - Legacy Crew report (kept for backward compatibility)
|
||||
- **dbconfig.php** - Database connection (env-aware)
|
||||
- **phpmailer/** - Email library
|
||||
|
||||
## Cron Schedule
|
||||
|
||||
```cron
|
||||
55 23 * * * BRAND=crew php /app/send_report.php >> /var/log/cron.log 2>&1
|
||||
56 23 * * * BRAND=merchbay php /app/send_report.php >> /var/log/cron.log 2>&1
|
||||
```
|
||||
|
||||
**23:55 CT** - Crew Sportswear
|
||||
**23:56 CT** - MerchBay
|
||||
|
||||
Both run daily, 1 minute apart.
|
||||
55 23 * * * cd /app && php index.php >> /var/log/cron.log 2>&1
|
||||
```
|
||||
|
||||
Runs daily at **11:55 PM Central Time**
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Crew Sportswear
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| DB_HOST_CREW | mysql | MySQL host for Crew |
|
||||
| DB_PORT_CREW | 3306 | MySQL port |
|
||||
| DB_NAME_CREW | custom_design | Crew database name |
|
||||
| DB_USER_CREW | crew_user | Crew database username |
|
||||
| DB_PASS_CREW | - | Crew database password |
|
||||
| SMTP_PASS_CREW | - | Gmail app password for mail@crewsportswear.com |
|
||||
|
||||
### MerchBay
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| DB_HOST_MERCHBAY | mysql | MySQL host for MerchBay |
|
||||
| DB_PORT_MERCHBAY | 3306 | MySQL port |
|
||||
| DB_NAME_MERCHBAY | merchbay_laravel | MerchBay database name |
|
||||
| DB_USER_MERCHBAY | merchbay_user | MerchBay database username |
|
||||
| DB_PASS_MERCHBAY | - | MerchBay database password |
|
||||
| SMTP_PASS_MERCHBAY | - | Gmail app password for support@merchbay.com |
|
||||
|
||||
### Shared
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| SMTP_HOST | smtp.gmail.com | SMTP server |
|
||||
| SMTP_PORT | 587 | SMTP port |
|
||||
|
||||
## Brand Configuration
|
||||
|
||||
The unified container handles both brands using the `BRAND` environment variable:
|
||||
|
||||
**Crew Sportswear (`BRAND=crew`)**:
|
||||
- Database: `custom_design`
|
||||
- From: `orders@crewsportswear.com`
|
||||
- To: `graphics@crewsportswear.com`
|
||||
- BCC: webmaster, angelo, production @crewsportswear.com
|
||||
- Admin: https://admin.crewsportswear.app
|
||||
- CSV: `daily_order_reports_crew/`
|
||||
|
||||
**MerchBay (`BRAND=merchbay`)**:
|
||||
- Database: `merchbay_laravel`
|
||||
- From: `orders@merchbay.com`
|
||||
- To: `graphics@crewsportswear.com`
|
||||
- BCC: webmaster, production @crewsportswear.com
|
||||
- Admin: https://merchbay.app
|
||||
- CSV: `daily_order_reports_merchbay/`
|
||||
|
||||
## Networks
|
||||
|
||||
Container must be on **crew-app-net** to access MySQL:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
- crew-app-net
|
||||
|
||||
networks:
|
||||
crew-app-net:
|
||||
external: true
|
||||
```
|
||||
|
||||
Create network if it doesn't exist:
|
||||
```bash
|
||||
docker network create crew-app-net
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./daily_order_reports_crew:/app/daily_order_reports_crew # Crew CSV archives
|
||||
- ./daily_order_reports_merchbay:/app/daily_order_reports_merchbay # MerchBay CSV archives
|
||||
- ./email.log:/app/email.log # Combined execution log
|
||||
```
|
||||
|
||||
Both brands write to the same `email.log` with prefixes `[CREW]` and `[MERCHBAY]`.
|
||||
|
||||
## Deployment
|
||||
|
||||
### Automated Deployment (Gitea Actions)
|
||||
|
||||
**Production deployment** is automated via Gitea Actions when pushing to `main` or `master` branch.
|
||||
|
||||
```bash
|
||||
# Trigger deployment
|
||||
git add .
|
||||
git commit -m "Update email reports"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The workflow will:
|
||||
1. Build Docker image
|
||||
2. Transfer to production server via SSH
|
||||
3. Deploy to `/var/www/apps/email_reports`
|
||||
4. Start container with cron
|
||||
5. Verify container is running
|
||||
|
||||
**Registry build** is triggered by version tags:
|
||||
|
||||
```bash
|
||||
# Create version tag
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
||||
This builds and pushes to your Docker registry.
|
||||
|
||||
### Manual Deployment
|
||||
|
||||
```bash
|
||||
# Deploy via docker-compose
|
||||
docker-compose up -d --build
|
||||
|
||||
# Or build specific image version
|
||||
docker build -t email-reports:1.0.0 .
|
||||
docker tag email-reports:1.0.0 your-registry/email-reports:1.0.0
|
||||
docker push your-registry/email-reports:1.0.0
|
||||
```
|
||||
|
||||
### Required Gitea Secrets
|
||||
|
||||
Configure in your repository settings:
|
||||
|
||||
- `DEPLOY_SSH_KEY` - SSH private key for deployment server
|
||||
- `DEPLOY_HOST` - Deployment server hostname/IP
|
||||
- `DEPLOY_USER` - SSH username
|
||||
- `REGISTRY_URL` - Docker registry URL (for version tags)
|
||||
- `REGISTRY_USER` - Registry username
|
||||
- `REGISTRY_PASSWORD` - Registry password
|
||||
|
||||
### Server Setup (First Time)
|
||||
|
||||
On your production server, create the deployment directory and `.env` file:
|
||||
|
||||
```bash
|
||||
# Create directory
|
||||
sudo mkdir -p /var/www/apps/email_reports
|
||||
sudo chown $USER:$USER /var/www/apps/email_reports
|
||||
cd /var/www/apps/email_reports
|
||||
|
||||
# Create .env file
|
||||
cat > .env << 'EOL'
|
||||
DB_HOST=mysql
|
||||
DB_PORT=3306
|
||||
DB_NAME=custom_design
|
||||
DB_USER=crew_user
|
||||
DB_PASS=your_secure_password
|
||||
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=mail@crewsportswear.com
|
||||
SMTP_PASS=your_gmail_app_password
|
||||
|
||||
EMAIL_TO=graphics@crewsportswear.com
|
||||
EMAIL_BCC=webmaster@crewsportswear.com,angelo@crewsportswear.com,production@crewsportswear.com
|
||||
|
||||
APP_URL=https://www.crewsportswear.com
|
||||
ADMIN_URL=https://admin.crewsportswear.app
|
||||
EOL
|
||||
|
||||
chmod 600 .env
|
||||
|
||||
# Create data directories
|
||||
mkdir -p daily_order_reports
|
||||
touch email.log
|
||||
chmod 666 email.log
|
||||
|
||||
# Ensure network exists
|
||||
docker network create crew-app-net || true
|
||||
```
|
||||
|
||||
Now push to trigger the first deployment!
|
||||
|
||||
### Multiple Instances
|
||||
|
||||
For MerchBay, create similar setup in `email_reports_merchbay/`:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml in email_reports_merchbay/
|
||||
services:
|
||||
email-reports-merchbay:
|
||||
build: .
|
||||
container_name: email_reports_merchbay
|
||||
environment:
|
||||
- DB_NAME=merchbay_db
|
||||
- EMAIL_TO=orders@merchbay.com
|
||||
# ... other env vars
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Container Health
|
||||
|
||||
```bash
|
||||
# Container status
|
||||
docker ps | grep email_reports
|
||||
|
||||
# Should show email_reports_unified
|
||||
|
||||
# Health check
|
||||
docker inspect email_reports_unified | grep -A 5 Health
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# Real-time cron logs (both brands)
|
||||
docker exec email_reports_unified tail -f /var/log/cron.log
|
||||
|
||||
# Email execution logs (prefixed by brand)
|
||||
docker exec email_reports_unified tail -f /app/email.log
|
||||
|
||||
# Example log output:
|
||||
# 2026-01-02 23:55:00 [CREW] successfully sent (5 orders)
|
||||
# 2026-01-02 23:56:00 [MERCHBAY] No order for today
|
||||
|
||||
# Last 50 lines
|
||||
docker logs --tail 50 email_reports_unified
|
||||
|
||||
# Filter by brand
|
||||
docker exec email_reports_unified grep "\[CREW\]" /app/email.log | tail -10
|
||||
docker exec email_reports_unified grep "\[MERCHBAY\]" /app/email.log | tail -10
|
||||
```
|
||||
|
||||
### Verify Cron Schedule
|
||||
|
||||
```bash
|
||||
# View active crontab (should show both jobs)
|
||||
docker exec email_reports_unified crontab -l
|
||||
|
||||
# Expected:
|
||||
# 55 23 * * * BRAND=crew php /app/send_report.php >> /var/log/cron.log 2>&1
|
||||
# 56 23 * * * BRAND=merchbay php /app/send_report.php >> /var/log/cron.log 2>&1
|
||||
|
||||
# Check if cron is running
|
||||
docker exec email_reports_unified ps aux | grep crond
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Database Connection Failed
|
||||
|
||||
```bash
|
||||
# Test MySQL connectivity
|
||||
docker exec email_reports_crew ping mysql
|
||||
|
||||
# Test database connection
|
||||
docker exec email_reports_crew php -r "new PDO('mysql:host=mysql;dbname=custom_design', 'user', 'pass');"
|
||||
|
||||
# Check network
|
||||
docker network inspect crew-app-net
|
||||
```
|
||||
|
||||
### Email Not Sending
|
||||
|
||||
```bash
|
||||
# Enable debug mode
|
||||
docker exec email_reports_crew sed -i 's|// \$mail->SMTPDebug|\$mail->SMTPDebug|' /app/index.php
|
||||
|
||||
# Run manually with debug
|
||||
docker exec email_reports_crew php /app/index.php
|
||||
|
||||
# Check SMTP credentials in .env
|
||||
```
|
||||
|
||||
### Cron Not Running
|
||||
|
||||
```bash
|
||||
# Check cron daemon
|
||||
docker exec email_reports_crew ps aux | grep crond
|
||||
|
||||
# Restart container
|
||||
docker restart email_reports_crew
|
||||
|
||||
# View crontab
|
||||
docker exec email_reports_crew cat /etc/crontabs/root
|
||||
```
|
||||
|
||||
### Wrong Timezone
|
||||
|
||||
```bash
|
||||
# Verify timezone
|
||||
docker exec email_reports_crew date
|
||||
docker exec email_reports_crew cat /etc/timezone
|
||||
|
||||
# Should show: America/Chicago
|
||||
```
|
||||
|
||||
### Permissions Issues
|
||||
|
||||
```bash
|
||||
# Fix CSV directory permissions
|
||||
docker exec email_reports_crew chmod 755 /app/daily_order_reports
|
||||
|
||||
# Fix log file
|
||||
docker exec email_reports_crew chmod 666 /app/email.log
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Update Cron Schedule
|
||||
|
||||
Edit Dockerfile and rebuild:
|
||||
```dockerfile
|
||||
RUN echo "30 22 * * * cd /app && php index.php" > /etc/crontabs/root
|
||||
```
|
||||
|
||||
### Rotate Logs
|
||||
|
||||
```bash
|
||||
# Manually clear logs (optional)
|
||||
docker exec email_reports_crew truncate -s 0 /var/log/cron.log
|
||||
docker exec email_reports_crew truncate -s 0 /app/email.log
|
||||
```
|
||||
|
||||
### Backup Reports
|
||||
|
||||
```bash
|
||||
# Archive old CSV files
|
||||
tar -czf daily_reports_backup_$(date +%Y%m%d).tar.gz daily_order_reports/
|
||||
|
||||
# Or sync to S3/backup location
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
1. **Never commit `.env`** - Use `.env.example` only
|
||||
2. **Use Gmail App Passwords** - Not your main password
|
||||
3. **Restrict network access** - Only join necessary networks
|
||||
4. **Rotate credentials** - Change passwords regularly
|
||||
5. **Monitor logs** - Check for unauthorized access
|
||||
|
||||
## Advantages of Separate Container
|
||||
|
||||
✅ **Isolation** - Reports run independently of web apps
|
||||
✅ **Reusability** - Can serve multiple apps (Crew + MerchBay)
|
||||
✅ **Simple Deployment** - Single purpose, easy to update
|
||||
✅ **Resource Control** - Limit CPU/memory for cron jobs
|
||||
✅ **Independent Scaling** - Restart without affecting web traffic
|
||||
✅ **Clean Separation** - No coupling with Laravel/framework
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Test database connectivity
|
||||
2. Verify SMTP credentials
|
||||
3. Run manual test: `docker exec email_reports_crew php /app/index.php`
|
||||
4. Wait for 23:55 or adjust cron for testing
|
||||
5. Monitor logs for first automated run
|
||||
6. Set up similar container for MerchBay reports
|
||||
Reference in New Issue
Block a user