Building a Multi-Domain Executive Reporting System with AWS Lambda, SES, and DynamoDB
Over the past development session, we built and deployed a comprehensive executive reporting pipeline that generates custom C-suite intelligence across four distinct business entities—each with its own strategic lens and KPI framework. This post covers the technical architecture, infrastructure decisions, and deployment patterns we used to create a scalable, maintainable reporting system.
What Was Done
We created an automated executive reporting system that:
- Generates five specialized reports (CEO, CTO, Accounting, CMO, CFO) tailored to different stakeholder perspectives
- Sends reports via AWS SES to stakeholder inboxes with BCC tracking
- Stores report artifacts and metadata in DynamoDB for audit trail and historical analysis
- Integrates with existing project handoff documentation and asset inventory
- Includes a secondary reporting path for three additional domain-specific reports (3028 51st St Rental, Expert Yacht Delivery, DangerousCentaur Client Portfolio)
The core implementation lives in two Python scripts: /Users/cb/Documents/repos/tools/send_exec_reports.py (primary production version) and /Users/cb/Documents/repos/tools/send_exec_reports_2.py (secondary/experimental variant). Both leverage the existing infrastructure we've already deployed across our four main domains.
Technical Architecture
Data Ingestion and Context Gathering
Each report type requires a different data model. Rather than building separate ETL pipelines, we unified data collection around three primary sources:
- Project Handoff Registry: Structured markdown files at
/Users/cb/Documents/repos/agent_handoffs/projects/containing mission statements, tech stacks, deployment status, and financial models for each entity - AWS Infrastructure State: Live queries against Lambda functions, S3 buckets, CloudFront distributions, and DynamoDB tables to surface actual deployment topology and resource utilization
- Git Repository Audit: File modification timestamps and commit history to establish development velocity, stability metrics, and technical debt indicators
The CEO report, for example, requires a full asset inventory. Rather than hard-coding asset lists, we:
# Pseudo-code pattern used in send_exec_reports.py
def gather_asset_inventory():
assets = {}
for entity in ENTITIES:
# Pull from project handoff
handoff = load_handoff(f'agent_handoffs/projects/{entity}.md')
assets[entity]['dns'] = handoff.get('domains')
assets[entity]['infra'] = handoff.get('aws_resources')
assets[entity]['team'] = handoff.get('team_assignments')
return assets
This approach allows reports to stay current without manual updates.
Report Generation Strategy
Each report follows a structured template but with domain-specific content:
- CEO Report: Inventory of all assets, critical shortfalls ranked by business impact, missing KPIs, and 30-day priority agenda
- CTO Report: Stack audit (QOS + JADA + QDN + DC), security gap analysis, cost optimization opportunities (~$25/mo savings identified), UX deficits, and dev cycle maturity assessment
- Accounting Report: Revenue recognition framework, chart of accounts design, expense audit by category, and Q1 2027 profitability roadmap
- CMO Report: Channel visibility matrix, case for email blast deployment (3,676 recipients, modeled at $10K–50K upside), OTA sequencing strategy, and 30/60/90-day milestones
- CFO Report: Monthly burn rate model (~$7–9K/mo), capital deployment framework (zero-cost → low-cost → revenue-producing tiers), break-even analysis (6 charters/month), and financial guardrails
Email Delivery and Configuration
Reports are delivered via AWS SES, which we've already integrated into the infrastructure. The key configuration points:
- Verified Sender:
admin@queenofsandiego.com(pre-verified in SES console for production account) - Recipient: Primary delivery to
c.b.ladd@gmail.comwith BCC toadmin@queenofsandiego.comfor audit trail - SES Region: us-west-2 (configured in
repos.envunderAWS_SES_REGION) - Environment Variable Pattern: Sender address, recipient lists, and SES config sourced from
repos.envrather than hard-coded
The sending pattern uses boto3's SES client with HTML email formatting:
import boto3
from botocore.exceptions import ClientError
ses_client = boto3.client('ses', region_name=os.getenv('AWS_SES_REGION'))
try:
response = ses_client.send_email(
Source=SENDER_EMAIL,
Destination={'ToAddresses': [recipient], 'BccAddresses': [audit_email]},
Message={
'Subject': {'Data': f'Executive Report: {report_type}'},
'Body': {'Html': {'Data': html_content}}
}
)
print(f"Email sent. Message ID: {response['MessageId']}")
except ClientError as e:
print(f"SES error: {e.response['Error']['Message']}")
Infrastructure and Deployment
The reporting system spans multiple AWS services and repositories:
- S3 Buckets: Report artifacts archived to
s3://qos-reports-archive-prod/exec-reports/YYYY/MM/for historical analysis and compliance - DynamoDB Table:
executive_reportstable with partition keyreport_typeand sort keygenerated_timestampfor rapid lookups and audit logging - Lambda Integration: Reports can be triggered via scheduled Lambda function (EventBridge rule) or invoked directly from CLI for ad-hoc generation
- CloudWatch Logs: All SES send operations logged to
/aws/lambda/send-exec-reportsfor monitoring and troubleshooting
The ShipCaptainCrew Lambda function at /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py was also updated during this session to handle event creation, role management, and waiver processing—work that informed some of the data models used in the reporting system.
Key Technical Decisions
Why Markdown Handoffs Instead of Database-First Design?
We chose to keep project metadata in markdown handoff files rather than migrating to a dedicated config database. Rationale: version-controlled, human-readable, easy to update during standup, and already integrated into agent handoff workflow. The reports layer sits on top, parsing these files programmatically.
Why Five + Three Report Model?