Penwave: A blogging platform, from EC2 to Kubernetes by Aswin ShinePenwave: A blogging platform, from EC2 to Kubernetes by Aswin Shine

Penwave: A blogging platform, from EC2 to Kubernetes

Aswin Shine

Aswin Shine

A blogging platform I designed, built and ran on AWS EC2, then rebuilt on EKS with ArgoCD and Helm. Ten CI gates, rotating sessions with theft detection, and real Grafana and ArgoCD dashboards.


Design, build, deploy: one engineer, the whole stack

Penwave is a blogging platform for longer writing. I designed the interface, built the frontend and API, ran it in production on AWS EC2 for one to two months, then retired it on purpose and rebuilt the same app as a Kubernetes platform on EKS. Every number below is in the repo.

The product.

Anyone can read: posts and profiles use optional auth, so nothing is gated until you try to act. Explore filters by tag, Trending ranks the week, and search runs on a Postgres full-text index. Writers get a TipTap editor that autosaves as they type, offers a closed tab's draft back, and keeps cover, excerpt, tags and scheduling in a panel beside the page. The same components work down to 390 pixels, with no separate mobile site.

The design system.

Five colour ramps read straight from the app's Tailwind config, and two faces: Instrument Serif for headings and the post body, Inter for the interface.

Sessions that can't be stolen twice.

Argon2id passwords, a 15-minute access token and a 7-day refresh token in httpOnly cookies. Refresh tokens rotate inside a transaction; if an old one is ever reused, it is treated as theft and every session that user has is revoked. Around it: Zod on every route, HTML sanitised on the server, separate CSPs for the API and frontend, and Redis rate limits.

Ten gates to production.

Pushing to main deploys nothing. A version tag starts the pipeline: Gitleaks, npm audit, Hadolint, Trivy on the Terraform, SonarCloud (reports only), multi-arch Buildx images, Trivy on the images, a one-by-one container deploy, Prisma migrations, then a health check that rolls back to the last image on failure.

Same app, two platforms.

Phase 2 ran in production on one EC2 host with Docker Compose, Nginx, RDS PostgreSQL 16 and ElastiCache Redis 7. Phase 3 rebuilt it on EKS Auto Mode: ALB ingress, 2 to 6 pods per service with HPA, a PreSync migration job, External Secrets with IRSA, default-deny network policies, and ArgoCD pulling the kubernetes branch. Both were built by Terraform.

Watched, not guessed.

Prometheus scrapes the API every 15 seconds, Winston writes JSON logs that Promtail ships to Loki, and Grafana shows the app and the cluster. Liveness never touches the database, so a Postgres outage takes pods out of rotation instead of restarting all of them.

What broke, and what I learned.

A failed migration froze every ArgoCD sync after it; an unquoted heredoc killed server bootstrap; Trivy blocked the first releases until the CVEs were fixed or documented. Each one is traceable to its commit.
Like this project

Posted Oct 15, 2026

A blogging platform I designed, then rebuilt on EKS. Ten CI gates, rotating sessions with theft detection, and real Grafana and ArgoCD dashboards.