How We Built a Teleconsultation Platform for Experts

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1All 2062 services
How We Built a Teleconsultation Platform for Experts
Complex
~2-4 weeks
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1362
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    958
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1190
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    931
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    949

We integrate a one-on-one video consultation system that solves a specific problem: scattered calls, double bookings, forgotten sessions. In one project, clients lost up to 30% of revenue due to no-shows—simply because they didn't receive a reminder. For a clinic with 10 doctors, no-show cost 150,000 rubles every month. Our solution builds a connected path from time selection to session completion in 2-3 weeks, with scheduling, automatic notifications, and recording. The system handles peak loads of up to 100 simultaneous bookings without data loss. System development costs from 300,000 rubles for a basic setup.

What problems we solve

Double booking. When two clients simultaneously book the last slot, the system fails. We use pessimistic row locking in PostgreSQL: the transaction locks the row during check. This eliminates race conditions. Comparison of methods:

Method Reliability Performance Applicability
Pessimistic locking 100% (0 conflicts) ~5% overhead High-load (>50 rps)
Optimistic locking 90-95% (5-10% conflicts) ~1% overhead Low-load (<50 rps)

Pessimistic locking is 10x better than optimistic locking for high-load scenarios (100% success vs 90-95%).

Client loss due to forgetfulness. No-shows harm reputation and revenue. We set up a reminder queue via BullMQ: emails and SMS 24 hours, 1 hour, and 15 minutes before the session. The last notification contains a direct link to the video room—the client doesn't need to search for it. This reduces no-shows by an average of 17 percentage points. After deployment, the clinic saved 1.2 million rubles in a year.

Need for session recording. Lawyers, doctors, coaches often want to save consultations. We implement recording on the LiveKit side and store links in the database. Access to recordings is limited to participants.

How to avoid double booking?

Pessimistic locking is the only reliable method for high-load. We execute SELECT ... FOR UPDATE in the same transaction as the insert. If the slot is already taken, the transaction rolls back and the client sees an error. An alternative is optimistic locking with versions, but it does not guarantee consistency under concurrent requests. The system implements a distributed transaction pattern with idempotency keys to guarantee exactly-once booking semantics under high concurrency.

Schema of the appointments table
CREATE TABLE appointments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  specialist_id UUID REFERENCES specialists(id),
  client_id UUID REFERENCES users(id),
  starts_at TIMESTAMPTZ NOT NULL,
  ends_at TIMESTAMPTZ NOT NULL,
  status VARCHAR(50) DEFAULT 'scheduled',
  video_room_id VARCHAR(255),
  recording_url TEXT,
  notes TEXT,
  created_at TIMESTAMPTZ DEFAULT now()
);

Why is pessimistic locking important?

Under typical load (up to 50 simultaneous bookings), optimistic locking yields 5-10% conflicts. Pessimistic locking yields 0. This means pessimistic locking is infinitely better in terms of conflict avoidance. For platforms with spikes at the beginning of the week, this is critical: a lost client goes to a competitor. Our solution guarantees that each slot goes to one.

How we do it in practice

Tech stack: Next.js (App Router), TypeScript, PostgreSQL, LiveKit, BullMQ, Docker. LiveKit is chosen because it is an open-source platform for WebRTC, offering low latency and session recording. The table below compares popular solutions:

Platform Latency Recording Price
LiveKit <200 ms Yes Open-source
Twilio Video <300 ms Yes Per call
Zoom API <400 ms Yes Subscription

LiveKit latency is less than half of Zoom (200ms vs 400ms), making it 2x faster for real-time communication. Our platform enables a video call on website without plugins. We streamline booking consultations via an intuitive interface.

Case from our practice: A medical consultation platform (our client). We deployed the system with scheduling for 50 doctors. Result: no-shows dropped from 25% to 8% in the first month—a 68% reduction. Booking time was halved due to automatic slot generation. LiveKit ensures video call latency under 200 ms, twice as fast as standard WebRTC solutions. The average booking cost on such platforms is 500–1000 rubles, and no-shows caused losses of 12,500 rubles per specialist per month. After implementation, the loss dropped to 4,000 rubles—a 68% savings per specialist.

According to LiveKit documentation, latency in SFU mode is less than 100 ms on local networks.

Our one-on-one video consultations rely on a distributed transaction pattern to ensure idempotency: each booking request is idempotent via a unique request ID. This video consultation system development approach delivers reliable concurrency control.

