Case Study

Synectus Medico: building a multi-tenant medical injury litigation SaaS platform

How I built Synectus Medico — a production multi-tenant SaaS for personal injury clinics with 6 user roles, 18+ modules, and real-time collaboration using Next.js 14.

Personal injury clinics in the US operate in a complicated space. A patient comes in after a car accident. They have an attorney. The attorney has a case manager. The clinic has several physicians. There are multiple facilities. The billing involves invoices, reductions, and cheque settlements. And all of this needs to be tracked, documented, and billed, often across a period of months.

Most clinics manage this with a combination of generic software, spreadsheets, and phone calls. The result is predictable: cases fall through cracks, billing gets delayed, attorneys call constantly asking for status updates, and clinic staff spend significant time on coordination rather than care.

Synectus Medico was built to solve this. It is a multi-tenant SaaS platform for medical injury litigation case management. This is the case study of how it was built, what the technical challenges were, and what the platform looks like in production.

The business problem

Personal injury clinics have a specific, underserved software need. Their workflow is fundamentally different from a standard medical practice in several ways.

Multi-party coordination. A standard clinic has patients and staff. A personal injury clinic has patients, physicians, attorneys, case managers, and referring doctors. All of them need access to different parts of the same case information. There is no off-the-shelf tool designed for this.

Billing complexity. PI billing involves a reduction negotiation process (the payer offers less than the billed amount) and LOPs (Letters of Protection, documents the clinic provides to attorneys promising to wait for settlement payment). Standard medical billing software does not model this workflow.

Documentation requirements. PI cases require detailed medical documentation that may be used as legal evidence. The quality and completeness of physician reports directly affects case outcomes. Clinics need documentation tools that produce legally defensible records.

Attorney relationship management. Attorneys need visibility into their clients' cases without accessing other patients' data. Most EMR and practice management tools do not have an attorney-facing portal.

The existing options for personal injury clinics were: generic EMR (too generic, no attorney portal), enterprise case management software (too expensive, built for law firms), or spreadsheets (error-prone, not HIPAA compliant, not scalable).

Architecture decisions

Before writing any application code, I made several architectural decisions that shaped the entire platform.

Shared database with subdomain-based tenant isolation. The multi-tenant model uses a shared database with a tenant identifier on every record. Each clinic accesses the platform through a unique subdomain. The subdomain value is extracted from requests and used to filter all database queries for that tenant. A clinic at abc-clinic.platform.com can only access records tagged with their clinic ID.

I considered database-per-tenant but rejected it. The operational cost of spinning up a new database for each clinic, managing migrations across potentially hundreds of separate databases, and handling cross-clinic reporting for super admins would have been prohibitively complex. Shared database with proper row-level security and API-level filtering provides the isolation required while keeping infrastructure manageable.

Six-role permission model. Rather than starting with two or three roles and adding more later (the usual approach that creates mess), I designed the full permission model upfront: Super Admin (platform level), Clinic Admin (all clinic data), Executive (clinic reporting), Physician (own patients only), Attorney (own clients only), Doctor (referring physician, limited read).

Each role has a flat permission key map. UI components check a permission key against the user's permission set before rendering. Components that the user cannot access are removed from the DOM entirely.

API-first, with JWT-based role enforcement. Every data access decision happens at the API level, not the UI level. The JWT token contains the user's role and clinic ID. API handlers extract both and use them to filter database queries. An attorney cannot receive another attorney's client data regardless of how the request is constructed.

Real-time via Socket.io rooms. Real-time events (task board updates, case status changes, SMS delivery confirmations) are broadcast to Socket.io rooms scoped by clinic ID. Events never cross tenant boundaries.

The six user roles: how they differ

One of the most complex aspects of the platform is the role differentiation. Here is how each role experiences the platform differently.

Super Admin. Sees all clinics. Creates and configures clinic tenants. Manages platform-wide settings. Sends broadcast notifications to all clinic users. Impersonates users for support. The super admin view has a separate navigation and administrative interface layer.

Clinic Admin. The primary operator within a clinic. Manages clinic configuration, user accounts, staff roles, and master data (exam types, document types, payer list, facility list). Has access to all modules. The go-to person for everything that needs to be set up or changed within the clinic.

Executive. Sees the reporting and analytics view. Cannot edit patient records or configuration. This role is designed for clinic owners and managers who need performance visibility without operational access.

Physician. Sees only their own assigned patients. Their homepage shows their exam queue: patients scheduled for exams with them, organized by appointment date. They access the report template builder to complete medical documentation. They do not see billing detail or other physicians' patients.

Attorney. Sees only their own clients. Their portal shows case status, billing summary (without internal billing notes), LOPs, and relevant documents. This is a read-heavy role designed to eliminate attorney phone calls to the clinic.

Doctor. Referring physicians external to the clinic. Limited read access to their referred patients' progress. No editing capability.

The key modules

Patient management. The patient record is the central object in the platform. It contains demographics, insurance, case type, attorney and case manager assignments, physician assignments, alert flags, and links to all related appointments, documents, billing records, and communication history. The 4-tab detail view organizes all this: Procedures, Documents, History Log, Report.

