Devlog 3: XenoDeal | The Bots Assemble
June 23
At LAST Phase 2 is done. Alerts are firing, deals are in the works, and the Telegram bot is notifying me about jerseys and iPhones. So, I decided to step things up a notch by starting Phase 3, which adds multi-user support. It was (again) buns.
The Great Architecture Debate
After I completed Phase 2, the following question arose: how can i make this shippable? Right now, XenoDeal is just a self hosted, single user, lightweight app. It connects to one WhatsApp number and one Telegram chat. That’s not something anyone can just… test.
My first solution was to set up multi-client/user support. One wwebjs Client per user, managed by a clientPool.js session manager. Everyone can make themselves an instance, have their own group selection, while not having to worry about hosting.
The good news is that the classifier, deals table, and alert system remain unchanged. The only required adjustment was in the WhatsApp layer: a Map<chatId, Client> instead of one hardcoded client, with a spawnClient(chatId) function. Every event handler references the user’s chatId via closure to know which subscriber it belongs to. No global state, no complex routing logic. Clean.
The new onboarding flow is as follows:
- User DMs
/start - Bot asks for their WhatsApp number
- They reply with it
-
spawnClient(chatId, phone)is called - wwebjs emits
qr, we callrequestPairingCode(phone)instead of sending a QR image - User receives a code like
ABCD-1234, enters it in WhatsApp → Linked Devices - Connected ✅
No QR image needed, no ENV finagling, nothing. Just a string to type in, which is MILES better UX for a bot.
New tables added: subscribers, user_groups. New column: messages.subscriber_id. New files: clientPool.js, state.js, commands.js. Old single-client init: deleted.
Bugzilla: The Sequel (Speed Round)
Here’s another speed round of the issues I faced today; roughly the same amount as yesterday:
1. “Houston! We have an IPv6 Problem…”
-
Problem:
bot.launch()was timing out during thegetMehandshake with Telegram at random. Worked sometimes, failed other times. - **Fix:**Added
require('dns').setDefaultResultOrder('ipv4first')onindex.js, plus akeepAliveHTTPS agent on the Telegraf instance.
2. “Silent Treatment”
-
Problem: Bot received
/start, asked for phone number, user replied… and you get ghosted. -
Fix: One missing
String()cast in/start. Took way too long to find.
3. “The Ghost of Chromium Past”
- Problem: Previous test run left a Chromium process hanging. Next launch: “The browser is already running for auth_data/session-7145622406.”
-
Fix:
pkill -f chromium+ delete the session folder.
4. “t”
-
Problem:
requestPairingCodethrew a single-letter minified error:t. No stack trace, no message. Just…t. -
Fix: Drop the alpha version, and pin the stable
2.3000.1017054665instead.
5. “The Error in the Error Handler’s House”
- Problem: After bug 4 threw, the catch block tried to DM the user an error message. That also timed out, with the SAME cold IPv6 issue, firing during Chromium’s initial page load which was already hammering the event loop.
-
Fix: Wrapped the notification send in its own
try/catch. A failed notification shouldn’t throw an unhandled rejection on top of the original error.
What’s Next
-
Finish commands:
/addgroup,/threshold,/categories,/status,/deals -
restoreAllSessions(): reconnect everyone on process restart -
messageHandler.js: wire live capture per subscriber -
sendDealAlert(): fan-out to all matching subscribers - Sold detection
- Dashboard post-ship
- First public ship
“We keep going.” — Me, after every bug today
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.