Всем привет! Мы — ребята из команды разработки спецпроектов Тинькофф: Гена, Кирилл, Витя, Миша, Никита и Леша. Команда спецпроектов разработала и запустила проекты «Монополия Тинькофф», «5 букв», «Пока, пакет» и многие другие. Мы расскажем о том, как создаем благотворительные проекты и почему процесс сбора заявок не так прост, как кажется.

Поделимся, как разрабатывали систему приема и оценки заявок для грантового конкурса, какие библиотеки для валидации и моделирования статусной модели заявки использовали. Расскажем, как проектирование архитектуры без архитектора помогает нам прокачивать разработчиков и динамично реагировать на требования бизнеса.

Поддержка будет

Цель проекта — поддержать благотворительные организации. Конкурс проводится с 2021 года, и в нем поучаствовали больше тысячи НКО. Для участия в проекте фонды оставляли заявки на сайте проекта, а независимые эксперты из некоммерческого сектора оценивали заявки, выбирали самые актуальные, предоставляли помощь и контролировали целевое использование денежных средств.

Проект «Поддержка будет» — не единственный наш грантовый проект. Второй год подряд мы запускаем проект «Скиньте мяч», в рамках которого выделяем гранты на реализацию социальных инициатив в городах по всей России. Проекты похожи по функциональным и нефункциональным требованиям, а различаются тем, что в проекте «Поддержка будет» принимают участие НКО, а в проекте «Скиньте мяч» — физические лица.

Шер проекта «Поддержка будет»
Шер проекта «Поддержка будет»

Работа с требованиями

Техническая реализация проекта «Поддержка будет» может показаться довольно простой — это сайт, на котором можно заполнить заявку для участия или посмотреть результаты предыдущих запусков проекта.

В дополнение к этому проект должен: 

  • собирать и безопасно хранить заявки;

  • предоставлять интерфейс для безопасной и непредвзятой модерации и оценки заявок; 

  • хранить историю действий модераторов и экспертов;

  • перезапускаться в минимальные сроки и с минимальными издержками на разработку.

На первом этапе мы определились с функциональными и нефункциональными требованиями. В разработке требований у нас участвуют менеджер проекта, фронтенд- и бэкенд-разработчики и тестировщик. Мы намеренно отказались от роли архитектора, потому что в условиях динамичной разработки проектов архитектор становится бутылочным горлышком, а его ошибка стоит очень дорого. 

Задачи с высокой степенью неопределенности требуют быстрого и профессионального реагирования на местах, поэтому мы сделали акцент на T-shape-развитии разработчиков. Наши ребята способны самостоятельно проектировать инфраструктуру и решать сложные задачи. 

Мы работаем в небольших продуктовых командах, поэтому нам легко закрепить зоны ответственности, а конфлюенс как единый источник истины о системе и оперативная коммуникация внутри команды позволяют быстро подстраивать проектируемую систему под требования бизнеса.

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

В контексте проекта «Поддержка будет» наша команда сконцентрировалась на таких нефункциональных требованиях:

  • data retention — хранение персональных данных в соответствии с юридическими ограничениями;

  • security — безопасная авторизация пользователей/админов/экспертов, разграничение прав и доступов в систему;

  • auditability — возможность системы ответить на вопросы, кто, что и когда делал с данными;

  • flexibility — возможность системы адаптироваться к меняющимся требованиям.

Чтобы удовлетворить все требования, нам потребовалось реализовать веб-приложение для приема заявок на конкурс, веб-приложение для модерации и оценки заявок и приложение для сохранения заявок, безопасного доступа к данным и авторизации пользователей, админов и экспертов.

Система сбора и оценки заявок

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

Простая задача по сбору и хранению заявок осложняется большим количеством персональных данных в заявке. Важное требование — прозрачность процесса оценки заявок и безопасная передача ПД экспертам из профильных организаций. А еще оценка 500+ заявок для каждого конкурса требует времени, а значит, дополнительных расходов, поэтому в наших интересах сделать процесс максимально быстрым, удобным и прозрачным. Проанализировав требования, мы решили спроектировать и разработать собственную систему для приема и оценки заявок. 

Первый элемент системы — веб-приложение для сбора заявок. Мы подключили интеграцию с Tinkoff ID, чтобы сделать вход в приложение простым и безопасным. Дизайн веб-приложения тоже не вызвал трудностей. Задачу создать дружелюбный интерфейс с референсами к айдентике Тинькофф ребята-дизайнеры выполнили на отлично. Следующим шагом был выбор безопасного и эффективного хранилища данных.

Страница авторизации пользователя в проекте. В качестве авторизационного провайдера используется Tinkoff ID
Страница авторизации пользователя в проекте. В качестве авторизационного провайдера используется Tinkoff ID

База данных для хранения заявок

