Featured Project
Boticum CRM — Multi-Tenant SaaS CRM (Web & Mobile)
A multi-tenant SaaS CRM where WhatsApp and Instagram DMs flow into one shared inbox.
Sales teams claim conversations, build customer profiles, manage leads and deals, and
send invoices and campaigns — from a Next.js web app or a React Native mobile app
running on the same backend.
The source code is in a private GitHub repository because the system runs in production.
Access is available on request.
Request Code Access by Email
Technology Stack
Next.js 16 (App Router)
TypeScript
React Native + Expo
Expo Router
Supabase (Postgres, Auth, Realtime, Vault)
Row Level Security
Inngest (background jobs)
Meta WhatsApp Cloud API
Instagram Graph API
OpenAI API
Stripe
next-intl (i18n)
Zod
Vitest
pnpm Monorepo
Vercel
EAS Build
Screenshots — Web App
Captured from a local environment with demo data. Some modules are blurred because the
product is in commercial use.
Context & Background
Small and mid-sized businesses in the UAE sell mostly through WhatsApp and Instagram.
In practice this means several salespeople replying from one shared phone, customers
getting answered twice (or not at all), and no record of who talked to whom. Boticum
CRM was built to fix that: every message arrives in a shared inbox, one agent locks
the conversation, and everything the team learns about the customer is saved on a
single customer card.
It is a SaaS product, so many companies (tenants) use the same system while their data
stays fully separated. Each company can have branches, and the owner decides what
managers and agents are allowed to see and do. Its first market is Dubai, but the
product was designed from the start so that language, currency, and tax rules can be
configured per country.
I started with the architecture: locked design decisions, around 40 use cases, an ERD,
and a security model. I then built the system in seven phases. The web apps and the
database run in production, and a real WhatsApp Business number already receives and
sends messages through the live system.
Web Application
Two separate Next.js apps deployed on Vercel. Keeping them apart means a tenant login
can never reach the platform back office.
-
Tenant app (the CRM itself, served per company subdomain): dashboard,
shared inbox, customers, leads, sales pipeline, tasks, invoices, campaigns,
reports, exports, notifications, and settings.
-
Admin back office (for the Boticum team): tenant management and
suspension, platform billing, audit logs, and the platform's own WhatsApp number
used to send one-time codes.
-
Server components and server actions handle all data access, and every query goes
through the permission engine. There is no separate backend service.
Mobile Application
A single React Native + Expo codebase for iOS and Android, built with EAS. It uses
the same shared packages (core and db) as the web, so
permission and validation logic is written once.
-
Tab navigation for Inbox, Customers, Leads, Pipeline and
More (tasks, invoices, campaigns, team, search, account).
-
Live chat with image and document attachments, creating and editing customers, lead
status changes, and approving deletion requests on the go.
-
A separate admin area in the same app for platform staff (tenants, audit log,
platform WhatsApp).
-
No payments on mobile: the app never shows prices or purchase
links. This keeps it compliant with App Store and Google Play in-app purchase rules.
Billing is only available on the web.
Realisations
The delivered system includes the following modules:
-
Shared Omnichannel Inbox: WhatsApp and Instagram DMs arrive through
one Meta webhook, get matched to the right tenant, and are stored as contact,
conversation, and message. An agent locks a conversation so no one else replies to
the same customer at the same time. Updates appear live through Supabase Realtime.
-
Channel Connections: Each tenant connects its own WhatsApp number
(Meta Embedded Signup or manual setup) and Instagram professional account. Every
tenant's access token is stored encrypted in Supabase Vault and never in plain
database columns.
-
Customer 360: Customer cards with custom fields, categories, notes,
tasks, activities, and a timeline of every interaction. Customers can be filtered by
source (lead, WhatsApp, Instagram, manual, import) and exported to Excel/CSV.
-
Lead Generation: Public capture forms with their own URLs, lead
scoring, colour-coded status stages that match Meta's Leads Center, two-way sync
between a lead and its customer record, and lead-to-customer conversion.
-
Sales Pipeline: A kanban board of deals with configurable stages,
drag-to-move, and won/lost tracking.
-
Branches & Configurable RBAC: Owner, manager, and agent roles
plus custom roles. Permissions are a matrix of resource × action × scope
(own / branch / all / none) that the owner edits in the UI, not in code.
-
Invoicing: Tenants invoice their own customers with UAE VAT through a
country-aware tax layer. A paid/unpaid badge appears on the customer card.
-
Automation Engine: An event-driven, n8n-style builder with triggers
(message received, lead created, deal won or lost), conditions, and actions (auto-reply,
send email, assign lead, create deal or task, call an external webhook). The OpenAI API
classifies the intent of incoming customer messages so the right flow runs
automatically.
-
Email & WhatsApp Marketing: Campaigns sent by background jobs,
with a per-tenant sender identity, a suppression list, and approved WhatsApp templates.
-
WhatsApp Credit Wallet: A prepaid balance with a configurable
commission per message, automatic top-up, and a block with a top-up prompt when the
balance runs out.
-
Public REST API (/v1): API-key authentication, pagination, rate
limits, and outgoing webhooks so tenants can connect their own tools.
-
Platform Billing: Stripe subscriptions, paid add-ons that are
checked both in the UI and in the API, usage metering, and a flow from failed payment
to suspension to recovery.
-
Account Security: Owners can freeze users and reset their passwords,
and users can reset their own. Deleting a record requires owner approval followed by a
one-time code sent via WhatsApp, with email as a fallback.
-
Reporting & Audit: Dashboards, agent statistics, notifications,
a full audit log, and data retention rules.
Architecture & Security
-
Tenant isolation with Row Level Security: every tenant table has a
tenant_id and an RLS policy. A custom Supabase access-token hook puts
the tenant, role, and branch into the JWT. A set of RLS test scenarios proves that
one company can never read another company's data.
-
Two layers of authorization: the database enforces the tenant
boundary, and a shared TypeScript engine enforces branch, role, and ownership rules.
-
Background work in Inngest: webhook follow-up work, campaign sending,
and scheduled jobs run outside the request cycle, so the web requests stay fast.
-
Data model: more than 45 tables and around 40 SQL migrations, covering
CRM, messaging, invoicing, billing, wallet, API keys, and audit.
-
Testing: 400+ unit tests with Vitest, type checks across the whole
monorepo, and end-to-end checks of the webhook, public API, invoicing, and login for
all three roles.
What I Learned — Hard Skills
- Designing a multi-tenant SaaS architecture and data model from scratch
- PostgreSQL Row Level Security, JWT claims, and Supabase auth hooks
- Next.js App Router with server components, server actions, and route handlers
- Building a cross-platform mobile app with React Native, Expo Router, and EAS
- Sharing code between web and mobile in a pnpm monorepo
- Integrating the Meta WhatsApp Cloud API and Instagram Graph API with webhooks
- Storing secrets in Supabase Vault and building rotation flows
- Event-driven background jobs with Inngest
- Subscription billing and usage metering with Stripe
- REST API design with versioning, rate limiting, and outgoing webhooks
What I Learned — Soft Skills
- Turning a business problem into written specifications before writing code
- Planning a large build in phases and keeping a detailed progress log
- Debugging production problems with third-party platforms from logs and documentation
- Weighing security, cost, and app store rules when making product decisions
- Gathering feedback from partners who tested the live system and turning it into features
My Role
This is my own product and I built it end to end. I wrote the architecture and the
database schema, implemented the web apps, the mobile app, and all the integrations,
and handled deployment and production debugging. The most valuable lesson was that
connecting to real platforms like Meta and Stripe takes as much work as building the
features themselves: webhook subscriptions, token lifecycles, message templates, and
delivery rules all had to be understood and handled correctly.