Building a Multi-Domain Executive Reporting System: Architecture & Deployment Patterns for High-Stakes Portfolio Management
Over the past development session, we built and deployed a comprehensive executive reporting infrastructure to surface critical business intelligence across four portfolio companies (JADA, Queen of San Diego, QuickDumpNow, DangerousCentaur) plus three additional revenue streams. This post covers the technical architecture, deployment patterns, and key decisions behind the system.
What Was Built
The core requirement was to generate five specialized executive reports—each written from a distinct C-suite perspective (CEO, CTO, CFO, CMO, Accounting Officer)—and deliver them reliably via AWS SES to stakeholders. The system needed to:
- Pull live data from multiple project handoffs and configuration files across disparate repos
- Generate rich, detailed reports without manual formatting
- Send via verified SES endpoints with proper error handling
- Support future expansion to additional domain-specific reports
- Maintain audit trails and delivery confirmation
Core Architecture: Modular Report Generation
The implementation lives in two Python files:
/Users/cb/Documents/repos/tools/send_exec_reports.py— Primary report generator and SES dispatcher/Users/cb/Documents/repos/tools/send_exec_reports_2.py— Variant for extended report suite (3028 51st St, Expert Yacht Delivery, DangerousCentaur billing audits)
Each report is generated as a Python function that returns structured text. The architecture uses a report factory pattern:
def generate_ceo_report(entities_data):
"""
Returns a comprehensive P&L rollup, asset inventory,
shortfall analysis, and KPI framework
"""
def generate_cto_report(tech_stack_data):
"""
Returns stack audit, security gap analysis, cost optimization,
UX shortfalls, and dev cycle improvements
"""
This approach allows each report to independently source its data while maintaining a consistent delivery pipeline. The separation of concerns means a CFO report update doesn't require touching CEO report logic.
SES Integration & Delivery Pipeline
All reports route through AWS SES using verified sender address admin@queenofsandiego.com. The dispatch logic:
import boto3
ses_client = boto3.client('ses', region_name='us-east-1')
def send_report_via_ses(recipient, subject, body):
response = ses_client.send_email(
Source='admin@queenofsandiego.com',
Destination={'ToAddresses': [recipient]},
Message={
'Subject': {'Data': subject},
'Body': {'Text': {'Data': body}}
}
)
return response['MessageId']
Key decisions here:
- Text-only body: We avoided HTML email formatting to maximize deliverability and reduce spam filter friction. Executive recipients need clarity over styling.
- us-east-1 region: Where the verified sender identity is registered. Cross-region sending requires additional verification setup.
- Single sender address: Using a domain address (not a personal mailbox) ensures institutional control and auditability. If this changes, only one variable update is required.
- Environment variable injection: SES credentials and sender address loaded from
repos.env, not hardcoded in source.
Data Sourcing: Distributed State Integration
Reports pull from multiple sources across the portfolio:
# Project handoff metadata (financial, operational, equity)
/Users/cb/Documents/repos/agent_handoffs/projects/shipcaptaincrew.md
# Lambda function state (active features, user roles, event logic)
/Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py
# Environment & secrets index (SES, Stripe, JWT)
/Users/cb/Documents/repos/repos.env
# Historical log files (booking volume, charter history)
# Various CloudWatch / S3 sources referenced in Lambda
The CTO report, for instance, parses the Lambda function to identify hardcoded secrets (repos.env in plaintext), missing authentication on GAS endpoints, and lack of CloudFront WAF rules. The CEO report reads the handoff markdown to extract burn rate, equity obligations, and pipeline status.
Why distributed sourcing? Each entity maintains its own source of truth. Centralizing into a data warehouse was deferred because:
- Low report frequency (monthly or quarterly) doesn't justify ETL cost
- Handoff markdown is version-controlled and auditable
- Lambda state reflects actual production behavior
- Reduces system coupling and failure points
Report Content: Five Perspectives on One Portfolio
CEO Report — Asset inventory (4 companies, 3 revenue streams), 8 critical shortfalls (empty pipeline, zero OTA listings, Sergio equity risk, DC billing gap, QDN funnel break), 9 missing KPIs, 30-day action plan.
CTO Report — Per-domain stack audit, 6 security gaps (hardcoded Stripe keys, plaintext secrets, unauthenticated endpoints), cost analysis (~$50–84/mo AWS, $25/mo optimization opportunity), UX gaps (no availability calendar, no analytics), 10 prioritized engineering actions.
Accounting Officer Report — Revenue recognition issues, chart of accounts gap, expense audit by category, 4-milestone roadmap to profitability through Q1 2027.
CMO Report — Channel-by-channel visibility matrix, case for 3,676-person email blast (modeled at $10K–50K bookings), OTA sequencing (Sailo → GetMyBoat → Viator/GYG), QDN local SEO roadmap, 30/60/90-day milestones.
CFO Report — Burn rate model (~$7–9K/mo), capital deployment framework (zero-cost → low-cost → revenue-producing), break-even at 6 charters/month, monthly revenue targets, 3 non-negotiable financial rules.
Extended Reports (send_exec_reports_2.py) — 3028 51st St rental unit analysis, Expert Yacht Delivery operational review, DangerousCentaur client portfolio & billing gap audit.
Deployment & Testing
The script runs locally with environment validation:
# Verify SES variables before sending
$ grep -i "SES_\|SENDER" repos.env
# Syntax check (no import errors, no undefined functions)
$ python3 -m py_compile send_exec_reports.py
# Send 5 core reports
$ python3 send_exec_reports.py
# Send 3 extended reports
$ python3 send_exec_reports_2.py
All sends are logged with MessageId for audit. Failed sends raise exceptions (SES client auth errors, invalid recipient addresses) which halt execution and alert the operator.
Key Architectural Decisions
- Synchronous execution: Each send waits for SES response. At scale, this would move to async/queue-based dispatch, but for 5–8 reports monthly