Self-hosted платформа обработки данных

uproj

Превращает сырые данные в решения — на вашей инфраструктуре, за дни, а не кварталы.

6Grain · Руанда

Проблема

Данные есть — пользоваться ими трудно

🛰️

Разрозненность

У каждого провайдера свой API, формат и авторизация.

🐘

Объём

Терабайты на область. Скачать на ноутбук нереально.

🧪

Разовые скрипты

Ноутбуки аналитиков не становятся повторяемым пайплайном по расписанию.

🔒

Суверенитет

Облачный SaaS — данные и результаты уезжают из страны.

🧰

Обвязка

80% любого проекта — инфраструктура: каталог, тайлинг, хранилище, доступ.

Медленно

Месяцы от «есть идея» до «работает каждую ночь».

Идея

Платформа берёт на себя скучные 80%, чтобы аналитики делали ценные 20%.

Что такое uproj

Каталог, среда исполнения и API self-hosted

🗂️

Каталог

Каждый вход и результат — элемент каталога, один индекс с поиском.

⚙️

Исполнение

Загрузил скрипт на Python, R или Java → запускается в песочнице, по расписанию и с масштабированием.

🔌

API + UI

Открытые стандарты (STAC, OGC), тайлы карты, загрузки, веб-интерфейс.

Работает на ваших серверах. Данные никуда не уходят.

Что вы получаете
Дни
от идеи до пайплайна, работающего каждую ночь — не месяцы
Любой
любой источник или аналитика на Python, R или Java — всё в одном каталоге
On-prem
данные и результаты никогда не покидают ваши серверы

Вся платформа на одной схеме

🌐
Браузер
веб-интерфейс
⌨️
CLI / SDK
скрипты оператора
Вход
🚪
Edge · единая точка входа
один порт, маршрутизация путей
Сервисы платформы
🖥️
Веб-интерфейс
обзор, запуск, контроль
🔌
REST + OGC API
процессы · джобы · запуски
🗂️
Каталог (STAC)
входы + результаты
🗺️
Тайлы карты
превью на карте
🔐
Авторизация
идентичность и доступ
Данные и вычисления
📦
Объектное хранилище
сцены и результаты
⚙️
Песочница исполнения
контейнер на запуск
🐘
PostgreSQL
индекс каталога + состояние
Для ваших аналитиков

Аналитик пишет скрипт — на Python, R или Java. Платформа делает из него сервис по расписанию с каталогом — без DevOps.

01

Что делает платформа

Один пайплайн, от и до

Загрузка
Затягиваем данные
Зеркалируем сцены из любого источника в каталог.
Подготовка
Считаем
Индексы, композиты, маски — ваша аналитика.
Публикация
Обратно в каталог
Результаты ложатся элементами каталога, готовы к работе.
Отдача
Карта · API · загрузка
Открыть на карте, спросить API, скачать файл.
Расписание
Cron + цепочки
Cron запускает цепочку; каждый завершённый этап запускает следующий, без ручного вмешательства.
Переиспользование
Единый источник
Входы и результаты — с поиском, в одном месте.

Подключайте любой источник данных

📡

Публичные архивы

Открытые спутниковые и растровые архивы — затягиваются по расписанию.

🏢

Коммерческие провайдеры

API и фиды вендоров — под вашими ключами.

🗺️

Ваши данные

Дрон, аэросъёмка, векторные границы — всё, к чему есть коннектор.

Коннектор — это просто Python: новый источник = скрипт, а не проект.

Каталог — всё в одном месте

Входы и результаты — с поиском и пагинацией, превью и загрузкой.

Три понятия — вся модель

📦

Процесс

Загруженный версионируемый Python-проект. Иммутабельный — адресуется версией.

🗓️

Джоба

Сохранённая конфигурация: какой процесс, какие параметры, опциональное расписание.

▶️

Запуск

Одно исполнение — состояние, логи и полученный результат.

Открывается прямо в QGIS

Результаты открываются в QGIS по открытым стандартам — без экспорта и копий.
02

Данные и продукты из коробки

Четыре источника, зеркалируются по расписанию

🛰️

Sentinel-2 L2A

Оптическая поверхностная отражательная способность от Element 84. Маска облаков по SCL, обрезка по стране, COG.

🛰️

Landsat 8/9 C2 L1

Сцены USGS (OLI/TIRS). Облака, тени и cirrus убираются по QA_PIXEL, обрезка по стране.

📡

