Перейти до вмісту

Уніфіковане накладання електронного підпису різних сервісних центрів України

Матеріал з K2 ERP Wiki

Критично критично: платформа повинна зберігати, який саме тип підпису було створено: detached, enveloped, container, PDF, XML або hash-sign. |- | Невідповідність підписанта | Підписала інша особа. SEO-опис

! | Verification + signer matching. | style="background:#bbdefb;" | Блакитний |- | Підпис отримано | SIGNED | Підпис або контейнер отримано. Перевірено

31. MVP

payload={"signature_request_id": str(request.id)},
"raw_result": result.raw,

! Тип

)

GET /api/v1/signature/dashboard?date_from=2026-05-01&date_to=2026-05-31

async def start_signature_session(signature_request_id: str, db: "Session") -> None:

pass

27. Dashboard керівника

23.2. signature_integrations

"certificate_info": result.certificate_info,
document_type=document.document_type,

8. Уніфікований бізнес-процес

- Polling Worker - AC-16 Підпис відповідає документу. SEO-опис
"provider_id": provider_repository.get_by_code(db, "MANUAL_UPLOAD").id,

30. Acceptance Criteria

"signature_type": command.signature_type,

11. Очікуваний результат

щоб контролювати доступні сценарії підписання. Очікуваний результат

"phone": "+380671112233",

35. Джерела

- credentials_encrypted jsonb Зашифровані credentials.=== Варіант 3. 7.3. Підписання через локальний агент === Опційно
CAdES Формат CMS-підпису. Тип
Відокремлений підпис DETACHED Статус стає VERIFIED. |- Секрети потрапили в лог }
},
"email": "client@example.com",
v
document = document_repository.get_by_external_id(
"file_type": "signature",
id uuid Так
ASIC Запускається локальний або файловий сценарій. SEO-опис

9. Основні сутності

Зелений #c8e6c9 style="background:#bbdefb;" | Блакитний
Очікує вибору провайдера WAITING_PROVIDER Підписант ще не обрав спосіб підпису. Підписант

Етап 4. Адаптери

self.adapters = adapters
- Ручне завантаження Хто завантажив, файл, hash.

я хочу вибрати спосіб підписання: Дія, Приват24 SmartID, файловий КЕП або інший КНЕДП,

request.document.status = "VERIFIED"
Що зберігати - SmartIDAdapter - qr_payload text - file_hash_sha256 Hash документа. Verification Service перевіряє підпис. Колір - конкурентні переваги - document_id uuid Документ. SEO-опис style="background:#fff9c4;" | Жовтий
Підписується SIGNING Виконується бізнес-процес підписання. Валідація, hash, версії, політики 3. Тип - document_id uuid - AC-11 Підпис отримано. SEO-опис

Метою задачі виступає як створення уніфікованого Python-сервісу електронного підпису для роботи з різними сервісними центрами та провайдерами КЕП України. |}

Provider Adapters

def get_allowed_providers(self, document_type: str, signer_type: str) -> list [str]:
expected_hash=document_version.file_hash_sha256,

Етап 9. Production hardening

"signature_request_id": None,
AC-18 Керівник відкриває dashboard.=== 17.11. Перевірка підпису === Показати інструкцію користувачу. # Чи потрібно підтримувати ІІТ DLL/SO напряму? |- Ручне рішення для бізнесу - Signer Підписант. Як зменшити }

4. Типи підписання

try:
)
pass
Підходить для - version_number Номер версії. ! * Інструкції ПриватБанку щодо створення SmartID. # Чи потрібні нагадування про прострочення?
! |-
| signer_id
| uuid
| Підписант. Збереження і перевірка
 "file_mime_type": "application/pdf",
{| class="wikitable"
 callback_repository.create_raw_event(

[[Категорія:КЕП]]

Уніфікований компонент застосовується для для:
=== 30.1. Провайдери ===
 "document_date": "2026-05-07",
|-
| Unified Signature API
| Єдиний REST API для K2 ERP. Помилки

{| class="wikitable"

 )
щоб підписати документ зручним для мене способом. {| class="wikitable"

* зміненого документа;
* невалідного callback;
* відхилення користувачем;
* невідповідності підписанта;
* невалідного пароля файлового ключа;
* фінального статусу VERIFIED;
* ручного рішення для бізнесу адміністратора. | Запропонувати іншого провайдера або manual upload. ! | Hash і document version lock. | style="background:#f3e5f5;" | Фіолетовий
|-
| Скасовано
| CANCELLED
| Заявку або документ скасовано. |-
| Створення заявки
| Підписант, строк, provider_code. | Показати користувачу помилку. | ASIC / p7s container. |-
| is_active
| boolean
| Активність. * Офіційна сторінка SmartID ПриватБанку. |-
| LocalAgentUnavailableError
| Локальний агент недоступний. SEO-опис
{| class="wikitable"
 |
 | 2. Поле
|-
| Чернетка
| DRAFT
| Документ створений, але ще не готовий до підпису. |-
| created_at
| timestamp
| Дата створення. платформа розраховує hash документа. Поле
{| class="wikitable"

 v

== 19. Валідація перед підписом ==
{| class="wikitable"

7. Варіанти реалізації

"signature_format": signature_format_detector.detect(file.filename, stored_file.bytes),

from fastapi import APIRouter, Request, HTTPException

Окремо варто відзначити який надає K2 ERP / CRM / документообігу один уніфікований API; так само реалізовано ПриватБанк SmartID, файловий КЕП, ІІТ, КЕП ДПС і інші КНЕДП. |-
raw_result jsonb Вона підсвічується фіолетовим. |- payload jsonb - created_at timestamp Дата перевірки.
![[Категорія:Інтеграції]]
 db.commit()
 db=db,
{{SEO
|title=Технічне завдання: Уніфіковане накладання електронного підпису різних сервісних центрів України для Python
|description=Технічне завдання на реалізацію уніфікованого Python-модуля електронного підпису для різних сервісних центрів України: Дія.Підпис, ПриватБанк SmartID, файловий КЕП, ІІТ, ДПС, хмарний КЕП, p7s, ASIC, CAdES, XAdES, перевірка підпису, callback, polling, dashboard та журналювання.
|keywords=Python, КЕП, електронний підпис, Дія.Підпис, SmartID, Приват24, ІІТ, ДПС, ЦСК, КНЕДП, p7s, ASIC, CAdES, XAdES, FastAPI, K2 ERP, електронний документообіг
}}

 @abstractmethod

 request = signature_request_repository.get_by_id(db, signature_request_id)
</div>
! SEO-опис
 )

=== 17.10. Завантаження підписаного документа ===


</pre>
 request = signature_request_repository.get_by_id(db, signature_request_id)
=== 10.1. користувач системи обирає провайдера ===

! |-
| Audit Logger
| Логує всі дії. 

* реалізувати callback endpoint;
* реалізувати polling worker;
* реалізувати raw event storage;
* реалізувати idempotency. |-
| file_name
| varchar
| Назва файлу. |}

 db.commit()

{| class="wikitable"
 )
! * Документація КНЕДП ДПС. # Чи потрібен довгостроковий архів підписаних документів? | style="background:#fff9c4;" | Увага
|-
| Підписано
| Підпис отримано. |-
| Статуси
| WAITING_SIGNATURE, SIGNING, SIGNED, VERIFIED. | style="background:#c8e6c9;" | Норма
|-
| Перевірено
| Підпис валідний. |-
| Provider Router
| Вибирає провайдера підпису. |}

== 23. Модель даних ==

 raise HTTPException(status_code=401, detail="Invalid callback")
'''Технічний стек:''' Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker, S3-compatible file storage, локальні crypto adapters. |-
| signed_at
| timestamp
| Час підписання. Очікуваний результат
! Приклад

 "provider_session_id": response.get("session_id"),

 result = await verifier.verify(
 "external_signer_id": "CLIENT-001",
=== 17.3. Створення документа ===
 "idempotency_key": "K2-DOC-2026-000123-sign-v1",
 @abstractmethod
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 "expires_at": response.get("expires_at"),
 "provider_code": "DIIA_SIGN",
Як адміністратор, 
=== 15.1. Загальний інтерфейс провайдера ===
 def __init__(self, adapters: dict [str, SignatureProviderAdapter]):
== 36. Див. так само ==
=== 23.3. sign_documents ===
 db=db,
 document_version = document_version_repository.get_by_id(db, request.document_version_id)
 async def create_signature_session(self, request: dict) -> dict:
=== Етап 1. Аналіз провайдерів ===
=== 30.4. Перевірка ===
! Критерій
=== 24.2. Запуск сесії через router ===
<pre>

! |-
| CallbackValidationError
| Callback не пройшов перевірку. |-
| IITAdapter
| інтеграційні функції ERP з бібліотеками ІІТ або локальним агентом. Тип
я хочу бачити dashboard підписання, 
 document_file_id=document_version.file_id,
POST /api/v1/signature/documents
=== 10.2. K2 ERP функціонує з єдиним API ===
! stored_file = await file_storage.save(file)


! | style="background:#c8e6c9;" | Високий
|-
| КНЕДП ДПС
| TAX_CSK
| Файловий ключ / ІІТ / локальне підписання
| Часто застосовується для для податкових документів. Поле
! SEO-опис

POST /api/v1/signature/callback/{provider_code}
платформа повинна логувати:
користувач системи підписує документ поза системою та завантажує результат. | Документ стає VERIFY_ERROR. v

<pre>

 return existing
=== Варіант 4. 7.4. Ручне завантаження підпису ===
! | XAdES. |}

До MVP входить:

 "document_id": str(document.id),
 "idempotency_key": command.idempotency_key,
'''Критично критично:''' бізнес-система не повинна напряму залежати від конкретного сервісного центру підпису. |-
| signature_request_id
| uuid
| Заявка. | style="background:#eeeeee;" | Сірий
|}

 "expires_at": command.expires_at,

== 34. Відкриті питання ==
! |-
| AC-3
| Адміністратор створює провайдера файлового КЕП. |-
| provider_code
| Провайдер підпису. return signature_file

* реалізувати dashboard API;
* реалізувати списки проблемних документів;
* реалізувати статистику по провайдерах;
* реалізувати експорт журналу. |}

 request.error_message = str(exc)

async def verify_signature(signature_request_id: str, signature_file_id: str, db: "Session") -> None:

 "callback_context": {
<syntaxhighlight lang="python">
GET /api/v1/signature/providers

== 14. технічна архітектура рішення для бізнесу ==

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
=== 17.12. Dashboard ===
K2 ERP / CRM / Website

<syntaxhighlight lang="json">

== 28. Безпека ==
=== 24.5. Перевірка підпису ===
<syntaxhighlight lang="python">

! Dashboard показує результат. Тип підпису
=== 14.1. Загальна схема ===
 request.status = "MANUAL_REVIEW"

 "full_name": "Іван Петренко",

== 18. Приклад запиту на створення заявки ==
<syntaxhighlight lang="python">
<pre>

! Обраний adapter створює сесію або локальну операцію підпису. |-
| Документ змінено
| Підпис здатна бути накладений на стару версію. | document.pdf + document.pdf.p7s
|-
| Вкладений підпис
| ENVELOPED
| Підпис вбудований у документ або XML. |-
| file_hash_sha256
| varchar
| Hash файлу. "file_id": "file-001",
<pre>
! |-
| name
| varchar
| Назва. signature_session_repository.create(

* реалізувати VerificationService;
* реалізувати перевірку p7s;
* реалізувати перевірку контейнерів;
* реалізувати статуси перевірки;
* реалізувати ручну перевірку. |-
| priority
| integer
| Пріоритет у списку. | style="background:#ef9a9a;" | Червоний
|-
| Hash не збігається
| HASH_MISMATCH
| Підпис не відповідає версії документа. Очікує
{| class="wikitable"

 )
{| class="wikitable"
! Колір

 raise BusinessError("Document cannot accept signature in current status")
 db=db,
 pass
=== Варіант 1. 7.1. Хмарний підпис через API ===
 adapter = provider_router.get_adapter(provider.code)
 data={
10. | style="background:#ffcc80;" | Помаранчевий
|-
| Прострочено
| EXPIRED
| Строк підписання минув. |-
| old_status
| varchar
| Старий статус. |-
| Комунікація
| Browser  Local Agent  Crypto Library  результат у K2 ERP. |-
| SignatureResultError
| Не вдалося отримати підпис. provider = provider_repository.get_by_code(db, command.provider_code)
 "signer": {
! | Вимкнути інтеграцію, повідомити адміністратора. SEO-опис
 "signature_request_id": request.id,

 db=db,
<pre>
! | Вони підсвічуються помаранчевим. | платформа показує статус UNAVAILABLE. |-
| signature_type
| varchar
| DETACHED, ENVELOPED, CONTAINER. 
 data={
=== Етап 3. Уніфікований інтерфейс ===
! Причина
5. |-
| file_id
| uuid
| Файл у сховищі. * Офіційна сторінка Дія.Підпис. |-
| Ризики
| Не можна зберігати пароль до ключа на сервері. | style="background:#eeeeee;" | Сірий
|}

=== 23.8. signature_verifications ===

{| class="wikitable"
[[Категорія:ДПС]]
sha256(file_bytes)
платформа повинна не допускати дублювання заявок і підписів. |-
| Dashboard API
| інформаційні дані для контролю. Код
[[Категорія:K2 ERP]]
</pre>
=== 17.5. Створення заявки на підпис ===
 except Exception as exc:
|-
| Дія.Підпис
| DIIA_SIGN
| API / QR / deep link / callback
| Хмарний сценарій через застосунок Дія. | Опційно
|}

 data={

 },

* перелік провайдерів підпису, які потрібно підтримати в MVP;
* офіційну документацію кожного API-провайдера;
* credentials для хмарних сервісів;
* тестові ключі або тестові акаунти;
* список форматів документів;
* вимоги до підпису: detached, embedded, container;
* правила перевірки підпису;
* список КНЕДП, які треба підтримати;
* вимоги до зберігання документів;
* вимоги до журналювання;
* вимоги до K2 ERP;
* вимоги до UI підписанта;
* вимоги до мобільного сценарію;
* вимоги до довгострокового архіву. Код
 "k2_entity": "contract",
 )
 request.status = "VERIFY_ERROR"
=== 27.3. Проблемні документи ===

</div>
 "k2_entity_id": "contract-001"
{| class="wikitable"

 document = document_repository.get_by_id(db, document_id)

платформа повинна забезпечити:
 "tax_id": "1234567890"
! Поле
 )

== 3. Підтримувані провайдери підпису ==

GET /api/v1/signature/documents/{document_id}/signature-file

- created_at timestamp - Callback дублюється style="background:#ef9a9a;" | Критично
Прострочено Не підписано у строк. Єдиний API підписання KPI
if not await adapter.verify_callback(request, payload):
request.status = "VERIFIED"

До MVP не входить: користувач системи використовує файловий КЕП. Компонент

- event_type varchar style="background:#ef9a9a;" | Критично
Помилки перевірки - file_type varchar - certificate_info jsonb - AC-21 - Створення сесії - expires_at timestamp - result varchar - SignerMismatchError style="background:#ffcc80;" | Помаранчевий
Ручна перевірка MANUAL_REVIEW - integration_type varchar - new_status varchar Trust list / manual review. Критерій

12. Статуси провайдера

"signed_at": result.signed_at, - is_active boolean Активність. Статус

30.6. Dashboard

Поле
- ManualUploadAdapter Ручне завантаження p7s / контейнера. Критерій

я хочу вмикати або вимикати провайдерів підпису,

AC-15 користувач системи завантажує p7s. Сутність
signature_file = signature_file_repository.get_by_id(db, signature_file_id)
Дія.Підпис 18 92 90 2 Норма
Приват24 SmartID 12 64 63 1 Норма
Файловий КЕП 6 40 37 3 Контроль
ІІТ / ЦСК 4 52 51 1 Норма
Ручне завантаження 3 12 10 2 Ручна перевірка
async def check_connection(self) -> dict:
pass
)
signature_validator.validate_document_for_signing(document, command)
},

30.3. Підписання

signature_verification_repository.create(
07.05.2026 Договір №123 Дія.Підпис Іван Петренко Прострочено Не завершено підписання Створити нову заявку
07.05.2026 Акт №45 SmartID Олена Сидоренко Помилка перевірки Hash не збігається Ручна перевірка
07.05.2026 Звіт XML Файловий КЕП Бухгалтер Помилка Невірний пароль ключа Повторити підписання
"document_id": document.id,

25. Обробка помилок

  • HTTPS для всіх endpoint-ів;
  • зберігання секретів у secret storage;
  • шифрування credentials;
  • заборону зберігання пароля до файлового КЕП;
  • заборону передачі приватного ключа на backend, якщо застосовується для локальний агент;
  • перевірку callback signature;
  • ідемпотентність callback;
  • контроль версій документа;
  • контроль hash;
  • рольову модель;
  • маскування персональних даних у логах;
  • журнал усіх дій;
  • контроль доступу до файлів;
  • окремі права на ручну перевірку;
  • окремі права на зміну провайдера;
  • окремі права на повторне підписання. |-
document_type varchar CONTRACT, ACT, REPORT. Провайдер

async def upload_manual_signature(document_id: str, file: "UploadedFile", user: "User", db: "Session"): щоб не реалізовувати окрему логіку для кожного сервісного центру. | style="background:#fff9c4;" | Жовтий

Очікує підпису WAITING_SIGNATURE розроблена заявка на підпис. Статус
expected_signer_id=request.signer_id,
v
request.status = "WAITING_SIGNATURE"
  • єдиний API для всіх видів підписання;
  • підтримку декількох провайдерів підпису;
  • створення заявки на підписання;
  • підготовку документа до підпису;
  • розрахунок hash документа;
  • підписання PDF, XML, JSON, DOCX, ZIP або довільного файлу;
  • підтримку відокремленого підпису;
  • підтримку вкладеного підпису;
  • підтримку підписаного контейнера;
  • отримання результату підписання;
  • перевірку підпису;
  • перевірку цілісності документа;
  • перевірку підписанта;
  • перевірку сертифіката;
  • збереження файлів підпису;
  • збереження підписаних документів;
  • журналювання всіх подій;
  • dashboard контролю;
  • fallback-сценарії для ручного підписання. Без цього неможливо правильно перевіряти й використовувати результат. |-
Помилка }
async def get_session_status(self, session_id: str) -> dict:
style="background:#ef9a9a;" | Червоний
Сертифікат відкликаний CERT_REVOKED - AC-13 - AC-2 - base_url varchar - id uuid style="background:#ef9a9a;" | Червоний
Ручна перевірка MANUAL_REVIEW Потрібне втручання адміністратора. SEO-опис

Сервіс повинен забезпечити:

- Document Документ, який потрібно підписати. Очікуваний результат
- file_size integer - Signature Storage Зберігає підписані файли. Створюється signature_request. Колір - AuthError - Вибір провайдера }

 @abstractmethod

* timeout;
* HTTP 429;
* HTTP 500;
* HTTP 502;
* HTTP 503;
* HTTP 504;
* тимчасової недоступності провайдера;
* тимчасової помилки polling;
* тимчасової помилки отримання результату;
* тимчасової помилки перевірки;
* повторного callback з тим самим callback_id. |}

<syntaxhighlight lang="python">

! SEO-опис
K2 ERP / Dashboard / Archive
GET /api/v1/signature/signature-requests/{request_id}/status
|-
| Створення документа
| Тип, номер, hash, реліз системи. SEO-опис

{| class="wikitable"
 payload={
! |-
| signature_request_id
| uuid
| Заявка. "signer_type": "CLIENT",

* повна технічна підтримка всіх КНЕДП України;
* повна технічна підтримка всіх форматів ASIC / XAdES;
* складний UI локального агента;
* архів довгострокового зберігання за окремим регламентом;
* автоматичне юридичне трактування підпису;
* повна інтеграційні функції ERP з усіма ЕДО-системами;
* власний КНЕДП. |-
| supported_signature_types
| jsonb
| DETACHED, ENVELOPED, CONTAINER. | style="background:#ef9a9a;" | Червоний
|-
| Вимкнений
| DISABLED
| Провайдер вимкнений адміністратором. №

 callback_id = callback_service.get_callback_id(provider_code, payload)
 async def cancel_session(self, session_id: str) -> dict:
6. * Офіційна сторінка підписання документів на порталі Дія. |-
| status
| varchar
| ACTIVE, DISABLED, UNAVAILABLE. Параметр
! |-
| XML-підпис
| XML_SIGN
| Підпис XML-документа. | style="background:#ef9a9a;" | Червоний
|-
| Не той підписант
| SIGNER_MISMATCH
| Підписант не відповідає очікуваному. |-
| callback_url
| varchar
| Callback URL. Пріоритет

{| class="wikitable"

! |}

 def get_adapter(self, provider_code: str) -> SignatureProviderAdapter:

! |-
| document_version_id
| uuid
| реліз системи. | Запропонувати інший провайдер. |-
| mime_type
| varchar
| MIME type. |-
| status
| varchar
| Статус. | Вони підсвічуються червоним. |-
| Signature Session
| Сесія підписання. | Опційно
|-
| JSON
| Технічні документи або структуровані payload. |-
| FileKeyAdapter
| Підписання файловим КЕП. | Створення сесії, підписання, тест. |-
| signer_identifier
| varchar
| РНОКПП / ЄДРПОУ, якщо доступно. ! | Провайдер доступний для локального підпису. |}

 return self.adapters [provider_code]

== 10. User Story ==

! | style="background:#fff9c4;" | Важливий
|-
| ІІТ / користувач системи ЦСК-1
| IIT_CSK
| DLL / COM / SO / Java / JS / локальний агент
| Універсальний локальний crypto-provider для українських КЕП. |-
| Hash-підпис
| HASH_SIGN
| Провайдер підписує hash, а не сам файл. Коментар
=== 10.4. Керівник бачить контроль ===
 provider_code=provider_code,
 signature_file = signature_file_repository.create(

=== 15.2. Provider Router ===

<pre>
=== 17.7. Callback від провайдера ===
! from abc import ABC, abstractmethod
|-
| Активний
| ACTIVE
| Провайдер доступний для підписання. |-
| code
| varchar
| DIIA_SIGN, PRIVAT24_SMARTID, IIT_CSK тощо. "raw_request": payload,

* реалізувати SignatureProviderAdapter;
* реалізувати ProviderRouter;
* реалізувати PolicyEngine;
* реалізувати SignatureRequestService. |-
| AC-19
| виступає як помилки підписання. # Чи потрібен локальний агент для файлового КЕП? |-
| signer_id
| Підписант. |-
| PDF-підпис
| PDF_SIGN
| Підпис у PDF або супровідний p7s. | style="background:#ef9a9a;" | Червоний
|-
| Сертифікат прострочений
| CERT_EXPIRED
| Сертифікат недійсний. {| class="wikitable"
class SignatureProviderAdapter(ABC):
== 5. Підтримувані формати ==
 existing = signature_request_repository.get_by_idempotency_key(
 payload = await request.json()
 async def verify_signature(self, document: bytes, signature: bytes, options: dict) -> dict:
! |-
| Реалізація
| Localhost API, WebSocket або protocol handler. |-
| expires_at
| timestamp
| Строк дії. №
=== 24.1. Створення заявки ===
[[Категорія:SmartID]]
|-
| id
| uuid
| ID події. | Помилка API, помилка перевірки. # Чи потрібен експорт журналу в Excel? # Чи потрібна інтеграційні функції ERP з K2 ERP задачами? |-
| AC-6
| Документ змінено після заявки. Параметр
class SignaturePolicyEngine:

 signature_queue.enqueue(
=== 17.1. Список провайдерів ===

! |-
| Signature Policy Engine
| Визначає, які провайдери доступні для документа. # Чи виступає як офіційний API-доступ до SmartID? | Так
|-
| DOCX
| Документи Word. # Які формати документів підписуємо: PDF, XML, DOCX, ZIP? |-
| Перевірка підпису
| Результат, підписант, сертифікат. |-
| AC-10
| користувач системи обирає файловий КЕП. | style="background:#c8e6c9;" | Зелений
|-
| Невалідний
| INVALID
| Підпис не пройшов перевірку. |-
| Локальний агент недоступний
| користувач системи не здатна підписати файловим КЕП. №
Перед створенням заявки платформа повинна перевірити:
 raise BusinessError("Provider is not allowed for this document")

=== 23.1. signature_providers ===

 if result.code == "VALID":

* наявність документа;
* наявність актуальної версії документа;
* наявність file_id;
* доступність файлу у сховищі;
* розмір файлу;
* MIME type;
* hash документа;
* тип документа;
* тип підписанта;
* доступні провайдери для документа;
* чи підтримує провайдер формат документа;
* чи підтримує провайдер потрібний тип підпису;
* чи не був документ змінений після створення заявки;
* чи не підписаний документ цим підписантом раніше;
* чи виступає як idempotency_key;
* чи дає можливість бізнес-процес підписання. |-
| UnsupportedFormatError
| Провайдер не підтримує формат. |-
| document_name
| varchar
| Назва. Статус
 task_name="verify_uploaded_signature",
 "signature_file_id": str(signature_file.id),
! |-
| source
| varchar
| K2_ERP, PYTHON_SERVICE, PROVIDER, USER. * Документація ІІТ / користувач системи ЦСК-1. |-
| entity_type
| varchar
| document, request, session, verification, provider. | платформа зберігає файл і запускає перевірку. | style="background:#c8e6c9;" | Норма
|-
| Помилки підпису
| Помилки провайдера або локального агента. Формат


 "raw_response": response,
<div style="border-left: 6px solid #1565c0; background: #e3f2fd; padding: 12px 16px; margin: 16px 0;">
! Поле

[[Категорія:Python]]
! | DRAFT, DISABLED, CANCELLED. SEO-опис
=== Етап 7. Перевірка підпису ===
{| class="wikitable"

 "expires_at": "2026-05-07T14:30:00+03:00"
</div>
застосовується для для Дія.Підпис, SmartID та інших хмарних КЕП. | Так
|-
| XML
| Податкова, формування звітів, структуровані документи. |}

== 17. API Python-сервісу ==

@router.post("/api/v1/signature/callback/{provider_code}")
</syntaxhighlight>
 provider = request.provider
 "document_type": "CONTRACT",
|-
| AC-8
| користувач системи обирає Дія.Підпис. | style="background:#fff9c4;" | Важливий
|-
| Інші КНЕДП
| OTHER_QTSP
| Через ІІТ / файловий ключ / API
| Підключаються через адаптер. | Маскування, secure logging. | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка авторизації
| AUTH_ERROR
| Невірні credentials. |-
| idempotency_key
| varchar
| Ключ дедублікації. Документ
3. |-
| status
| varchar
| Статус. |-
| supported_signature_types
| jsonb
| DETACHED, ENVELOPED, CONTAINER. Вибір адаптера
__TOC__
 idempotency_key=command.idempotency_key,
 |
 |-- DiiaSignAdapter
 |-- SmartIDAdapter
 |-- FileKeyAdapter
 |-- IITAdapter
 |-- TaxCSKAdapter
 |-- ManualUploadAdapter
 |
 "signature_request_id": request.id,
 @abstractmethod
 |
 | 4. | Dashboard, список документів, картка документа. |}

 "provider_name": result.provider_name,

 if document_type == "TAX_REPORT":
 return ["IIT_CSK", "TAX_CSK", "FILE_KEY"]

 if signer_type == "CLIENT":
! |-
| integration_type
| varchar
| API, LOCAL_AGENT, FILE_KEY, MANUAL_UPLOAD. |-
| created_by
| Хто створив версію. |-
| DocumentChangedError
| Документ змінився після заявки. Поле
=== 10.3. Адміністратор керує провайдерами ===
=== 17.2. Перевірка провайдера ===
|-
| API провайдера недоступний
| Хмарний підпис не функціонує. | style="background:#c8e6c9;" | Високий
|-
| ПриватБанк SmartID / Приват24
| PRIVAT24_SMARTID
| API / polling / callback / ручне завантаження
| Хмарний КЕП ПриватБанку. Параметр
|-
| конкурентні переваги
| користувач системи не передає файл ключа в систему. Тип

* реалізувати завантаження документа;
* реалізувати версіонування;
* реалізувати hash;
* реалізувати дедублікацію. | style="background:#bbdefb;" | Блакитний
|-
| Тимчасово недоступний
| UNAVAILABLE
| API або локальний агент недоступний. SEO-опис
</syntaxhighlight>
 "status": "CREATING",

=== 14.2. Основні компоненти ===

== 11. Статуси документа ==

 "status": "ACTIVE",
 )
=== 27.2. Приклад dashboard по провайдерах ===
|-
| document_version_id
| ID версії. "result": result.code,
{| class="wikitable"
 "file_name": "contract_123.pdf",
 "file_id": stored_file.id,
12. |-
| Різні формати підписів
| Не всі формати однаково перевіряються. |-
| Недоліки
| Менше автоматизації. |-
| created_at
| timestamp
| Дата. | style="background:#fff9c4;" | Важливий
|-
| Ручне завантаження підпису
| MANUAL_UPLOAD
| Upload p7s / container
| Fallback-сценарій. |}

! |-
| is_active
| boolean
| Активність. |}

=== 17.6. Отримання статусу заявки ===

 task_name="start_signature_session",

=== 24.3. Callback controller ===
! |-
| style="background:#bbdefb;" | Блакитний
| #bbdefb
| операційна дія виконується або тестовий режим. |}

 payload = signature_mapper.to_provider_payload(request)

== 32. Етапи реалізації ==
! | style="background:#ffcc80;" | Резервний
|}

 "signer_name": result.signer_name,

=== 30.2. Документи ===
 @abstractmethod
2. | Створюється сесія SmartID. | платформа пропонує іншого провайдера або блокує заявку. Дія системи

 result=result,

* єдиний Signature API;
* довідник провайдерів;
* Provider Router;
* Signature Provider Interface;
* технічна підтримка Дія.Підпис як адаптера, якщо виступає як API-доступ;
* технічна підтримка SmartID як адаптера, якщо виступає як API-доступ;
* технічна підтримка ручного завантаження p7s;
* технічна підтримка файлового КЕП через локальний агент або ІІТ-адаптер;
* версіонування документа;
* hash документа;
* створення заявки;
* статуси;
* callback endpoint;
* polling worker;
* збереження підпису;
* перевірка підпису;
* dashboard API;
* журнал подій;
* retry;
* unit-тести;
* mock adapters. SEO-опис

! | style="background:#ef9a9a;" | Червоний
|-
| Невідомий формат
| UNKNOWN_FORMAT
| Формат підпису не розпізнано. |}

 },

13. Єдина логіка кольорів

17.9. Завантаження файлу підпису

async def signature_callback(provider_code: str, request: Request):

id uuid - provider_name varchar - file_id uuid - Особливості Статус стає SIGNED. Тип
"qr_payload": response.get("qr_payload"),
id uuid Опційно
P7S - external_document_id varchar - source varchar Опційно
ZIP Пакет документів. Тип помилки
data={
- document_date date INVALIDATED. Поле } style="background:#c8e6c9;" | Зелений
Тестовий режим TEST_MODE - status varchar - DiiaSignAdapter - Рекомендація - provider_session_id - file_hash_sha256 - certificate_settings jsonb Прострочення, недоступність, відхилення. if existing:
  • офіційний сервіс КЕП Дії. |}

критично: різні провайдери мають різні способи роботи: API, callback, polling, QR/deep link, файловий ключ, локальний агент, DLL/SO-бібліотека, JavaScript-бібліотека або ручне завантаження p7s. if provider_code not in self.adapters:

  • реалізувати DiiaSignAdapter;
  • реалізувати SmartIDAdapter;
  • реалізувати ManualUploadAdapter;
  • реалізувати FileKey/IITAdapter;
  • реалізувати mock adapters. Критерій
AC-1 - base_url varchar URL API, якщо виступає як. технічна підтримка в MVP
Критерій
"signature_type": "DETACHED",
- document_number varchar - Callback Controller SHA-256 hash. |- file_size - AC-17 - Signature File - current_version_id uuid - Особливості style="background:#f3e5f5;" | Фіолетовий
Колір
ProviderNotAllowedError Провайдер не дозволений для документа. request = signature_request_repository.create( Поле - Signature Request - Червоний #ef9a9a - version_number integer - mime_type - callback_url varchar style="background:#ef9a9a;" | Червоний
Помилка перевірки VERIFY_ERROR Підпис не пройшов перевірку. Параметр
Retry заборонений для:
 allowed_providers = policy_engine.get_allowed_providers(

{| class="wikitable"
=== 15.3. Signature Policy Engine ===

 async def get_signature_result(self, session_id: str) -> dict:

== 1. Мета ==
 db=db,
! "document_number": "123",
Приклад:
7.=== Етап 2. Базовий Python-сервіс ===

! |-
| signer_name
| varchar
| ПІБ підписанта. |-
| Локальне підписання
| Тип агента, результат, без пароля ключа. Дата
Як керівник, 
! | style="background:#e3f2fd;" | інформаційні матеріали
|-
| Очікують підпису
| Активні заявки. |-
| provider_id
| uuid
| Провайдер. |-
| callback_event_id
| ID callback-події. |-
| file_hash_sha256
| varchar
| Hash. Підписано
{
! | MANUAL_REVIEW. SEO-опис

 request.status = "SIGN_ERROR"
! |}

=== 30.5. Ручне завантаження ===

POST /api/v1/signature/documents/{document_id}/upload-signature
 "external_document_id": "K2-DOC-2026-000123",
POST /api/v1/signature/documents/{document_id}/signature-requests
8. |}

<pre>

</div>

<pre>
 if signer_type == "EMPLOYEE":
 return ["FILE_KEY", "IIT_CSK", "PRIVAT24_SMARTID"]

 return ["DIIA_SIGN", "PRIVAT24_SMARTID", "FILE_KEY", "MANUAL_UPLOAD"]
</syntaxhighlight>

== 16. * Внутрішня документація K2 ERP. |}

! |-
| Підписаний контейнер
| CONTAINER
| Документ і підпис зберігаються в контейнері. | Провайдер доступний у списку. | style="background:#c8e6c9;" | Зелений
|-
| Підпис перевірено
| VERIFIED
| Підпис валідний. K2 ERP створює документ. |-
| Обов'язкова умова
| Автоматична перевірка підпису після завантаження. | платформа дає можливість створити заявку. накладання електронного підпису через різних провайдерів України: '''Дія.Підпис''' забезпечується через '''Головна ідея:''' розробити єдиний Python-сервіс підписання. Дія
! | Заблокувати заявку. | MANUAL_REVIEW. |-
| raw_request
| jsonb
| Запит. |}

! return ["DIIA_SIGN", "PRIVAT24_SMARTID", "MANUAL_UPLOAD"]

* додати rate limiting;
* додати alerting;
* додати dead letter queue;
* додати backup файлів;
* додати моніторинг провайдерів;
* додати secure secret storage. Ключ

=== 23.7. signature_files ===
! ! |-
| provider_name
| varchar
| КНЕДП / провайдер сертифіката. |-
| AC-14
| Підписант не збігається. SEO-опис
=== 24.4. Ручне завантаження підпису ===

 "deep_link": response.get("deep_link"),

Python Unified Signature Service

Значення
v
Код

2. Область сценарії використання

response = await adapter.create_signature_session(payload)

33. Ризики

"source": "MANUAL_UPLOAD",
},
Signature Provider - deep_link text - idempotency_key } користувач системи підтверджує підпис. конфігурація провайдера == - credentials_encrypted jsonb Зашифровані credentials. Провайдер
  • визначити провайдерів MVP;
  • отримати документацію Дія.Підпис;
  • отримати документацію SmartID;
  • визначити локальну бібліотеку для файлового КЕП;
  • визначити формати підпису;
  • визначити правила перевірки. ! |-
AC-9 - Document Version Service Документ стає VERIFIED. |- Фіолетовий #f3e5f5 Запропонувати інший провайдер. |- ProviderUnavailableError }

async def create_signature_request(command: "CreateSignatureRequestCommand", db: "Session") -> "SignatureRequest":

20. Hash і версії документа

- signature_format varchar - created_at - entity_id uuid ID сутності. Поле
)
verification_queue.enqueue(
return {"status": "already_processed"}
  • цілісність документа;
  • відповідність підпису конкретній версії документа;
  • валідність підпису;
  • валідність сертифіката;
  • підписанта;
  • дату та час підписання;
  • chain trust;
  • статус відкликання сертифіката, якщо доступно;
  • формат підпису;
  • відповідність очікуваному типу підписанта;
  • чи не змінювався документ після підпису. | XML із XAdES.
    '''Управлінський результат:''' керівник і відповідальні особи повинні бачити, через який провайдер підписано документ, хто підписав, коли, чи пройшла перевірка, які документи очікують підпису, які прострочені, які мають помилки або потребують ручної перевірки. | style="background:#eeeeee;" | Сірий
    |-
    | Готовий до підпису
    | READY_TO_SIGN
    | Документ перевірено. SEO-опис
    |-
    | Валідний
    | VALID
    | Підпис успішно перевірений. SEO-опис
    Можливі результати:
    я хочу викликати один API підписання, 
    == 21. Перевірка підпису ==
    
    === Варіант 2. 7.2. Локальне підписання файловим ключем ===
    == 6. Передумови ==
     elif result.code in ["SIGNER_MISMATCH", "UNKNOWN_FORMAT"]:
    Кожна реліз системи документа повинна мати:
     "provider_id": provider.id,
    == 26. Retry-логіка ==
    === 23.5. signature_requests ===
    class SignatureProviderRouter:
    ! |}
    
    === Етап 8. Dashboard та аудит ===
    
    <pre>
    
     "document_name": "Договір поставки №123",
     @abstractmethod
     if callback_repository.exists(callback_id):
     db=db,
    |-
    | id
    | uuid
    | ID провайдера. |-
    | style="background:#ffcc80;" | Помаранчевий
    | #ffcc80
    | Потрібна дія або виступає як ризик. {| class="wikitable"
    
    ! pass
    
    4. ! |-
    | provider_id
    | uuid
    | Провайдер. |-
    | VerificationError
    | Підпис не пройшов перевірку.=== 23.6. signature_sessions ===
    
     )
    
    * договорів;
    * актів виконаних робіт;
    * рахунків;
    * заяв;
    * кадрових документів;
    * первинних бухгалтерських документів;
    * податкових документів;
    * документів ЕДО;
    * заявок у CRM;
    * документів K2 ERP;
    * пакетів документів;
    * XML-звітів;
    * PDF-документів;
    * підтвердження юридично значущих дій. |-
    | KeyReadError
    | Не вдалося прочитати файловий ключ. ! |-
    | created_at
    | timestamp
    | Дата. # Чи виступає як офіційний API-доступ до Дія.Підпис? Код
    === 23.4. sign_document_versions ===
    |-
    | AC-12
    | Підпис валідний. # Чи потрібно підписувати документи співробітниками? | Він бачить статистику по всіх провайдерах. external_document_id=command.external_document_id,
     "signer_id": command.signer_id,
    ! SEO-опис
    ! |-
    | Callback
    | provider_code, callback_id, raw payload. Де застосовується для
     provider_code=provider_code,
    
    === 27.1. Основні KPI ===
    
    9. SEO-опис
    
     signer_type=command.signer.signer_type,
    
    На ПК користувача встановлюється агент підпису. | Статус стає VERIFY_ERROR. |-
    | Невідомий КНЕДП
    | Сертифікат не розпізнано. |-
    | provider_id
    | uuid
    | Провайдер. | Стара заявка стає INVALIDATED. | Провайдер доступний у списку. Тип
    
    ! |-
    | signature_request_id
    | uuid
    | Заявка. Результат
    
     signature_file_id=signature_file.file_id,
    
    ! |-
    | provider_session_id
    | varchar
    | ID сесії провайдера. Тип
    Verification Service повинен перевіряти:
     adapter = provider_router.get_adapter(provider_code)
     verifier = verification_service_factory.get_verifier(signature_file.signature_format)
    </pre>
    ! SEO-опис
    ! SEO-опис
    
     raise ValueError(f"Unsupported signature provider: {provider_code}")
    
    {| class="wikitable"
     if command.provider_code not in allowed_providers:
     else:
    
PDF Найчастіший формат договорів, актів, рахунків. POST /api/v1/signature/documents/{document_id}/verify
},
"file_hash_sha256": stored_file.sha256,
- конкурентні переваги - Verification Service style="background:#c8e6c9;" | Високий
Файловий КЕП FILE_KEY Локальне підписання Ключ типу Key-6.dat або інший файловий контейнер. Ризик
pass

22. Дедублікація

Провайдер

Як розробник K2 ERP,

Як користувач системи, Для реалізації задачі необхідно отримати:

db.commit()
external_document_id - Signature Integration style="background:#ffcc80;" | Потрібна дія
Ручна перевірка Потрібне втручання. Тип

15. Unified Signature Provider Interface

</syntaxhighlight>
id uuid - AC-20 - settings jsonb Технічні конфігурація. Колір

29. Логування та аудит

"signer_identifier": result.signer_identifier,
- supported_formats jsonb - AC-7 Idempotent callback. SEO-опис
provider_code varchar Інструкція, fallback, healthcheck агента.</syntaxhighlight>
  • створити FastAPI-проєкт;
  • налаштувати PostgreSQL;
  • створити моделі провайдерів, документів, заявок, сесій;
  • налаштувати Alembic;
  • реалізувати healthcheck. |-
supported_formats jsonb PDF, XML, P7S, ASIC. Поле Очікуваний результат

Критично критично: якщо документ змінено після створення заявки, попередню заявку потрібно перевести в INVALIDATED. |}

17.8. Ручне завантаження підпису

callback_id=callback_id,
signature_processor.process_provider_result(
id uuid - Ризики style="background:#ffcc80;" | Помаранчевий
Помилка підписання SIGN_ERROR Помилка під час підписання. ! HTML

</syntaxhighlight>

finally:

GET /api/v1/signature/documents/{document_id}/available-providers

- raw_response jsonb Відповідь. Критерій

router = APIRouter()

! },

щоб контролювати прострочені, помилкові та непідписані документи. | Очікує підпису, вибір провайдера. | SIGN_ERROR або retry. SEO-опис


Retry дозволений для:
! |-
| Polling
| Старий статус, новий статус. |-
| AC-4
| Провайдер недоступний. Призначення

GET /api/v1/signature/documents/{document_id}/signed-file
[[Категорія:API]]
Signature Provider Router
{| class="wikitable"
|-
| AC-5
| Документ валідний. | style="background:#f3e5f5;" | Контроль
|}

 if document.status not in ["READY_TO_SIGN", "WAITING_SIGNATURE", "SIGN_ERROR"]:

! |-
| Verification Result
| Результат перевірки. Тип
! Очікуваний результат
=== Етап 6. Callback / polling ===
|-
| конкурентні переваги
| функціонує з багатьма КНЕДП. | Статус стає MANUAL_REVIEW. |-
| Document Version
| реліз системи документа, яка передається на підпис. * Офіційна партнерська документація конкретних провайдерів. |-
| Provider Adapter
| Програмний адаптер конкретного провайдера. db.commit()

 return request

Signature Storage + Verification Service
</div>
<pre>
 payload=payload,
|-
| Документів створено
| Загальна кількість документів. Signature Storage зберігає файл підпису / контейнер. |-
| Audit Event
| Подія журналу. | Signature format detector і окремі verifier-и. |-
| provider_code
| varchar
| Провайдер. | style="background:#c8e6c9;" | Зелений
|-
| Відхилено користувачем
| DECLINED_BY_USER
| користувач системи відмовився від підписання. |-
| document_version_id
| реліз системи документа. Подія
|-
| Підходить для
| Fallback або MVP без API. K2 ERP повинна працювати з єдиним інтерфейсом: створити заявку, отримати статус, отримати підпис, перевірити підпис, зберегти результат. Тип інтеграції
=== 17.4. Отримання доступних провайдерів для документа ===
{| class="wikitable"
! 1. | signed.pdf або pdf.p7s. # Чи потрібно перевіряти РНОКПП / ЄДРПОУ підписанта? | VERIFY_ERROR. |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка, вимкнено, скасовано або архів. |-
| priority
| integer
| Пріоритет. | Створюється сесія Дії. K2 ERP отримує фінальний статус. | Так
|-
| XAdES
| XML-підпис. Стан
=== Етап 5. Документи та hash ===

== 24. Приклад Python-логіки ==

! | Відхилити callback. Код
POST /api/v1/signature/providers/{provider_code}/check-connection

<pre>
}
{| class="wikitable"

 result = await adapter.parse_callback(payload)
! |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування дії користувача. |-
| id
| uuid
| ID заявки. |}

<syntaxhighlight lang="python">

# Які провайдери мають бути в MVP?
return {"status": "ok"}

23.9. signature_events

"document_version_id": document.current_version_id,