Files
sasa-maillist/.github/copilot-instructions.md
2025-10-13 14:05:01 +00:00

6.3 KiB

Copilot Instructions: Mail List Manager (Postfix + SES + MySQL + API + Web)

Architecture Overview

This is a complete containerized mailing list management system with four services:

  1. Web Frontend (Port 3000) - Nginx serving modern HTML/CSS/JS interface
  2. REST API (Port 8000) - FastAPI backend with token authentication
  3. MySQL Database (Internal) - Stores lists, members, and subscriptions
  4. Postfix Mail Server (Port 25) - SMTP server with native MySQL integration

Key Architecture Principles:

  • Real-time operation: Changes take effect immediately without Postfix reload
  • Native integration: Postfix queries MySQL directly (no Python scripts)
  • Security-first: Private Docker network, token auth, sender whitelist
  • User-friendly: Web interface for easy management by non-technical users

Configuration Pattern

Dynamic Database-Driven Architecture:

  1. Data Flow: Web UI → REST API → MySQL ← Postfix (real-time queries)
  2. Credentials: All sensitive data in .env file (SES, MySQL, API_TOKEN)
  3. Mail Processing:
    • Email arrives for list@lists.sasalliance.org
    • Postfix queries MySQL via mysql_virtual_alias_maps.cf
    • MySQL returns comma-separated member emails
    • Postfix expands alias and delivers via SES
  4. Security: Private Docker network (maillist-internal), sender whitelist (@sasalliance.org)

No Static Configuration:

  • Virtual aliases are stored in MySQL database, not config files
  • Changes take effect immediately without container restarts
  • Postfix caches query results for performance

Key Files and Their Roles

Docker & Environment

  • docker-compose.yaml: Multi-service orchestration (mysql, postfix, api, web)
  • .env: All credentials and configuration (SES, MySQL, API_TOKEN)

Web Frontend (web/)

  • index.html: Single-page application interface
  • static/js/api.js: API client with authentication
  • static/js/ui.js: UI helpers and modal management
  • static/js/app.js: Main application controller
  • static/css/style.css: Complete styling system
  • nginx.conf: Nginx configuration for static file serving

REST API (api/)

  • main.py: FastAPI application with all CRUD endpoints
  • requirements.txt: Python dependencies (fastapi, mysql-connector-python, etc.)
  • Dockerfile: Python 3.11 container build

Database (database/)

  • schema.sql: Database initialization with tables and sample data
  • Tables: lists, members, list_members (many-to-many junction)

Postfix (postfix/)

  • main.cf.template: Core Postfix config with MySQL virtual alias maps
  • mysql_virtual_alias_maps.cf: Native Postfix MySQL query configuration
  • sender_access: Sender whitelist (sasalliance.org domain allowed)
  • sasl_passwd.template: SES authentication template
  • entrypoint.sh: Container startup with MySQL health check and config generation

Development Workflows

Building and Running:

Always use sudo for Docker commands. Don't bother opening the simple browser UI for Docker as it is not very useful.

sudo docker-compose up --build    # Build and start all services
sudo docker-compose logs -f       # Monitor all service logs
sudo docker-compose logs -f api   # Monitor specific service

Managing Lists and Members:

Via Web Interface (Recommended):

  1. Open http://localhost:3000
  2. Enter API_TOKEN from .env file
  3. Use intuitive interface to manage lists, members, and subscriptions
  4. Click "Subscriptions" button on any member for toggle-based subscription management

Via REST API:

# Get all lists
curl -H "Authorization: Bearer $API_TOKEN" http://localhost:8000/lists

# Create new list
curl -X POST http://localhost:8000/lists \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"list_name":"Test","list_email":"test@lists.sasalliance.org","active":true}'

# Subscribe member to list
curl -X POST http://localhost:8000/subscriptions \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"list_email":"test@lists.sasalliance.org","member_email":"user@example.com"}'

Via Direct Database Access:

docker-compose exec mysql mysql -u maillist -p maillist
# See database/README.md for SQL examples

Testing Mail Delivery:

# From inside container
docker-compose exec postfix bash
echo "Test message" | mail -s "Subject" community@lists.sasalliance.org

# Check logs for SES relay status
docker-compose logs postfix | grep -E "(sent|bounced|deferred)"

# Verify MySQL query works
docker-compose exec postfix postmap -q "community@lists.sasalliance.org" \
  mysql:/etc/postfix/mysql_virtual_alias_maps.cf

Security Considerations

  • All credentials stored in .env file (git-ignored)
  • MySQL on private Docker network (no host port mapping)
  • API requires Bearer token authentication
  • Sender whitelist restricts who can send to lists (@sasalliance.org only)
  • SASL password file permissions set to 600 in entrypoint
  • TLS encryption enforced for SES relay (smtp_tls_security_level = encrypt)
  • Web interface requires token for all operations

Configuration Conventions

  • Hostname Pattern: lists.sasalliance.org for mailing lists, origin domain sasalliance.org
  • Virtual Aliases: Dynamically queried from MySQL database in real-time
  • SES Region: EU West 2 (email-smtp.eu-west-2.amazonaws.com)
  • Port Mapping: Standard SMTP port 25 exposed to host
  • Database Tables: lists, members, list_members (many-to-many design)
  • API Port: 8000 for REST API
  • Web Port: 3000 for web interface

Common Modifications

Adding Recipients to a List: Use web interface or API - changes are immediate!

Creating New Mailing List:

  1. Via Web: Click "Add List" button, fill in form
  2. Via API: POST to /lists endpoint with list details
  3. Via MySQL: INSERT into lists table

Adding New Member:

  1. Via Web: Click "Add Member" button in Members tab
  2. Via API: POST to /members endpoint
  3. Via MySQL: INSERT into members table

Managing Subscriptions:

  1. Via Web: Click "Subscriptions" button on member, toggle lists
  2. Via API: POST/DELETE to /subscriptions endpoint
  3. Via MySQL: INSERT/DELETE in list_members table

Credential Updates:

  1. Edit .env file with new credentials
  2. Restart affected services:
    • SES: docker-compose restart postfix
    • MySQL: docker-compose restart mysql
    • API: docker-compose restart api