Files
email_reports/README.md
Frank John Begornia d0d82aa8e1 Unified email reports
2026-01-02 01:19:07 +08:00

12 KiB

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

cp .env.example .env
vim .env

Configure your environment variables:

# 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

# Build image
docker-compose build

# Start container
docker-compose up -d

# Check logs
docker logs -f email_reports_crew

3. Test Manually

# 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:

docker network create crew-app-net

Volumes

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.

# 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:

# Create version tag
git tag v1.0.0
git push origin v1.0.0

This builds and pushes to your Docker registry.

Manual Deployment

# 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:

# 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/:

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# Verify timezone
docker exec email_reports_crew date
docker exec email_reports_crew cat /etc/timezone

# Should show: America/Chicago

Permissions Issues

# 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:

RUN echo "30 22 * * * cd /app && php index.php" > /etc/crontabs/root

Rotate Logs

# 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

# 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