Требования к качеству при проверке приложения
Stripe проверяет каждое приложение, отправленное на маркетплейс, по обширному набору требований к качеству. Если разобраться в этих стандартах до начала разработки, вы сэкономите время и сократите число итераций проверки.
Обзор
Проверка Stripe App оценивает приложение по шести ключевым областям:
- Прозрачное ценообразование: понятное информирование о стоимости
- Функциональность приложения: надёжность и полнота
- Стандарты разработчика: качество кода и использование API
- Качество UX: стандарты пользовательского интерфейса и опыта
- Безопасность: защита данных и безопасные практики
- Правовое соответствие: конфиденциальность и нормативные требования
Прозрачное ценообразование
Приложение должно понятно сообщать пользователям обо всех затратах:
- Раскрытие цен: все цены указываются заранее, в листинге на маркетплейсе
- Никаких скрытых платежей: пользователь не должен столкнуться с неожиданными списаниями после установки
- Условия пробного периода: если вы предлагаете пробный период, чётко укажите его продолжительность и что произойдёт после его окончания
- Сценарии перехода на платный план: любые предложения апгрейда должны быть ненавязчивыми и явно необязательными
- Валюта: по возможности показывайте цены в валюте пользователя
Caution
Приложения, которые скрывают цены или списывают средства без явного согласия пользователя, отклоняются сразу.
Форматирование даты и времени
Все даты и время, которые показывает приложение, должны следовать соглашениям Stripe Dashboard:
- Используйте локаль пользователя для форматирования дат, когда она доступна
- Показывайте время в часовом поясе пользователя
- Для недавних событий используйте относительные метки времени (например, «2 часа назад»)
- Для более старых событий используйте абсолютные метки времени с полной датой и временем
- Для любых полей дат, обращённых к API, следуйте ISO 8601
// Good: Use Stripe's date formatting utilitiesimport { formatDate, formatRelativeTime } from '@stripe/ui-extension-sdk/utils';
const formattedDate = formatDate(timestamp); // Locale-awareconst relativeTime = formatRelativeTime(timestamp); // "2 hours ago"Настройки приложения
Если приложению нужна настройка:
- Сделайте отдельное представление настроек, доступное из вьюпорта приложения
- По возможности подставляйте разумные значения по умолчанию
- Проверяйте все вводимые данные и показывайте понятные сообщения об ошибках
- Позволяйте менять настройки без переустановки приложения
- Сохраняйте настройки между сессиями через Stripe Secret Store API
Поддержка sandbox
Приложение должно корректно работать в режиме sandbox (тестовом) в Stripe:
- Совместимость с тестовым режимом: все функции должны работать в тестовом режиме
- Тестовые данные: используйте реалистичные тестовые данные, которые демонстрируют возможности приложения
- Никаких боевых данных в sandbox: никогда не показывайте рабочие данные в тестовом режиме
- Аккуратная деградация: если функция недоступна в sandbox, покажите понятное сообщение с объяснением причины
- Укажите
sandbox_install_compatible: trueв манифесте
{ "sandbox_install_compatible": true}Функциональность приложения
Надёжность
- Приложение не должно падать или зависать при обычной работе
- Все заявленные функции должны работать так, как описано
- Сетевые ошибки должны обрабатываться аккуратно, с возможностью повторить попытку
- Приложение должно оставаться отзывчивым во время фоновых операций
Полнота
- Никаких заглушек, функций «скоро появится» и неработающих ссылок
- Все элементы интерфейса должны быть рабочими: никаких мёртвых кнопок и неактивных элементов управления
- Подсказки и ссылки на документацию должны вести на существующие страницы
- Удаление приложения должно полностью убирать все его данные и вебхуки
Производительность
- Интерфейс должен отрисовываться за 3 секунды при обычном соединении
- Фоновая синхронизация не должна блокировать интерфейс
- Большие наборы данных должны загружаться постранично или лениво
- Сводите количество вызовов API к минимуму, чтобы не упереться в лимиты частоты запросов
Стандарты разработчика
Использование API
- Используйте последнюю стабильную версию Stripe API
- Следуйте рекомендациям Stripe API по пагинации, обработке ошибок и идемпотентности
- Не превышайте лимиты частоты запросов, реализуйте экспоненциальную задержку при повторах
- Для обновлений по событиям используйте вебхуки, а не опрос
Качество кода
- Никаких ошибок и предупреждений в консоли в production-сборках
- Удалите всё отладочное логирование перед отправкой
- Обрабатывайте все граничные случаи (пустые состояния, отсутствующие данные, сетевые сбои)
- Следуйте паттернам библиотеки компонентов Stripe, чтобы интерфейс выглядел единообразно
Версионирование
- Используйте семантическое версионирование (MAJOR.MINOR.PATCH)
- Документируйте несовместимые изменения при обновлении версии
- По возможности сохраняйте обратную совместимость
Качество UX
Реклама
- Никакой рекламы: приложение не должно показывать рекламу в любом виде
- Никакого кросс-промо: не продвигайте в интерфейсе приложения другие продукты и услуги
- Только собственный бренд: показывайте только свою фирменную символику, а не сторонние бренды (кроме партнёров по интеграции, таких как Brevo)
Язык и содержание
- Единая терминология: используйте одни и те же термины во всём приложении
- Профессиональный тон: придерживайтесь профессионального и лаконичного стиля общения Stripe Dashboard
- Без жаргона: избегайте технического жаргона, непонятного продавцам
- Проверка орфографии: убедитесь, что в текстах нет орфографических и грамматических ошибок
- Только английский: весь текст интерфейса приложений маркетплейса должен быть на английском
Диалоги подтверждения
Запрашивайте подтверждение пользователя для разрушительных или значимых действий:
// Good: Confirm before destructive actionsconst handleDisconnect = async () => { const confirmed = await showConfirmation({ title: 'Disconnect Brevo Integration', message: 'This will stop syncing customer data to Brevo. You can reconnect at any time.', confirmLabel: 'Disconnect', cancelLabel: 'Cancel', destructive: true, });
if (confirmed) { await disconnectIntegration(); }};Действия, которые требуют подтверждения:
- Отключение интеграций
- Удаление синхронизированных данных
- Изменение настроек, влияющих на поток данных
- Сброс конфигурации к значениям по умолчанию
Состояния загрузки
Всегда показывайте индикаторы загрузки для асинхронных операций:
// Good: Show loading state during data fetchconst CustomerSyncStatus = () => { const { data, isLoading, error } = useSyncStatus();
if (isLoading) { return <Spinner label="Loading sync status..." />; }
if (error) { return <Banner type="critical" title="Failed to load sync status"> {error.message} </Banner>; }
return <SyncStatusDisplay data={data} />;};Требования:
- Показывайте спиннеры или скелетоны во время загрузки данных
- Блокируйте кнопки на время отправки формы
- Показывайте индикаторы прогресса для длительных операций
- Никогда не показывайте пустой экран во время загрузки
Сообщения об ошибках
Давайте понятные сообщения об ошибках, подсказывающие следующий шаг:
// Bad: Generic error"Something went wrong"
// Good: Specific and actionable"Unable to sync customer data to Brevo. Please verify your Brevo API keyin Settings and try again."Рекомендации по сообщениям об ошибках:
- Объясняйте простым языком, что произошло
- Предлагайте конкретное действие, которым пользователь решит проблему
- Давайте возможность повторить неудавшуюся операцию
- Записывайте подробности ошибки в журнал для отладки (не показывая их пользователю)
- Указывайте коды ошибок для обращения в поддержку, когда это применимо
Безопасность
Secret Store API
Используйте Stripe Secret Store API для хранения всех конфиденциальных данных:
import { createHttpClient, STRIPE_API_KEY } from '@stripe/ui-extension-sdk/http_client';
// Good: Store secrets using the Secret Store APIconst storeBrevoApiKey = async (apiKey: string) => { const stripe = createHttpClient(STRIPE_API_KEY); await stripe.apps.secrets.create({ name: 'brevo_api_key', payload: apiKey, scope: { type: 'account' }, });};
// Good: Retrieve secrets from the Secret Storeconst getBrevoApiKey = async () => { const stripe = createHttpClient(STRIPE_API_KEY); const secret = await stripe.apps.secrets.find({ name: 'brevo_api_key', scope: { type: 'account' }, }); return secret.payload;};Никогда не храните конфиденциальные данные в:
- Локальном хранилище или хранилище сессии
- Cookies
- Параметрах URL
- Жёстко зашитых значениях в исходном коде
- Файлах конфигурации в открытом виде
Криптография
- Никакой самодельной криптографии: не реализуйте собственные алгоритмы шифрования
- Используйте встроенные примитивы безопасности Stripe (Secret Store, секреты подписи)
- Используйте HTTPS для всех внешних вызовов API
- Проверяйте подписи всех вебхуков перед обработкой
Работа с данными
- Запрашивайте только те разрешения, которые приложению действительно нужны
- Не храните данные Stripe сверх того, что необходимо для работы приложения
- Реализуйте политики хранения данных, согласованные с вашей политикой конфиденциальности
- Предусмотрите механизм, позволяющий пользователю запросить удаление данных
Правовое соответствие
Политика конфиденциальности
У приложения должна быть публично доступная политика конфиденциальности, которая описывает:
- Какие данные приложение собирает из Stripe
- Как эти данные хранятся, обрабатываются и передаются
- Политику хранения и удаления данных
- Права пользователей в отношении их данных
- Контакты для вопросов о конфиденциальности
- Соответствие применимым нормам (GDPR, CCPA и другим)
Условия обслуживания
- Опубликуйте понятные условия обслуживания для своего приложения
- Не включайте условия, противоречащие Условиям обслуживания Stripe
- Ясно укажите любые ограничения на использование
Нормативное соответствие
- Соблюдайте все применимые нормы о защите данных
- Заключайте соответствующие соглашения об обработке данных
- Поддерживайте запросы на переносимость и удаление данных
- Ведите журналы аудита доступа к данным и их обработки
Сроки процесса проверки
| Стадия | Продолжительность |
|---|---|
| Первичная подача | 5-10 рабочих дней |
| Проверка доработок | 3-7 рабочих дней |
| Финальное одобрение | 1-2 рабочих дня |
| Публикация | Сразу после одобрения |
Tip
Устраняйте все замечания проверки за одну доработку, чтобы не проходить несколько циклов проверки. Команда Stripe даёт конкретные и выполнимые комментарии по каждой найденной проблеме.
Частые причины отклонения
- Отсутствие обработки ошибок: приложение падает при сетевых ошибках или неожиданных данных
- Недостаточные состояния загрузки: пустые экраны во время загрузки данных
- Непрозрачные цены: цены раскрыты в листинге не полностью
- Избыточные разрешения: запрос разрешений, которые приложению не нужны
- Нерабочий режим sandbox: приложение не работает в тестовом режиме
- Проблемы безопасности: хранение секретов вне Secret Store API
- Отсутствие политики конфиденциальности: нет доступного URL политики конфиденциальности
- Неполная функциональность: функции «скоро появится» или контент-заглушки