Мы развиваем собственные облачные технологии и умеем предоставлять внутренним пользователям множество решений по модели Software as a Service. К таким решениям относится и Database as a Service. Для хранения пользовательских данных мы использовали PostgreSQL, предоставляемый по модели DBaaS, чтобы наши пользователи не переживали за сохранность и безопасность хранения данных. 

Преимущества от использования базы данных по модели DBaaS:

  • банковские инструменты SRE/SLA;

  • банковские инструменты Observability;

  • хранение персональных данных в соответствии с законодательством РФ;

  • отказоустойчивое и проверенное решение.

Это очень важные преимущества, когда речь идет о долгосрочной поддержке проекта. Нам необходимо хранить данные надежно и безопасно, а еще получать оперативную обратную связь о состоянии инфраструктуры. 

Для реализации формы мы использовали UI Kit платформы Тинькофф, чтобы подчеркнуть преемственность интерфейсов и переиспользовать гибкую палитру React-компонентов платформы от простых инпутов до сложных календарей с интервалами дат. У нас пока нет возможности поделиться UI Kit под React, но можно посмотреть возможности опенсорсной реализации UI Kit под Angular.

Наиболее приоритетными требованиями к форме были: 

  • гибкость к изменениям в требованиях;

  • скорость синхронизации схемы валидации данных;

  • сохранение промежуточного состояния заявки в БД;

  • целостность данных при сохранении заявки.

Решение этой задачи прошло несколько итераций. Первый же запуск проекта показал, что верстка формы с помощью formik или react-hook-form требует слишком много времени. Требования бизнеса могут стремительно меняться. Нужно быстро удалять или добавлять поля формы, при этом успевать синхронизировать валидацию данных на бэкенде и фронтенде.

Синхронизация схемы данных с помощью JSON-схемы

Синхронизация схемы валидации данных отнимала время, потому что каждая задача на изменение полей формы включала как минимум двух разработчиков — изменить на бэкенде, изменить на фронтенде. Ребята-разработчики предложили использовать JSON-схему для валидации данных заявки на бэкенде и для верстки формы в веб-приложении. 

Первым решением стала библиотека react-jsonschema-form, которую мы внедрили в админку на первом запуске проекта. Библиотека доказала, что JSON-схема интуитивно понятна и ее структуру несложно изучить. UI-схема казалась избыточной, а подключить к библиотеке react-jsonschema-form UI Kit Тинькофф было непросто. 

Мы решили написать собственную реализацию, которая не поддерживает рекурсивный рендеринг, но имеет согласованную с дизайнерами стилизацию и структуру. Для этого взяли formik и написали вокруг него библиотеку с множеством валидаторов, поддержкой кастомных сообщений об ошибках, валидацией на onBlur или onSubmit, поддержкой полей типа Date, File, Range и другими опциями, которые кастомизируются за пару секунд с помощью JSON-схемы.

Часть секции «Информация об организации» в форме заявки, сверстанная с помощью JSON-схемы с использованием UI Kit платформы Тинькофф
// Часть JSON-схемы для рендера формы в веб-приложении 
// и валидации данных в NodeJS-приложении
{
  // ...
  organizationInn: {
    formRowParams: {
      title: 'Информация об организации',
      sectionId: SectionId.UserOrganization,
    },
    type: 'string',
    fieldType: 'plane',
    initial: '',
    validators: {
      isRequired: true,
      minLength: 10,
      maxLength: 10,
    },
    errorMessages: {
      isRequired: 'Заполните поле',
      minLength: 'ИНН должен состоять из 10 цифр',
      maxLength: 'ИНН должен состоять из 10 цифр',
    },
    component: {
      isNumber: true,
      type: 'dadata-company-autocomplete-suggestion',
      label: 'ИНН',
      placeholder: '7710140679',
      dataQA: 'organization-inn',
      pathToFieldValueInSuggestion: 'data.inn',
      showCompanyNameInSuggestion: true,
      fieldToAutocompleteMap: {
        organizationOgrn: 'data.ogrn',
        organizationName: 'value',
        organizationLegalAddress: 'data.address.value',
        ['fundHead.name']: 'data.management.name',
      },
    },
  },
  // ...
}

Следующим шагом стал перенос JSON-схемы на бэкенд и валидация данных заявки с помощью пакета ajv. Мы решили хранить схему в базе данных, чтобы безрелизно вносить в нее правки. Так мы получили единый источник истины о структуре заявки.

Диаграмма коммуникации для отрисовки формы в веб-приложении и валидации данных на бэкенде
Диаграмма коммуникации для отрисовки формы в веб-приложении и валидации данных на бэкенде

Преимущества выбранного подхода: 

  • для изменения полей формы не нужно ставить задачу на фронтенд- и бэкенд-разработчика. С задачей справится, причем очень быстро, всего один человек;

  • не нужно синхронизировать валидацию данных заявки на бэкенде и поля в форме на фронтенде. Валидация на бэкенде и форма всегда синхронны;

  • существенно возросла скорость перезапуска проекта и уменьшились затраты на разработку.

