Sociair
A business operating system built from scratch: social publishing, a unified inbox, e-commerce, calls, support tickets and accounting, all in one window. I worked across the modules rather than one corner of it, and the real-time layer underneath holds steady at fifty thousand events a day.
- Role
- Full-Stack
- Scope
- Modules, system-wide
- Stack
- Vue · Nuxt · Laravel
- Data
- MySQL · WebSocket
- Timeline
- 2024
50K+
real-time, across every module
CONTEXT
A small business in Nepal selling through Facebook and Instagram typically runs on five or six disconnected tools: a scheduler for posts, a separate inbox per platform, a personal phone for customer calls, a spreadsheet for orders, another for stock, and a notebook for deliveries.
Sociair collapses all of that into one window. Social publishing and a unified inbox, a no-code storefront with inventory and order tracking, telephony in the dashboard, support ticketing, and the accounting side: sales and invoicing, purchases and suppliers, financial reports, banking and taxes. The company publishes figures of 2,000+ clients and 1,000+ active users.
I worked across those modules rather than owning one corner, so the work was as much about what they share as what each one does.
THE HARD PART
A dozen modules in one product is a different problem from a dozen small products. A social post, an order, a phone call, a support ticket and an invoice have genuinely different shapes, lifecycles and failure modes, but they all describe the same customer, and the person using them expects the system to know that.
Working across all of them makes the repeated parts the real difficulty. If every module invents its own way to list, filter, paginate, authorise and push live updates, a developer moving between modules relearns the codebase at every stop, and the customer record fragments into a dozen half-copies.
Underneath everything the real-time layer carries 50,000+ events a day, so nothing could be kept current by polling.
WHAT I BUILT
- Chat: a unified inbox pulling messages, comments and DMs from Facebook, Instagram, WhatsApp, Viber and TikTok into one thread model, with search, filter and sort, saved quick replies, and live status indicators.
- Social media: multi-account connection and publish-once fan-out, so a post composed once goes to every connected platform.
- E-commerce: a no-code storefront with inventory, checkout, order tracking and multi-channel selling.
- Calls: telephony inside the dashboard. Place and receive calls, automatic logging of contact, time and duration, live contact tagging mid-call, and follow-ups created straight off the call.
- Tickets: support requests tracked from creation to closure, with prioritisation and real-time status.
- The real-time layer beneath all of it: WebSocket delivery sustaining 50K+ events a day.
- Vue and Nuxt frontend on a Laravel and MySQL backend.
REVISIONS · THE CALLS I MADE
Every module reads the same customer record
An owner has one customer, rather than a social follower, a separate store buyer, a caller and a ticket requester who happen to share a name. Making the customer a shared entity is the whole reason these modules belong in one product. Without it, this is a bundle of tools behind the same login.
One normalised message model, an adapter per channel
Five platforms means five webhook shapes, five auth models, and five ideas of what a conversation is. Pushing that variance out to per-channel adapters means adding Viber or TikTok touches the edge, rather than the thread view an agent stares at all day.
Publishing reuses the chat adapters
Posting is the inbox run backwards: one internal post becomes many platform payloads. Treating outbound as a fan-out over the same per-platform adapters meant social publishing reused the mapping layer chat already needed, instead of a second integration codebase.
One module skeleton, repeated deliberately
Listing, filtering, pagination, permissions and live updates recur in every module. Solving them once and repeating the shape is what made it possible for one developer to move from tickets to calls to commerce without relearning the codebase each time.
WebSocket push as the system-wide default
At this event volume, polling either lags visibly or hammers the database to stay current. Making push the default for every module, not only chat, means a ticket status, a new order and an incoming call all land live without each module inventing its own refresh.
OUTCOME
- Modules shipped across the system: chat, social publishing, e-commerce, calls and tickets, all on a shared customer record.
- Real-time delivery holding steady at 50K+ events a day.
- Five messaging channels arriving in a single thread model.
- 2,000+ clients and 1,000+ active users, per the company’s published figures.