Appointment scheduling. FullCalendar v6 with three views: week grid (default for daily clinic operations), month grid (capacity planning), and list (filtering and searching appointments). Drag-drop rescheduling with optimistic updates. Exam type catalog with auto-calculated end times. Multi-facility filtering. Sign-in sheet PDF generation for a date range.

Medical report template builder. 21 element types configurable without developer involvement. Elements include text fields, vitals blocks, range scales, checkbox groups, body chart annotation (Fabric.js canvas), spine level selector, optical measurements, signature pad, smart notes builder, and more. Clinics create specialty-specific templates. Physicians fill out per-patient instances of those templates.

Medical billing. A 5-stage state machine: pending_invoice, pending_reduction, pending_cheque, cheque_received, paid. Each transition has specific dialogs, required fields, and business logic. CPT code management with bilateral pricing. Aging bucket classification. Reminder scheduling. Bulk CSV/Excel export.

Document management. Documents are classified by type (LOP, invoice, report, referral, imaging, insurance card, policy). AWS S3 storage with signed URL access. Role-based visibility. Automatic LOP generation on exam scheduling. Document version tracking.

SMS communication. Chat-style interface with patient conversation threads. Template management for common messages. Real-time delivery status via Socket.io. Twilio integration for SMS delivery.

Kanban task management. Real-time multi-user Kanban board with Socket.io sync. Card features: title, description, assignees, tags, priority (Low/Medium/High/Critical), due date, attachments. Optimistic drag-drop with rollback on API failure. Column customization.

Attorney portal. Client-specific filtered view. Billing status visibility without internal notes. LOP and document access. Case timeline.

Technical challenges worth documenting

Optimistic drag-drop on the Kanban board. The Kanban board uses @atlaskit/pragmatic-drag-and-drop for drag interactions. The state management is a 1,300-line Redux Toolkit slice using entity adapters for normalized state. When a user drags a card, the Redux state updates immediately (optimistic). The API call to persist the move happens in the background. If the API fails, the slice rolls back to the previous state. Getting this right required careful state snapshotting before each drag operation.

21-element template builder without performance degradation. The template builder manages complex nested state: a template has many elements, each element has type-specific configuration, the user can reorder elements with drag-drop, and multiple elements can be editing simultaneously. Redux entity adapters handle the normalized state. Component-level memoization prevents unnecessary re-renders when one element changes.

Canvas body chart integration. Fabric.js manages the canvas state for body chart annotation. The challenge was integrating Fabric.js with React's render cycle without them interfering with each other. Fabric.js manages the canvas DOM directly, which conflicts with React's virtual DOM. The solution: a single useEffect initializes the Fabric canvas on mount and stores the canvas instance in a ref. All subsequent interaction is with the Fabric API through the ref, not React state.

Multi-tenant Socket.io room management. Socket.io real-time events must be scoped to tenants. On connection, the server validates the user's JWT and joins their socket to a room identified by clinic:{clinicId}. All clinic-specific events emit to this room. Super admin connections join a separate platform:admin room for platform-level events.

Outcomes

The Synectus Medico platform ships with:

  • 6 distinct user roles with component-level permission management
  • 18+ modules covering patient management, billing, scheduling, documents, tasks, and communication
  • 21 report template element types configurable without developer involvement
  • 97 page-level components organized across the module hierarchy
  • Real-time collaboration for all clinic users via Socket.io
  • A complete personal injury billing lifecycle from invoice to settlement
  • Attorney portal eliminating routine status-check phone calls
  • Canvas-based body chart annotation for injury documentation

The platform is in active production use across personal injury clinics. Clinic staff report that the attorney portal alone has significantly reduced inbound phone calls from attorneys asking for billing and case status updates.

Lessons learned

Invest more in discovery than feels comfortable. The PI clinic workflow took two full weeks to properly understand before any code was written. That investment paid for itself immediately because the data model was correct from the start.

Design the permission model before any feature. Starting with a complete picture of all six roles and their access requirements prevented permission-model debt. Adding roles midway through a project is significantly harder than designing them upfront.

Optimistic UI is worth the complexity. The Kanban board, drag-drop scheduling, and status updates all use optimistic updates. The additional Redux complexity is real, but the resulting UI feels responsive in a way that server-round-trip UI does not.

Socket.io room scoping must be enforced on the server, not trusted from the client. Early in development, room assignment used the client-provided clinic ID. This was immediately changed to use the server-side JWT decode. Client-provided identifiers should never be trusted for access control.

// common questions

FAQ

Conclusion

Synectus Medico shows what is possible when healthcare software is built specifically for a clinical workflow rather than adapted from a generic platform.

The combination of multi-tenant architecture, a six-role permission model, a 21-element report template builder, real-time collaboration, and a complete PI billing lifecycle in one platform addresses the actual operational problems personal injury clinics face.

If you are building a similar platform for a specialty clinic or healthcare SaaS startup, the architecture decisions documented here are a useful starting point for avoiding the most expensive mistakes.

Building something similar?

Book a free 30-minute discovery call. No pitch, just a conversation about what you are building and how to approach it right.

Start the Conversation