All posts
§03 · Writing26.05.044 min read Updated 26.05.20

Building krealalejo.dev: The Technical Bill

Some projects you finish. Others you close.

Finishing means the last feature is done. Closing means you've reflected on what it cost, what it taught you, and whether it was worth it. krealalejo.dev is closed.

Here's the technical bill.

What Was Actually Built

Infrastructure provisioned with Terraform: A VPC with public subnets, an EC2 t4g.micro running Docker Compose (Nginx + Spring Boot), an S3 bucket for uploaded images and thumbnails, DynamoDB for all application data, two Lambda functions, a Cognito User Pool for admin authentication, and SES for email notifications. Every resource defined in code, every change applied through a plan.

CI/CD via GitHub Actions: Two pipelines. One for the Nuxt frontend — push to main, Vercel builds and deploys automatically. One for the Spring Boot API — build, package into a Docker image, push to Amazon ECR, SSH into EC2, pull and restart. Manual deployments: zero.

Backend API in Java with Spring Boot 3.5: DDD-layered architecture with a pure domain layer (no framework imports), application use cases, and infrastructure adapters. REST endpoints for blog posts, CV data, project metadata, and a contact form. JWT validation against Cognito on all write endpoints.

Frontend in Nuxt 4: SSR for all public pages (blog, portfolio, CV, contact). SPA admin panel for managing blog posts. Server routes as a BFF layer — no direct browser-to-API communication for write operations.

Event-driven processing: An S3 Lambda trigger that generates WebP thumbnails when images are uploaded. A DynamoDB Streams Lambda that sends an email via SES when a new contact lead is created.

The Monthly Cost

Running this infrastructure costs close to nothing.

The EC2 instance is stopped when not in active development — it only needs to run when the portfolio is being accessed, and for a personal site, that means keeping it running for demos and then stopping it. Elastic IPs are free when attached to a running instance, so the only cost when the instance is stopped is the EIP reservation fee (around €3.50/month in eu-west-1).

DynamoDB On-Demand: free at this request volume. S3: free under 5 GB. Lambda: free under 1 million invocations/month. SES: free under 62,000 emails/month. Cognito: free under 50,000 monthly active users.

The actual monthly cost in steady state is under €5.

What I'd Do Differently

Terraform state management from day one. I started with local state and migrated to S3 remote state partway through. That migration, while not technically difficult, created unnecessary risk. Remote state with locking should be the default starting point.

More aggressive access pattern analysis before DynamoDB. I had to revise the key design once when I added the CV section because I'd underspecified the access patterns upfront. A two-hour design session before writing any code would have prevented that.

End-to-end tests earlier. The unit and integration tests cover individual layers well. But there were integration bugs between the Nuxt server routes and the Spring Boot API (specifically around how error responses are surfaced) that only appeared when testing the full stack. Those should have been caught earlier.

What This Was Actually For

krealalejo.dev isn't primarily a portfolio. It's a learning environment that happens to look like a portfolio.

The constraint of operating every layer yourself — DNS, SSL, networking, CI/CD, auth, storage, compute, events — forces you to understand each piece in a way that using managed platforms doesn't. When something breaks, you can't open a support ticket with Vercel or Netlify. You read the logs, trace the request, and fix it.

That debugging skill is the most transferable thing this project produced. Not the Terraform configuration, not the DDD architecture, not the pipeline. The ability to look at a system you built and find the fault.

The bill is under €5/month. The return was worth considerably more.


What's the most valuable thing a side project has taught you that you couldn't learn on the job?