Skip to content

ghostreindeer09/wuphf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WUPHF

A MERN side project inspired by The Office's infamous all-channels-at-once communication startup.

Send a single message and blast it across multiple channels:

  • Slack
  • Email
  • SMS

One message in. Multiple notifications out.

This repo contains three pieces that share one backend:

server/   the Express API — fans a message out across channels
client/   the public website — compose a message, pick channels, send
cli/      a personal terminal client — same backend, plus character
          voices, Telegram, and a fake fax

Overview

WUPHF is built around a simple idea: every communication channel behaves the same way from the application's perspective.

Each adapter implements a common interface:

async function send(message) {
  // throws on failure
}

module.exports = { send };

Because every channel follows the same contract, the route handler doesn't need to know whether it's talking to Slack, Twilio, Resend, or anything else.

The fan-out logic simply calls .send() on each selected adapter and uses Promise.allSettled() to ensure that one failure doesn't stop the others.

Example:

  • Invalid phone number? SMS fails.
  • Expired Slack webhook? Slack fails.
  • Email still sends.
  • Request still completes.

Architecture

Adding a new channel requires only two steps:

  1. Create a new adapter in server/channels/
  2. Register it in the ADAPTERS map inside server/routes/wuphf.js

No route changes. No business logic changes.

server/channels/
├── slack.js
├── email.js
├── sms.js
└── your-new-channel.js

This keeps channel-specific code isolated while the routing layer remains completely generic.

cli/ follows the same instinct one level up: it's a second, independent client of the exact same /api/wuphf endpoint the website uses, rather than a fork or a separate service. Nothing in server/ knows or cares whether a request came from the website's "WUPHF it" button or a terminal command — same rate limiter, same validation, same Slack/Email channels underneath.


Setup

Backend

cd server
npm install

cp .env.example .env
# Fill in the credentials for whichever channels you want to use

npm run dev

Frontend

cd client

npx create-react-app .
# (or use Vite if you prefer)

# Drop WuphfPanel.jsx and WuphfPanel.css into src/
# Import <WuphfPanel /> inside App.js

npm start

CLI

cd cli
npm install

cp .env.example .env
# Add a free Groq API key (console.groq.com/keys) for character
# voices, and a Telegram bot token (via @BotFather) if you want
# Telegram delivery

npm link
wuphf characters

The CLI talks to the same deployed backend (WUPHF_API_BASE in its .env) — it doesn't need its own database, deployment, or hosting. See cli/README.md for full usage.

Partial Configuration Is Fine

You do not need all three channels configured to run the application.

If a channel is missing required environment variables, WUPHF returns a channel-specific error while continuing to process the others.


Suggested Build Order

1. Start with Slack

Build the smallest possible end-to-end loop:

React Form
    ↓
Express Route
    ↓
Slack
    ↓
MongoDB Log
    ↓
UI Response

Once this works, you've validated the entire architecture.


2. Add MongoDB Logging

The WuphfLog model is already wired into the route, making persistence the next logical step.


3. Add Email (Resend)

Email requires a bit more setup (such as verifying a sending domain), but the implementation is just as straightforward as Slack.


4. Add SMS (Twilio)

Save Twilio for last.

Common gotchas:

  • Trial accounts can only message verified numbers.
  • Numbers must be in E.164 format:
+15551234567

Not:

(555) 123-4567
555-123-4567
555 123 4567

Twilio will reject improperly formatted numbers immediately.


5. Add the CLI

Once the backend and website are solid, cli/ is a low-risk way to extend WUPHF without touching production:

  • Character voices — rewrites your message in the voice of an Office character (Michael, Dwight, Creed, and six others) using Groq's free tier, entirely client-side, before the message ever reaches the backend.
  • Telegram — a fourth delivery channel, but handled entirely in the CLI rather than added to the deployed backend, so it needs no new public env vars and no new attack surface.
  • Fax — a fake, theatrical "transmission," generating a styled HTML page that looks like a faxed document. Nothing is actually transmitted; it's pure bit.

All three CLI features deliberately avoid touching server/ — they either call the existing /api/wuphf endpoint exactly like the website does, or (Telegram, fax) skip the backend entirely and run client-side. The backend doesn't know personalities, Telegram, or fax exist.


Project Structure

server/
├── channels/
│   ├── channel.interface.js   # Contract documentation
│   ├── slack.js
│   ├── email.js
│   └── sms.js
│
├── models/
│   └── WuphfLog.js
│
├── routes/
│   └── wuphf.js               # POST: fan-out
│                              # GET: message history
│
├── index.js
├── .env.example
└── package.json

client/
└── src/
    ├── WuphfPanel.jsx
    └── WuphfPanel.css

cli/
├── characters/
│   └── roster.js              # Voice descriptions per character
├── fax/
│   ├── buildFaxHTML.js        # Generates the fake fax document
│   └── printFaxTransmission.js
├── cli.js                     # send / fax / characters commands
├── personality.js             # Groq-based character rewriting
├── telegram.js                # Telegram Bot API adapter
└── .env.example

Design Principles

  • Adapter Pattern for channel integrations
  • Loose coupling between routing and delivery providers
  • Failure isolation via Promise.allSettled()
  • Easy extensibility for future channels
  • Single responsibility for each adapter
  • New surface area (CLI, personalities, Telegram, fax) extends the system from the outside — through the same public endpoint, or entirely client-side — rather than growing the deployed backend's responsibilities

A Note on the Joke

The joke in The Office is that nobody actually wants every message delivered through every possible channel.

It's not productivity.

It's noise.

Building WUPHF for real makes that painfully obvious.

The first time a single:

"Running 5 minutes late"

causes:

  • your phone to buzz,
  • your inbox to ping,
  • and Slack to light up,

you'll understand both Michael's excitement and Ryan's business model better than any pitch deck ever could.

"Why send a message one way when you can send it five ways?"

About

A MERN-stack recreation of The Office's WUPHF, fanning out a single message to Slack, email, and SMS through a fault-tolerant adapter architecture.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages