Skip to content

Repository files navigation

πŸ—‚οΈ Deskops AI

The AI back office for small businesses that run on WhatsApp

Deskops AI reads incoming customer messages, grounds itself in the shop's real catalog, stock and ledger, and takes action β€” quoting, invoicing, adjusting inventory and writing the books β€” while every money decision still stops for the owner's approval.

Next.js React TypeScript Vercel AI SDK Supabase

IDEALIZE 2026 β€” Open Category Prototype


Table of Contents


The Problem

A small shop owner's day is not spent running the shop. It's spent on WhatsApp.

"What's the price of this?" Β· "Do you have 20 in stock?" Β· "Can you send me a bill?"

Every one of those messages requires the owner to stop, check a physical shelf or a spreadsheet, do arithmetic in their head, type a reply, and β€” later, if they remember β€” write the sale into a book. Multiply by fifty messages a day.

Generic AI chatbots make this worse, not better. A chatbot that confidently quotes a price it invented, or promises stock the shop doesn't have, costs the owner a customer and their reputation.

Deskops AI is built on the opposite premise: the AI is never allowed to know a number. It has to go and look it up.


What It Does

πŸ“₯ Reads Ingests WhatsApp messages via WAHA webhook, per-business, signature-verified
πŸ” Grounds Retrieves the shop's real catalog, stock levels, customer history and ledger before responding
🧠 Reasons Plans a multi-step tool sequence β€” check stock β†’ look up customer β†’ price the order β†’ draft the invoice
βœ‹ Stops Anything that becomes money queues in Approvals; the owner approves before it's real
πŸ“š Records Stock movements, invoices, ledger entries and audit logs all written automatically

πŸ€– The AI Agent

This is not a chatbot, and not a single-prompt wrapper. It is a tool-calling agent that plans across multiple steps, queries live business data, and writes to the database β€” with a human approval gate on financial actions.

Design: one orchestrator, scoped specialist toolsets

Deskops AI runs a single reasoning loop (the Orchestrator) that is handed different scoped tool groups depending on context. Specialists β€” Inventory, Sales, Customer, Books β€” are capability boundaries, not separate agent processes. This was a deliberate choice: it gives one coherent plan per customer message instead of several agents negotiating with each other, and it keeps token cost and latency inside what a small shop can afford.

flowchart TD
    A["πŸ“± Customer message<br/>(WhatsApp)"] --> B["WAHA webhook<br/>HMAC verified"]
    B --> C["Job queue<br/>(idempotent, deduped)"]
    C --> D["🧠 Orchestrator<br/>runOrchestrator()"]

    D --> E["RAG grounding<br/>retrieveContext()"]
    E --> D

    D --> T{"Tool loop<br/>max 6 steps"}

    T --> T1["πŸ“¦ Inventory<br/>checkStock"]
    T --> T2["πŸ‘€ Customer<br/>lookupCustomer<br/>getCustomerContext<br/>saveCustomerDetails"]
    T --> T3["πŸ’° Sales<br/>draftAndQueueInvoice<br/>reviseInvoice Β· cancelInvoice<br/>sendProductImage Β· escalateToOwner"]
    T --> T4["πŸ“Š Books<br/>getBooksSnapshot"]

    T1 & T2 & T3 & T4 --> DB[("πŸ—„οΈ Supabase<br/>Postgres + RLS")]
    DB --> T

    T --> R["✍️ Reply drafted"]
    T --> AP["⏸️ Approvals queue<br/>(money actions)"]
    AP --> O["πŸ‘” Owner approves"]
    R --> W["πŸ“€ Sent to customer"]
    O --> W

    style D fill:#4f46e5,color:#fff
    style AP fill:#f59e0b,color:#000
    style DB fill:#3FCF8E,color:#000
Loading

The tools it can actually call

Every tool is a real, typed, Zod-validated function that hits Postgres. None of them are stubs.

Tool Group What it does
checkStock Inventory Real stock levels and prices from the catalog
lookupCustomer Customer Find a customer by WhatsApp number + order history
getCustomerContext Customer Pull conversation and relationship context
saveCustomerDetails Customer Persist name, address, phone as they're learned
draftAndQueueInvoice Sales Build an invoice from catalog prices β†’ queue for approval
reviseInvoice Sales Replace the full item list when the customer changes their order
cancelInvoice Sales Void an unpaid invoice on cancellation
sendProductImage Sales Send catalog imagery into the chat
escalateToOwner Sales Hand off to a human when the agent shouldn't decide
getBooksSnapshot Books Income/expense totals computed from the real ledger

Sales tools are only mounted when the run is bound to a real conversation β€” the agent physically cannot draft an invoice outside a customer chat.

Worked example β€” input β†’ steps β†’ output

πŸ“₯ INPUT

"Hi, do you have 20 ceramic mugs? What is the price?"

βš™οΈ STEPS
  1. Webhook β†’ queue. Message deduped against webhook_events, enqueued as a job.
  2. Ground. retrieveContext() pulls the top 6 relevant business documents into the system prompt.
  3. Plan. Orchestrator determines this needs stock verification and a quote.
  4. Tool call β†’ checkStock({ query: "ceramic mug" }) β†’ real stock count and unit price from products.
  5. Tool call β†’ lookupCustomer({ phone }) β†’ returning customer? prior orders?
  6. Tool call β†’ draftAndQueueInvoice({ items }) β†’ totals computed in TypeScript, not by the model β†’ row written to approvals with status pending.
  7. Log. Token usage written to model_usage; the action lands in audit_logs.
πŸ“€ OUTPUT

A grounded reply to the customer with true stock and true pricing β€” plus an invoice sitting in the owner's Approvals queue. On approval: stock_movements adjusts inventory, ledger_entries books the sale, and the dashboard updates in realtime.

Why this qualifies as an agent

Requirement How Deskops AI satisfies it
Tool use 10 typed tools with Zod schemas, all hitting live Postgres
Multi-step workflow stopWhen: stepCountIs(6) β€” the loop chains tool calls and re-reasons on each result
Decision-making Chooses which specialists to engage from the message alone; decides when to escalate vs. act
Memory Conversation history, persisted customer profiles, and RAG retrieval over business documents
Planning Sequences dependent calls β€” stock must resolve before an invoice can be priced
Real consequences Writes invoices, moves stock, books ledger entries β€” not a simulated demo path

Guardrails & Responsible AI

Implemented in src/lib/ai/guardrails.ts and enforced at the tool layer:

Guardrail Implementation
πŸ”’ The model never does arithmetic Every total is computed in TypeScript from catalog prices. verifyAmountAgainstSource() rejects any figure the model echoes that doesn't match the database.
βœ‹ Human-in-the-loop on money draftAndQueueInvoice writes to approvals with pending status. Nothing financial executes without owner action.
πŸ”’ PII redaction redactPii() strips phone numbers and emails before any text reaches a log line or model trace.
🏒 Tenant isolation Row Level Security on every table β€” enforced by Postgres, not application code.
🚦 Abuse protection Upstash rate limiting on agent endpoints.
βœ… Webhook authenticity HMAC signature verification on every WAHA inbound event.
πŸ“Š Cost transparency Per-business token accounting in model_usage.

Tech Stack

Layer Technology Why
Framework Next.js 16.2 (App Router) Β· React 19.2 Server Components + Route Handlers in one deployable
Language TypeScript 5 Tool schemas are typed end to end
Agent runtime Vercel AI SDK 7 (ai) Provider-agnostic tool calling and streaming
Models Google Gemini (default) Β· OpenAI Β· Anthropic Claude Β· Groq Swappable per business in Settings β€” no code change
Database Supabase (Postgres + RLS + Realtime) Multi-tenant isolation enforced at the database
Vector search pgvector via embeddings / documents RAG grounding over business data
WhatsApp WAHA Self-hostable WhatsApp HTTP API
Jobs Supabase pg_cron β†’ worker route Async agent runs + daily insight generation
Rate limiting Upstash Redis Serverless-native
Data fetching TanStack Query 5 Cache + realtime invalidation
UI Tailwind v4 Β· shadcn/ui Β· Radix Β· Base UI Β· HugeIcons Accessible primitives
Charts / Motion Recharts Β· GSAP Β· Lenis Dashboard analytics and landing page
Validation Zod 4 Tool input schemas and API boundaries
Hosting Vercel Native Next.js + cron support

System Architecture

flowchart LR
    subgraph Client["πŸ–₯️ Dashboard"]
        UI["Next.js App Router<br/>React Server Components"]
        TQ["TanStack Query<br/>+ Supabase Realtime"]
    end

    subgraph Edge["⚑ API Layer"]
        WH["/api/waha/webhook"]
        AG["/api/agent/run"]
        CP["/api/copilot"]
        JW["/api/jobs/worker"]
        REST["/api/products Β· invoices<br/>customers Β· books Β· approvals"]
    end

    subgraph Brain["🧠 Agent Layer"]
        OR["Orchestrator"]
        TL["Tool Layer"]
        RAG["RAG Retrieval"]
        GR["Guardrails"]
    end

    subgraph Data["πŸ—„οΈ Supabase"]
        PG[("Postgres + RLS")]
        RT["Realtime"]
        CRON["pg_cron"]
    end

    WA["πŸ“± WhatsApp<br/>via WAHA"] <--> WH
    UI --> REST --> PG
    UI --> CP --> OR
    WH --> JW --> OR
    AG --> OR
    OR <--> TL <--> PG
    OR <--> RAG <--> PG
    OR --> GR
    CRON --> JW
    RT --> TQ --> UI

    style OR fill:#4f46e5,color:#fff
    style PG fill:#3FCF8E,color:#000
Loading

Message lifecycle: WhatsApp β†’ WAHA β†’ signature-verified webhook β†’ deduped job β†’ orchestrator β†’ RAG grounding β†’ tool loop β†’ reply + approval queue β†’ owner action β†’ stock/ledger writes β†’ realtime dashboard update.


Data Model

21 tables, Row Level Security enabled on every one, scoped by business_id.

Expand full table list
Domain Tables
Tenancy businesses Β· business_members
Messaging conversations Β· messages Β· webhook_events
Catalog products Β· product_categories Β· suppliers
Inventory stock_movements Β· reorders
Sales invoices Β· invoice_items Β· payments Β· customers
Accounting ledger_entries
Agent approvals Β· jobs Β· model_usage Β· daily_insights
RAG documents Β· embeddings
Audit audit_logs

Migrations live in supabase/migrations/ and run in order.


Getting Started

Prerequisites

  • Node.js 20+
  • Supabase project (supabase.com) or local CLI
  • WAHA instance for WhatsApp (waha.devlike.pro) β€” optional for dashboard-only development
  • At least one AI provider API key (Gemini is the default and has a free tier)

1. Clone and install

git clone https://github.com/<your-org>/deskops-ai.git
cd deskops-ai
npm install

2. Configure environment

cp .env.example .env.local
Variable Required Purpose
NEXT_PUBLIC_SUPABASE_URL βœ… Supabase project URL
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY βœ… Client-side anon key
SUPABASE_SERVICE_ROLE_KEY βœ… Server-side admin operations
GEMINI_API_KEY βšͺ️ Default provider
OPENAI_API_KEY βšͺ️ Alternative provider
ANTHROPIC_API_KEY βšͺ️ Alternative provider
GROQ_API_KEY βšͺ️ Alternative provider
AI_PROVIDER βšͺ️ Fallback provider β€” google | openai | anthropic | groq
WAHA_BASE_URL βšͺ️ WAHA instance URL
WAHA_API_KEY βšͺ️ WAHA authentication
WAHA_WEBHOOK_SECRET βšͺ️ HMAC secret for inbound webhook verification
CRON_SECRET βšͺ️ Bearer token guarding the job worker route
UPSTASH_REDIS_REST_URL βšͺ️ Rate limiting
UPSTASH_REDIS_REST_TOKEN βšͺ️ Rate limiting

⚠️ At least one provider key is required for the agent to run. API keys stay in the environment β€” users select a provider in Settings, they never paste keys into the app.

3. Apply migrations

supabase link --project-ref <your-project-ref>
supabase db push

4. Run

npm run dev

β†’ http://localhost:3000

5. Onboard

Sign up, complete onboarding to create your business, then add products under Products. The agent has nothing to ground itself in until the catalog exists.

6. Connect WhatsApp (optional)

  1. Start a WAHA session and note the session name
  2. Set the session on your business record
  3. Point the WAHA webhook at https://<your-domain>/api/waha/webhook
  4. Set WAHA_WEBHOOK_SECRET on both sides

Without WAHA, you can still exercise the full agent through the in-dashboard Copilot (/api/copilot).


Project Structure

