$ show locphamnguyen/ZaloCRM
ZaloCRM is a production-grade, multi-tenant customer relationship management system deeply integrated with the Vietnamese Zalo messaging platform. It serves real-estate sales teams by unifying contact management, real-time chat, lead scoring/automation, appointment scheduling, media library, RBAC, privacy controls, and third-party integrations (Facebook Lead Ads, Telegram bridge, Google Sheets). The system is deployed as a Node.js/Fastify monolith with PostgreSQL (Prisma ORM), Redis (BullMQ queues, rate limiting), MinIO/S3-compatible storage, and Socket.IO for real-time events. It relies on the unofficial Zalo SDK (zca-js) for messaging operations and supports multiple AI providers (Anthropic, Gemini, OpenAI) for reply drafting, sentiment analysis, and appointment parsing. The architecture follows an open-core model: the Community edition ships with extension stubs (`_ee-stubs`) that are replaced in the Enterprise edition. Key entry points include auth routes (JWT with rotating refresh tokens), Zalo account management (QR login, reconnect), friend sync (cron-driven diff-then-emit), and a rich chat operations module (reactions, edits, forwards). Background jobs handle lead pool assignment, care session monitoring, scoring decay, and engagement pattern classification. The system maintains strong data invariants through Prisma extensions (tenant context, RLS preparation, safe-contact-write) and a custom privacy layer that redacts private-nick messages based on viewer role. Data flows center on the Zalo account pool: inbound messages are ingested via socket listeners or friend sync, routed to conversations via a global-aware resolver, and triggers automation hooks (care sessions, auto-tags, sequence advancement). Analytics are derived from daily engagement materialization and scoring engine (4 dimensions with weights). External dependencies are managed via Redis-backed rate limiters, while storage operations are abstracted behind a `StorageDriver` interface with local/R2 implementations. The codebase is actively maintained with daily commits, extensive Prisma migrations, and a comprehensive test suite covering privacy invariants, merge policies, and regression scenarios.
The LLM identified 5 files worth highlighting for reuse:
Implements a tenant context using Node.js AsyncLocalStorage to propagate orgId, userId, and role across async operations without explicit parameter passing. Provides `withTenant()` and `runSystemQuery()` wrappers used by all workers and cron jobs. This pattern is directly reusable in any multi-tenant Node.js application and demonstrates clean separation of tenant vs. system-level execution.
Defines a `StorageDriver` interface (upload, download, delete, exists) with two implementations: `r2-driver.ts` (S3-compatible, content-hash dedup) and `minio-client.ts` (dispatcher with local fallback). The abstraction allows swapping storage backends without touching business logic. This is a textbook strategy pattern that can be extracted and reused in any application requiring cloud/local storage.
A Fastify `onSend` hook that scans outgoing JSON responses for sensitive fields (e.g., nick UUIDs, phone numbers) that should have been redacted but were not, and logs warnings with context (route, org, user). Guards against privacy regressions (past audits H8/H9/H11). This pattern is reusable across any web framework to add runtime data leak detection and demonstrates advanced security engineering.
A generic event buffer that accumulates events (e.g., typing indicators, reactions) and flushes them in batches after a configurable interval. Used to reduce Zalo API calls and WebSocket emissions. Supports key-based deduplication and clear-on-exit. This is a clean, reusable utility for any system needing to batch rapid-fire events.
Implements a rule engine for automatically assigning CRM tags (active, cooling, cold, frozen, rewarmed, stuck, ready, atrisk, has-appointment) based on lead scoring signals. Uses mutual-exclusion logic to ensure only one tag per contact per category. Decoupled from the scoring engine via a cron-triggered pipeline with batch processing. The rule structure can be extracted and applied to any classification system with mutually exclusive states.