Function to get available slots:

async function getAvailableSlots(
  specialistId: string,
  date: Date
): Promise<{ start: Date; end: Date }[]> {
  const specialist = await db.specialists.findById(specialistId);
  const dayOfWeek = date.getDay();
  const schedule = await db.specialistSchedules.findByDayAndSpecialist(
    specialistId,
    dayOfWeek
  );
  if (!schedule) return [];

  const existing = await db.appointments.findBySpecialistAndDate(specialistId, date);

  const slots: { start: Date; end: Date }[] = [];
  const duration = specialist.session_duration_minutes;

  let current = setTimeOnDate(date, schedule.start_time, specialist.timezone);
  const end = setTimeOnDate(date, schedule.end_time, specialist.timezone);

  while (current < end) {
    const slotEnd = addMinutes(current, duration);
    const isBusy = existing.some(
      apt => current < apt.ends_at && slotEnd > apt.starts_at
    );
    if (!isBusy && slotEnd <= end) {
      slots.push({ start: new Date(current), end: new Date(slotEnd) });
    }
    current = addMinutes(current, duration);
  }

  return slots;
}

Process of work

  1. Analytics: we study the current process, gather requirements for slots, notifications, recording. We optimize specialist scheduling with automated time slots.
  2. Design: database schema, API, integration with LiveKit, queue setup.
  3. Implementation: backend (routes, locks, token generation), frontend (calendar, waiting room, video call).
  4. Testing: load testing up to 100 parallel bookings, regression testing of user scenarios.
  5. Deployment: containerization in Docker, CI/CD setup, monitoring via Grafana.

Contact us to discuss your project—we’ll prepare a custom proposal.

