Building Automated Technical Blog Infrastructure Across Four Domain Properties
Overview
Implemented a fully automated technical blog generation system that captures development work across four properties (queenofsandiego.com, sailjada.com, dangerouscentaur.com, and burialsatseasandiego.com) and publishes granular technical posts in real-time. This system creates an auditable record of all infrastructure and development changes for stakeholder visibility.
What Was Done
1. Multi-Domain Blog Infrastructure
Created four distinct tech blog subdomains, each with independent S3 origins and CloudFront distributions:
- tech.queenofsandiego.com — S3 bucket:
qos-tech-blog, CloudFront Distribution ID:E2CDMWVX2AAWJZ, Certificate:*.queenofsandiego.comwildcard - tech.sailjada.com — S3 bucket:
jada-tech-blog, CloudFront Distribution ID:E1RHVCMPS4SDCC, Certificate:*.sailjada.comwildcard - tech.dangerouscentaur.com — S3 bucket:
dc-sites(shared wildcard origin), CloudFront Distribution ID:E2Q4UU71SRNTMB, Namecheap DNS CNAME - tech.burialsatseasandiego.com — S3 bucket:
bats-tech-blog, CloudFront Distribution ID:E2X4PCLF6JWVJ1, GoDaddy DNS CNAME with ACM validation
2. Automated Post Generation Pipeline
Built a Python-based generation system that:
- Captures Claude Code development sessions via session transcript hooks
- Parses JSONL-formatted session transcripts to extract file modifications, command execution, and tool usage
- Generates semantically rich HTML posts with file paths, function names, and architectural decisions
- Filters sensitive data (credentials, API keys, tokens) before publishing
- Routes posts to appropriate domain based on file paths (queenofsandiego.com files → tech.queenofsandiego.com, etc.)
- Automatically invalidates CloudFront cache after upload
Technical Architecture
Session Capture Hook
Created /Users/cb/.claude/hooks/tech_blog_stop.sh that executes on Claude Code session stop. This hook:
- Accesses the latest session transcript from
~/.claude/sessions/ - Parses the JSONL format to extract tool_use entries (code edits, file creates, command execution)
- Invokes the blog generator with the transcript path and detected domain property
- Logs execution to
~/.claude/logs/tech_blog_generation.logfor debugging
Blog Generator (tech_blog_generator.py)
The core generator handles:
- Transcript Parsing: Reads JSONL session data and extracts write/edit operations on specific file types (Python, HTML, JavaScript, shell scripts)
- Content Generation: Creates structured technical narratives that explain what was modified, why, and the architectural implications
- Secret Filtering: Regex patterns remove hardcoded credentials, API keys, AWS secret keys, and sensitive configuration values
- Property Routing: Maps file paths to domains (e.g.,
/repos/sites/queenofsandiego.com/→ QOS blog) - S3 Upload & CDN Invalidation: Uploads generated HTML to the appropriate S3 bucket and invalidates the CloudFront distribution to ensure cache refresh
Infrastructure Init (tech_blog_init.py)
Bootstrap script that provisions all required infrastructure:
- Creates S3 buckets with appropriate naming conventions and bucket policies for CloudFront origin access
- Provisions CloudFront distributions with Origin Access Control (OAC) for secure S3 integration
- Configures DNS records — Route53 alias records for queenofsandiego.com and sailjada.com; Namecheap CNAMEs for dangerouscentaur.com; GoDaddy CNAME with ACM validation for burialsatseasandiego.com
- Validates ACM certificate ownership via DNS CNAME records (particularly important for burialsatseasandiego.com which uses a different registrar)
- Stores infrastructure metadata in
~/.claude/projects/memory/tech_blogs_infrastructure.jsonfor future reference
Key Decisions & Rationale
Wildcard Certificates vs. Domain-Specific
Leveraged existing wildcard certificates (*.queenofsandiego.com and *.sailjada.com) rather than creating new domain-specific certs. This reduced ACM validation overhead and simplified certificate management. For dangerouscentaur.com (which already had a wildcard CloudFront distribution), we reused the existing infrastructure by pointing a CNAME to that distribution.
Per-Domain S3 Buckets
Each property gets its own S3 bucket rather than a shared bucket with path-based routing. This provides:
- Clear separation of concerns and access control policies per domain
- Independent CloudFront distributions (better cache invalidation granularity)
- Simpler billing attribution and resource tracking
- Reduced blast radius if a bucket is accidentally misconfigured
Automated Session-Based Generation
Rather than manual blog updates, the system triggers automatically on Claude Code session stop. This ensures:
- No work is forgotten or left undocumented
- Posts are published within minutes of completion
- Sergio and other stakeholders have real-time visibility into development activity
- The audit trail is comprehensive and granular, not a high-level summary
Multi-Registrar DNS Strategy
Different properties use different registrars and DNS providers (Route53 for queenofsandiego.com/sailjada.com, Namecheap for dangerouscentaur.com, GoDaddy for burialsatseasandiego.com). The infrastructure init script handles each provider's DNS API independently, allowing future expansion without significant refactoring.
Integration with Ship's Papers Menu
Updated the navigation structure in /repos/sites/queenofsandiego.com/index.html to include a "Tech Blog" link under the Ship's Papers dropdown. This link points to https://tech.queenofsandiego.com/, making the technical documentation discoverable alongside operational resources.
What's Next
- Landing Page: Create index pages for each tech blog that display recent posts chronologically with search/filter capabilities
- Enhanced