Документообіг та узгодження (Approvals + Internal Documents)¶
Тип: horizontal-модуль (community)
Backend: backend/approvals/ (движок) + backend/internal_documents/ (документи-консументи)
Frontend: секція «Внутрішні документи» (frontend/dop/internal-documents/)
Статус: ✅ реалізовано (2026-05-31)
Архітектура / план: planning/internal-documents-approval-2026-05-31.md · AI-bundle: docs/ai/domains/{approvals,internal_documents}/
Призначення¶
Внутрішні документи компанії — службові записки, рапорти, накази, договори — проходять складну процедуру узгодження та підписання між підрозділами (автор → начальник → суміжний відділ → директор → канцелярія). Модуль веде сам документ, проганяє його через налаштовуваний маршрут, фіксує підписи/рішення кожного підписанта і дає кожному виконавцю чергу «мені на узгодження».
Ключове архітектурне рішення: движок узгодження (approvals) — generic і polymorphic (працює над будь-яким
документом через GenericFK), а конкретні документи (InternalDocument, ContractDocument) — його перші
консументи. Завтра на узгодження можна пустити будь-який інший документ без переробки движка.
Дві групи сутностей¶
Движок approvals¶
| Модель | Роль |
|---|---|
ApprovalRoute + ApprovalRouteStep |
Шаблон маршруту: впорядковані стадії. Кроки з однаковим order — паралельні (всі мусять погодити); різні order — послідовні. |
ApprovalProcess + ApprovalTask |
Запущений екземпляр на конкретному документі (снапшот кроків — редагування маршруту не зачіпає процеси в роботі). |
ApprovalSigningKey |
Person-bound Ed25519-ключ (Tier-2 self-sign, TEST MODE). |
ApprovalDelegation |
Делегування узгоджень заступнику на період. |
Документи-консументи internal_documents¶
| Модель | Роль |
|---|---|
InternalDocumentKind |
Налаштовуваний вид (службова / рапорт / наказ) + маршрут за замовчуванням. |
InternalDocument |
Generic внутрішній документ (kind / title / body / route). |
ContractDocument |
Договір (наша юрособа / контрагент / сума / строк / route) — підписується від імені юрособи. |
ContractDocument≠essentials.Contract. Останній — обліковий довідник (тарифи, прив'язка до клієнта, вимір для накладних).ContractDocument— документ узгодження й підписання. Це різні життєві цикли (D7). Зв'язок між ними (підписаний договір → обліковий контракт) — опційний follow-up, не реалізовано.
Життєвий цикл документа¶
draft ──send-for-approval──▶ on_approval ──(усі кроки погоджено)──▶ approved
│
├── відхилено ───────────────────▶ rejected
├── повернено на доопрацювання ──▶ draft (редагувати + переслати)
└── відкликано автором ──────────▶ draft
InternalDocument/ContractDocument — no-posting документи (не пишуть у PostingGroup/реєстри): обліковий
state лишається інертним, робочий стан веде status + лінкований ApprovalProcess. Статус документа
синхронізується з результатом процесу автоматично (через domain-event, без зв'язування движка з документом).
Підписи — дворівневі¶
- Tier-1 (audit) — для більшості кроків: запис «хто / коли / рішення / коментар».
- Tier-2 (crypto) — Ed25519-підпис над канонічним тілом документа (TEST MODE; у проді — КЕП/КЕС). Два режими:
- person self-sign (службова) — особистим ключем користувача;
- on-behalf-of-org (договір) — ключем юрособи (
edo.SigningKey), з перевіркою повноважень (OrgMembership— який користувач уповноважений підписувати за яку юрособу).
Рівень підпису — атрибут кроку маршруту.
Що вміє маршрут¶
- Послідовні + паралельні стадії.
- Виконавець кроку: конкретна людина / роль (будь-який носій) / динамічно «керівник автора» (через
core.User.manager). - Умовна маршрутизація — крок застосовується лише якщо документ задовольняє умову (напр. сума ≥ X → додати фіндиректора); інакше крок пропускається.
- Дедлайни на крок + детекція overdue; авто-ескалація прострочених кроків угору по ланцюгу
керівників (cron-команда
escalate_overdue_approvals). - Делегування — заступник діє за делегатора на період.
- Необов'язкові кроки (
is_optional) — не блокують стадію.
Робочі місця (UI) — секція «Внутрішні документи»¶
| Пункт | Що |
|---|---|
| Внутрішні документи | Список / створення / надсилання службових + трек узгодження (погодити / повернути / відхилити). |
| Договори | Те саме для ContractDocument (підпис від імені юрособи). |
| Мої узгодження | Черга кроків, що очікують на мою дію (з бейджем «прострочено»). |
| Налаштування узгодження (admin) | Конструктор маршрутів (кроки + виконавці + умови + дедлайни + optional), види документів, делегування. |
Паперові версії / скани: у кожному документі — блок «Файли» (загальний DocumentAttachment):
завантаження сканів підписаного паперу, PDF, додатків. Цифровий трек = внутрішній запис; скан = паперовий
артефакт.
API (огляд)¶
/api/v1/internal-documents/documents/ CRUD + {id}/send-for-approval/ + {id}/approval/
/api/v1/internal-documents/contracts/ CRUD + {id}/send-for-approval/ + {id}/approval/
/api/v1/internal-documents/kinds/ CRUD видів
/api/v1/approvals/processes/ (read) процеси з кроками
/api/v1/approvals/tasks/{id}/{approve,reject}/ дія над кроком (reject: send_back=true → доопрацювання)
/api/v1/approvals/tasks/mine/ черга поточного користувача
/api/v1/approvals/{routes,route-steps}/ конструктор маршруту (admin)
/api/v1/approvals/delegations/ делегування
/api/v1/essentials/org-memberships/ хто за яку юрособу підписує (D8)
/api/v1/attachments/?content_type=internal_documents.internaldocument&object_id=… скани
Авторитетність кроку — у сервісі (approve_task/reject_task перевіряють assignee / роль / делегата /
повноваження юрособи), не в entity-RBAC; маршрути/види/делегування — admin-gated.
Налаштування (швидкий старт)¶
- Налаштування узгодження → Маршрути — створити маршрут, додати кроки (виконавці / умови / дедлайни).
- → Види документів — створити вид (службова/рапорт/…) з маршрутом за замовчуванням.
- (для договорів і Tier-2) Org-membership — призначити, хто підписує за яку юрособу.
- Демо-дані:
python manage.py seed_internal_documents(маршрут + 3 види на тенант).
Новий backend-app у dev потребує:
migrate+seed_shop(AppStore-реєстрація) + доменний seed + рестарт Daphne (без autoreload).
Обмеження / поза scope¶
ContractDocument ↔ essentials.Contractміст (підписаний → обліковий контракт) — не реалізовано.- Глибша HR-ієрархія (синхрон
User.manager←Employee/Position) — окремий HRM-трек. - Auto-escalation потребує налаштованого cron на
escalate_overdue_approvals. - Tier-2 крипто — TEST MODE (приватний ключ у БД); прод — КЕП/КЕС.