Appearance
Stage 5a: MiniWhatsApp β Local Test Harness π± β
A standalone WhatsApp-lookalike web app that talks to Orbita over HTTP + WebSocket, so we can iterate on real external messaging without touching Meta's API.
Status: β
Complete Lives at: /Users/sajithmr/1box/miniwhatsapp/ (sibling project, NOT inside orbita-core) Plugin: orbita-core/plugins/whatsapp-mock.plugin.tsPort: 4000 (miniwhatsapp) β 3210 (orbita)
Why This Exists β
The hardest part of "real WhatsApp" is iteration speed. You can't fluently debug Meta's Business API β slow approvals, template rules, 24-hour windows, webhooks behind public URLs. So we built a pretend WhatsApp that speaks the same shape:
- Users register with a phone number (any string, no OTP)
- Send messages browser-to-browser via WebSocket
- Orbita sends outbound via
POST /api/send - Orbita receives inbound via webhook
POST /wa-webhook
Swap the plugin's URL later β real WhatsApp works. Core unchanged.
Architecture β
βββββββββββββββββββββββ βββββββββββββββββββββββββ
β MiniWhatsApp :4000 ββββββWSββΊβ Browser chats β
β - server.ts β β - public/index.html β
β - data.json (disk) β β - public/admin.html β
ββββββββββββ¬βββββββββββ βββββββββββββββββββββββββ
β
β POST /wa-webhook (inbound message)
βΌ
βββββββββββββββββββββββ
β Orbita :3210 β
β - whatsapp-mock βββββ watches matching inboxes
β .plugin.ts βββββ POST /api/send (outbound)
β - InboxManager β
βββββββββββββββββββββββEndpoints (miniwhatsapp side) β
| Method | Path | Who calls it | Purpose |
|---|---|---|---|
POST | /api/send | Orbita plugin | Push outbound message (Orbita β a user) |
GET | /api/users | Anyone | List registered users |
GET | /api/messages | Browser UI | History for current thread |
WS | / | Browser UI | Live inbound/outbound events |
GET | / | Browser | Chat UI (public/index.html) |
GET | /admin.html | Browser | Contact admin UI |
Endpoints (orbita side) β
| Method | Path | Who calls it | Purpose |
|---|---|---|---|
POST | /wa-webhook | miniwhatsapp server | Forward incoming browser message into agent's inbox |
The Plugin (whatsapp-mock.plugin.ts) β
Lives in orbita-core/plugins/ and implements the Plugin API from Stage 4b:
typescript
// Maintains a contact book: agentName β phone number
// (stored in its own MongoDB collection, NOT in core)
watch(inbox):
if inboxMsg.toAgent has a phone number mapping:
POST http://localhost:4000/api/send
{ to: phone, text: formatMessage(inboxMsg) }
onWebhook("/wa-webhook"):
resolve phone β agentName via contact book
inbox.send("whatsapp-mock", agentName, "external_message", {...})The plugin OWNS the phoneβagent mapping. The core never sees phone numbers.
Running It β
bash
# Terminal 1 β Orbita core
cd orbita-core
npm start # port 3210
# Terminal 2 β MiniWhatsApp
cd ../miniwhatsapp
npm start # port 4000
# Browsers:
# http://localhost:4000/ β chat as any user
# http://localhost:4000/admin.html β manage contacts
# http://localhost:3210/talk β chat with AxiomOpen multiple incognito windows to simulate multiple people.
Why admin.html exists β
Initial plan was curl-driven contact management. Multi-line curl in zsh kept biting us with quoting. The admin page is a visual form for:
- Register a new user (name + phone)
- Map agent name β phone (this is the plugin's contact book)
- Simulate inbound messages (for testing without a second browser)
What this unblocks β
- Full end-to-end external messaging with zero Meta dependency
- Any number of concurrent "users" (one per browser window)
- Real HTTP + WebSocket transport (no in-memory shortcuts that lie about concurrency)
- Confidence that the Plugin API genuinely handles external systems
- Real WhatsApp is now just a new plugin with the same shape
Not Implemented (by design) β
- β Authentication (any name/number accepted β it's a dev tool)
- β Message encryption
- β Media messages (text-only)
- β Templates / 24h windows (those are Meta-specific)
- β Delivery receipts beyond "received by server"
These belong in 5b-whatsapp (real Meta plugin).