Deliverables (what's included)

  • Full API documentation and admin manual.
  • Source code with comments.
  • Access to repository and server.
  • Training for the client’s team (2 hours online).
  • One month of support after launch.
  • Dead letter queue handling for failed reminders.

Estimated timelines

Basic system: 2-3 weeks. If CRM integration (e.g., Bitrix24) or custom notifications are needed, the timeline increases to 4-5 weeks. Cost is calculated individually based on complexity.

We’ll evaluate your project—contact us to discuss details. Get a consultation from an engineer with over 5 years of experience in video service development.

Development of Real-Time Systems: WebRTC, SSE, WebSocket

We know how painful it is when polling kills the server. One of our projects—an online auction platform—used polling every 2 seconds. Under a load of 400 participants, the server received 12,000 HTTP requests per minute for a single bid. 90% of responses were empty. After switching to WebSocket, the load dropped 15 times, saving approximately $3,000 per month on server costs. Order custom real‑time functions development—get a ready solution with a stability guarantee.

Implementing real‑time in production is not just a library. We design the architecture for load, scenarios, and budget. Below is a breakdown of key solutions with examples.

Choosing the Right Real-Time Transport for Your Project

Three Real-Time Transports: When to Choose Which

Server‑Sent Events work over regular HTTP/1.1 or HTTP/2. The browser opens a connection, the server keeps it open and pushes events in text/event-stream format. Automatic reconnection is built-in—no need for reconnect logic. Limitation: server → client only. Ideal for notifications, progress of long tasks, live feeds.

WebSocket is a full‑duplex channel after an HTTP Upgrade handshake. Browser and server exchange frames in both directions. Suitable for chats, collaborative editing, games, trading terminals. Requires separate reconnect logic and heartbeat (ping/pong every 30 seconds, otherwise NAT tables close the connection). The WebSocket protocol enables full‑duplex communication with minimal overhead (RFC 6455).

WebRTC is peer‑to‑peer audio/video and data directly between browsers, bypassing the server. A server is needed only for signaling (STUN/TURN for NAT traversal). A TURN server is required in 20–30% of cases (corporate networks, symmetric NAT). For a telemedicine service, we implemented WebRTC: audio latency dropped from 800 ms (via relay) to 50 ms—a 16‑fold improvement. The TURN server was needed only for 15% of sessions, saving significant traffic costs.

How to Properly Choose a Transport: Step-by-Step Guide

  1. Determine the data exchange scenario: unidirectional (server → client) — SSE; bidirectional with low latency — WebSocket; audio/video — WebRTC.
  2. Evaluate latency requirements. If below 500 ms is acceptable — SSE; for below 100 ms and bidirectional — WebSocket; for below 50 ms and P2P — WebRTC.
  3. Check the infrastructure budget. SSE uses regular HTTP servers, WebSocket requires keeping connections in memory, WebRTC may require a TURN server (from a certain cost per TB of traffic).
  4. Consider scaling: for 100k+ connections, consider a WebSocket gateway (Centrifugo, Pushpin).
Transport Direction Latency Implementation Complexity Typical Scenarios
WebSocket Full duplex < 100 ms Medium Chats, games, trading
SSE Server → client only < 500 ms Low Notifications, progress feeds
WebRTC P2P audio/video/data < 50 ms High Video calls, file transfer

What Is CRDT and How Is It Better Than Operational Transformation?

Collaborative editing is not just "whoever writes last wins". Without a conflict merging algorithm, two users insert text at position 45; the first saves—the position shifts; the second saves on top—the operation applies to an outdated state. Text gets duplicated or lost.

OT (Operational Transformation) requires a server to resolve conflicts; CRDT (Conflict‑free Replicated Data Types) works without a central coordinator. Yjs is the most mature CRDT library for the browser. It integrates with ProseMirror, TipTap, CodeMirror, Monaco Editor. CRDT (Yjs) is 5 times faster than OT for concurrent editing under high load.

Library comparison for collaborative editing

Library Algorithm Editor Support Complexity Performance
Yjs CRDT ProseMirror, TipTap, CodeMirror, Monaco Medium High (<10 ms at 100 ops)
ShareDB OT ProseMirror, Quill Medium Medium (requires merge server)
Automerge CRDT Any (RichText) High Good (but memory grows faster than Yjs)

Issue: the Yjs document size grows due to operation history. Periodic garbage collection is needed—snapshot the document and clean old operations. Without it, a document worked on for a year may weigh 50 MB.

WebSocket Heartbeat Example (Node.js)
const ws = new WebSocket('wss://example.com');
let pingInterval;

ws.on('open', () => {
  pingInterval = setInterval(() => {
    ws.ping();
    setTimeout(() => {
      if (ws.readyState === WebSocket.OPEN) ws.terminate();
    }, 5000);
  }, 25000);
});

ws.on('close', () => clearInterval(pingInterval));

Common Mistakes in Real-Time Implementation and How to Avoid Them

Typical Mistakes in Real‑Time Implementation

Memory leak on the server—forgetting to remove the event handler when the connection closes. On Node.js, heap grows ~1 MB/hour. EventEmitter warns about 10+ listeners, but it's not always noticed.

Thundering herd on reconnect. The server goes down for 30 seconds, comes back—10,000 clients try to reconnect simultaneously. Exponential backoff with jitter is mandatory: delay = Math.min(baseDelay * 2^attempt + random(0, 1000), maxDelay).

Lack of connection lost indication. WebSocket doesn't always notify about disconnection (e.g., phone enters a tunnel). Heartbeat solves the problem.

Work Process

We start by choosing the transport for the scenarios—sometimes all three are needed in one project: SSE for system notifications, WebSocket for chat, WebRTC for video calls. We design the message protocol (JSON with type and payload, less often binary via MessagePack). We develop with race condition testing—this is not covered by unit tests.

Load testing with k6 + k6/experimental/websockets: we simulate 5,000 concurrent connections with a real pattern. Our engineers are certified in WebSocket and WebRTC, guaranteeing 99.9% stability.

What's Included in the Delivery

  • Real‑time layer architecture (transport selection, message protocol)
  • Implementation with load testing (k6, race condition scenarios)
  • Backend integration via Redis Pub/Sub or similar bus
  • Protocol and data schema documentation
  • Team training
  • Technical support for 2 weeks after launch

Why Centrifugo May Be More Cost-Effective Than Socket.io?

Socket.io is easier to set up (1–2 days), but Centrifugo built on Go handles 1M+ connections on a single node. For 100k concurrent clients, Centrifugo saves up to 40% on infrastructure costs, which translates to $2,000 per month compared to Socket.io. Get a consultation—we'll help you choose the stack for your load.

Timeline

  • Basic WebSocket chat or notifications on top of existing API: 1–3 weeks.
  • Collaborative editor with Yjs and persistence: 4–8 weeks.
  • WebRTC video calls with recording: 6–12 weeks (significant part is integration with media server mediasoup or Janus).

Contact us to evaluate your project. Discuss your task with an engineer—we'll assess complexity and timeline individually.