Bitrix Doctor Schedule Component: Caching and MIS Integration

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Showing 1 of 1All 1626 services
Bitrix Doctor Schedule Component: Caching and MIS Integration
Simple
~1 day
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1356
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    943
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    828
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    1073

Bitrix Doctor Schedule Component: Caching and MIS Integration

A doctor page with a "Book by phone" text is lost online traffic. Users want to see specific available days and times, not call the reception desk. Displaying a schedule is a separate task from online booking: the schedule must be clear, fast, and up-to-date, even if the "Book" button leads to a phone call. We design the architecture so that data loads from the MIS or highload blocks, caches with auto-invalidation, and renders in an adaptive UI. This article covers our approach with real code and cases for clinics with 50+ doctors.

Why Ready-Made Solutions Do Not Work

Most ready-made Marketplace modules either show an empty table or require manual slot entry. They do not integrate with your internal MIS, do not handle complex appointment rules (recurring patterns, days off). The result is either outdated data or page load times up to 10 seconds.

What Problems We Solve

Data Consistency

The schedule must synchronize with the MIS (1C:Medicine, MedMix, iMed) via REST or SQL. If a schedule change occurs in the MIS, it appears on the site within the TTL cache period (2–5 minutes), not after a day.

Performance

A page listing 50+ doctors should not take 10 seconds to load. In a recent project we reduced load time from 3.2s to 0.4s. We use a single SQL query for the nearest date, cache the result with tags. For AJAX navigation, we update in the background using \Bitrix\Main\Data\Cache.

Mobile Adaptation

A date slider on mobile is not just horizontal scrolling—it is a component with touch events. For desktop, a weekly grid with green cells.

How We Implement the Schedule Component

Stack: PHP 8.1, Bitrix ORM, highload blocks (local_doctor_slots), tagged cache. Component local:doctor.schedule with parameters DOCTOR_ID, WEEKS_AHEAD, VIEW_TYPE. Slot loading algorithm: each slot is a highload block record with fields DOCTOR_ID, SLOT_DATE, SLOT_TIME, STATUS, PATIENT_ID (if booked), SOURCE (manual/api). Highload blocks filter 5–10 times faster than information blocks on large datasets (50k+ records).

For template selection we consider doctor type. For dense schedules (therapists), a weekly grid showing all slots works best. For narrow specialists (surgeon, neurologist), a compact list of upcoming dates is more suitable—it hides empty cells and focuses on available windows. On mobile devices we use a date slider with touch events; it is intuitive but imposes a heavier JS load.

Component Code

/local/components/local/doctor.schedule/class.php:

class DoctorScheduleComponent extends CBitrixComponent
{
    public function executeComponent(): void
    {
        $doctorId  = (int)($this->arParams['DOCTOR_ID'] ?? 0);
        $weeksAhead = (int)($this->arParams['WEEKS_AHEAD'] ?? 2);

        if (!$doctorId) {
            $this->arResult = ['ERROR' => 'Doctor not specified'];
            $this->includeComponentTemplate();
            return;
        }

        $dateFrom = new \DateTime();
        $dateTo   = (clone $dateFrom)->modify("+{$weeksAhead} weeks");
        $slots = $this->loadSlots($doctorId, $dateFrom, $dateTo);
        $scheduleByDate = [];
        foreach ($slots as $slot) {
            $date = $slot['SLOT_DATE'];
            if (!isset($scheduleByDate[$date])) {
                $scheduleByDate[$date] = [
                    'date'        => $date,
                    'day_name'    => $this->getDayName(new \DateTime($date)),
                    'free_count'  => 0,
                    'slots'       => [],
                ];
            }
            $scheduleByDate[$date]['slots'][] = $slot;
            if ($slot['STATUS'] === 'free') {
                $scheduleByDate[$date]['free_count']++;
            }
        }
        $nextFreeSlot = $this->getNextFreeSlot($slots);
        $this->arResult = [
            'DOCTOR_ID'      => $doctorId,
            'SCHEDULE'       => $scheduleByDate,
            'NEXT_FREE_SLOT' => $nextFreeSlot,
            'DATE_FROM'      => $dateFrom->format('Y-m-d'),
            'DATE_TO'        => $dateTo->format('Y-m-d'),
        ];
        $this->setResultCacheKeys(['SCHEDULE', 'NEXT_FREE_SLOT']);
        $this->includeComponentTemplate();
    }

