New
Apps 1,895Makers 1,890This week 1,690
Promote your app−30%
3views in
the last 30 days

Codeback

Instagram DM customer intelligence and lead qualification SaaS

Built with Claude Code

by dev-mubassir · Unclaimed · from INIndia · added Oct 29, 2026
no ratings0 comments

Codeback — Generalized AI Instagram DM Customer Intelligence & Sales SaaS

Codeback is a generalized, high-performance Instagram DM Customer Intelligence, Lead Qualification, Sales & Support SaaS. Built for Video & Photo Editors, Product Sellers, Used Phone/Laptop Sellers, Clothing & Fashion Boutiques, Agencies, Freelancers, Coaches, E-commerce, and Content Creators.

Codeback syncs incoming Direct Messages via signature-verified Meta webhooks, qualifies hot commercial leads, filters spam and threats, extracts sponsorship deals, and drafts replies using only the business facts the owner entered. Replies are drafted, never sent, unless the tenant explicitly opts in — see Reply modes.


🏛️ System Architecture

┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                       Next.js 16 App Router                                      │
│                             (Cloudflare-Inspired SaaS Light Interface)                           │
│                                                                                                  │
│ ┌──────────────┐ ┌───────────┐ ┌───────────────┐ ┌──────────────┐ ┌─────────────┐ ┌────────────┐ │
│ │  AppShell    │ │ Dashboard │ │ 3-Column Inbox│ │ Onboarding   │ │ Settings KB │ │ Profile    │ │
│ └──────────────┘ └───────────┘ └───────────────┘ └──────────────┘ └─────────────┘ └────────────┘ │
└───────────────────────────────────────────────┬──────────────────────────────────────────────────┘
                                                │ REST API + Socket.io Real-time
┌───────────────────────────────────────────────▼──────────────────────────────────────────────────┐
│                                    Node.js Express Backend                                       │
│                                                                                                  │
│ ┌────────────────────────┐ ┌───────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ │
│ │ Email/Pass Auth & OAuth│ │ Webhook Handler (HMAC)│ │ Socket.io Server    │ │ Account Deletion│ │
│ └────────────────────────┘ └───────────────────────┘ └─────────────────────┘ └─────────────────┘ │
└───────────────────────────┬─────────────────────────────────────────┬────────────────────────────┘
                            │                                         │
┌───────────────────────────▼──────────┐ ┌────────────────────────────▼────────────────────────────┐
│ PostgreSQL (Prisma ORM + migrations) │ │ Token-Optimized AI Engine & Real-time Synchronization    │
│ • Persistent Business Profile Context│ │ • Real-time Active Chat Stream Appending                │
│ • AES-256-GCM Encrypted IG Tokens    │ │ • Live Smart Folder Counter Badges                      │
│ • Strict Tenant & Session Isolation  │ │ • Non-Business Summary Suppression (0 AI Calls)        │
│ • Cascading Message/Account Deletion │ │ • Anti-Loop Pacing + Per-Conversation Send Claim         │
└──────────────────────────────────────┘ └─────────────────────────────────────────────────────────┘

✨ Core SaaS Features

1. ⚡ Live Real-Time Chat Updates & Smart Folder Synchronization

  • Active Open Chat Live Streaming: When reading an open chat thread, new incoming customer DMs are appended to the screen in real time (0ms delay) with auto-scroll and instant read status synchronization via Socket.io.
  • Real-Time Smart Folder Counter Badges: The sidebar folders display live numeric badges that update the moment a message or a new classification arrives, with no page refresh.
  • Folder matching (matchesFolder):
    • All / Unread: everything, or unread: true.
    • Needs your reply: needsAttention, needsHuman, critical/high priority, or priorityScore >= 70. This folder absorbed the old Needs Human folder, which matched a strict subset of the same conversations under a second name.
    • Hot leads: hot_lead category, purchaseIntent >= 80, or hot-lead customer type.
    • Leads and questions: every commercial inquiry — services, products, pricing, availability, delivery.
    • Customers: returning buyers.
    • General questions / Support: FAQs, and after-sales or delivery follow-ups.
    • Brand deals: sponsorships and collaborations, which are one concept in the UI.
    • Spam and scams: filtered bots, phishing, and abuse.
  • Folder icons come from the shared SVG set (app/components/Icon.js), not emoji.

2. 🔐 Email & Password Authentication + Dynamic Onboarding

  • Independent Application Auth: Standard signup, login, and robust session termination (POST /auth/logout) with bcryptjs password hashing and secure session cookies (codeback.sid).
  • Interactive Onboarding Wizard (/onboarding): 3-step setup with pre-filled, production-ready knowledge templates for 12 business categories (Video Editor, Used Devices, Clothing Boutique, Freelancer, Agency, Coach, Creator, Photo Editor, Graphic Designer, Product Seller, Local Business, E-commerce), plus a clean custom template for other.
  • Persistent Business Profile (BusinessProfile): Ground-truth context storing business name, categories, products/services, pricing rates, turnaround times, shipping coverage, payment methods, FAQs, and tone.

3. 🔒 Reply Modes (Fail-Closed by Default)

Three stored modes on BusinessProfile.autoReplyMode, and only smart can ever send a message:

Stored value Shown as Behaviour
human_only (schema default) Manual Nothing is ever sent. Every reply is written and sent by the owner.
suggest_only Suggested replies A draft is prepared; nothing leaves until the owner sends it.
smart Automatic Safe pricing, product, and service questions are answered on the owner's behalf.
  • Fails closed. effectiveReplyMode() in jobs/messageAnalysisJob.js is the single source for both gates. A user with no BusinessProfile row — or an unsaved one — resolves to human_only, never smart. Both gates previously used || 'smart', which inverted the schema default for exactly the accounts least likely to have finished setup: brand-new signups and reviewer test accounts. Anything that is not the literal string smart means do not send, so an empty or unrecognised value fails closed too.
  • Every surface reads the stored mode. The dashboard states it outright, the inbox compose footer changes with it, and the account page shows the real value. No screen asserts a fixed claim about sending.
  • The analysis pipeline runs in all three modes — classification, priority scoring, brand-deal extraction, summaries, notifications, live inbox updates. Only the send is withheld.

4. 🤖 Conversational Intelligence & Anti-Loop Pacing

  • Anti-Loop Acknowledgment Guard: Automatically detects short closing/acknowledgment replies (ok, thanks, got it, sure, cool, noted, will check, bye) and skips auto-replying so AI never traps customers in an endless conversation loop.
  • Consecutive Auto-Reply Cap (Max 2 in a row): Limits AI to at most 2 consecutive auto-responses without a human reply. If the customer continues asking further follow-ups, AI cleanly steps aside, flags needsHuman: true, and alerts the business owner for personal handling.
  • Daily Rate Limiting (Max 3 auto-replies / 24 hours per chat): Enforces a strict daily ceiling per conversation thread.

5. ⚡ Processing Cost Optimization (Keyword Pre-Filter)

  • No provider call on non-business or spam messages: If an incoming DM is not related to business, products, services, deals, or pricing (e.g. spam, scam, abusive, casual emoji/fan compliments), the system completely suppresses secondary Gemini/AI summary calls (0 extra API calls and 0 token cost).
  • Last 3 Messages Compact Summary: When summarizing valid customer inquiries, AI only analyzes the last 3 messages instead of large chat histories, slashing token consumption by up to 80%.

6. 📥 3-Column Structured Inbox & Smart CRM (/inbox)

  • Column 1 (Dedicated Filter Sidebar): Vertically stacks Connected Accounts and Smart Inbox Folders with live real-time count badges, plus a bottom-left user Profile link.
  • Column 2 (Squeezed Conversation List Panel): 300px min-width list showing contact avatar, 24h window radar dot, name & timestamp pushed to opposite ends, single-line ellipsis message preview (white-space: nowrap), and wrapped commercial badges.
  • Column 3 (Main Chat Workspace): Collapsible Conversation insights panel (lead quality, buying intent, suggested next step, summary), a live 24-hour messaging-window countdown, the message stream, and the reply composer.
  • Clear messages & delete conversation: DELETE /api/conversations/:id/messages clears history while keeping the contact and settings; DELETE /api/conversations/:id removes the thread and everything cascading from it.

7. 🛡️ Multi-Tenant Data Isolation & Security Hardening

  • Socket.io Handshake Session Authentication: Mounts express-session directly on io.engine.use(sessionMiddleware). Sockets are authenticated via socket.request.session.userId and auto-joined to user:${userId} on connection. Unauthenticated sockets and cross-tenant room join attempts are strictly rejected.
  • Socket Force-Disconnect on Logout: disconnectUserSockets(userId) terminates all active real-time connections when a user session is destroyed.
  • Disconnected Instagram Account Safety: Webhooks for disconnected accounts are cleanly skipped and logged without mutating state.
  • Account Re-Link Refusal: Completing OAuth for an Instagram account that already holds conversation history under another workspace is refused with 409 and audit-logged (ACCOUNT_RELINK_BLOCKED). Ownership — and therefore every contact, conversation, and message — never transfers silently. Accounts with no history may transfer, and that too is audit-logged. The earlier guard only counted BrandDeal rows, so an account with thousands of DMs and no sponsorship deal moved between tenants unnoticed.
  • OAuth CSRF state: GET /auth/instagram issues a 32-byte single-use state, stored on the session and verified with a timing-safe comparison before any token exchange with Meta. It is consumed whether or not it matches, so it can never be replayed, and expires after 10 minutes.
  • No Mock-OAuth Backdoor: The test_code_ / mock_short_token_ / mock_long_token_ short-circuits were removed outright, not gated behind an environment flag. They previously minted a token and profile for an arbitrary Instagram user id with no call to Meta whenever NODE_ENV !== 'production'.
  • Production Webhook Signature Gates: Structural code-level gates ensure webhook signature verification can never be bypassed in production (NODE_ENV=production), and requests are rejected outright if INSTAGRAM_APP_SECRET is unset.

8. 🔒 Application Security Hardening

  • Session-Only Authentication: Identity is derived exclusively from the server-side session — no client-supplied user_id is ever trusted (a former debug fallback that allowed account takeover by id was removed).
  • Session Regeneration on Every Privilege Transition: Login, registration, OAuth completion, and admin elevation all issue a new session id via lib/session.js. Writing userId onto the session id the client already presented allowed session fixation — an attacker who planted a valid signed cookie rode the victim's login. Admin elevation deliberately carries an existing user session across the regeneration so opening the admin panel does not log a signed-in user out of the main app.
  • Hardened Admin Access: Admins are admin_users rows created by backend/scripts/create-admin.js (see ADMIN.md) — no admin credential lives in the environment. Separate admin session (siffty.admin.sid, 30 min idle / 8 h absolute), Argon2id, lockout, password re-entry for destructive actions, a written reason and an audit row for every change, and a generic 404 to anyone who is not an admin. There is no impersonation and no DM viewer.
  • No Secret Leakage: passwordHash and access tokens are stripped from all API responses (sanitizeUser).
  • Strict CORS + CSRF Defense: Credentialed requests are limited to an explicit origin allowlist (no wildcard reflection), a cross-origin request guard protects all state-changing routes, and session cookies use SameSite=lax.
  • Security Headers & Rate Limiting: CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and HSTS (production) on every response; in-memory rate limiting on auth and admin-login endpoints.
  • Fail-Closed Secrets: In production the server refuses to start with an unset/default SESSION_SECRET, or a missing INSTAGRAM_APP_SECRET; token encryption uses a dedicated TOKEN_ENCRYPTION_KEY and never a public default.

9. 🔁 Concurrency & Duplicate-Send Protection

  • Per-Conversation Auto-Reply Claim: The auto-reply gate counts prior replies, awaits an AI call, then sends — a read-then-act sequence spanning an await. Workers take an atomic claim (Conversation.autoReplyClaimedAt, a conditional updateMany) before counting anything, so two concurrent analysis jobs can no longer both pass the consecutive/daily guards and both send a DM to the same real customer. Worker concurrency is 3, so this fired on a single instance. The claim expires after 2 minutes, so a crashed worker cannot wedge a conversation.
  • Atomic Analysis Writes: The AIAnalysis insert, the conversation's denormalized fields, and the message status are written in one $transaction. A crash mid-pipeline previously left an analysis row whose conclusions the conversation never adopted and a message stuck in processing forever.
  • Stalled-Analysis Sweeper: Messages left in processing by a dead worker are reset to pending every 5 minutes so they are re-analyzed rather than silently never classified.
  • Race-Free Get-or-Create: BusinessProfile, CreatorPreference, and Subscription use upsert, and BrandDeal.conversationId is now @unique with P2002 recovery — concurrent analyses can no longer create two deals for one conversation, nor fire duplicate notifications.

10. 📜 Legal Surfaces, Retention & Data Deletion

  • Public Legal Pages: /privacy, /terms, and /data-deletion are statically prerendered, reachable without logging in, and linked from the landing-page footer — the surfaces Meta App Review requires.
  • Meta Data Deletion Callback: POST /data-deletion/instagram implements Meta's signed_request contract, verifying the HMAC-SHA256 signature with a timing-safe comparison before deleting anything, and replying with the required { url, confirmation_code }. A forged secret or a tampered payload deletes nothing.
  • 30-Day Webhook Payload Retention: WebhookLog.payload contains customers' raw message text. A scheduled job nulls it 30 days after receipt and keeps the non-content metadata row. Previously the only cleanup was a manual admin button, so these bodies were retained indefinitely.
  • Deletion Actually Deletes: WebhookLog now cascades on account deletion instead of SetNull. Orphaned rows used to survive account deletion with customers' DM text intact, contradicting what DELETE /auth/account promises and what the privacy policy now states.

11. 🔤 Product Copy & Display Layer

Every human-readable string comes from one place, and no raw stored value reaches a screen.

Module Holds
frontend/src/content/copy.js Static UI strings grouped by surface — common, nav, dashboard, inbox, settings, account, auth, admin, errors, empty, toast, confirm, validation, meta
frontend/src/content/labels.js Display mapping for every enum, with a title-casing fallback so a value added to the backend before it is added here renders as "Hot Lead", never as raw hot_lead
frontend/src/content/templates.js The thirteen starter business profiles, structurally parallel: same fields in the same order, four services, three priced lines, three FAQs each
frontend/src/content/format.js One date format (29 Aug 2026), one currency format, correct pluralisation, and percentage suppression below a minimum sample size
frontend/src/content/contact.js The public support address. Throws during a production build if NEXT_PUBLIC_SUPPORT_EMAIL is unset
  • Storage and API payloads are unchanged. hot_lead, IGNORE_SPAM, human_only, NEEDS_RECONNECT and the rest stay exactly as written by the backend; only what a person sees changed.
  • Analytics endpoints return keys and counts, not display strings. GET /api/analytics/summary sends categoryMetrics with icon names and label keys; the frontend decides wording.
  • Card labels must match the query. autoRepliesSent counts direction: 'outbound', aiStatus: 'auto_replied' — the status written at the moment a message is actually delivered to Instagram. It previously counted aiStatus: 'completed', which marks an inbound message as classified, so a manual-mode account saw a large "AI Auto-Replied" number next to screens stating nothing is ever sent.
  • Percentages state their denominator and are suppressed below 10 conversations, because "100%" of one conversation is noise.
  • Emoji are not UI furniture. Icons come from app/components/Icon.js. Emoji survive only inside content a user typed.
  • AI prompts carry an output-style contract governing length, tense, register, and forbidden vocabulary, plus real fallback copy for failure and timeout. Instructions only — no model, schema, or parameter changes.

🛠️ Technology Stack

Layer Technologies
Frontend Next.js 16 (App Router), React 19, Vanilla CSS Modules & Tokens, Axios, Socket.io-client
Backend API Node.js v24, Express v4.21, Socket.io v4.8, Bcryptjs, Cookie-Parser, Express-Session
Database & ORM PostgreSQL 16 (all environments), Prisma ORM v6.19 with committed migrations
AI Providers Google Gemini (gemini-flash-lite-latest, gemini-flash-latest), Cloudflare Workers AI (@cf/cloudflare/clef-flash for DM classification), xAI Grok (grok-3-mini, grok-2-latest), OpenAI (gpt-4o-mini, gpt-4o)
Cryptography Node.js Crypto (AES-256-GCM, HMAC-SHA256, timing-safe comparison)
Testing Vitest + Supertest (58 tests) against a throwaway PostgreSQL

⚙️ Configuration

Required in every environment

Variable Notes
DATABASE_URL PostgreSQL connection string. The Prisma datasource is postgresql; a file: URL will fail at client construction.
SESSION_SECRET ≥ 32 chars. No fallback — the server refuses to boot without it.
TOKEN_ENCRYPTION_KEY 32-byte hex. Falls back to deriving from SESSION_SECRET, so rotating SESSION_SECRET without this set makes every stored Instagram token undecryptable.
INSTAGRAM_APP_ID / INSTAGRAM_APP_SECRET Required in production; the app secret also authenticates the webhook and the data-deletion callback.
WEBHOOK_VERIFY_TOKEN Meta webhook GET verification.
REDIRECT_URI Must match the Meta dashboard entry exactly, no trailing slash.
FRONTEND_URL / BACKEND_URL Also drive the CORS allowlist.

Text Generation Providers (Groq Cloud + Gemini Fallback)

Text generation (auto-reply, Draft AI reply, conversation summaries) runs on Groq Cloud (openai/gpt-oss-20b) as first-priority with automatic, zero-customer-error fallback to Gemini.

Environment Variables

Variable Default Notes
GROQ_API_KEY (none) Groq API Key (Bearer authentication).
GROQ_TEXT_MODEL openai/gpt-oss-20b Text generation model

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#instagram · #crm · #saas