Перейти к содержимому

CrewsForge — Шаг 6: Контракты и подписание

Статус: черновик на подтверждение · Шаг 6 из 9 Основание: ФТ раздел 3 (K-1…K-7), C-5, C-6, L-6; машина контрактинга (шаг 3, C05–C08); схема Contract/Party/PlanVersion (шаг 2)


Интеграция подписания — за портом (решение 0.5.3), модель Contract от провайдера не зависит.

interface SigningProvider {
createEnvelope(req: {
contractId: string;
documentPdf: Buffer; // готовый PDF генерим мы (см. §2)
signer: { name: string; email: string };
embedded: boolean; // embedded-подписание в интерфейсе платформы
expiresInDays: number; // конфиг, дефолт 14
metadata: { contractId; projectId; side };
}): Promise<{ envelopeExternalId: string; signUrl?: string }>;
voidEnvelope(envelopeExternalId, reason): Promise<void>;
downloadSigned(envelopeExternalId): Promise<Buffer>; // подписанный PDF + audit trail
parseWebhook(rawBody, signatureHeader): SigningEvent; // signed | declined | expired | viewed
}

Выбор провайдера для беты: BoldSign (адаптер №1, решение подтверждено 2026-08-21). Аргументы: Enterprise API $30/мес с включённым embedded signing/requesting и квотой 40 конвертов (перерасход $0.75/конверт) — десятикратно дешевле Dropbox Sign Standard ($300/мес) при идентичном для нас покрытии; соответствие ESIGN + eIDAS, SOC 2 Type II, GDPR; tamper-proof документы и audit trail. Ключевое условие выбора: бесплатный Sandbox — интеграция и e2e полностью без оплаты (тестовые документы с водяным знаком, автоудаление через 14 дней), платим с первого боевого конверта. Известные ограничения (молодой вендор, ограниченная кастомизация embedded-виджета) митигированы портом. Dropbox Sign / DocuSign — кандидаты в адаптер №2 при энтерпрайз-требованиях клиентов; замена — локальная задача одного адаптера.

Embedded по умолчанию: подписание происходит внутри интерфейса CF (iframe провайдера), не по email-ссылке — цикл SIGNING не покидает продукт, меньше отвалов. Email-ссылка — fallback конфигом.

2. Генерация документов — на нашей стороне

Заголовок раздела «2. Генерация документов — на нашей стороне»

Провайдеру уходит готовый PDF; шаблоны и рендеринг — наши. Альтернатива (шаблоны с merge-полями на стороне провайдера) отвергнута: приложение-план — это таблица этапов с суммами, сроками и критериями произвольной длины, рендерить её merge-полями невозможно, а версионировать шаблоны в чужом кабинете — значит потерять юридическую трассируемость.

КомпонентСодержимое
Рамочный договор A (Team ↔ Platform)Условия исполнения, полномочия подписанта, обязательство бесплатной доработки при несоблюдении критериев (M09), порядок споров/арбитража, декомпозиция вознаграждения (gross / комиссия / net — D-4)
Рамочный договор B (Founder ↔ Platform)Условия финансирования и приёмки, milestone-gated формулировки (никакого «escrow» — 7.6, проверяется линтером строк шаблона), обязанность решать претензии через платформенный арбитраж (анти-chargeback, шаг 5.6), права на артефакты (X-4)
Приложение-план (общее для A и B в соответствующей проекции)Из принятого PlanVersion: этапы, суммы, сроки, критерии приёмки дословно (критерии — часть предмета договора, раздел 6 ФТ)

Механика: шаблоны — в репозитории (libs/apis/providers/project-api/contracting/templates), версионируются как код; рендер HTML → PDF; на Contract добавляются поля (дельта к схеме шага 2):

templateVersion String @map("template_version") @db.VarChar(32) // git-версия шаблона
documentHash String? @map("document_hash") @db.VarChar(64) // sha256 отправленного PDF

Хэш до отправки + подписанный PDF из downloadSigned в S3 (signedFileKey) + audit trail провайдера = доказательная цепочка целостности (L-2/L-5-уровень для договоров). Юридические формулировки шаблонов — вне скоупа сессии, это работа юриста; архитектура фиксирует только структуру и данные подстановки.

3. Последовательность подписания (K-4) в терминах конвертов

Заголовок раздела «3. Последовательность подписания (K-4) в терминах конвертов»
C05: фаундер принял план
→ Contract A, B созданы (DRAFT), planVersionId = принятая версия
→ PDF(A) сгенерирован из шаблона + Party(TEAM) + PlanVersion
→ envelope A → подписант: TeamMember с canSign (email члена) [Contract A → SENT_FOR_SIGNING]
вебхук signed(A) → Contract A → SIGNED, signedFileKey, скачивание PDF
→ PDF(B) → envelope B → подписант: фаундер [Contract B → SENT_FOR_SIGNING]
вебхук signed(B) → Contract B → SIGNED → каскад P07 (проект ACTIVE)

Правила поверх машины:

СитуацияПоведение
Подписант A сменился в полёте (canSign передан другому)Guard C07 «подписант актуален»: конверт void, новый конверт новому подписанту. Смена полномочия действует немедленно (шаг 4.2)
Отказ от подписания (declined) любой сторонойКонтракт → DRAFT, конверт void, задача PLAN_MEDIATION администратору (симметрично C-4: отказ — не тупик). contractingStagePLAN_DRAFTING при необходимости новой версии плана
Конверт истёк (14 дней)Напоминания таймерами на 7-й и 12-й день (worker); истечение → задача администратору, перевыпуск конверта
Правка плана после создания конвертовЗапрещена без отзыва: новая версия плана → оба конверта void → цикл с C01. Подписываемый документ и PlanVersion.ACCEPTED не могут разойтись

Вебхуки провайдера — project-api /webhooks/signing: подпись провайдера, дедуп через WebhookEvent (provider: SIGNING), идемпотентные переходы.

Каждая сторона видит только свой договор: фаундер — B, команда — A; администратор — оба; оператор — ни одного (в договоре A суммы — O-1); арбитр — оба в рамках спора. Прямое следствие K-1: фаундер не сторона договора A и не имеет к нему интереса, а net-суммы команды в A — часть коммерческих условий платформа↔команда. Реализация — та же схема, что F-1: WHERE по стороне в репозитории клиентских поверхностей.

5. Новые этапы после старта — без перевыпуска конвертов

Заголовок раздела «5. Новые этапы после старта — без перевыпуска конвертов»

Проблема: этап, добавленный из разбора (R-2) или перепланирования, отсутствует в подписанном приложении. Перевыпускать конверты на каждый новый этап — трение, убивающее R-2 как «штатную операцию роста GMV».

Решение — акцепт внутри продукта. Рамочные договоры A и B включают пункт: дополнительные этапы согласуются через платформенный порядок — команда подтверждает объём (создание/принятие этапа), оператор утверждает план этапа (M01), фаундер акцептует финансированием (K-3: фондирование = принятие уже подписанных условий — расширяем действие правила на добавленные этапы). Доказательная база акцепта: журнал переходов (актор, время) + запись Hold. Конверты не перевыпускаются.

⚠️ Юридическая проверка обязательна: применимость click-through-акцепта дополнительных объёмов к рамочному договору в наших юрисдикциях (US ESIGN / eIDAS SES; отдельно ОАЭ и Сингапур на пост-бету). В пакет юристу. Архитектурно оба ответа поддержаны: если юрист потребует конверт на доп-этапы — это ещё один вызов порта в переходе M01, модель не меняется.

Guard C04 гарантирует: к моменту PLAN_SENT обе Party заполнены. Рендер договора берёт: реквизиты платформы (конфиг: Ryomen Corporation, Wyoming), Party(side) снапшот, PlanVersion.items, commissionRateBps проекта. Ничего не запрашивается в момент подписания — если данных не хватает, дефект произошёл раньше, на C04.

  1. ✅ ПОДТВЕРЖДЕНО: BoldSign как первый адаптер порта (условие — бесплатный тест-режим — выполнено: Free Sandbox), embedded-подписание с первого дня.
  2. PDF генерим мы, шаблоны версионируются в репозитории, провайдер только подписывает; templateVersion + documentHash добавляются в Contract (дельта схемы).
  3. Каждая сторона видит только свой договор (фаундер — B, команда — A).
  4. Дополнительные этапы — акцепт внутри продукта без перевыпуска конвертов; формулировка пункта рамочного договора — в пакет юристу.
  5. Отказ от подписания → медиация администратора (не тупик), истечение конверта 14 дней с напоминаниями.