William Mulianto

How I Build and Ship a Client Project

· 4 min read

After working with multiple clients across different industries, I’ve settled into a process that keeps projects on track without unnecessary overhead. Here’s how a typical project goes from first conversation to production.

Discovery First

Every project starts with a discovery phase. Before writing any code, I need to understand what we’re actually building and why.

This usually takes a few calls and some async back-and-forth:

  • What problem are we solving?
  • Who are the users?
  • What does success look like?
  • Are there existing systems this needs to integrate with?
  • What’s the timeline and budget?

I document everything in a simple project brief — not a 50-page spec, just enough to align on scope. This saves hours of rework later. The biggest source of project failure isn’t bad code — it’s building the wrong thing.

Scoping and Proposal

Once I understand the project, I break it down into phases. Each phase has a clear deliverable. This makes it easier for the client to see progress and for me to manage expectations.

A typical breakdown:

  • Phase 1 — Core functionality, MVP
  • Phase 2 — Integrations, admin panel, polish
  • Phase 3 — Testing, deployment, handoff

I quote per phase, not per hour. Hourly billing incentivizes slow work. Per-phase billing incentivizes shipping. I wrote more about this in why I use fixed pricing.

The proposal includes what’s in scope, what’s out of scope, timeline per phase, and payment terms. Clear scope prevents most disagreements.

Tech Stack Decisions

I pick the stack based on the project, not personal preference. That said, I have defaults that work for most cases:

  • Backend — Node.js with TypeScript
  • Database — PostgreSQL
  • ORM — MikroORM
  • Frontend — depends on the project (React, Astro, or plain HTML)
  • Hosting — VPS with Docker, Caddy as reverse proxy
  • CI/CDDrone CI with git tags, Watchtower for auto-deploy

For most client projects, this stack is fast to build with, easy to maintain, and cheap to host. I avoid overcomplicating things — if the project doesn’t need microservices, it doesn’t get microservices.

Development

I work in short cycles. Typically:

  1. Build a feature
  2. Push to a staging environment
  3. Get feedback from the client
  4. Iterate

Clients see progress early and often. This catches misunderstandings before they become expensive. A staging link they can click on is worth more than any number of screenshots or Figma prototypes.

I use git tags for versioning. Every deployment maps to a version. If something breaks, rolling back is straightforward.

Communication During Development

I send regular updates — usually end-of-day or end-of-week summaries depending on the project pace. Each update covers:

  • What was done
  • What’s next
  • Any blockers or decisions needed

This keeps the client informed without requiring constant calls. Most communication is async — a well-written message is almost always better than a meeting.

When calls are needed, I keep them short and focused. No status meetings for the sake of meetings.

Deployment

My deployment setup is lightweight:

  1. Push a git tag
  2. Drone CI builds the Docker image and pushes to the registry
  3. Watchtower detects the new image and restarts the container
  4. Caddy handles HTTPS and reverse proxy

The whole pipeline runs on a single VPS. No Kubernetes, no managed CI bills. For most client projects, this is more than enough.

I set up monitoring and make sure the client knows how to reach me if something goes down.

Handoff

When the project wraps up, the client gets:

  • Access to the repository
  • Documentation on how to deploy and maintain
  • A walkthrough of the codebase
  • Any credentials and access needed to manage the application

I write the code as if someone else will maintain it. Clear naming, simple structure, no clever tricks. The goal is that any competent developer can pick it up.

After Launch

I typically offer a support period after launch — usually a month. Bugs get fixed, small adjustments get made. This builds trust and often leads to follow-up work.

Most of my clients come back for additional features or new projects. Delivering well the first time is the best marketing.


If you have a project in mind, I’m available for freelance work. Get in touch — I typically respond within 24 hours.

Related