Массовая отправка документов на подписание с трекингом и напоминаниями

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

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Массовая отправка документов на подписание с трекингом и напоминаниями
Средний
~3-5 дней
Часто задаваемые вопросы

Массовая отправка документов на подписание: реализация с трекингом и напоминаниями

При слиянии двух компаний нужно разослать 5000 трудовых договоров за 48 часов. Ручная отправка потребует 10 сотрудников на неделю — с опечатками, потерянными письмами и нервотрёпкой. Мы автоматизируем этот процесс: загрузка CSV, генерация персонализированных PDF, отправка через очередь задач, отслеживание статусов и автоматические напоминания. Ниже — архитектура, которая выдержит нагрузку 10K+ документов без падения.

Какие проблемы решаем?

Генерация тысяч документов без подвисания сервера. Синхронная генерация убьёт сервер — используем очередь задач на BullMQ. Каждый документ генерируется отдельным воркером, параллельность до 10. Даже при пике в 5000 документов система остаётся отзывчивой.

Rate limiting email-провайдеров. Resend даёт 100 писем в секунду, Postmark — столько же. Для batch в 10K писем мы внедряем throttling в очереди: отправка идёт со скоростью 100–200 писем в минуту, чтобы не попасть в блокировку. Таймауты и повторные попытки — обязательны.

Отсутствие подписания у части получателей. Автоматические напоминания через 2 и 4 дня. Настраиваемое количество (до 3). Дашборд показывает, кто не открыл письмо, и позволяет отправить напоминание вручную.

Как мы это делаем?

Типовой стек: PostgreSQL + Redis + BullMQ + Node.js (NestJS) + Puppeteer для PDF. Воркеры развёрнуты в Docker на отдельном инстансе. Код хранится в GitLab CI, деплой в AWS ECS.

Кейс: для маркетплейса внедрили массовую отправку актов выполненных работ. Ежемесячно 15 000 актов. Ранее бухгалтерия тратила 3 дня на рассылку через Outlook. После внедрения — 30 минут. Ошибки сократились с 5% до 0.2%.

Процесс работы

  1. Аналитика. Собираем требования: объём, шаблоны документов, интеграции (CRM, бухгалтерия).
  2. Проектирование. Схема БД, очередь задач, API, страница подписания.
  3. Реализация. Разработка модулей: загрузка CSV, генерация PDF, отправка, дашборд.
  4. Тестирование. Нагрузочное тестирование с 10K документов, сценарии ошибок.
  5. Деплой. На сервер клиента или облако. Настройка CI/CD, мониторинг (Sentinel, Grafana).

Почему очередь задач лучше синхронной генерации?

Синхронная генерация 5000 PDF вызовет тайм-аут сервера. Очередь BullMQ с воркерами (параллельность 10) обрабатывает документы постепенно, не блокируя запросы. Redis хранит прогресс. Если воркер упал — задача автоматически перезапускается. Это даёт надёжность и масштабируемость.

Как работает очередь в коде?

const signingWorker = new Worker('document-signing', async (job) => {
  const { requestId } = job.data;
  const request = await db.signingRequests.findByPk(requestId);
  try {
    await db.signingRequests.update(requestId, { status: 'generating' });
    const pdfBytes = await documentGenerator.generate(
      request.template,
      request.templateData
    );
    const document = await documentStorage.store(pdfBytes, {
      batchId: request.batchId,
      requestId: request.id,
    });
    const signingUrl = `${process.env.APP_URL}/sign/${request.signingToken}`;
    await emailService.send({
      to: request.recipientEmail,
      subject: 'Документ ожидает вашей подписи',
      template: 'signing-invitation',
      data: {
        recipientName: request.recipientName,
        documentName: request.template.name,
        signingUrl,
        expiresAt: request.expiresAt,
      },
    });
    await db.signingRequests.update(requestId, {
      status: 'sent',
      documentId: document.id,
      sentAt: new Date(),
    });
    await db.signingBatches.increment(request.batchId, 'sent_count');
  } catch (error) {
    await db.signingRequests.update(requestId, {
      status: 'failed',
      errorMessage: error.message,
    });
    await db.signingBatches.increment(request.batchId, 'failed_count');
  }
}, {
  concurrency: 10,
  connection: redisConnection,
});

Ограничения и надежность

Email-провайдеры блокируют при превышении лимитов. Мы настраиваем очередь с паузой между отправками. Используем выделенные серверы отправки (SMTP-ретрансляторы) и отслеживаем статусы писем (bounce, spam). Гарантируем доставку 99%.

Автоматические напоминания

Если получатель не подписал, автоматика отправляет напоминания на 2-й и 4-й день. На 7-й день — отметка "просрочено" и уведомление менеджеру. В дашборде можно отправить повторное письмо с новой ссылкой. Настраиваемый лимит напоминаний — от 0 до 5.

async function sendSigningReminders() {
  const pending = await db.signingRequests.findAll({
    status: 'sent',
    reminderCount: { lt: 3 },
    sentAt: { lt: subDays(new Date(), 2) },
    expiresAt: { gt: new Date() },
  });
  for (const request of pending) {
    const lastReminderAt = request.lastReminderAt || request.sentAt;
    const daysSinceLastReminder = differenceInDays(new Date(), lastReminderAt);
    if (daysSinceLastReminder >= 2) {
      await emailService.sendReminder(request);
      await db.signingRequests.update(request.id, {
        reminderCount: request.reminderCount + 1,
        lastReminderAt: new Date(),
      });
    }
  }
}

Сравнение ручной и автоматической рассылки

Параметр Ручная (10 сотрудников) Автоматическая (наше решение)
Время на 5000 документов 40 человеко-часов 2 часа машинного времени
Ошибки (опечатки, потеря) 5–8% <0.5%
Стоимость за одну рассылку значительные затраты экономия
Трекинг статусов Excel Дашборд в реальном времени

Также добавляем сравнение по скорости: автоматическая рассылка в 20 раз быстрее ручной (40 часов против 2).

Модель данных

CREATE TABLE signing_batches (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name VARCHAR(500),
  template_id UUID REFERENCES document_templates(id),
  initiated_by UUID REFERENCES users(id),
  total_count INT NOT NULL,
  sent_count INT DEFAULT 0,
  signed_count INT DEFAULT 0,
  failed_count INT DEFAULT 0,
  status VARCHAR(50) DEFAULT 'pending', -- pending → processing → completed / partially_failed
  deadline_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE signing_requests (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  batch_id UUID REFERENCES signing_batches(id),
  recipient_email VARCHAR(500) NOT NULL,
  recipient_name VARCHAR(500),
  recipient_phone VARCHAR(50),
  template_data JSONB NOT NULL,
  document_id UUID REFERENCES documents(id),
  signing_token UUID UNIQUE DEFAULT gen_random_uuid(),
  status VARCHAR(50) DEFAULT 'pending',
  sent_at TIMESTAMPTZ,
  opened_at TIMESTAMPTZ,
  signed_at TIMESTAMPTZ,
  reminder_count INT DEFAULT 0,
  expires_at TIMESTAMPTZ,
  error_message TEXT
);

Загрузка и валидация CSV

async function processBatchUpload(file: Express.Multer.File, templateId: string) {
  const records = await parseCSV(file.buffer, { headers: true });
  const template = await db.documentTemplates.findByPk(templateId);
  const requiredFields = extractTemplateVariables(template.content);
  const errors: ValidationError[] = [];
  const validRows: RecipientRow[] = [];

  records.forEach((row, index) => {
    const rowErrors = [];

    if (!row.email || !isValidEmail(row.email)) {
      rowErrors.push(`Строка ${index + 2}: некорректный email`);
    }

    for (const field of requiredFields) {
      if (!row[field]) {
        rowErrors.push(`Строка ${index + 2}: отсутствует поле "${field}"`);
      }
    }

    if (rowErrors.length > 0) {
      errors.push(...rowErrors);
    } else {
      validRows.push(row);
    }
  });

  return { valid: validRows, errors, totalRows: records.length };
}

Страница подписания по токену

Получатель переходит по ссылке https://app.example.com/sign/{token} — авторизация не нужна, доступ только по токену:

app.get('/sign/:token', async (req, res) => {
  const request = await db.signingRequests.findOne({
    signingToken: req.params.token,
    status: { not: ['expired', 'signed', 'declined'] },
  });
  if (!request) return res.redirect('/sign/invalid');
  if (request.expiresAt < new Date()) {
    await db.signingRequests.update(request.id, { status: 'expired' });
    return res.redirect('/sign/expired');
  }
  if (!request.openedAt) {
    await db.signingRequests.update(request.id, { openedAt: new Date() });
  }
  res.render('signing-page', { request, document: request.document });
});

Дашборд мониторинга batch

Прогресс-бар: отправлено/подписано/не открыто/просрочено. Таблица с фильтрами по статусу. Экспорт в CSV. Кнопка «Отправить напоминание» для выбранных получателей.

Ориентировочные сроки

Этап Сроки
Загрузка CSV, валидация, очередь + генерация PDF + отправка 7–10 дней
Страница подписания по токену, напоминания, дашборд 5–7 дней
Интеграция с CRM / импорт существующих шаблонов 3–5 дней дополнительно

Что входит в работу?

Детальный список
  • Исходный код на GitHub/GitLab (закрытый репозиторий)
  • Инструкция по развёртыванию (Docker + docker-compose)
  • Документация по API (OpenAPI/Swagger)
  • Миграции БД
  • Нагрузочное тестирование (отчёт)
  • Гарантия 1 месяц на баги

Свяжитесь с нами для оценки вашего проекта. Получите консультацию по автоматизации подписания документов.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060