    private function loadSlots(int $doctorId, \DateTime $from, \DateTime $to): array
    {
        return LocalDoctorSlotsTable::getList([
            'filter' => [
                'DOCTOR_ID'   => $doctorId,
                '>=SLOT_DATE' => $from->format('Y-m-d'),
                '<=SLOT_DATE' => $to->format('Y-m-d'),
            ],
            'order'  => ['SLOT_DATE' => 'ASC', 'SLOT_TIME' => 'ASC'],
            'select' => ['ID', 'SLOT_DATE', 'SLOT_TIME', 'STATUS'],
        ])->fetchAll();
    }
}

Caching

Schedule data changes with each new booking. We cache with auto-invalidation:

$this->arParams['CACHE_TYPE'] = 'A';
$this->arParams['CACHE_TIME'] = 120;
// On slot creation, clear the component cache for the doctor
\CBitrixComponent::clearComponentCache('local:doctor.schedule', '', ['DOCTOR_ID' => $doctorId]);

For AJAX requests when switching weeks, we use a separate cache via \Bitrix\Main\Data\Cache.

Detailed Caching MechanismThe component uses tag-based caching with autoclaring on highload block events. A cache tag is assigned per doctor. When a slot is created or updated via the admin panel or API, the cache tag is invalidated, ensuring the next request fetches fresh data. The TTL of 120 seconds provides a balance between freshness and load.

Template: Weekly Grid

templates/.default/template.php:

$today = new \DateTime();
$daysOfWeek = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
?>
<div class="doctor-schedule" data-doctor-id="<?= $arResult['DOCTOR_ID'] ?>">
    <div class="schedule-nav">
        <button class="schedule-prev" data-offset="-7">← Previous week</button>
        <button class="schedule-next" data-offset="7">Next week →</button>
    </div>
    <div class="schedule-grid">
        <?php foreach ($arResult['SCHEDULE'] as $dateStr => $dayData): ?>
            <?php
            $dateObj   = new \DateTime($dateStr);
            $isPast    = $dateObj < $today;
            $dayOfWeek = (int)$dateObj->format('N') - 1;
            ?>
            <div class="schedule-day <?= $isPast ? 'past' : '' ?> <?= $dayData['free_count'] > 0 ? 'has-slots' : 'no-slots' ?>">
                <div class="day-header">
                    <span class="day-name"><?= $daysOfWeek[$dayOfWeek] ?></span>
                    <span class="day-date"><?= $dateObj->format('d.m') ?></span>
                </div>
                <?php if ($dayData['free_count'] > 0): ?>
                    <div class="slots-container">
                        <?php foreach ($dayData['slots'] as $slot): ?>
                            <?php if ($slot['STATUS'] === 'free'): ?>
                                <button class="slot-btn free"
                                        data-slot-id="<?= $slot['ID'] ?>"
                                        data-time="<?= substr($slot['SLOT_TIME'], 0, 5) ?>">
                                    <?= substr($slot['SLOT_TIME'], 0, 5) ?>
                                </button>
                            <?php endif; ?>
                        <?php endforeach; ?>
                    </div>
                    <div class="day-free-count"><?= $dayData['free_count'] ?> slots</div>
                <?php else: ?>
                    <div class="no-slots-label">No appointments</div>
                <?php endif; ?>
            </div>
        <?php endforeach; ?>
    </div>
    <?php if ($arResult['NEXT_FREE_SLOT']): ?>
        <div class="next-available">
            Next available appointment:
            <strong><?= date('d.m.Y', strtotime($arResult['NEXT_FREE_SLOT']['SLOT_DATE'])) ?></strong>
            at <strong><?= substr($arResult['NEXT_FREE_SLOT']['SLOT_TIME'], 0, 5) ?></strong>
        </div>
    <?php endif; ?>
</div>

AJAX Loading for Week Switching