Sentinel-1 γ⁰ RTC

Террейн-корректированный радар из Planetary Computer. VV/VH, линейный float32 + dB для показа, 10 м, EPSG:32735.

🗺️

Административные границы

Все уровни ADM из geoBoundaries (CC BY 4.0) как вектор — по ним же режутся остальные источники.

Все четыре — обычные ingest-скрипты, тот же контракт, что и у ваших собственных.

Оптические индексы — каждый тумблером

🌱

Вегетация

NDVI, EVI, MSAVI2, GNDVI — плюс NDRE по red-edge-каналу Sentinel-2.

💧

Влага и вода

NDMI — влажность полога; NDWI и MNDWI — открытая вода.

🔥

Гарь и застройка

NBR — выгоревшие площади, NDBI — застроенные поверхности.

Каждый индекс — один канал, один COG (int16 ×10000). Набор общий для Sentinel-2 и Landsat; red-edge для NDRE есть только у Sentinel-2.

Радар видит сквозь облака

📡

Поляриметрия Sentinel-1

Четыре dual-pol-индекса по линейному γ⁰: PolNDVI, DpRSI, RVI и dual-pol RVI (Mandal 2020).

🌧️

Всепогодно

Радар не зависит от облаков и работает днём и ночью — покрытие там, где оптика слепнет.

📈

Скользящий NDVI-композит

Перцентильная мозаика NDVI Sentinel-2 за скользящее окно (p80 = самое зелёное чистое наблюдение), обрезка по стране.

Радар плюс оптика дают сигнал без пропусков; композит — один чистый слой на каждый день.

03

Архитектура

Сервисы за единой точкой входа

🌐
Браузер
веб-интерфейс
⌨️
CLI / SDK
скрипты оператора
Вход
🚪
Edge · единая точка входа
один порт, маршрутизация путей
Сервисы платформы
🖥️
Веб-интерфейс
обзор, запуск, контроль
🔌
REST + OGC API
процессы · джобы · запуски
🗂️
Каталог (STAC)
входы + результаты
🗺️
Тайлы карты
превью на карте
🔐
Авторизация
идентичность и доступ
Данные и вычисления
📦
Объектное хранилище
сцены и результаты
⚙️
Песочница исполнения
контейнер на запуск
🐘
PostgreSQL
индекс каталога + состояние

Каждый кусок делает одно дело хорошо

🚪

Edge

Один порт, маршруты / · /api · каталог · тайлы · auth · хранилище.

🔌

API

REST + OGC API Processes — отправить работу, забрать результат.

🗂️

Каталог

STAC поверх PostgreSQL — входы и результаты, один индекс.

📦

Хранилище

S3-совместимое объектное хранилище для каждой сцены и результата.

🗺️

Тайлы

Тайлы карты на лету прямо из сохранённых растров.

🔐

Идентичность

OIDC-вход, API-токены, доступ по ролям.

Открытые стандарты, без лок-ина

🌐

STAC

Каталог говорит на STAC — работает с QGIS и всей экосистемой.

⚙️

OGC API

Процессы и тайлы по OGC — подключается любой совместимый клиент.

🗃️

Простые форматы

Cloud-optimized GeoTIFF, JSON, S3 — ничего проприетарного.

Данные остаются портативными — вы не заперты в нашем формате.

Работает там, где нужно вам

🐳

Контейнеры

Весь стек — контейнеры, поднимается одной командой.

🔌

Air-gap

Не требует звонков наружу; работает в закрытой сети.

🖥️

Ваше железо

На серверах, которые у вас уже есть, в вашем ЦОД.

On-prem по умолчанию — суверенитет не довесок, а исходное состояние.

04

Как работает запуск

От клика до результата в каталоге

1 · Триггер
Кнопка или cron
Создаётся запуск — человеком или по расписанию.
2 · Допуск
Планировщик
Проверка квоты и single-active; запуск → pending.
3 · Песочница
Контейнер
Изолированный контейнер с минимально необходимым доступом.
4 · Исполнение
Ваш Python
Читает входы, считает результат, пишет вывод.
5 · Публикация
Регистрация
Вывод сохранён и зарегистрирован элементом каталога.
6 · Готово
В каталоге
Результат, логи и статистика — видны и переиспользуемы.

Каждый запуск — песочница

🔒

Урезанные права

Без привилегий, non-root, лимиты CPU/RAM/процессов, жёсткий таймаут.

🔑

Ограниченный доступ