Следующий шаг — модерация и оценка.

Веб-приложение для модерации и оценки заявок

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

Чтобы наши пользователи не переживали за сохранность ПД и непредвзятую оценку заявки, а мы экономили время на оценке заявок на каждом перезапуске проекта, приложение должно включать функциональности:

  • первичная ручная модерация заявок до назначения на экспертов;

  • автоматическое распределение заявок на экспертов по профессиональным навыкам экспертов в зависимости от категории НКО;

  • распределение как минимум на двух экспертов; если оценки обоих экспертов не совпали, то назначение третьего;

  • распределение доступов между экспертами — эксперт видит только назначенные на него заявки;

  • логирование всех действий модераторов и экспертов в системе.

После сохранения в БД заявке присваивается статус. Каждое действие с заявкой переводит ее в новый статус: «На модерации», «Ожидает оценки» и т. д. Это классический конечный автомат. Для его проектирования мы использовали инструмент stately.ai и библиотеку xstate. 

Stately.ai позволяет прямо в веб-интерфейсе прогонять заявку по статусам и выявлять недостающие переходы или deadlock-и. С помощью stately.ai мы спроектировали статусную модель, а затем реализовали ее в коде и адаптировали интерфейс веб-приложения.

Статусная модель заявки, спроектированная в stately.ai с помощью библиотеки xstate
Статусная модель заявки, спроектированная в stately.ai с помощью библиотеки xstate

Для модерации и оценки заявок требуется открыть внешним экспертам доступ к заявкам. При этом заявки содержат большое количество ПД, поэтому просто рассылать экспертам файлы с заявками нельзя. А еще эксперт должен иметь доступ только к тем заявкам, что назначены на него для оценки, чтобы его оценка была максимально беспристрастной. 

На оценку каждой заявки назначаются минимум два эксперта, чтобы исключить субъективную оценку, а если оценки не совпадают (один отклонил, второй одобрил), то автоматически назначается третий эксперт.

Схема отбора заявки для участия в финальном этапе отбора заявок в рамках благотворительного конкурса «Поддержка будет»
Схема отбора заявки для участия в финальном этапе отбора заявок в рамках благотворительного конкурса «Поддержка будет»

Tinkoff ID позволил нам переиспользовать авторизацию из основного веб-приложения и в относительно короткие сроки интегрировать механизм продления сессии для пользователей, модераторов и экспертов. 

Для разграничения доступов мы просто использовали белый список идентификаторов модераторов/экспертов. Интеграция с Tinkoff ID помогла оставить внешних экспертов с доступом только к одной конкретной системе — веб-приложению для оценки заявок. Никакие другие доступы внешним подрядчикам не выдавались. В то же время мы подключили логирование каждого действия экспертов, чтобы исключить любые попытки сговора или некорректной оценки заявки. 

На этапе проектирования интерфейса нам снова помог UI Kit Тинькофф. С помощью него фронтенд-разработчик быстро собрал таблицу для отображения списка заявок с асинхронной пагинацией.

Таблица с сохраненными заявками. Вид для роли «админ». Все данные тестовые
Таблица с сохраненными заявками. Вид для роли «админ». Все данные тестовые

Максимальной унификации мы достигли с подключением JSON-схемы для отображения данных заявки, потому что безрелизная правка схемы вносит изменения в форму заявки у пользователей, одновременно та же схема используется для валидации данных в NodeJS-приложении и для отображения данных заявки у модераторов/экспертов.

Таблица c заявками, ожидающими оценки. Вид для роли «эксперт»
Таблица c заявками, ожидающими оценки. Вид для роли «эксперт»

Заключение

В плане функциональных и нефункциональных требований у спецпроекта «Поддержка будет» много ограничений из-за персональных данных пользователей в заявке. Поэтому мы спроектировали и успешно реализовали систему для приема, модерации и оценки заявок.

Использование JSON-схемы позволило безрелизно синхронизировать все элементы системы, а это уменьшило количество рутинных задач для разработчиков. Благодаря stately.ai и xstate мы спроектировали статусную модель заявки без deadlock-ов, а интеграция с готовыми решениями, такими как Tinkoff ID и Tinkoff UI Kit, значительно ускорила разработку. И главное, благодаря горизонтальному подходу к дизайну мы успешно реализовали все функциональные и нефункциональные требования.

В итоге у нас получилась автоматизированная и безопасная система для модерации и оценки заявок, которая отлично себя показала на грантовых проектах «Поддержка будет» и «Скиньте мяч». 

А самое ценное, что работа над такими проектами — это не только профессиональный челлендж, но и понимание, что ты помог сделать жизнь людей лучше.

Расскажите про ваши кейсы и пишите вопросы в комментариях!

Комментарии (0)