Legend
Онлайн-платформа для дистанционных сессий с метафорическими ассоциативными картами, рассчитанная на психологов и коучей. Ведущий и клиент одновременно работают за общим виртуальным столом: вытягивают карты из колод, раскладывают, переворачивают, увеличивают и перемещают, причем каждое действие мгновенно отражается у обоих участников. Клиент подключается по персональной ссылке прямо в браузере, без регистрации и установки чего-либо, а каждая завершенная сессия сохраняется в истории как снимок расклада, доступный для повторного разбора. Платформа закрытая, доступ выдается по инвайт-кодам, интерфейс полностью мультиязычный.
Задача
Требовалось перенести в онлайн живую офлайн-практику, где ключевую роль играет совместное взаимодействие двух человек за одним столом в реальном времени. Нужно было воспроизвести ощущение общего физического пространства: когда ведущий или клиент берет карту, она без задержки появляется, двигается и переворачивается у второго участника. При этом клиента нельзя обременять регистрацией, вход должен происходить по одной ссылке. Дополнительно бизнесу была необходима гибкая админ-панель для управления колодами, картами и языками интерфейса силами контент-менеджера, а также закрытая модель доступа по приглашениям.
Решение
Реализована веб-платформа на ASP.NET Core с серверным рендерингом и тонким клиентом. Сердцем продукта стал общий интерактивный стол, состояние которого синхронизируется между участниками по WebSocket-каналу на SignalR. Каждое действие (вытягивание набора карт из колоды, перемещение, поворот лицом вверх или вниз, увеличение, удаление, полная очистка стола) транслируется второму участнику в реальном времени с разделением ролей ведущего и клиента и разной видимостью элементов для каждой стороны.
Вход для клиента устроен предельно просто: переход по персональной ссылке вида /session/{hash} открывает стол без регистрации. Поскольку гостевая сторона не имеет постоянной привязки к аккаунту ведущего, ее события доставляются через серверную очередь команд, что гарантирует надежную доставку даже в обход прямой адресации SignalR.
Колоды и карты полностью управляются из админ-панели: загрузка изображений, добавление и удаление карт, переименование этапов. Локализация построена на динамической схеме, где добавление нового языка создает отдельную колонку в таблице переводов, а отсутствующие ключи дозаполняются автоматически при первом обращении. Благодаря этому контент-менеджер расширяет набор языков и правит тексты без единой строки кода и без передеплоя.
Архитектура и сложности
Самой сложной частью стала синхронизация общего стола в реальном времени с корректным разделением того, что видит ведущий и что видит клиент. Состояние расклада хранится в базе и проецируется на обе стороны через события SignalR, поэтому при переподключении или обновлении страницы стол восстанавливается в точности, без рассинхрона.
Отдельным вызовом была доставка событий неавторизованному клиенту. Прямая адресация по идентификатору пользователя работала только для авторизованного ведущего, поэтому для гостевой стороны спроектирован отказоустойчивый fallback через серверный буфер команд: события (имя клиента, активные карты, прокрутка колоды) накапливаются на сервере и забираются клиентом по опросу, что устранило потерю действий при нестабильном соединении.
Завершение сессии сохраняет полный снимок расклада в формате JSON вместе с длительностью встречи и именем клиента, что дало возможность повторного разбора прошлых сессий без хранения тяжелых скриншотов и без раздувания дискового пространства.
Локализация с изменяемой схемой базы потребовала аккуратной работы с динамическим SQL и автоматическим ALTER TABLE при добавлении языка, с безопасным фолбэком на русский для пропущенных значений. Поверх этого собрана продакшен-инфраструктура: cookie-аутентификация с хешированием паролей по HMACSHA512, закрытый доступ по инвайт-кодам, рассылка писем по SMTP через MailKit, SMS-уведомления, фоновые задачи на Quartz, эволюция схемы через двенадцать миграций EF Core и тонкий слой прямого доступа к SQL для операций, выходящих за рамки ORM.
Результат
- Офлайн-практика полностью перенесена в онлайн без потери ключевого сценария совместной работы за одним столом.
- Подключение клиента занимает один переход по ссылке: ноль шагов регистрации и ноль установок, барьер входа снят.
- Действия участников отражаются у второй стороны в пределах сотни миллисекунд, ощущение общего пространства сохраняется.
- Семь тематических колод с сотнями карт управляются контент-менеджером самостоятельно, разработчик для этого не требуется.
- Два языка интерфейса из коробки и неограниченное добавление новых без релиза, силами контент-команды.
- История сессий со снимками раскладов позволяет возвращаться к прошлым встречам и отслеживать динамику клиента.
- Двенадцать итераций схемы базы за время развития продукта прошли без простоев, миграции накатываются автоматически при старте приложения.
- Закрытая модель доступа по инвайтам обеспечила контролируемый и управляемый рост базы пользователей.
Стек
C#, ASP.NET Core 6 (MVC, Razor), SignalR (WebSocket), Entity Framework Core 6, SQL Server, T-SQL и динамический SQL, Quartz.NET, MailKit и MimeKit (SMTP), HtmlAgilityPack, Newtonsoft.Json, HMACSHA512, cookie-аутентификация, jQuery, мультиязычность на динамической схеме базы данных.
