Healthcare · Mental health
EASE neurofeedback therapy
Real-time EEG data pipeline for clinical therapy sessions
NestJS backend with dual databases (MongoDB + PostgreSQL), MQTT ingestion for live EEG sensor data, and multi-role clinical workflows.
EASE - Neurofeedback Therapy Platform
Domain: Healthcare / Mental Health / Neuroscience Engagement: Client project (backend ownership, embedded with client's in-house team) Team Size: Backend-focused
The Problem
A mental health startup was building a neurofeedback therapy platform that required processing real-time EEG (electroencephalogram) brain data during therapy sessions. The client had an in-house team handling frontend and product and brought us on to own the backend end-to-end.
The surface requirements looked familiar — patient management, scheduling, reports — but the real engineering problem sat underneath:
- Live EEG sample streams had to be ingested continuously during sessions without drops, reordering, or silent truncation
- Clinical observations were semi-structured and evolving per therapy protocol; patient/doctor/clinic/billing data was highly relational — one storage model would lose on either flexibility or integrity
- Multiple clinics had to share one platform with hard data isolation, not soft role checks
- Session data had to be audit-ready, because clinical decisions would be made against it
Off-the-shelf healthcare platforms couldn't handle the real-time EEG pipeline or the specialized neurofeedback workflow, and none of them could be extended to without forking.
What We Built
A full backend for the therapy management platform: real-time brain data ingestion, session lifecycle, clinical reporting, and multi-role access — delivered while the client's in-house team owned frontend and product.
Patient, Doctor & Clinic Management
- Full patient profiles with medical history and longitudinal session records
- Doctor profiles with specialization, scheduling, and patient assignment
- Multi-clinic support with institutional isolation at the ORM layer
Therapy Session Engine
- Session creation, scheduling, and lifecycle management
- Real-time EEG data capture during live sessions
- Session notes and clinical observations
- Progress tracking across multi-session therapy programs
- Protocol-based workflows so new protocols are config, not code
EEG Data Pipeline
- MQTT-based ingestion of live sensor streams
- Session-linked brain data with temporal indexing for replay and analysis
- Signal storage optimized for both session-scoped reads and cohort-scale analytics
- Data export for downstream clinical research
Clinical Reporting
- Automated report generation from session data
- Progress analytics across therapy programs
- Patient outcome tracking
- Exportable clinical summaries
Multi-Role Access Control
| Role | Capabilities |
|---|---|
| Patient | View sessions, reports, progress |
| Doctor | Manage patients, run sessions, write reports |
| Admin | Clinic management, staff oversight |
| Finance | Billing, payment tracking |
Architecture Deep Dives
Dual-database strategy — and exactly where the boundary sits
Clinical observations evolve: each therapy protocol defines its own set of notes, measurements, and scoring fields, and protocols change over time. Forcing that into a rigid relational schema would guarantee either painful migrations every protocol update or a dumping-ground JSON column that loses all query ergonomics. Patient–doctor–clinic–billing data, on the other hand, is classically relational — every useful query joins across those entities, and referential integrity is non-negotiable (you do not want a patient record orphaned from a clinic).
The decision: MongoDB for clinical / session / protocol data (schema flexibility with Mongoose validation at the edges), PostgreSQL via TypeORM for the relational core (identity, assignments, billing, audit). Each write path is owned by exactly one store; cross-store operations go through an application-level coordinator that is transactional where it must be and idempotent everywhere else. The boundary is explicit in the code structure so no engineer has to guess which database a given entity lives in.
MQTT real-time EEG pipeline
EEG data is not a batch upload problem. Samples arrive continuously during a session, must be bound to the correct session + patient + device, and cannot be silently dropped — a gap in data is a gap in a clinical record.
- Protocol: MQTT chosen for its lightweight pub/sub semantics, native support for lossy/lossless delivery modes, and good behavior over flaky consumer-grade clinic networks.
- Session-to-device binding: devices publish to session-scoped topics issued at session start; the ingestion worker rejects samples that don't belong to a currently-open session, so a misconfigured device can never leak into the wrong patient record.
- Timestamp authority: each sample carries both device-time and server-receive-time; clock skew is tolerated by normalizing at ingestion rather than trusting either side unilaterally.
- Temporal indexing: samples are persisted with session-scoped monotonic indices so session replay reconstructs the exact ordering even when packets arrive out of order.
- Reconnection & backpressure: the broker retains session topic state across short disconnects; the worker applies flow control when ingest outpaces persistence so memory doesn't balloon on bad days.
Session as a state machine
Sessions move through scheduled → in-progress → ingesting → completed → reported, with transitions gated by clear preconditions (a session cannot be in-progress without a bound device; cannot be reported without persisted samples). State lives in PostgreSQL; stream data lives in MongoDB; the state machine is the single place that guarantees they stay consistent.
Multi-clinic tenancy
Every identity-scoped entity carries a clinicId. ORM-layer query interceptors inject the current session's clinic scope into every read so "forgot the where clause" isn't a privilege-escalation bug. The same scope gates Mongo queries for session and EEG data. UI-level gating exists for ergonomics; security is enforced at the API and data layers so a compromised frontend cannot cross clinic boundaries.
Async work with Bull + Redis
Report generation, email delivery, and progress-aggregate recomputation all run as Bull jobs. Each carries an idempotency key; retries use exponential backoff; failed jobs surface through the error-tracking pipeline. Reports are versioned — regenerating a report produces a new immutable version rather than overwriting — because clinical decisions may reference a specific report snapshot and history cannot be rewritten.
Role-based access
Four roles (Patient, Doctor, Admin, Finance) are enforced through API-layer guards that resolve role + clinic scope from the validated JWT. The same role claims drive audit-log attribution so every clinical mutation is traceable to a specific actor.
Engineering Practices
Embedded with the client's team
Owning the backend while the client owned frontend and product meant contract discipline was the project's most important tool. API schemas were defined first, reviewed jointly, and treated as the source of truth — their frontend consumed them directly, and breaking changes surfaced as build failures on their side within minutes. Code review cut across both teams; incidents were triaged together. The pattern let a small backend team operate as a reliable seam in a larger product organization rather than a black box.
Clinical data integrity
- Session records and EEG samples are written append-only; corrections are new versioned entries, not overwrites
- Transport is TLS end-to-end (MQTT over TLS, HTTPS for the API); storage uses AWS-provided encryption at rest
- Every mutating endpoint writes to an audit log with actor, clinic, and target entity
- Sensitive file artifacts land in S3 with per-clinic path scoping and signed-URL access
Observability
- Sentry for exception capture with clinic and role tags attached
- Structured logs with correlation IDs across HTTP, MQTT workers, and Bull jobs — so a single session can be traced end-to-end
- Health endpoints for container probes; queue depth and MQTT broker backlog as first-class signals
- DTO validation at the edge so malformed payloads never reach domain code
Tech Stack
| Layer | Technology |
|---|---|
| Backend | NestJS 8, TypeScript 4.3 |
| Clinical / session store | MongoDB (Mongoose) |
| Identity / billing / relational store | PostgreSQL (TypeORM) |
| Queue | Bull (Redis-backed) |
| Real-Time | MQTT (TLS) for EEG sensor data |
| Storage | AWS S3 (per-clinic path scoping, signed URLs) |
| AWS SES | |
| Monitoring | Sentry + structured logs with correlation IDs |
| Auth | JWT with refresh rotation, API-layer role + clinic guards |
Outcome
- Production platform managing therapy sessions with real-time EEG data capture
- Dual-database architecture with an explicit, engineered boundary — not accidental polyglot persistence
- MQTT pipeline handling live EEG ingestion with session-bound topics, timestamp normalization, and replayable temporal indexing
- Multi-clinic tenancy enforced at the data and API layers rather than relying on UI gating
- Append-only, audit-ready clinical records that support the durability clinical decision-making demands
- Embedded operating model with the client's in-house team, built on shared API contracts and joint review
Key Takeaway
We owned the backend for a real-time clinical data product — MQTT-based EEG ingestion, a deliberately bicameral data model, state-machine-driven sessions, multi-clinic isolation, and audit-grade reporting — while working alongside the client's in-house frontend and product teams. This is the kind of engagement where getting the boundaries right, both between systems and between teams, determines whether the product scales past its first five clinics or collapses under them. It scaled.
More recent work
Healthcare · Patient management
Multi-stakeholder healthcare platform
A six-app healthcare ecosystem — the product our client took to Shark Tank
Patient app, resident web, staff portal, admin dashboard, shared SDK, and an AI emergency dispatcher — all sharing a single backend with role-isolated access. Built for a healthcare startup that was later featured on Shark Tank with the product we delivered.
Read the case study
Transportation · Smart city
TransitPal
Multi-modal routing and cashless ticketing for public transit
Proprietary IP we built and productised — launched on the App Store and Play Store. 150+ APIs, dynamic fare engine, real-time vehicle tracking, ONDC-certified, and a voice AI for 250+ metro stations.
Read the case study
Have a project like this?
Tell us what you're trying to build. Discovery calls this week, scope within 3 business days.