Как устроен Estate
Публичный сайт и кабинет написаны на Next.js, React и TypeScript. Go обслуживает прикладные API. Отдельные процессы отвечают за PostgreSQL, Estate CRM и локальную модель поиска. Файлы хранятся отдельно от базы с шифрованием.
Один объект — единый контекст
Объект недвижимости связан со сделкой, поручениями и обращением из чата через property_id. Сделки опираются на существующий модуль заявок: сохраняются календарь, исполнители, документы, версии и аудит. Покупатели используют модуль физических лиц, ИП, компаний и представителей.
Основные маршруты API
GET /api/v1/properties— публичный каталог.GET /api/v1/properties/:slug— карточка объекта.POST /api/v1/demo/login— вход staff / staff только при DEMO_MODE=true.GET, POST /api/v1/estate/deals— список и создание сделки.GET, PATCH /api/v1/estate/deals/:id— карточка и история изменений.GET, POST /api/v1/estate/deals/:id/documents— версии и формирование документов.POST /api/v1/estate/deals/:id/crm— постановка обмена в очередь.GET /api/v1/estate/crm— попытки обмена и сохранённые записи.POST /api/v1/estate/crm/:id/retry— безопасный повтор.
Прикладные маршруты покупателей, календаря, поручений, чатов, сотрудников и сессий сохранены. Защищённые запросы требуют заголовок Authorization: Bearer …. У каждой сессии есть срок действия; документы проверяют права на связанную сделку.
Шифрование файлов
Для каждой версии генерируется случайный 256-битный ключ данных. AES-256-GCM шифрует файл и проверяет его целостность. Ключ данных отдельно шифруется мастер-ключом. Зашифрованный ключ хранится в базе, мастер-ключ — в закрытой конфигурации сервиса. Схема применяется к документам, графическим подписям и вложениям, включая превью.
Это шифрование файлов на сервере. Авторизованный сервис расшифровывает их для пользователей с доступом; это не сквозное шифрование переписки.
Обмен с Estate CRM
Go отправляет событие в отдельный HTTP-сервис. Получатель сохраняет его с уникальным event_id. Запрос и ответ каждой попытки остаются в журнале. При повторе после потери ответа CRM сообщает о существующей записи. Сценарии отказа работают только в демо.
Локальный поиск и OCR
Модель intfloat/multilingual-e5-small работает локально через ONNX. Векторы имеют размерность 384, индексируются PostgreSQL / pgvector. Для запроса и записи используются соответствующие префиксы query: и passage:.
OCR извлекает поля из изображения локально через Python и Tesseract. Сотрудник проверяет результат до сохранения карточки. При нераспознанном изображении интерфейс сообщает об ошибке; незашифрованные отладочные копии не создаются.
Каналы подтверждения и desktop
В исходной реализации обычный вход использует email-код и уведомление Telegram. В демо внешние отправки отключены: сообщения остаются в локальном журнале. MAX — вариант дополнительного подключения при внедрении. Упрощённый вход staff / staff отделён от обычного сценария.
Desktop-клиент использует C++ и Qt, авторизацию через браузер, WebSocket и системные уведомления. Фактически проверенные сборки указаны на странице приложений. Поддержка macOS не заявлена.
Публикация и восстановление
Каждый релиз хранится отдельно. Переключение current сопровождается проверкой здоровья API, сайта, CRM и поиска. При ошибке возвращается предыдущий релиз. Сервисы запускаются пользовательским systemd; обновления и откаты не требуют sudo. На диске сохраняются действующий и два предыдущих релиза.
База содержит только синтетические данные и восстанавливается ежедневно в 04:00 по Москве. Платежи, юридически значимая электронная подпись и государственная регистрация не входят в демонстрацию.