From Idea to 30 Users in 7 Days: Scaling 'The Hangout Spot' on My Own Hardware.

From Idea to 30 Users in 7 Days: Scaling 'The Hangout Spot' on My Own Hardware.
💡
Update (March 23, 2026): Since I first drafted this, The Hangout Spot has grown from a 30-person beta to over 100 active users. While the architecture below was my "Day 7" reality, I've implemented clever new tricks (which I'll be sharing in my next post). For now, here is how the foundation was built.

The "Anti-Cloud" Social App: Building The Hangout Spot for $15/mo

They say, "Don't build your own infrastructure." They say, "Just use Vercel/AWS/Firebase."

I ignored them.

Last week, I launched The Hangout Spot—a privacy-first social hub designed to kill the "Social Obligation Loop." It’s currently serving about 30 active users (shoutout to my "Couch Potato" & "Video Game" beta cohort), handling real-time invites, push notifications, and geolocation.

And it’s all running on a single $15/mo VPS, orchestrated by Docker Compose. Here is the technical breakdown of how I built a "Big Tech" social app on a home lab budget.

1. The Stack: Boring is Better

I didn't use Kubernetes or Serverless Lambdas. I used the most robust, portable stack I know. For this build, I treated Gemini as my Senior Advisor, and I orchestrated the architecture and QC'd every line of logic, while using AI to accelerate the boilerplate and the glassmorphism UI.

  • Frontend: React (Vite) + PWA (Service Workers for offline support).
  • Backend: Node.js / Express.
  • Database: PostgreSQL (Managed via Prisma).
  • Orchestration: Docker Compose running inside a Linux Container (LXC).

The "Sidecar" Backup Strategy

The scariest part of self-hosting is data loss. I didn't want to rely on manual cron jobs on the host. Instead, I implemented a Sidecar Pattern in my docker-compose.prod.yml. I run a dedicated backups container that lives alongside the database. It wakes up every 30 minutes, dumps the Postgres data, compresses it, and saves it to a mounted volume.

YAML

# The "Sleep Easy" Container
backups:
  image: prodrigestivill/postgres-backup-local
  environment:
    - SCHEDULE=@every 30m
    - BACKUP_KEEP_DAYS=7
    - POSTGRES_EXTRA_OPTS=-Z9 # Maximum compression
  depends_on:
    - db

This means my "Disaster Recovery" plan is just docker compose up.

2. The Notification Engine: Building the "Bat Signal"

Social apps live or die by notifications, but I didn't want to spam my users. I built a Traffic Controller logic in notificationEngine.js that distinguishes between Info and Urgency based on Squad Selection.

We use VAPID keys to handle web push directly. This was a deliberate choice to avoid third-party trackers like OneSignal.

  • The Drop-In (Passive): If you post a hangout without selecting a specific Squad, it’s a "Passive" event. It appears in the feed, but no push notifications are sent. This is for the "I'm at the gym/coffee shop if anyone is around" vibe.
  • The Bat Signal (Active): If you explicitly select a Squad, it triggers a high-priority Push Notification to that specific group.

This is anti-spam by design. Because notifications are tied to Squads, there is no blast all button. To spam your entire friend list, you’d have to manually add every single connection into one giant group—and let’s be real, nobody has time for that. It forces intentionality, ensuring that when your phone buzzes, it actually matters.

  • The PWA Catch: Remember that iOS users must "Add to Home Screen" to receive these. I had to build a custom install prompt specifically to walk my iPhone-wielding friends through the "Share -> Add" struggle.

3. Privacy Engineering: The "Right to Lurk"

The hardest technical challenge wasn't the code—it was the philosophy. My app promises: "We track the party, not the people." Most social apps show you exactly who viewed your story; that creates anxiety. I wanted to show "Hype" (aggregate interest) without doxxing the lurkers.

The Solution: Masked Feed Objects

I implemented a middleware layer in feedEngine.js that checks the relationship between the Viewer and the Content. If you are in the "Squad," you see names. If you are a stranger, the API strictly sanitizes the object.

JavaScript

// Actual masking logic from feedEngine.js
const maskUser = (item) => {
    if (!canSeeDetails(item.userId)) {
        return {
            ...item,
            user: {
                name: (u.name || 'Anon').charAt(0) + '.', // "N." instead of "Nate"
                avatar: null, // No face shown
                isMasked: true
            }
        };
    }
    return item;
};

4. Why Self-Host?

Could I have put this on Vercel? Sure. But owning the hardware gives me:

  1. Zero Cold Starts: My Node API is always hot in memory.
  2. Data Sovereignty: I know exactly where my users' location data lives (on my encrypted SSD, not in a generic cloud bucket).
  3. Cost: Scaling to 1,000 users will cost me exactly $0 extra.

The Hangout Spot is proof that you don't need a VC budget to build big tech features. You just need Docker, some clever architecture, and a refusal to compromise on privacy.

Want to test the infrastructure? Head to https://thehangoutspot.com!