Креды на запуск: читает свои входы, пишет только свой вывод.

🌐

Сетевая изоляция

Не видит БД и сервис авторизации; исходящий трафик закрыт, при необходимости — по белому списку.

Враждебный или кривой код влияет только на свой запуск — и всё.

Надёжно по умолчанию

🗓️

Расписание

Cron на джобу; планировщик допускает запуски и держит квоты.

🔗

Цепочки джоб

Завершённый запуск запускает следующий — ingest → подготовка → анализ, без внешнего оркестратора.

🚦

Без завалов

Single-active guard — медленный запуск не наслаивается сам на себя.

📜

Полный аудит

Структурированные логи, статистика по каждому запуску, состояние каждого исполнения.

05

Как аналитики пишут скрипты

Контракт крошечный

🐍

Ваш Python

src/ с вашим кодом — любые библиотеки, что объявите.

📄

pyproject.toml

Обычные зависимости. Окружение собирает платформа.

📝

process.yaml

Объявляет параметры, типы и дефолты — из него строится форма в UI.

▶️

entrypoint

Один файл на запуск. Параметры берёт из окружения.

Заархивировал, загрузил — это процесс. Без Dockerfile и инфры.

Python, R или Java — один контракт

🐍

Python

pyproject.toml + entrypoint. Платформа собирает venv через uv и запускает.

📊

R

renv.lock + entrypoint .R. renv::restore() восстанавливает тот же набор пакетов и запускает.

Java

Maven-проект pom.xml. Платформа выполняет mvn package и запускает собранный jar.

Один контракт запуска для всех языков: те же параметры, то же хранилище, тот же каталог. Рантайм выбирается в process.yaml — платформа монтирует нужный образ и кэш зависимостей.

Один результат, три языка

🧮

Одна аналитика, три порта

Один и тот же NDVI-демо есть на Python, R и Java — те же входы, тот же контракт.

📦

Идентичный бандл на выходе

Каждый пишет один и тот же продукт: COG, превью PNG, CSV со статистикой и PDF-отчёт на одну страницу.

🗂️

Один элемент каталога

Все три публикуют результат одинаково — каталог не отличает, на каком языке он получен.

Доказательство: рантайм — это выбор, а не ограничение; команда пишет на привычном языке.

process.yaml — объявляете параметры

id: s2-ndvi
title: Sentinel-2 NDVI
category: preparation
entrypoint: src/main.py
inputs:
  - name: bbox
    type: bbox
    default: "28.8,-2.8,30.9,-1.0"
  - name: start_date
    type: string
    default: ""
  - name: max_cloud_cover
    type: integer
    default: 60
  • Типы строят форму в UI — bbox-пикер, дата, число.
  • Дефолты — джоба работает без настройки.
  • category задаёт расписание и поведение по умолчанию.
  • Никакой обвязки параметров — их передаёт платформа.

Категория задаёт поведение

📥

ingest

Затягивает внешние данные в каталог. По умолчанию — ночью.

🧮

preparation

Выводит продукты из данных каталога. Запускается после ingest.

📊

compute

Аналитика с результатами — по требованию или по расписанию.

Выбрал категорию — разумное расписание и публикация уже настроены.

SDK — это просто переменные окружения

import os, json

params = json.loads(os.environ["UPROJ_PARAMS"])
bbox = params["bbox"]

# read inputs straight from object storage via GDAL
src = "/vsis3/inputs/s2-l2a/.../red.tif"

# where to write + how to call back
out_dir = os.environ["UPROJ_OUTPUT_DIR"]
api     = os.environ["UPROJ_API_URL"]
token   = os.environ["UPROJ_SERVICE_TOKEN"]
  • Параметры приходят как JSON — без фреймворка парсинга.
  • Растры читаются на месте из хранилища — без скачивания.
  • Короткоживущий токен авторизует вызовы каталога.
  • Обычный Python — любые библиотеки на ваш вкус.

Разбор — ingest-скрипт

# 1. search the source for new scenes in the window
scenes = search(bbox, since=window_start)

# 2. mirror each asset into the catalog's storage
for s in scenes:
    for asset in s.assets:
        copy_to_storage(asset.url, key=object_key(s, asset))

    # 3. register the scene as a catalog item
    register_item(stac_item(s))
  • Поиск → зеркалирование → регистрация. Это ingest.
  • Уже зеркалированные сцены пропускаются — перезапуск дёшев.
  • Задал дату старта — бэкфилл; дальше катится вперёд по ночам.