document.querySelectorAll('.schedule-prev, .schedule-next').forEach(btn => {
    btn.addEventListener('click', async function() {
        const doctorId  = document.querySelector('.doctor-schedule').dataset.doctorId;
        const offset    = parseInt(this.dataset.offset);
        const dateFrom  = new Date(currentDateFrom);
        dateFrom.setDate(dateFrom.getDate() + offset);
        const res = await fetch('/local/ajax/doctor-schedule.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                doctor_id: doctorId,
                date_from: dateFrom.toISOString().split('T')[0],
                sessid: BX.bitrix_sessid()
            })
        });
        const data = await res.json();
        renderScheduleGrid(data.schedule);
        currentDateFrom = dateFrom;
    });
});

Displaying Schedule on the Doctor List Page

On the doctor catalog page, full schedule is unnecessary—just an indicator "Next appointment: tomorrow". This is one SQL query across all doctors:

SELECT DOCTOR_ID, MIN(CONCAT(SLOT_DATE, ' ', SLOT_TIME)) as NEXT_FREE_SLOT
FROM local_doctor_slots
WHERE STATUS = 'free' AND SLOT_DATE >= CURDATE()
GROUP BY DOCTOR_ID

How to Integrate the Schedule with the MIS?

MIS integration is a key step. If the MIS provides a REST API, we configure an agent with a period of 1–5 minutes. With direct SQL access, we create a materialized view or triggers. In any case, after synchronization we invalidate the tagged cache for the corresponding doctor.

Implementation Process

  • Requirements analysis and slot data model design.
  • Development of highload block schema with indexing.
  • Component coding (weekly grid + list templates).
  • AJAX and mobile date slider implementation.
  • MIS integration (REST or SQL) with sync agent.
  • Cache tuning and load testing (over 100 doctors tested).
  • Deployment and documentation.

What's Included in the Deliverables

  • Highload block schema design and caching system.
  • local:doctor.schedule component with two templates (weekly grid and list).
  • AJAX loading and mobile date slider.
  • MIS integration (REST/SQL) and synchronization agent.
  • Testing with real data (50+ doctors) and load testing.
  • Operation and administration documentation.
  • Admin access and training session.
  • One month post-launch support.

Template Comparison

Parameter Weekly Grid Date List
Best for Dense schedules (therapists) Sparse slots (surgeons)
Informativeness Shows all booked and free slots Focuses on available dates
Mobile adaptation Date slider with touch events Vertical list
Load speed Requires more data (all slots) Less data (only dates)

Performance: Highload Blocks vs. Information Blocks

Parameter Highload Blocks Information Blocks
Query time for 50k records ~150 ms ~800 ms
Index flexibility Indexes on any fields Only standard indexes
Integration complexity Simple ORM Requires meta fields
Suitable for Tabular data (slots) Content data (news)

According to Bitrix documentation (https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&CHAPTER_ID=04225), highload blocks are optimized for tabular data and perform 5–10 times faster than information blocks.

Typical Implementation Mistakes

  • Storing schedule in an information block (slow filtering). We use highload blocks—ORM works faster, indexes are easier to set.
  • Not invalidating cache when booking via admin panel or API. We use OnAfterAdd/Update/Delete highload block events.
  • Ignoring time zones. Doctors may work in different branches—store times in UTC, convert on the client side.

How to Get Started?

We have implemented 20+ projects for clinics with a performance guarantee. Development cost starts from $1,200 per component. Contact us to discuss your project and we can show a demo with your data. Get a free consultation.

Medical Website Development on 1C-Bitrix: Clinics and Doctors

The most tricky integration in medical projects is synchronization of schedules with MIS. MEDIALOG provides slots via SOAP, INFOCLINIC via REST with token authorization, 1C:Medicine via COM object or web service. Each interprets a free slot differently: with or without buffer time, with lunch break blocking or not. If these nuances are not considered, you get double bookings and furious patients at the reception. We build medical solutions on 1C-Bitrix with a detailed focus on this layer — integrations with MIS, LIS, and insurance companies. Over 10 years, we have launched more than 50 medical projects, including clinics with 100+ doctors. Get a consultation — contact us, attach a list of used MIS, and we will provide exact timelines within one business day.

