avlogo
Spider
Home
About
WorkSpace
Contact
Book a Call
avlogo

Aviralyadav Aviralyadav

I'm Aviral - a full-stack developer, freelancer & problem solver. Thanks for checking out my site!

Genral

  • Home
  • About Me
  • Projects

Specifics

  • Guest Book
  • Bucket List
  • Uses

Genral

  • Home
  • About Us
  • Projects

Specifics

  • Guest Book
  • Bucket List
  • Uses

Contact

  • Contact Us
  • Links
  • RSS

© 2025 Aviral Yadav. All rights reserved.

Privacy Policy•Terms of Use
Made withCodeForTravel
All Projects

Curated Work / automation-platform

Automation Social Media PlatformAutomation Social Media Platform

One dashboard to automate replies across Instagram, WhatsApp & Telegram.

NEXT.JSREACT.JSTAILWIND CSSPOSTGRESQLPRISMANODE.JSSHADCN/UINEXT AUTHVERCEL
Type
Full-Stack SaaS
Role
Full-Stack Developer
Timeline
2024
Status
Private Project
Automation Social Media Platform screenshot 1
Automation Social Media Platform screenshot 2

Overview

I built a full-stack SaaS platform that collapses Instagram, WhatsApp, and Telegram into a single operational dashboard — one unified inbox, one automation layer, one place to manage every connected account. The hard part was never the UI; it was making three very different messaging APIs behave like one predictable system, delivering webhooks that never double-fire, and running a user-configurable rules engine that can auto-reply, tag, and alert in real time without stepping on itself. Under the hood it's Next.js (App Router) on Vercel, PostgreSQL through Prisma, NextAuth for Google sign-in, and shadcn/ui for a dashboard that stays fast even when a conversation is updating live. This write-up is about the engineering decisions that made "unify three platforms" actually reliable rather than a demo that breaks the first time Meta retries a webhook.

A full-stack automation platform built to streamline social media engagement across Instagram, WhatsApp, and Telegram — intelligent auto-replies, real-time alerts, and secure account access, built to scale.

Key Features

  • Secure Google authentication powered by NextAuth.
  • Cross-platform automation for Instagram, WhatsApp, and Telegram.
  • Real-time alerts for events like Instagram Reel engagement and activity spikes.
  • Modern, accessible UI built with shadcn/ui and responsive layouts.

Why I Built This

Small teams and solo operators run their whole customer conversation across Instagram DMs, WhatsApp, and Telegram at once, and every one of those apps is a separate tab, a separate login, and a separate set of missed messages. I kept watching people lose leads simply because a DM sat unanswered for six hours while they were heads-down in WhatsApp. The problem wasn't effort — it was that no single surface showed them everything, and nothing responded on their behalf when they couldn't.

So I built the thing I wished existed: one inbox that ingests all three channels, plus an automation layer that answers instantly based on rules the user defines. I specifically wanted it to feel trustworthy — no duplicate auto-replies, no messages silently dropped, no shared login that leaks one client's account to another. That reliability bar is what turned this from a weekend CRUD app into a real systems project.

Architecture Overview

The system is a single Next.js App Router application deployed on Vercel, split cleanly into three planes: an auth-gated dashboard, a set of thin webhook/API route handlers, and a domain library where all the real logic lives. Every inbound message from Instagram, WhatsApp, or Telegram is funneled through provider-specific adapters into one normalized Message shape, so the rules engine, the inbox, and the alerting layer never have to know which platform a message came from. PostgreSQL (via Prisma) is the source of truth for accounts, conversations, messages, rules, and the dedupe/outbox tables that keep ingestion honest.

