Building a Multi-Tenant Executive Reporting System: Infrastructure, SES Integration, and Automated Distribution
Over the past development session, we built and deployed a comprehensive executive reporting infrastructure across four distinct business entities (JADA, QueenofSanDiego, QuickDumpNow, DangerousCentaur) with specialized reports tailored to C-suite stakeholders. This post details the technical architecture, infrastructure decisions, and deployment patterns used to generate and distribute role-specific business intelligence automatically.
What Was Done
We created a multi-report generation system that:
- Synthesized operational data across four separate business entities into five specialized executive reports
- Automated report delivery via AWS SES with verified sender addresses and BCC tracking
- Deployed to
/Users/cb/Documents/repos/tools/send_exec_reports.pyas the primary generation script - Integrated with existing environment variable configuration stored in
repos.env - Created role-specific analyses for CEO, CTO, Accounting Officer, CMO, and CFO perspectives
- Established a repeatable pattern for adding stakeholder-specific reports (3028 51st St Rental, Expert Yacht Delivery, DangerousCentaur Client Portfolio)
Technical Architecture
Report Generation Pipeline
The primary script (send_exec_reports.py) follows a straightforward but extensible pattern:
# Pseudo-structure of report generation flow
1. Load environment configuration from repos.env
2. Validate SES sender credentials and recipient lists
3. For each stakeholder persona:
- Load business entity data
- Apply role-specific analysis filters
- Generate narrative report (KPIs, shortfalls, recommendations)
- Construct email via SES API
4. Batch send via boto3 SES client
5. Log delivery confirmations and any failures
Why this approach? Multi-tenant reporting requires role-based filtering to prevent information leakage while maintaining a single source of truth for underlying business data. By separating the data-gathering phase from the analysis phase, we can rerun reports against updated data without regenerating the entire analysis framework.
AWS SES Integration
Email delivery uses AWS Simple Email Service (SES), leveraging verified sender addresses configured in the account. The implementation validates two critical variables from repos.env:
SES_SENDER_ADDRESS— verified sender (e.g.,admin@queenofsandiego.com)SES_REGION— SES endpoint region (typicallyus-west-2orus-east-1)
The boto3 SES client is instantiated with explicit region binding to prevent routing failures across AWS partitions:
import boto3
ses_client = boto3.client('ses', region_name=os.getenv('SES_REGION'))
# Send with explicit message parameters
response = ses_client.send_email(
Source=sender_address,
Destination={
'ToAddresses': [primary_recipient],
'BccAddresses': [tracking_address] # c.b.ladd@gmail.com for audit trail
},
Message={
'Subject': {'Data': subject_line, 'Charset': 'UTF-8'},
'Body': {'Text': {'Data': email_body, 'Charset': 'UTF-8'}}
}
)
BCC addressing to c.b.ladd@gmail.com ensures executive visibility of all outbound reports without modifying recipient lists, critical for audit compliance and stakeholder communication tracking.
Report Content: Five Specialized Perspectives
CEO Report: Full asset inventory (4 entities), 8 critical shortfalls (empty sales pipeline, zero revenue tracking systems, 0 OTA listings, broken QDN funnel, DC billing model absent), 9 missing KPIs, and a 30-day action plan prioritized by business impact.
CTO Report: Stack audit across all four domains with specific findings: hardcoded Stripe keys in Lambda, plaintext credentials in repos.env, unauthenticated GAS endpoints, missing WAF, estimated AWS spend ($50–84/mo), UX gaps (no availability calendar, zero analytics instrumentation), CI/CD absence, and 10 engineering action items ranked by security and user value.
Accounting Report: Revenue recognition gaps, complete chart of accounts template, expense categorization audit, identification that no accounting system currently exists, and a 4-milestone roadmap to profitability through Q1 2027 via tighter cost controls and revenue automation.
CMO Report: Channel visibility matrix across email, SMS, OTA, and social; quantified opportunity case (3,676-person blast list × $10K–50K average charter value = $36.7M–184M upside); OTA sequencing strategy (Sailo first for verification, GetMyBoat next, Viator/GuideMyGuide after proof-of-concept); QDN local SEO roadmap; 30/60/90-day deployment milestones.
CFO Report: Monthly burn rate modeling ($7–9K/mo), tiered capital deployment framework (zero-cost experiments first, low-cost automation second, revenue-producing initiatives third), break-even threshold (6 charters/month), monthly revenue targets through Q4 2026, and three non-negotiable financial rules (no marketing spend without attribution, no infrastructure spend above $100/mo per entity, every hire must map to $5K+/mo revenue).
Infrastructure & Deployment
The reporting system integrates with existing infrastructure:
- Configuration Management: Environment variables stored in
repos.env(Git-ignored, loaded at runtime) — SES credentials, region, sender addresses - Execution Environment: Local Python 3.9+ with boto3 library; can scale to Lambda for scheduled execution (future: EventBridge cron trigger)
- Data Sources: Project handoff markdown files (
/agent_handoffs/projects/*.md), AWS service inspection (SES verified addresses, DDB tables, Lambda env vars), manual business context - Audit Trail: BCC copy sent to c.b.ladd@gmail.com; SES delivery status logged to
send_exec_reports.pystdout
Key Design Decisions
Why 5 Reports? Each persona (CEO, CTO, Accountant, CMO, CFO) has fundamentally different decision-making criteria. Mixing them into a single report obscures key insights and wastes executive time. Role-specific reports ensure signal-to-noise ratio stays high.
Why SES Over Other Email Services? SES is zero-cost within AWS free tier and integrates natively with boto3. For <5 stakeholders, operational complexity is minimal. If blast lists scale, migration to Sendgrid/Mailgun is straightforward (same boto3 → SDK swap).
Why Environment Variables for Configuration? Separates secrets (SES region, verified addresses) from code. Enables safe Git workflows without credential leakage. repos.env is loaded at runtime and never committed.
Why BCC Instead of Manual Distribution? Eliminates human error in recipient lists, creates immutable audit trail, ensures stakeholders see identical content.
Extension Points for Future Work
Three additional reports are que