Digital Wave CRM
A production CRM serving 12,000+ sales professionals. Handles 2M+ contacts, real-time pipeline tracking, automated workflows, and role-based access across enterprise teams.
Digital Wave CRM is a production sales platform serving 12,000+ professionals across 40+ organisations. It replaces a legacy system that had reached its scaling limits — the monolith could no longer support the data volume, real-time requirements, or mobile access needs of a modern sales team.
The platform handles 2M+ contact records, supports real-time pipeline tracking, automated workflow triggers, role-based access control, and integrates with major email and calendar providers. It processes an average of 850 concurrent users during peak hours with sub-200ms API response times.
I led the full-stack engineering effort, made all architectural decisions, and built the core platform from the ground up over 14 months.
The existing CRM was a decade-old PHP monolith deployed on a single server. As the organisation grew from 200 to 12,000 users, the system developed chronic issues: page loads exceeding 8 seconds, daily outages during peak usage, a 48-hour data sync delay with external systems, and no mobile support whatsoever.
The sales team had developed workarounds — spreadsheets, manual email logging, and Slack messages to track deals. Data accuracy dropped, pipeline visibility was lost, and management had no reliable forecasting capability.
The core requirements were: real-time CRM with sub-second response times, comprehensive offline-capable mobile experience, automated workflow engine for sales processes, enterprise-grade permission system, and seamless migration path from the legacy system without data loss.
We evaluated five CRM platforms (Salesforce, HubSpot, Pipedrive, Zoho, custom build) before concluding that custom development was the only viable option. The off-the-shelf solutions could not handle the organisation's custom sales methodology, multi-entity data model, or the complex role-based access requirements.
The key insight from user research was that sales reps needed to log activities in under 5 seconds — any friction in data entry led to incomplete records. This drove the decision to build a context-aware quick-add system and voice-to-text note entry.
I conducted technical spikes on three real-time architectures: WebSocket-based (Socket.io), Server-Sent Events, and polling with Redis cache. WebSockets won on latency but introduced connection management complexity. We chose a hybrid approach — WebSockets for active sessions with SSE fallback, plus Optimistic UI updates for instant feedback.
Required SSR for SEO on public-facing pages, ISR for marketing content, and client-side rendering for the authenticated CRM dashboard. Next.js provided all three rendering strategies without maintaining separate applications.
The domain model was complex — 40+ entity types with deeply nested relationships. NestJS's modular architecture, decorator-based validation, and OpenAPI generation meant we could maintain clear boundaries between CRM, Workflow, and Reporting modules without a monolith.
The CRM data model involves highly relational data — contacts, deals, activities, notes, files, emails, and calendar events all interconnected. PostgreSQL's CTE support, JSON columns for flexible metadata, and mature migration tooling made it the clear choice. We used a single database with careful indexing rather than microservices with separate databases, keeping cross-entity queries fast without distributed transaction overhead.
We needed SAML/SSO for enterprise customers, MFA, role-based access control, and a clean developer experience. Clerk provided all of this with a fraction of the maintenance burden compared to self-hosting Auth0 or building on Passport.js. The trade-off is vendor lock-in, but the saved development time (estimated 6-8 weeks) made the decision clear.
The team was small (3 engineers) and we did not have dedicated DevOps support. ECS with Fargate provided container orchestration without managing control planes. We used a single ECS cluster with service auto-scaling, RDS for the database, ElastiCache for Redis, and CloudFront for CDN — a simple, well-understood stack.
Evaluated frameworks, databases, and real-time architectures. Built prototype of the deal pipeline component with each candidate stack.
Implemented 40+ entities, RESTful API, authentication, and base permissions.
Drag-and-drop pipeline, deal stages, activity logging, and quick-add system.
Custom DSL for sales workflows, trigger system, and webhook integration.
Migrated 2M+ contacts and 150K+ deals from legacy system with zero data loss.
Full platform launch with SSO, audit logging, and enterprise admin panel.
When a sales rep updates a deal stage, 50+ team members need to see that change within seconds. We initially used WebSocket broadcasts per organisation, but this caused connection storms during peak hours. We solved it by batching updates into 200ms windows and using organisation-specific Redis channels with back-pressure detection.
The legacy system could not be taken offline. We ran a 6-week dual-write migration: every new write went to both systems while a background process backfilled historical data. The trickiest part was reconciling the legacy system's flat data model (everything was a 'note') with our structured entity model. We built a custom transformation layer that mapped 12 legacy record types to 40+ entities.
Sales teams wanted to automate sequences like 'if a deal stays in Negotiation for 7 days, send a follow-up email and assign a task.' We considered Zapier, Make, and Temporal. Temporal gave us the durability and retry semantics we needed. I built a custom DSL that compiles to Temporal workflows, allowing non-technical admins to define triggers and actions through a visual builder.
Average page load reduced from 8s to under 1s (92% improvement).
API response times at p95 under 200ms during peak usage (850 concurrent users).
12,000+ active users across 40+ organisations.
Zero data loss during migration of 2M+ contacts and 150K+ deals.
99.97% uptime since GA launch (measured over 6 months).
Sales team reporting time reduced by an estimated 70% (automated reports replaced manual spreadsheets).
Note: these metrics are from production monitoring (Datadog) and internal surveys. No external audit has been conducted.
I would introduce message queues earlier. We started with direct database writes and added a Kafka-style queue (via Temporal) only after we hit write contention during peak hours. Starting with async writes for all non-critical operations would have saved a significant refactor.
The monolithic NestJS API served us well, but at our current scale I would split the Workflow Engine into a separate service. It has different scaling characteristics (CPU-heavy workflow compilation vs. I/O-bound API requests) and would benefit from independent deployment.
I underestimated the complexity of the permission system. The initial RBAC model was too simple — we needed row-level security based on team hierarchy, deal ownership, and temporary delegations. PostgreSQL Row-Level Security policies eventually solved this, but it required a mid-project database schema refactor.
Optimistic UI updates with server reconciliation provide the best UX for collaborative tools. Users should see their change instantly and only be notified if the server rejects it.
A well-designed data model is the single highest-leverage engineering decision. Every feature request became easier to implement because the entity relationships were designed for extensibility from the start.
Invest in migration tooling before you launch. The dual-write system we built took 3 weeks but saved months of downtime and data loss risk.
14 months from kickoff to GA launch
3 engineers, no dedicated DevOps or QA
The first version generated documents (contracts, proposals) synchronously during API requests. Complex documents with tables and images took 10-15 seconds, blocking the entire request thread. This caused cascading timeout failures during peak usage. We had to pause the rollout and spend 2 weeks building an async job queue with polling before continuing.
We launched with org-level RBAC — every user in an organisation had the same permissions. By customer three, we needed team hierarchies. By customer seven, we needed temporary delegations and deal-level access. The retrospective schema migration to support row-level security touched 12 tables and required a full weekend of read-only mode.
Our initial WebSocket implementation broadcast every change to every connected client in an organisation. At 500 concurrent users, this worked. At 850, we hit connection storms and message queue backpressure. We had to redesign to batching updates into 200ms windows with organisation-specific Redis channels. This cost 3 weeks of engineering time during the busiest phase of development.
The CRM has 40+ entity types across 4 modules. Top-level tabs would have created a cluttered header. A collapsible sidebar groups related entities (Contacts, Deals, Activities) under module headings, and the active section shows a secondary nav for sub-entities. This pattern supports the complexity without overwhelming new users.
User research showed sales reps needed to log activities in under 5 seconds. A full-page form for every entry would have been rejected. We built a slide-over panel that pre-fills context (current deal, contact, or account) based on what the user is viewing. The panel supports keyboard-only entry and tab-based field navigation for power users.
Building and maintaining separate iOS and Android apps was not feasible for a 3-person team. We invested in PWA capabilities (offline support, push notifications, home screen install) and touch-optimised the interface — larger tap targets, swipe gestures for pipeline stages, and sticky action buttons within thumb reach.
Enterprise procurement requirements often mandate accessibility compliance. Rather than retrofitting, we built with semantic HTML, proper ARIA labels, keyboard navigation for all features, and sufficient colour contrast from day one. The audit logging system also tracks accessibility compliance per customer.