Why is MIS integration the main project risk?

70% of the complexity of a medical website is the synchronization layer with external systems. The rest is essentially regular Bitrix with infoblocks and ORM. But if the MIS delivers data with a delay or in its own format, the patient sees 'no available slots' despite an empty schedule. We solve this with two-level caching: data from MIS is cached with tagged cache for 2 minutes, and the agent updates the schedule every 3 minutes. The compromise between server load and freshness is proven on projects with 50+ doctors. Checks show that this approach reduces server load by 40% compared to real-time direct queries to MIS.

Types of Medical Projects

Clinic and Medical Center Websites. Not a business card, but a working booking tool:

  • Service catalog via infoblock linked to price list from 1C:Medicine.
  • Doctor profiles: specializations, experience, certifications — all from the MIS directory, no manual duplication.
  • Online appointment with real-time schedule via two-way synchronization.
  • Patient personal account: visit history, test results, prescriptions. Data pulled by patient_id from MIS.
  • Cost calculator for examination programs — component with selection from b_iblock_element with prices.
  • Section for corporate clients: DMS and occupational health checkups.

Laboratory Portals. The main thing is speed of result delivery:

  • Test catalog with preparation rules and turnaround times.
  • Online ordering: select lab or request home collection.
  • Personal account with results in PDF and interactive trend charts (chart.js using data from LIS).
  • Interpretation: norms, deviations, recommendations — automatically generated from reference values.
  • Integration with LIS for automatic result publication. Patient receives a push notification instead of waiting for a call.
  • Check-ups — comprehensive programs combining multiple tests.

Pharmacy E-commerce Stores. E-commerce with pharmaceutical specifics — you can't just attach a cart:

  • Catalog linked to the State Register of Medicines (GRLS) — mandatory requirement.
  • Prescription vs non-prescription: different ordering logic. Prescription drugs — only reservation with pickup at pharmacy, remote sale is prohibited (Federal Law 61).
  • Integration with "Chestny ZNAK" / MDLP — marking, without it the pharmacy cannot operate.
  • Availability and price check across network pharmacies via warehouse system API.
  • Analogues and generics: comparison by INN (International Nonproprietary Name).

Telemedicine. Not a future trend but a mandatory channel:

  • Video conferences via WebRTC with encryption.
  • Electronic prescriptions and referrals.
  • Chat: text, photos, documents — stored encrypted.
  • Integration with EHR (Electronic Health Record).
  • Online consultation scheduling and payment via sale.paysystem.

How to overcome the main challenge in online doctor appointment?

This is where most medical projects fail. The patient couldn't get through by phone — they go to competitors. The booking module must work flawlessly.

Schedule — free slots considering appointment duration per service type. Not an abstract "available time," but a specific interval from MIS. Synchronization every 2-3 minutes — a compromise between load and freshness.

Multi-channel booking — website, mobile app, Telegram bot, widget. All channels hit a single API endpoint that locks the slot via SELECT ... FOR UPDATE until confirmed.

Reminders — SMS via sms.ru or smsc.ru API 24 hours and 2 hours before. Reduces no-shows by 30-40%.

Cancellation and rescheduling — from personal account, no phone call needed. Slot is automatically freed in MIS.

Anti-collision — double bookings eliminated at database transaction level. If MIS and website try to occupy the same slot simultaneously, the first to commit wins.

Comparison of Popular MIS

Parameter MEDIALOG INFOCLINIC 1C:Medicine
Protocol SOAP (WSDL) REST + OAuth COM-object / CommerceML
Synchronization speed 5-10 sec per request 1-3 sec 2-5 sec (depends on volume)
Documentation Closed, contract only Open Swagger Corporate
Timezone support No, requires manual handling Yes, but buggy Built-in
Typical errors Connection drop during large exports Incorrect time zone for slots Lock conflicts during parallel booking

REST API of INFOCLINIC is 2-3 times faster than SOAP of MEDIALOG, but requires careful timezone handling. Ready-made Bitrix modules reduce MIS integration time by 3-4 times compared to custom development. Our wrapper library for these MIS catches 95% of typical errors.

How to ensure compliance with 152-FZ in development?

Medical data is a special category of personal data under Federal Law 152-FZ. Leaking a diagnosis is not just a fine, but criminal liability under Article 137 of the Criminal Code of the Russian Federation.

Consent acquisition procedure According to Article 10 of 152-FZ, processing of special categories of personal data is allowed only with written consent. We implement this via a consent module in Bitrix tied to each record. The form includes a checkbox "Consent to processing of personal data" and a link to the policy. Consent data is stored in a separate HL-block linked to the user and creation time.
  • Federal Law 152-FZ — full package: consent to processing, policy, notice to Roskomnadzor. Not a formal checkbox but working documents.
  • Medical confidentiality — role-based access via Bitrix roles: CUser::GetUserGroup(). Medical records are visible only to the attending physician and department head; receptionist sees only the schedule.
  • Encryption — TLS 1.3, encryption of sensitive fields in DB via pgcrypto (PostgreSQL) or AES in application layer.
  • Access audit — log in b_event_log: who, when, which records were accessed. Handler on every SELECT to tables with medical data.
  • Proactive protection — Bitrix WAF, file integrity checker, anomaly monitoring.
  • Hosting — Tier III data center certified for medical data processing. Certified ISPDn.

Integrations with Medical Systems

This is 70% of the project's complexity. The rest is essentially regular Bitrix.

MIS:

  • MEDIALOG — SOAP services, synchronization of schedules, appointments, patient data. Closed documentation, we work via WSDL.
  • INFOCLINIC — REST API with OAuth. More modern interface but its own timezone quirks.
  • 1C:Medicine — exchange via web service or CommerceML. Price lists, financial data, reporting.
  • N3.Health (EGISZ) — data transmission to the state unified system. Mandatory for licensed healthcare facilities.

LIS:

  • Automatic result upload to personal account — via webhook or polling. Patient receives push notification.
  • Trend charts for regular tests (glucose, cholesterol) — visualization of changes.

Insurance Companies:

  • Real-time DMS policy and limit verification via insurance API.
  • Automatic service approval.
  • Upload of registers for payment — format depends on the insurance company, each has its own XSD.

SEO for Medical Websites

YMYL topic. Google and Yandex have high requirements, and keyword-stuffed text won't work.

  • E-E-A-T — content written or verified by doctors. Qualifications and sources (PubMed, clinical guidelines) are cited.
  • Schema.org — markup for MedicalOrganization, Physician, MedicalProcedure, MedicalCondition. Implemented via component generating JSON-LD from infoblock data.
  • Local SEO — Google My Business, Yandex.Business, maps, review aggregation.
  • Federal Law "On Advertising" — mandatory disclaimer about contraindications on every service page. Automatic insertion via component template.

Mobile Adaptation

Over 70% of patients search for a doctor on their phone. Inconvenient mobile booking = lost patient.

  • Mobile-first design, priority on booking forms.
  • Sticky "Call" and "Book" buttons on screen.
  • Booking in 2-3 taps.
  • PWA with push notifications via Service Worker + FCM.
  • Optimization: Lighthouse Performance > 90 on mobile networks.

What's Included in the Result

Each project comes with documentation and warranty support:

  • Technical specification with integration description (signed by both parties).
  • Access to all external services (MIS, payment gateways, SMS providers) — setup and testing.
  • Training for administrators on Bitrix admin panel (2-3 sessions of 2 hours each).
  • DB schema with indexes, description of agents and events.
  • 12-month warranty on identified integration errors.
  • Support per SLA: critical incidents — 4 hours.

Timelines and Cost

Cost is calculated individually based on the number of integrations and complexity of business processes. Most time is spent on MIS integration and testing edge-case booking scenarios. The Bitrix website itself is a standard task, but the medical logic layer on top requires deep domain expertise.

Project Type Timelines
Clinic business card website 2-4 weeks
Website with online booking and MIS integration 2-3 months
Laboratory portal 2-4 months
Telemedicine platform 3-6 months
Pharmacy e-commerce store 3-5 months

Get an individual assessment for your project — contact us, attach a list of used MIS, and we will provide exact timelines and cost within one business day.