Разбор — preprocess-скрипт

# read bands in place, compute the index
red = read("/vsis3/inputs/s2-l2a/.../red.tif")
nir = read("/vsis3/inputs/s2-l2a/.../nir.tif")
ndvi = (nir - red) / (nir + red)

# write a cloud-optimized GeoTIFF + register it
write_cog(ndvi, f"{out_dir}/ndvi.tif")
register_item(stac_item("s2-ndvi", scene_id))
  • Читает исходники из хранилища, пишет COG.
  • Публикует обратно в каталог как новый продукт.
  • Тот же шаблон для любого индекса, маски или композита.

Загрузка — авто-версионирование

Каждая загрузка — новая иммутабельная версия; в проде ничего не ломается.

Свяжите джобу с расписанием

Выбрал процесс, заполнил форму (дефолты уже стоят), добавил cron — готово.
06

Платформа в работе

Каталог — все входные данные

Входы и результаты в одном браузере с поиском и пагинацией.

Карта и анализ

Сцены и результаты на одной интерактивной карте — наложение, перекраска, инспекция.

Maps · Analysis — анализ результатов на месте

🗺️

Стек слоёв

Накладывайте любое число растров каталога; перетаскивание для порядка, прозрачность и палитра на слой.

🎚️

Легенды в реальных единицах

Шкала каждого слоя — в физических единицах; классовые карты получают подписанный чип на категорию.

🎯

Клик — и видно значение

Один клик показывает значение пикселя сразу по всем видимым слоям.

🛰️

Подложки и поиск

Подложки OSM, спутник или топо, поиск места для перехода куда угодно.

Джобы — конфигурации + расписание

Каждая джоба: процесс, параметры, опциональный cron, кнопка запуска.

Запуски — всё под контролем

Состояние, логи и результат в каталоге для каждого запуска.

Секреты — шифрованные, по владельцу

Креды хранятся шифрованно, привязаны ко входу процесса, не отдаются обратно.

Панель операций

Контейнеры, диск и последние запуски — оператору с одного взгляда.

Настройки — на лету, без рестарта

Лимиты, доступ и категории из UI; изменения применяются сразу.

Пользователи и доступ

Идентичность на OIDC — админы и пользователи, настоящий ролевой доступ.
07

Эксплуатация и доверие

Безопасность по слоям

🧱

Песочница запусков

Урезанные контейнеры — без привилегий, с лимитами и таймаутом.

🔑

Изолированное хранилище

Каждый запуск видит только свои данные, ничего больше.

🌐

Сетевая изоляция

Запуски не видят БД и сервис авторизации; исходящий трафик закрыт, при необходимости — по белому списку.

👤

Идентичность и RBAC

OIDC-вход, API-токены, админ vs пользователь — настоящий контроль доступа.

Делитесь осознанно, по умолчанию — приватно

👤

Видно владельцу

Процесс виден владельцу и админам — ничего не открывается случайно.

🤝

Шаринг по желанию

Один флаг — и процесс виден остальной команде.

🌍

Публичные ссылки, fail-closed

Открыть результат или его тайлы по анонимной ссылке можно только через явный белый список — выключено, пока сами не включите.

Любое расширение аудитории — осознанное действие, а не поведение по умолчанию.

Эксплуатация без сюрпризов

📊

Наблюдаемость

Структурированные логи, статистика по каждому запуску, дашборд оператора.

💾

Бэкапы

Дамп БД и инвентаризация хранилища — одной командой.

⬆️

Установка и обновление

Установка и обновление — по одной команде, без ручных шагов.

08

Почему uproj

Не ноутбук. Не облачный счёт.

📓

против ноутбуков

Повторяемо, по расписанию, с каталогом, многопользовательски — не разовый скрипт.

☁️

против облачных SaaS

On-prem и суверенно — без egress-платы за сцену, на вашем железе.

🧩

Расширяемо

Любой новый источник или аналитика — это просто код на Python, R или Java; тот же контракт.

Куда движемся дальше

🛡️

Строже по исходящему трафику

Декларативные белые списки исходящего трафика на процесс.

📈

Стек наблюдаемости

Опциональные метрики и дашборды для крупных развёртываний.

GPU-вычисления

Тяжёлая аналитика на ускоренных рантаймах.

Давайте сделаем

Ваши данные, ваши серверы, ваши аналитики — в проде на следующей неделе.

6Grain · uproj.6grain.com