~/kevin-hoang
2026Stealth

Marketing Automation SaaS

Founder & Full-Stack Engineer

This product has not launched yet, so this page covers how it is built rather than what it does. It is a multi-service SaaS that turns raw inputs into finished, on-brand images and videos and publishes them on a schedule. Six containerized services cooperate through a database and a job queue, and the whole system starts with one command.

Next.js
TypeScript
Prisma
PostgreSQL
Redis
BullMQ
Puppeteer
Remotion
Stripe
NextAuth
Claude API
Docker

What are the six services, and why split them up?

A Next.js app in TypeScript, with Prisma over PostgreSQL, serves the product and its API. Redis backs a BullMQ job queue, and a long-running worker process executes the jobs. Rendering is isolated in two services of its own: a headless-Chrome service (Puppeteer) that turns HTML templates into images, and a Remotion service that composes videos from React components.

Keeping heavy, memory-hungry rendering out of the web app means a long render never slows down a page request, and each renderer can restart or scale on its own. Docker Compose runs all six services together, and the app container applies database migrations at startup, so a fresh checkout becomes a working, migrated system with a single command.

How do long video renders report their progress?

A video render can take minutes, so it never runs inside a request. The web app enqueues a job; the worker starts the render on the video service, polls it, and mirrors its progress onto the BullMQ job, which the interface polls in turn. Every render has a hard 20-minute ceiling, and the finished MP4 is uploaded to a media CDN (Cloudinary) whose URL becomes the job's result.

The services authenticate one another with a shared-secret header, so neither renderer is an open endpoint.

How does scheduled publishing stay reliable?

Each publish is a delayed queue job rather than a row that a cron job scans for, so every post fires at its own time and a failed attempt can be retried. The same worker refreshes long-lived OAuth tokens for connected third-party accounts before they expire, refreshes engagement metrics, runs a nightly data sync, and sweeps up media that users have deleted.

Where do billing, sign-in, and AI fit in?

NextAuth handles sign-in with Google OAuth and email magic links. Stripe manages subscriptions, with webhooks keeping the database in step, and the Stripe CLI forwards events during development. The Claude API drafts copy and describes uploaded images. The model is a configuration setting, so development can run on a smaller, cheaper model than production.

How is the rendered output kept consistent between machines?

The image renderer ships its own font files inside its container instead of relying on whatever the host has installed, so an image looks the same on a laptop and in production. Video compositions are ordinary React components driven by typed input props, which makes them as reviewable as the rest of the code.

Want to talk through how it was built?

I'm open to remote and Massachusetts roles. Happy to walk through the architecture, the trade-offs, or the code.