Skip to content
Muralidharan Vivekananthan

Workshop

Things I built because the manual version was irritating.

Personal projects. Same way of looking at a problem as at work — just without a ticket queue.

01

ApplyFlow

Outreach that keeps going after you close the laptop

GitHub Repo →(Private — access provided on request)

Sending a lot of cold emails by hand was tedious. ApplyFlow takes a campaign — a list of roles, a resume, a schedule — and sends personalized mail in the background through the user's own Gmail.

You sign in with Google, upload a spreadsheet of companies and roles, attach a resume, and watch sent / failed / in-progress counts on a dashboard. You can cancel a campaign; pending mail stops.

Spreadsheet rows need Company Name, Role Name, and Company Mail ID. Headers are checked, emails are validated, and a file is capped at 400 rows. Duplicate recipients are skipped. One mail goes out every three minutes per campaign. Delivery is at-least-once, not exactly-once. Cancel marks the campaign stopped; it does not purge the queue. The dashboard polls about every four seconds.

Gallery

Tap a frame to open it.

Why the pieces exist

  • React — campaigns, uploads, and progress. A SPA talking to the Go API. Local UI is Vite; production build is static files in S3 served by CloudFront.
  • Go API — users, campaigns, templates, outreach state, and a /health check. It runs as a container on ECS Fargate in ap-south-2 (Hyderabad). The scheduler lives in the same process.
  • Go worker — a second Fargate service. It pulls from SQS and sends the mail, so a slow Gmail call never sits on the HTTP request. Queue visibility is two minutes; failed sends can be retried.
  • PostgreSQL on RDS — private in the VPC. Progress survives a refresh. The API reaches it through security groups, not a public database port. A stopped bastion host is only for a laptop SSH tunnel to the database.
  • S3 — resumes and spreadsheets, separate from the database.
  • SQS — the handoff between "this email is due" and "send it."
  • In-process scheduler — campaign start times. A Go loop inside the API periodically claims due outreach and puts it on the queue. The queue is not the clock.
  • Google OAuth and the Gmail API — mail goes out from the user's Gmail. Sign-in returns a token to the React app. Access and refresh tokens stay on the server.
  • ECS Fargate — container orchestration for the API and worker services with auto-scaling and isolated execution environments.
  • ECR — container registry storing Docker images tagged with git SHA for traceable deployments.
  • Application Load Balancer — distributes traffic across API instances with health checks.
  • CloudFront — CDN serving the React frontend with HTTPS termination and edge caching.
  • CloudWatch — centralized logging and monitoring for all Fargate tasks.
  • GitHub Actions with OIDC — CI/CD pipeline assuming IAM roles without stored credentials.
  • Docker Compose & LocalStack — local development environment mimicking AWS services.
  • AWS CLI — infrastructure provisioning for S3 buckets and SQS queues.

Let's connect

To discuss more about this system or the engineering decisions behind it, let us connect.

Connect with me