src/
  app/
    (dashboard)/
      inbox/            # unified live conversation view
      automations/      # visual rules builder
      accounts/         # connect / manage channels
      layout.tsx        # NextAuth-gated shell
    api/
      webhooks/
        meta/route.ts        # IG + WhatsApp (shared Meta HMAC)
        telegram/route.ts     # secret-token verified
      auth/[...nextauth]/route.ts
      realtime/route.ts        # mints scoped pub/sub tokens
  lib/
    channels/           # adapters -> normalized Message
      instagram.ts
      whatsapp.ts
      telegram.ts
    rules/
      engine.ts         # evaluate(rules, message)
      conditions.ts     # keyword, first-touch, hours, sender
      actions.ts        # reply / tag / alert / forward
    ingest.ts           # persist + dedupe raw events
    queue.ts            # outbox enqueue + worker dispatch
    crypto.ts           # provider-token encryption
    prisma.ts
prisma/
  schema.prisma
  • Frontend Next.js App Router with React Server Components for the initial inbox render, shadcn/ui + Tailwind for the component system, and a thin client subscription that patches conversations live without re-fetching the whole thread.
  • API surface Route handlers stay deliberately dumb — they verify the signature, persist the raw event, and return 200 fast. Every non-trivial decision happens downstream in lib/, which keeps handlers within Vercel's serverless time budget.
  • Data layer PostgreSQL through Prisma, with the schema modeling User → Account → Conversation → Message plus Rule, ProcessedEvent (idempotency), and OutboxJob tables.
  • Auth NextAuth with the Google provider for human login to the dashboard; per-channel provider tokens (Meta/Telegram) are stored separately and encrypted at rest, never mixed with the session layer.
  • Realtime A hosted pub/sub service carries live inbox and alert events, because Vercel serverless functions can't hold persistent socket connections — the app mints short-lived, channel-scoped subscription tokens per user.

Webhook Ingestion & Idempotency

Meta, WhatsApp Cloud API, and Telegram all deliver via webhooks, and all three will happily send you the same event more than once — on retry, on redelivery, or when a subscription overlaps. If I processed inline and naively, a single customer message could fire two auto-replies. So the ingestion path is built around one rule: acknowledge fast, dedupe hard, process later.

Each handler first verifies authenticity — Meta events are validated against the X-Hub-Signature-256 HMAC using the app secret, and Telegram against the secret token header I register with setWebhook. Only then does it write the raw payload and return 200 immediately. The actual work is deferred to an outbox-driven worker so a slow rule evaluation can never blow the serverless timeout and trigger a redelivery storm.

  • Dedupe key Every event carries a provider message/update ID; I insert it into a ProcessedEvent table with a UNIQUE constraint. A duplicate insert throws, I catch it, and the event is skipped — the database, not application logic, is the source of truth for 'have I seen this.'
  • Persist-then-process Raw events land in an OutboxJob row before any business logic runs, so a crash mid-processing loses nothing; the worker picks the job back up on the next tick.
  • Fast ack Handlers return 200 in well under a second, which is what keeps Meta and Telegram from marking the endpoint unhealthy and backing off deliveries.
  • At-least-once, effectively-once I assume delivery is at-least-once and lean on the unique constraint + idempotent actions to make the observable result exactly-once, which is the honest way to handle webhooks you don't control.

The Rules Engine & Real-Time Alerts

The automation layer is a small rules engine that evaluates a user's rules against the normalized Message and produces actions. Rules are stored as structured JSON in Postgres, so users build them in the dashboard without me shipping code — each rule is an ordered set of conditions (keyword/regex match, first-message-from-sender, outside business hours, sender attributes) and actions (send a templated reply, tag the conversation, forward, or raise an alert). The engine evaluates in priority order and supports both first-match and match-all modes, so a catch-all fallback rule never shadows a specific one.

Because the same normalized shape feeds the engine regardless of channel, a rule like 'auto-reply with hours + book link on the first WhatsApp message after 6pm' is written once and behaves identically on Instagram or Telegram. When an action is 'alert' — or when a message can't be auto-handled and needs a human — I publish an event to the pub/sub channel scoped to that user, and the dashboard surfaces it live: the inbox reorders, a badge updates, and the operator sees it without refreshing.

  • Declarative rules Conditions and actions are data, not code — evaluated by a pure evaluate(rules, message) function that's trivial to unit-test against fixture messages.
  • Idempotent actions Auto-reply actions are keyed to the triggering event ID so a replayed webhook can't double-send, closing the loop with the ingestion layer's dedupe.
  • Scoped realtime Pub/sub channels are namespaced per user and per account, so a live alert only ever reaches the operator who owns that conversation.

