Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# BritCRM
<div align="center">

![License](https://img.shields.io/github/license/britsync07-prog/crm?style=flat-square&label=license&color=06b6d4) ![Language](https://img.shields.io/github/languages/top/britsync07-prog/crm?style=flat-square&color=0ea5e9) ![Stars](https://img.shields.io/github/stars/britsync07-prog/crm?style=flat-square&color=f59e0b) ![Last commit](https://img.shields.io/github/last-commit/britsync07-prog/crm?style=flat-square&color=22c55e) ![Repo size](https://img.shields.io/github/repo-size/britsync07-prog/crm?style=flat-square&color=94a3b8)

</div>

> A self-hosted Next.js CRM that unifies sales pipelines, real-time team chat, LiveKit video meetings, AI email outreach, and an MCP server for AI agents.

BritCRM is an all-in-one customer relationship platform for small teams and agencies: leads, customers, deals, invoicing, campaigns, meetings, and automations in one deployable Node process. It is designed to run on a single VPS with SQLite, expose its data to human users through a React App Router UI, and to AI agents through a first-party Model Context Protocol (MCP) server.

## Overview

The application consolidates what would otherwise be five SaaS subscriptions: a sales CRM (leads, customers, pipelines, deals), a billing module (clients, invoices, quotations synced to an external BritLedger bookkeeping service), an outreach engine (IMAP inbox sync, campaign sending, open/reply tracking), a meeting tool (self-hosted LiveKit rooms with virtual backgrounds and booking forms), and internal chat (Socket.io workspaces and channels). An admin area adds user/organization management, pricing plans, system SMTP, and newsletters.

Status: production-deployed on a VPS (`truecrm.online`, PM2-managed via `ecosystem.config.cjs`), with 14 Prisma migrations and roughly 55 models. Development has been fast and iterative; recent work focused on meeting-quality effects, MCP hardening, SEO surfaces, and billing alignment.

## Features

- Lead and customer management with categories, tags, pipelines, stages, and deals; bulk operations including multi-select deletion.
- Lead finder/scaper: Puppeteer- and Cheerio-driven scraping services with scrape jobs, logs, status polling, stop control, and downloadable result files.
- Email outreach: campaigns with per-campaign analytics, lead options, open tracking pixel, scheduled reply-checking worker, and inbound webhook ingestion.
- Unified inbox: IMAP account sync via `imapflow`/`mailparser`, batch email operations, and per-account settings.
- Team workspaces: Socket.io channels (public/private with role allowlists), presence lists, invites, custom roles, and nicknames - all authorized server-side per event.
- LiveKit video meetings: room creation, join tokens via server SDK, booking forms with availability checks, and browser-side virtual backgrounds with local MediaPipe segmentation assets.
- Calendar: events, reminders, settings, and a reminder worker loop; meeting scheduling ties into public forms.
- Billing: clients, invoices, quotations with direct line-item entry, plus BritLedger integration for bookkeeping, VAT, payments, and reports.
- Stripe monetization of the CRM itself: subscription checkout, customer portal, and signature-checked webhooks driven by admin-configured pricing plans/offers.
- Form builder with public submission endpoints and availability-aware meeting forms.
- Automation engine: workflow steps with execution logs and an admin operations dashboard.
- Newsletter management with subscribe/unsubscribe endpoints secured by a signing secret.
- MCP agent server: Streamable HTTP endpoint at `/api/mcp` (stdio for local dev) exposing resources and tools across mail, leads, outreach, forms, calendar, billing, and admin domains, authenticated by revocable per-user bearer tokens.
- Gemini-powered AI agents for lead enrichment and content tasks.
- Technical SEO and AI-discovery surfaces: metadata helpers, an `llms.txt` route, and feature/solution landing pages.

## Tech Stack

| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 + TypeScript |
| Custom server | Node.js HTTP server hosting Next, Socket.io 4, background workers, and LiveKit subprocess |
| Database | SQLite via Prisma 7 with the `@prisma/adapter-better-sqlite3` driver adapter |
| Realtime | Socket.io (JWT-authenticated handshake, workspace/channel rooms) |
| Video | Self-hosted LiveKit server v1.9.12 (`livekit-server-sdk`, `@livekit/components-react`, track processors for backgrounds) |
| Auth | bcrypt password hashing, jose JWT (HS256) in httpOnly cookies |
| Email | nodemailer (sending), imapflow + mailparser (inbox sync), handlebars-free template modules |
| Scraping | puppeteer, cheerio, node-html-parser |
| AI | @google/generative-ai (Gemini), @modelcontextprotocol/sdk |
| Payments | stripe SDK (checkout sessions, portal, webhooks) |
| Styling | Tailwind CSS 4, lucide-react icons, react-hot-toast |
| Ops | PM2 (`ecosystem.config.cjs`), tsx for scripts, ESLint 9 |

## Architecture

- **Single-process server (`server.js`).** One Node entry point boots Next.js, spawns the LiveKit binary (`--dev` locally, env-provided keys in production), registers graceful shutdown hooks, starts the reminder and outreach-reply worker intervals, and attaches Socket.io. Every socket handshake must present a valid session cookie (JWT verified with `jose`, HS256); workspace/channel joins re-query membership and private-channel role allowlists from Prisma before joining a room.
- **HTTP API (`src/app/api/**`).** Route handlers grouped by domain: auth (login, me, password reset), organization/team/workspace membership, channels and messages, meetings, calendar, emails, forms (public + submissions), outreach (campaigns, tracking, replies, analytics), newsletter, pricing, Stripe (checkout/portal/webhook), MCP, and internal cron-triggered endpoints protected by a shared secret header.
- **Data layer (`prisma/`).** SQLite schema covering users, organizations, workspaces/channels/messages, meetings, employees/attendance, customers, leads, deals, campaigns, automations, forms, calendar, newsletters, MCP access tokens, pricing plans, and more; generated client lives under `src/generated`.
- **Domain libraries (`src/lib/`).** `auth.ts` (JWT sessions + global API key path), workers (`reminder-worker.ts`, `outreach-worker.ts`, `outreach-reply-worker.ts`), `britledger/*` (bookkeeping client), `scraper-service.ts` + `google-maps-scraper.ts`, `mailer.ts`/`system-mailer.ts` (transactional vs newsletter SMTP streams), `mcp-tokens.ts`, `pricing.ts`, `seo.ts`.
- **MCP layer (`src/mcp/`).** `server.ts` builds the unified "britcrm" MCP server; `tools/` implements domain tools (admin, billing, calendar, forms, leads, mail, outreach); `resources/` exposes docs and snapshots; `src/app/api/mcp/route.ts` terminates the Streamable HTTP transport with origin allowlisting and bearer-token resolution.
- **Frontend (`src/app/**`).** Dashboard routes for leads, customers, billing, campaigns, inbox, calendar, meet, team, settings, and onboarding, plus public marketing pages (landing, pricing, solutions, privacy/terms) and `/meet/[id]` for guest meeting joins.

## Project Structure

```text
crm/
+-- server.js               # Next + Socket.io + LiveKit spawn + worker loops
+-- ecosystem.config.cjs    # PM2 production config
+-- prisma/                 # schema.prisma, migrations/, seed.ts
+-- src/
�   +-- app/
�   �   +-- api/            # REST-ish route handlers by domain
�   �   +-- admin/          # Users, organizations, pricing, system email, ops
�   �   +-- meet/[id]/      # LiveKit meeting room with background effects
�   �   +-- portal/ billing/ leads/ campaigns/ inbox/ calendar/ ...
�   �   +-- mcp/            # Public MCP documentation page
�   +-- components/         # Feature components (workspace, inbox, billing, admin)
�   +-- lib/                # auth, workers, britledger client, scrapers, mailers, seo
�   +-- mcp/                # MCP server, tools/, resources/
�   +-- generated/          # Prisma client output
+-- scripts/                # create-admin.ts, IMAP/inbox diagnostic scripts
+-- livekit/                # LiveKit binary target dir (populated by setup script)
+-- socket.io/              # Reserved placeholder directory
+-- docs/                   # mcp/ plans + README, seo/ guide, superpowers/ plans & specs
```

## Getting Started

### Prerequisites

- Node.js 20+ (Next.js 16 requirement; 22 recommended)
- Native build toolchain for `better-sqlite3` (C/C++ compiler on Windows/Linux)
- LiveKit server binary v1.9.12 for meetings (downloaded by the setup script on Linux)
- PM2 for production process management

### Installation

1. Install dependencies (also generates the Prisma client):
   ```bash
   npm install
   ```
2. Apply database migrations:
   ```bash
   npx prisma migrate dev
   ```
3. Seed initial data if needed:
   ```bash
   npx tsx prisma/seed.ts
   ```
4. Create the first admin user:
   ```bash
   npm run admin:create
   ```
5. Optional - fetch the LiveKit server binary:
   ```bash
   npm run setup:livekit
   ```

### Environment Variables

Names only - never commit real values:

| Variable | Purpose | Example placeholder |
|---|---|---|
| `DATABASE_URL` | SQLite file URL for Prisma | `file:./prisma/dev.db` |
| `JWT_SECRET` | Signing key for session JWTs and socket verification | `change-me-long-random` |
| `PORT` / `NODE_ENV` | Server port and mode | `3001`, `production` |
| `SOCKET_ALLOWED_ORIGINS` | CORS origins accepted by Socket.io | `https://example.com` |
| `INTERNAL_CRON_SECRET` | Header secret protecting internal cron trigger endpoints | `change-me-random` |
| `GLOBAL_API_KEY` | Machine-to-machine admin API key (`x-api-key`) | `change-me-random` |
| `LIVEKIT_API_KEY` / `LIVEKIT_API_SECRET` | Credentials passed to the spawned LiveKit server | `change-me` |
| `LIVEKIT_HOST` / `NEXT_PUBLIC_LIVEKIT_URL` | Meeting endpoints exposed to clients | `https://meet.example.com`, `wss://meet.example.com` |
| `APP_URL` / `NEXT_PUBLIC_APP_URL` / `NEXTAUTH_URL` / `NEXT_PUBLIC_API_URL` / `NEXT_PUBLIC_SITE_URL` | Canonical app URLs used for links, MCP origin allowlist, SEO | `https://example.com` |
| `GEMINI_API_KEY` | Google Gemini key for AI agents | `change-me` |
| `STRIPE_SECRET_KEY` / `STRIPE_WEBHOOK_SECRET` | Stripe subscription billing | `sk_test_...`, `whsec_...` |
| `BRITLEDGER_API_URL` / `BRITLEDGER_EMAIL` / `BRITLEDGER_PASSWORD` | External BritLedger bookkeeping service credentials | `change-me` |
| `BRITLEDGER_PASSWORD_SECRET` | Shared secret for BritLedger user sync (falls back to `JWT_SECRET`) | `change-me` |
| `SYSTEM_SMTP_HOST` / `SYSTEM_SMTP_USER_*` / `SYSTEM_SMTP_PASSWORD` / `SYSTEM_SMTP_FROM_*` / `SYSTEM_SMTP_PORT_*` | Admin-managed system SMTP streams (transactional + newsletter) | `change-me` |
| `UNSUBSCRIBE_SECRET` | Signing secret for unsubscribe links | `change-me-random` |
| `EXTERNAL_API_BASE_URL` / `EXTERNAL_API_KEY` (+ `NEXT_PUBLIC_` variants) | External lead-finder API | `https://api.example.com`, `change-me` |
| `AUTO_REMINDER_WORKER` / `REMINDER_WORKER_SECONDS` | In-process reminder loop toggles/timing | `true`, `60` |
| `AUTO_OUTREACH_REPLY_WORKER` / `OUTREACH_REPLY_WORKER_SECONDS` | Outreach reply-polling loop toggles/timing | `true`, `180` |
| `BRITCRM_MCP_USER_ID` / `BRITCRM_MCP_USER_EMAIL` | Local stdio MCP operator identity only (not for end users) | `local-dev-user` |

### Running

- Development (custom server on port 3001):
  ```bash
  npm run dev
  ```
- Production build and start:
  ```bash
  npm run build
  npm start
  ```
- Production via PM2:
  ```bash
  pm2 start ecosystem.config.cjs
  ```
- Local MCP stdio transport:
  ```bash
  npm run mcp
  ```

## Challenges Faced & Solutions

- **Browser virtual backgrounds were low quality and fragile** - a long commit arc (`Add LiveKit background effects`, then `Improve meeting background segmentation quality`, `Remove heavy virtual background wrapper`, `Use prebuilt virtual background processor`, `Use stronger meeting segmentation model`, `Serve MediaPipe background assets locally`) shows repeated rewrites. Solution: settled on LiveKit's prebuilt track processor fed by a stronger segmentation model, with MediaPipe WASM/model assets served from the app itself instead of a CDN, eliminating network flakiness and version drift.
- **Processed preview tracks broke camera geometry and mobile** - enabling effects distorted aspect ratios and crashed on some phones. Solution: `Preserve camera aspect ratio in meeting effects` kept source dimensions through the processing pipeline, `Guard meeting background canvas dimensions` clamped canvas sizes before rendering, and `Make meeting camera preview mobile safe` hardened the preview path; `Require manual camera preview before meeting join` added an explicit pre-join gate so permissions and device selection are confirmed up front.
- **Meetings failed for users without cameras or microphones** - join flows assumed media existed. Solution: `Allow meeting join without camera or mic` decoupled room admission from device publishing so guests can observe calls, while processed tracks are only published when actually produced (`Publish processed meeting preview track`).
- **Realtime chat needed real authorization, not just a socket connection** - anyone holding a socket could otherwise join any room. Solution: the server verifies the signed session JWT during the handshake, then `join-workspace`, `join-channel`, and every `chat:message` re-validate ownership/membership against Prisma, including private-channel role allowlists; unauthorized requests are rejected with explicit error events, and allowed origins are restricted via `SOCKET_ALLOWED_ORIGINS`.
- **AI agents needed safe, scoped CRM access** - early MCP exposure risked over-broad access. Solution: `Add unified MCP server tools` consolidated domain tools behind one server, `Add per-user MCP setup page` introduced self-service bearer tokens backed by the `McpAccessToken` model (tools act strictly as the token's user and revocation blocks future calls), and `Harden MCP docs and transport` tightened origin checks and published safe-by-default agent documentation at `/mcp/docs`.
- **Bulk lead deletion silently misbehaved** - the finder page's optimistic state diverged from the server action's accepted selections. Solution: `Fix bulk lead deletion` corrected `finder/actions.ts` validation and resynchronized `LeadsPageClient.tsx` state so deletions match exactly what was selected.
- **Billing balances drifted from the external ledger** - the built-in billing module and BritLedger disagreed on outstanding amounts. Solution: `Align billing balance flow with BritLedger` routed balance computation through the dedicated `src/lib/britledger` client (invoices, payments, quotations, VAT), making the external ledger authoritative for money owed.

## Known Limitations & Roadmap

- Released under the MIT License (see [LICENSE](./LICENSE)).
- SQLite plus a single Node process caps horizontal scale; moving to Postgres or splitting workers into separate processes would be required for multi-instance deployments.
- The committed `prisma/dev.db` (plus `-shm`/`-wal`) and `dev-server*.log` files should be removed from history and ignored.
- `ecosystem.config.cjs` embeds placeholder/default credential values inline; production secrets should live exclusively in the environment.
- Debug/diagnostic surfaces remain reachable: `api/debug-session`, `api/test-route`, root-level `test-*.js` scripts, and several `check-*` scripts.
- Several commit messages ("hehe", "je", "gs") obscure history; conventional commits would improve traceability.
- `socket.io/` and `livekit/` directories are placeholders/binaries rather than code; no automated test suite exists beyond ad-hoc scripts.

## Security Notes

Observed practices: bcrypt password hashing; jose-signed HS256 session JWTs stored in httpOnly, sameSite=lax cookies (secure flag in production) with 24-hour expiry; mandatory JWT verification for every Socket.io handshake followed by per-event database-backed authorization; CORS origin allowlists for both sockets and the MCP transport; shared-secret headers guarding internal cron endpoints; per-user, revocable MCP bearer tokens whose tools operate strictly within the token owner's records (admin tools additionally require `role === "ADMIN"`); Stripe webhooks verified against `STRIPE_WEBHOOK_SECRET`; `sanitize-html` available for rendering untrusted mail content; signed unsubscribe links.

Hygiene warnings (filenames only): `prisma/dev.db`, `prisma/dev.db-shm`, `prisma/dev.db-wal`, `dev-server.log`, `dev-server-err.log`, `server-log.txt`, `error.txt`, and `lint_results.txt` are tracked in git; `ecosystem.config.cjs` contains placeholder/default key material inline (`your-secure-api-key`-style values and LiveKit dev defaults). Rotate anything sensitive that ever touched the dev database and purge these paths from history.

## Contact

- 📧 Email: [saimon@ascentraconsulting.co.uk](mailto:saimon@ascentraconsulting.co.uk)
- 💼 LinkedIn: [Musfiqur Rahman Saimon](https://www.linkedin.com/in/musfiqur-rahman-saimon-a5994b3aa)
- 🐙 GitHub: [@britsync07-prog](https://github.com/britsync07-prog)
- 🌐 Portfolio: [brit-os.pages.dev](https://brit-os.pages.dev/)

## License

MIT License � Copyright (c) 2026 Musfiqur Rahman Saimon. See [LICENSE](./LICENSE).


---
Keywords: self-hosted crm, livekit, team chat, mcp server, nextjs, prisma, stripe billing