src/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ (auth)/                  login Β· signup
β”‚   β”œβ”€β”€ auth/callback/           OAuth return
β”‚   β”œβ”€β”€ onboarding/              business setup
β”‚   β”œβ”€β”€ dashboard/
β”‚   β”‚   β”œβ”€β”€ inbox/               + [conversationId]
β”‚   β”‚   β”œβ”€β”€ products/            + [productId] Β· new
β”‚   β”‚   β”œβ”€β”€ inventory/           + reorders
β”‚   β”‚   β”œβ”€β”€ invoices/            + [invoiceId] Β· new
β”‚   β”‚   β”œβ”€β”€ customers/           + [customerId]
β”‚   β”‚   β”œβ”€β”€ books/               + reports
β”‚   β”‚   β”œβ”€β”€ approvals/           ⏸️ human-in-the-loop gate
β”‚   β”‚   └── settings/            integrations Β· models Β· team
β”‚   └── api/                     26 route handlers
β”‚       β”œβ”€β”€ agent/run            agent entry point
β”‚       β”œβ”€β”€ copilot/             in-dashboard agent chat
β”‚       β”œβ”€β”€ waha/webhook         inbound WhatsApp (HMAC verified)
β”‚       β”œβ”€β”€ jobs/worker          cron-driven async runs
β”‚       β”œβ”€β”€ rag/search           vector retrieval
β”‚       β”œβ”€β”€ approvals/           approve / reject queue
β”‚       └── …                    products Β· invoices Β· customers Β· books Β· inventory Β· reorders Β· insights Β· onboarding Β· business Β· settings
β”‚
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ agents/                  orchestrator.ts Β· prompts/orchestrator.ts
β”‚   β”œβ”€β”€ tools/                   inventory Β· sales Β· customer Β· books Β· context Β· index
β”‚   β”œβ”€β”€ ai/                      provider.ts Β· guardrails.ts Β· embeddings.ts
β”‚   β”œβ”€β”€ rag/                     ingest.ts Β· retrieve.ts
β”‚   β”œβ”€β”€ db/                      14 server-side data-access modules
β”‚   β”œβ”€β”€ query/                   TanStack Query hooks Β· keys.ts Β· realtime.ts
β”‚   β”œβ”€β”€ jobs/                    enqueue.ts Β· worker.ts
β”‚   β”œβ”€β”€ waha/                    client.ts Β· verify.ts
β”‚   β”œβ”€β”€ supabase/                admin Β· client Β· server Β· proxy
β”‚   β”œβ”€β”€ invoice/                 image.tsx (render) Β· send.ts
β”‚   └── utils/                   contact.ts Β· money.ts
β”‚
β”œβ”€β”€ components/                  auth Β· copilot Β· customers Β· dashboard Β· inbox
β”‚                                inventory Β· invoices Β· landing Β· products Β· ui
β”œβ”€β”€ hooks/
β”œβ”€β”€ types/
└── proxy.ts

supabase/migrations/             schema Β· RLS Β· pg_cron Β· realtime publication
docs/instructions/               engineering reference

Feature Tour

Page Purpose
Home Today's business summary + anything awaiting the owner
Inbox Every WhatsApp conversation in one place, with agent activity inline
Products Catalog with pricing, stock and imagery
Inventory Live stock levels, low-stock flags, Reorders queue
Invoices Quotes and invoices β€” create, revise, cancel
Customers Profiles, contact details, full order history
Books Automatic ledger from every sale, with Reports
Approvals ⏸️ The safety gate β€” money actions wait here
Settings WhatsApp Integrations, AI Models, Team management

Roadmap

Next phase

  • Payment reconciliation β€” the payments table is modeled but not yet wired to a payment provider; close the loop from invoice β†’ payment β†’ ledger automatically
  • Supplier reorder automation β€” suppliers and reorders exist; let the agent draft purchase orders when stock crosses threshold, subject to the same approval gate
  • Proactive agent runs β€” move beyond reactive replies: daily insights already run on cron, extend to "three customers asked about an out-of-stock item this week"
  • Multi-channel β€” the WAHA adapter is isolated behind an interface; add Instagram DM and Telegram
  • Voice notes β€” transcribe inbound WhatsApp audio, a very common input for this user base
  • Sinhala / Tamil support β€” evaluate model performance on local-language customer messages

Hardening

  • Automated test suite over the tool layer and approval state machine
  • Agent evaluation harness β€” scored regression set of customer messages
  • Per-business cost caps using model_usage data

Deviations from the Proposal

πŸ“Œ To be completed before submission. The guidelines require any pivot in tech stack, features or agent behaviour to be explicitly justified. Fill this in against your original proposal.

Area Proposed Built Justification
e.g. Agent topology Multiple autonomous agents One orchestrator with scoped specialist toolsets Single coherent plan per message; lower latency and token cost β€” critical for the target user's budget

If there were no deviations, state that explicitly β€” judges are evaluating how closely execution aligns with the original idea.


Licensing & Third-Party Credits

Dependency License Use
Vercel AI SDK Apache-2.0 Agent tool-calling runtime
Supabase JS MIT Database client
WAHA Apache-2.0 (core) WhatsApp HTTP API
TanStack Query MIT Data fetching

AI model APIs β€” Google Gemini, OpenAI, Anthropic and Groq are used via their official commercial APIs under their respective terms of service. No model weights are redistributed. API keys are supplied by the deployer and never bundled.

πŸ“Œ Add a LICENSE file to the repository root and state the project's own license here.


Team

Team ONYX β€” IDEALIZE 2026, Open Category

Name Institution Role
Imesh Madushan NIBM Team Leader
Thiloko Indhuwari NIBM Member
Mayantha Udayanga NIBM Member
Nithija Kalpa NIBM Member

Built for the shop owners whose phone never stops.

About

AI back office for small businesses that run on WhatsApp - a tool-calling agent that checks real stock and pricing, drafts quotes and invoices, and books every sale, with owner approval on all money actions.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages