Платформа для ботанических садов (SaaS) — демо-сборка¶
Эта страница собирает разделы для демо и презентаций стейкхолдерам: обзор, роль, архитектура, решения, дорожная карта и демонстрация.
Содержание¶
- Краткое описание
- Обзор
- Роль и обязанности
- Архитектура и интеграции
- Решения, компромиссы и риски
- Дорожная карта и демонстрация
Краткое описание¶
Статус¶
MVP / проведение пилота
Роль¶
Сооснователь, технический владелец архитектуры, системный проектировщик
Стек¶
Java 21, Spring Boot, PostgreSQL/PostGIS, MinIO/S3-compatible storage, Angular, OpenLayers, Docker
Ценность проекта¶
Для ЦА (ботанические сады, питомники, селекционеры, держатели научных коллекций и частных собраний растений):
-
переход от разрозненных Excel/локальных БД к единой web-платформе;
-
единый таксономический слой как основа сопоставимости коллекционных данных;
-
управляемое раскрытие данных, публичные страницы и QR-сценарии;
-
база для сетевых сценариев обмена между организациями.
Для профессионального профиля:
-
проектирование и реализация SaaS от доменной идеи до MVP и пилотного запуска;
-
работа с multi-tenancy, RBAC, доменной моделью данных, API, GIS, AI-assisted импортом, подготовкой публичных данных и приведение в соответствие законодательным нормам (152-ФЗ);
-
осознанное и экономичное применение AI без передачи архитектурных решений модели.
Что демонстрирует¶
Этот проект демонстрирует мои способности:
-
работать на стыке системного анализа, системного дизайна, имплементации и деплоя.
-
довести идею до запуска системы с несколькими зонами доступности и дорожной картой масштабирования
-
стратегически планировать имплементацию SaaS малого-среднего масштаба
-
безопасно и контролируемо применять LLM-генерацию кода для имплементации фичей
Обзор¶
Botanical SaaS - мультитенантная SaaS-платформа для ботанических садов, питомников, селекционеров, научных коллекций и частных собраний растений.
Система заменяет разрозненные Excel-файлы, локальные базы данных и устаревшие desktop-инструменты единой web-платформой для управления живыми коллекциями растений, научной таксономией, геоданными, публичными страницами организаций, QR-этикетками, импортом, списками и контролируемым обменом данными.
Моя зона ответственности включала доменное моделирование, backend-архитектуру, проектирование модели доступа, проектирование структуры данных и API, техническую документацию, backend-реализацию и подготовку системы к cloud-ready deployment.
Роль и обязанности¶
Моя роль¶
Я выступал как сооснователь и технический владелец архитектуры системы.
Моя работа включала:
- перевод экспертных знаний предметной области в структурированную SaaS-модель;
- проектирование backend-архитектуры, API, структур данных, доменной модели;
- реализацию backend-функциональности и интеграционной логики;
- проектирование RBAC с учетом прав доступа в контексте организации (тенанта);
- моделирование экземпляров растений, таксономии, мест размещения, списков, фотографий, импортов и публичных страниц;
- подготовку архитектурной документации, C4-диаграмм и ADR;
- согласование технических решений с экспертом предметной области;
- использование AI-assisted development tools для ускорения реализации при сохранении ручного контроля над архитектурой, моделью данных, API-контрактами, ревью и deployment-решениями.
Применение ИИ¶
Проект разрабатывался с использованием AI.
LLM применялись для ускорения реализации, генерации шаблонного кода и быстрых итераций. Ключевые решения оставались под ручным контролем:
- интерпретация требований;
- доменное моделирование;
- архитектурные решения;
- границы данных;
- модель доступа;
- код ревью;
- дебаг;
- решения по развертыванию;
- техническая документация.
Архитектура и интеграции¶
Архитектура¶
Контейнерная диаграмма (C4 Container)¶
C4Container
title Диаграмма контейнеров для Botanical SaaS MVP
Person(user, "Пользователь")
System_Boundary(sys, "Система") {
Container(spa, "Single Page Application", "Angular 21, OpenLayers", "Пользовательский интерфейс")
Container(static, "Frontend Static", "nginx", "Контейнер для хранения<br/> статических frontend-файлов")
Container(backend, "Backend Business Logic", "Spring Boot", "Бизнес-логика")
ContainerDb(reldb, "Relational DB", "PostgreSQL + PostGIS", "Экземпляры растений, списки,<br/> пользователи, RBAC-роли")
ContainerDb(objStore, "Object Storage", "MinIO", "Фотографии и мультимедиа.<br/> Файлы импорта коллекций")
}
Boundary(ext, "Внешние системы", "") {
Container_Ext(global, "global", "Таксономический справочник")
Container_Ext(vernacular, "WikiData", "Справочник народных названий<br/> растений")
Container_Ext(llm, "LLM", "Интеллектуальное распознавание<br/> видов")
}
Rel(user, spa, "Использует для<br/> управления коллекциями растений")
Rel(spa, static, "Получает Angular<br/> static UI bundles", "HTTPS")
Rel(spa, backend, "Отправляет API-вызовы", "HTTPS REST")
Rel(backend, reldb, "Читает/записывает данные", "SQL")
Rel(backend, objStore, "Загружает/читает медиа", "S3 API")
Rel(backend, global, "Запрашивает таксоны/культивары,<br/> записывает культивары", "HTTPS/REST")
Rel(backend, vernacular, "Получает названия видов<br/> на национальных языках", "HTTPS/REST")
Rel(backend, llm, "Использует LLM API<br/> для получения подсказок по названиям видов", "HTTPS/OpenAI API compatible")
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="3")
Потоки интеграции¶
Импорт каталога таксономии¶
Система включает ручной механизм обновления внутреннего справочника таксонов из выгрузки xls с сохранением идентификаторов.
Пополнение национальных названий таксонов¶
Система включает автоматический механизм пополнения внутреннего справочника народных названий растений из открытых источников с учетом ограничений публичного API.
Smart Import¶
Платформа включает мастер импорта XLS для переноса существующих коллекций растений в систему.
Поток поддерживает загрузку файла, выбор листа, сопоставление колонок (в том числе с помощью ИИ), определение значений, нечеткое совпадение, асинхронную обработку, построчные результаты, экспорт Excel с ошибочными строками.
Для сопоставления названий колонок атрибутам сущностей системы, а также для более точного распознавания вида, культивара или перечисления(enum'а) предусмотрена интеграция с LLM и легкая обвязка(harness). Подтверждение распознавания (если оно не было 100%) осуществляется пользователем.
Решения, компромиссы и риски¶
Ключевые решения¶
Разделение frontend и backend¶
Система использует отдельный Angular frontend и Spring Boot backend API. Это снижает связность, позволяет независимо развивать UI и backend-логику, а также создает основу для будущих клиентских каналов.
Root-unit soft multi-tenancy¶
Каждый tenant представлен корневым organizational unit. Tenant-scoped entities содержат root_unit_id, а доступ ограничивается через repositories, specifications, services и API-level checks.
Context-aware authorization¶
Права доступа зависят не только от глобальной роли пользователя, но и от текущей организации и выбранного организационного контекста.
Это соответствует B2B-сценариям, где один и тот же пользователь может иметь разные права в разных организациях или подразделениях.
PostGIS как часть доменной модели¶
Местоположение растений, участки сада, оранжереи, грядки и полигоны моделируются как spatial data, а не как вторичный map overlay.
Гибридная модель текущего состояния и истории¶
Система разделяет текущее операционное состояние и данные, связанные с историей изменений и audit trail. Это позволяет эффективно работать с текущими записями и сохранять трассируемость важных изменений.
Контролируемое публичное раскрытие данных¶
Публичные страницы, карточки растений, списки, фотографии и данные карты публикуются через отдельные public endpoints и DTO.
Visibility rules предотвращают случайное раскрытие внутренних данных тенанта.
Архитектурные компромиссы¶
1. Мягкая мультитенантность вместо полноценной¶
Контекст¶
Система проектируется для множества организаций (как мультитентная). На ранней стадии продукту важны низкая операционная сложность, высокая скорость разработки и достижения функциональных требований (таксономический слой и возможность развивать сетевые сценарии между организациями).
Принятое решение¶
Для изоляции данных используется логическая multi-tenancy модель через атрибут root_unit_id. Корневое подразделение организации является границей организации, все сущности внутри дерева получают ссылку на этот root unit.
Отклонённая альтернатива¶
database-per-tenant или schema-per-tenant.
Обоснование¶
- снижение инфраструктурной сложности на ранней стадии
- допускает поглощение организаций или выделение отделов в организации с минимальной миграцией сущностей
Компромиссы¶
- Изоляция данных логическая, а не физическая, поэтому любая ошибка фильтрации тенанта в любом API может привести к нарушению изолированности тенантов.
- Сложнее выполнять резервное копирование данных отдельной организации, их восстановление, экспорт и физическое удаление (право на забвение).
- Сложнее выделить крупного клиента на отдельную инфраструктуру.
- Шардинг и региональное разделение данных потребуют дополнительного проектирования.
Компенсирующие меры¶
- Все сущности, принадлежащие определенной организации, несут
root_unit_id. - Доступ ограничивается на нескольких уровнях: запросы репозиториев, спецификации JPA, проверки уровня бизнес-логики, авторизация на уровне методов контроллеров.
- Центральная авторизация вынесена в
AccessControlService. - Публичные API возвращают только public DTO и не раскрывают внутренние поля.
- Для критичных сценариев написаны интеграционные тесты запрета доступа к чужому тенанту.
- В целях соответствия 152-ФЗ выделена отдельная зона доступности для пользователей РФ (всего пока два). Запланировано проектирование механизма репликации публичных данных между зонами доступности с учетом возможного отключения РФ-сегмента сети от глобального интернета.
Триггер пересмотра¶
- появление enterprise-клиентов с требованием физической изоляции
- рост объёмов данных до уровня noisy-neighbor проблем
- необходимость регионального хранения данных или юридическом требовании отделять данные организаций физически.
2. Модульный монолит вместо микросервисов¶
Контекст¶
Продукт с широкой доменной моделью: растения, таксономия, культивары, списки, места, импорт, публичные страницы, пользователи, роли, медиа и обмен между организациями. Команда маленькая, а доменная модель ещё активно уточняется. Кроме того не ясно, насколько будет разниться нагрузка на отдельные сущности.
Принятое решение¶
Backend реализован как модульный монолит на Spring Boot: единый артефакт, но с разделением по доменным зонам через контроллеры, сервисы, репозитории, DTO.
Отклонённая альтернатива¶
Набор микросервисов: сервис таксономии, сервис коллекций (+ импорт), сервис медиа, сервис авторизации и идентификации, сервис ГИС, сервис публичных ресурсов.
Почему это разумно сейчас¶
Монолит снижает оверхед от распределенных систем: нет сетевых контрактов между сервисами, нет распределенных транзакций, необходимости строить инфраструктуру поиска сервисов, нет сложной обозреваемости и оркестрации межсервисных отказов. Это ускоряет доставку и позволяет держать доменную модель целостной, пока продукт ещё не вышел за границы первых пилотов.
Компромиссы¶
- Нельзя независимо масштабировать отдельные доменные модули.
- Ошибка в одном модуле может повлиять на весь backend.
- Со временем появляется риск неявных зависимостей между доменными областями.
- Импорт, медиа и GIS могут иметь разные профили нагрузки, но пока живут в одном приложении.
Компенсирующие меры¶
- Жёсткое пакетное разделение по доменным областям. Сервисный слой как граница для бизнес-логики, DTO как граница API. Тем самым снижается стоимость выделения ограниченного контекста в сосбтвенный сервис
- Асинхронное выполнение тяжёлых импортов, чтобы не держать один поток и не хватать таймауты.
Триггер пересмотра¶
Выделение сервисов имеет смысл, когда конкретный модуль получает независимый масштаб нагрузки, отдельную команду владения, отдельный график релизов или отдельные требования к отказоустойчивости. Первые кандидаты на выделение: import pipeline, media processing/storage gateway, public map/search read model.
3. Монорепозиторий для backend и frontend вместо отдельных репозиторий¶
Контекст¶
Проект разрабатывается небольшой командой, где один разработчик отвечает за архитектуру, backend, frontend, deployment и интеграцию. Для таких условий важнее скорость согласованных изменений, чем организационная независимость команд.
Принятое решение¶
Backend и frontend хранятся в одном репозитории.
Отклонённая альтернатива¶
Отдельные репозитории для backend, frontend, инфраструктура и документация.
Почему это разумно сейчас¶
Монорепо позволяет делать атомарные изменения API и UI, проще держать архитектурный контекст целиком, быстрее проводить full-stack рефакторинг и LLM-генерацию кода. Результат более стабильный потому что модель видит связанную картину продукта.
Компромиссы¶
- Границы ответственности могут размываться при росте команды.
- Сложнее ограничивать доступ к отдельным частям кодовой базы.
- Выше риск широких изменений без понимания радиуса влияния.
Компенсирующие меры¶
- Раздельные frontend/backend папки и независимые команды сборки и запуска.
- Интеграционные тесты взаимодействия frontend и backend.
Триггер пересмотра¶
Раздельные репо станут оправданными, если появятся независимые команды с разным релизным циклом, разные политики доступа к коду, необходимость публиковать части системы независимо.
4. Docker Compose вместо cloud native.¶
Контекст¶
На ранней стадии нужно быстро разворачивать систему на VPS, демонстрировать продукт, проводить пилоты и держать инфраструктурные расходы низкими.
Принятое решение¶
Backend, frontend, PostgreSQL/PostGIS и MinIO запускаются в одном Docker Compose контуре.
Отклонённая альтернатива¶
Полноценная cloud-native инфраструктура с отдельными мощностями под БД, объектное хранилище, с автоскейлингом контейнеров, мониторинг и развертку с множественными зонами доступности.
Почему это разумно сейчас¶
Docker Compose даёт быстрый быстрый холодный старт, воспроизводимое окружение, низкую стоимость и простую операционную модель. Для MVP, демо-стенда и раннего пилота это лучше, чем преждевременная сложность cloud native.
Компромиссы¶
- Один VPS является единой точкой отказа.
- БД, объектное храниище и сервисы конкурируют за ресурсы.
- Масштабирование в основном вертикальное.
- Нет полноценной high availability модели, нет учёта пиков нагрузки. Нельзя считать продуктовой архитектурой.
- Резервное копирование, восстановление и мониторинг становятся критичными операционными задачами.
Компенсирующие меры¶
- Сервисы остаются stateless.
- Конфигурация должна быть env-based.
- Данные БД и объектного хранилища живут в персистивных томах с регулярными резервным копированием.
- Reverse proxy / TLS / rate limits выносятся в инфраструктурный слой.
- Целевой путь миграции должен быть заранее описан: отдельные инстансы PostgreSQL/PostGIS, S3-совместимые хранилища, горизонтальное масштабирование контейнеров сервисов.
Триггер пересмотра¶
Переход нужен при появлении платящих клиентов, SLA-ожиданий, роста объёма фото/импортов, требований к высокой доступности, регулярных простоев VPS или необходимости регионального размещения данных.
... для портфолио опубликована только часть компромиссов.
См. также Architecture Decision Records.
Дорожная карта и демонстрация¶
Дорожная карта¶
| Фаза | Цель | Инфраструктура | Exit criteria |
|---|---|---|---|
| MVP / demo | показать рабочую систему и основные сценарии | VPS + Docker Compose | demo flow, backup, базовая наблюдаемость |
| Pilot | загрузить реальные данные и собрать обратную связь | VPS + регулярные backup-процедуры, при росте медиа перейти на внешний S3 | импорт реальной коллекции, список UX/data проблем |
| Первые покупатели | обеспечить предсказуемую эксплуатацию | отдельная БД, внешнее S3-совместимое объектное хранлище, мониторинг | платящая организация, процедура восстановления, поддержка |
| Рост | подготовить масштабирование и региональные контуры | отдельная БД, внешнее S3-совместимое объектное хранлище, отдельные workers (импорт), оптимизация чтения, региональная стратегия | рост числа тенантов, SLA ожидания, региональное распределение тенантов |
Скриншоты и демо¶
Глобальная карта¶
Управление растениями¶
Управление местами и границами¶
Импорт растений с AI-поддержкой¶
Что демонстрирует проект¶
Этот проект демонстрирует мои способности:
- работать на стыке системного анализа, backend дизайна, имплементации и деплоя.
- довести идею до запуска системы с несколькими зонами доступности и дорожной картой масштабирования
- стратегически планировать имплементацию SaaS малого-среднего масштаба
- безопасно и контролируемо применять LLM-генерацию кода для имплементации фичей