Backend Systems

The backend is intentionally boring in the good way: a well-normalized relational schema, a single query layer through Prisma, and a strict separation between who-you-are (NextAuth session) and what-you-can-act-on (connected provider accounts). Multi-account access is the load-bearing feature here — a user can connect several Instagram, WhatsApp, and Telegram accounts, and every conversation, message, and rule is foreign-keyed to a specific Account that is in turn owned by a User. That ownership chain is enforced on every read and write, so there's no path where one account's data leaks into another's view.

  • Relational modeling User → Account → Conversation → Message as the spine, with Rule, ProcessedEvent, and OutboxJob as supporting tables; Prisma migrations keep the schema versioned and reproducible across environments.
  • Secure multi-account Provider access tokens live in their own encrypted column (via lib/crypto), decrypted only at send-time — a leaked session can't hand an attacker the underlying channel credentials.
  • Query safety Every Prisma query is scoped by the authenticated user's ID at the boundary, so authorization is a property of the data-access layer rather than something each route has to remember to check.
  • Outbound sends Replies fan back out through the same channel adapters that ingested them, so the send path reuses one place per provider for auth, formatting, and error handling.

Key Decisions

  • Prisma over raw SQL The relationship graph (users, accounts, conversations, messages, rules) changes often as features land; Prisma's typed client + migrations caught schema drift at compile time and made the ownership joins readable. I accepted a bit of query overhead in exchange for that safety.
  • Persist-then-process over inline handling Doing rule evaluation inside the webhook handler was simpler but fragile — one slow action and Vercel times out and Meta retries. Writing to an outbox and returning 200 immediately decoupled 'received' from 'handled' and killed an entire class of duplicate-delivery bugs.
  • Database-enforced idempotency over app-level checks A UNIQUE constraint on the provider event ID is impossible to race; an in-memory 'have I seen this' check isn't, especially across serverless instances. I let Postgres be the arbiter.
  • One normalized Message shape over per-channel logic Adapters absorb every quirk of Instagram, WhatsApp, and Telegram at the edge, so the rules engine, inbox, and alerts are written once. Adding a fourth channel later becomes 'write an adapter,' not 'touch everything.'
  • JSON rule definitions over hardcoded flows Users configure automations without a deploy. Rules-as-data made the engine a pure, testable function and turned automation into a product surface instead of a code change.
  • Hosted pub/sub over serverless WebSockets Vercel functions can't hold long-lived connections, so rather than fight the platform I offloaded realtime to a managed pub/sub and minted short-lived scoped tokens — reliable live updates without running my own socket infrastructure.

What I Learned

  • Webhooks are at-least-once, always You cannot trust an external platform to deliver exactly once. Designing every handler to be safely replayable — and letting the database enforce it — was the single biggest reliability unlock.
  • Normalize at the edge Pushing all provider weirdness into thin adapters kept the core of the system clean and made testing dramatically easier, because the whole engine runs on plain fixture objects.
  • Work with the platform's grain Fighting Vercel's serverless model on realtime and long-running work was a losing game; leaning into fast-ack + outbox + hosted pub/sub gave me a more robust system with less code to own.
  • Authorization belongs in the data layer Scoping every query by owner at the boundary — instead of remembering to check in each route — made multi-account isolation a structural guarantee rather than a discipline I had to maintain by hand.

Tech Stack

NEXT.JSREACT.JSTAILWIND CSSPOSTGRESQLPRISMANODE.JSSHADCN/UINEXT AUTHVERCEL

Like what you see?

Explore more work or get in touch.

More ProjectsGet in Touch