From 999171a6265f68834c5360dea55f1ea58f57db9b Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Fri, 27 Mar 2026 17:22:54 +0100 Subject: [PATCH] Add document approval workflow Introduce a complete approval system for document publishing. Document versions can now require approval from selected reviewers before being published, with automatic publishing once all approvers have approved. - Add approval quorum and decision tables with backfill migration - Implement request approval, approve, and reject flows with electronic signature support for approve decisions - Add employee approvals page with dedicated tab and pending approvals view - Add changelog field to publish and request approval flows - Pre-select previous version's approvers in the publish dialog - Show quorum approvers in document list with 100 approver hard limit - Expose approval workflow through GraphQL, MCP, and CLI - Remove legacy default approvers feature entirely - Add comprehensive e2e test coverage for approval workflows Signed-off-by: Sacha Al Himdani --- .../form/PeopleMultiSelectField.tsx | 10 +- .../src/hooks/forms/useDocumentForm.tsx | 1 - .../CompliancePageDocumentListItem.tsx | 2 +- .../documents/DocumentLayout.tsx | 102 +- .../_components/CreateDocumentDialog.tsx | 13 - .../_components/DocumentLayoutDrawer.tsx | 76 +- .../documents/_components/DocumentList.tsx | 12 +- .../_components/DocumentListItem.tsx | 66 +- .../documents/_components/PublishDialog.tsx | 323 ++++++ .../_components/PublishDocumentsDialog.tsx | 106 +- .../approvals/DocumentApprovalsPage.tsx | 161 +++ .../approvals/DocumentApprovalsPageLoader.tsx | 73 ++ .../_components/DocumentApprovalList.tsx | 212 ++++ .../_components/DocumentApprovalListItem.tsx | 172 +++ .../documents/approve/DocumentApprovePage.tsx | 534 ++++++++++ .../approve/DocumentApprovePageLoader.tsx | 43 + .../_components/DocumentSignatureListItem.tsx | 3 +- .../DocumentSignaturePlaceholder.tsx | 3 +- .../employee/EmployeeApprovalsPage.tsx | 89 ++ .../employee/EmployeeApprovalsPageLoader.tsx | 38 + .../EmployeeDocumentSignaturePage.tsx | 6 +- .../EmployeeDocumentSignaturePageLoader.tsx | 5 +- .../employee/EmployeeDocumentsPage.tsx | 19 +- .../employee/EmployeeDocumentsPageLoader.tsx | 9 +- .../employee/EmployeeTabsLayout.tsx | 22 + .../_components/ApprovableDocumentRow.tsx | 64 ++ .../employee/_components/DocumentRow.tsx | 6 +- .../employee/_components/VersionActions.tsx | 2 +- .../employee/_components/VersionRow.tsx | 2 +- apps/console/src/routes.tsx | 41 +- apps/console/src/routes/documentsRoutes.ts | 13 +- e2e/console/document_test.go | 138 +-- e2e/console/document_version_test.go | 304 ++++-- e2e/console/mapping_test.go | 4 - e2e/internal/factory/factory.go | 14 +- packages/emails/emails.go | 44 +- packages/emails/scripts/build.ts | 5 + packages/emails/src/DocumentApproval.tsx | 36 + .../src/ElectronicSignatureCertificate.tsx | 4 +- .../emails/templates/document-approval.txt | 20 + .../electronic-signature-certificate.txt | 2 +- pkg/coredata/document.go | 102 +- pkg/coredata/document_approver.go | 154 --- pkg/coredata/document_filter.go | 21 + pkg/coredata/document_version.go | 50 +- .../document_version_approval_decision.go | 458 ++++++++ ...cument_version_approval_decision_filter.go | 51 + ...t_version_approval_decision_order_field.go | 55 + ...ocument_version_approval_decision_state.go | 100 ++ .../document_version_approval_quorum.go | 336 ++++++ ...ent_version_approval_quorum_order_field.go | 55 + ...document_version_approval_quorum_status.go | 79 ++ pkg/coredata/document_version_approver.go | 154 --- pkg/coredata/document_version_filter.go | 61 +- pkg/coredata/electronic_signature.go | 12 +- .../electronic_signature_document_type.go | 95 +- pkg/coredata/entity_type_reg.go | 6 + pkg/coredata/membership_profile.go | 181 +--- pkg/coredata/migrations/20260319T160000Z.sql | 95 ++ pkg/docgen/template.html | 2 + pkg/esign/completion_certificate_worker.go | 7 +- pkg/esign/service.go | 67 ++ pkg/probo/actions.go | 24 +- pkg/probo/document_approval_service.go | 985 ++++++++++++++++++ pkg/probo/document_service.go | 272 ++--- pkg/probo/policies.go | 57 +- pkg/probo/service.go | 7 + pkg/server/api/console/v1/schema.graphql | 297 +++++- .../document_version_approval_decision.go | 80 ++ .../types/document_version_approval_quorum.go | 73 ++ .../api/console/v1/types/employee_document.go | 141 +++ .../api/console/v1/types/signable_document.go | 83 -- pkg/server/api/console/v1/v1_resolver.go | 821 ++++++++++++--- pkg/server/api/mcp/v1/helpers.go | 41 - pkg/server/api/mcp/v1/schema.resolvers.go | 124 +-- pkg/server/api/mcp/v1/specification.yaml | 59 +- pkg/server/api/mcp/v1/types/document.go | 25 +- pkg/trust/document_service.go | 54 +- 78 files changed, 6483 insertions(+), 1600 deletions(-) create mode 100644 apps/console/src/pages/organizations/documents/_components/PublishDialog.tsx create mode 100644 apps/console/src/pages/organizations/documents/approvals/DocumentApprovalsPage.tsx create mode 100644 apps/console/src/pages/organizations/documents/approvals/DocumentApprovalsPageLoader.tsx create mode 100644 apps/console/src/pages/organizations/documents/approvals/_components/DocumentApprovalList.tsx create mode 100644 apps/console/src/pages/organizations/documents/approvals/_components/DocumentApprovalListItem.tsx create mode 100644 apps/console/src/pages/organizations/documents/approve/DocumentApprovePage.tsx create mode 100644 apps/console/src/pages/organizations/documents/approve/DocumentApprovePageLoader.tsx create mode 100644 apps/console/src/pages/organizations/employee/EmployeeApprovalsPage.tsx create mode 100644 apps/console/src/pages/organizations/employee/EmployeeApprovalsPageLoader.tsx create mode 100644 apps/console/src/pages/organizations/employee/EmployeeTabsLayout.tsx create mode 100644 apps/console/src/pages/organizations/employee/_components/ApprovableDocumentRow.tsx create mode 100644 packages/emails/src/DocumentApproval.tsx create mode 100644 packages/emails/templates/document-approval.txt delete mode 100644 pkg/coredata/document_approver.go create mode 100644 pkg/coredata/document_version_approval_decision.go create mode 100644 pkg/coredata/document_version_approval_decision_filter.go create mode 100644 pkg/coredata/document_version_approval_decision_order_field.go create mode 100644 pkg/coredata/document_version_approval_decision_state.go create mode 100644 pkg/coredata/document_version_approval_quorum.go create mode 100644 pkg/coredata/document_version_approval_quorum_order_field.go create mode 100644 pkg/coredata/document_version_approval_quorum_status.go delete mode 100644 pkg/coredata/document_version_approver.go create mode 100644 pkg/coredata/migrations/20260319T160000Z.sql create mode 100644 pkg/probo/document_approval_service.go create mode 100644 pkg/server/api/console/v1/types/document_version_approval_decision.go create mode 100644 pkg/server/api/console/v1/types/document_version_approval_quorum.go create mode 100644 pkg/server/api/console/v1/types/employee_document.go delete mode 100644 pkg/server/api/console/v1/types/signable_document.go delete mode 100644 pkg/server/api/mcp/v1/helpers.go diff --git a/apps/console/src/components/form/PeopleMultiSelectField.tsx b/apps/console/src/components/form/PeopleMultiSelectField.tsx index e8b98e3bc..d5c31c540 100644 --- a/apps/console/src/components/form/PeopleMultiSelectField.tsx +++ b/apps/console/src/components/form/PeopleMultiSelectField.tsx @@ -1,5 +1,5 @@ import { useTranslate } from "@probo/i18n"; -import { Avatar, Badge, Button, Field, IconCrossLargeX, Option, Select } from "@probo/ui"; +import { Badge, Button, Field, IconCrossLargeX, Option, Select } from "@probo/ui"; import { type ComponentProps, Suspense, useState } from "react"; import { type Control, Controller, type FieldValues, type Path } from "react-hook-form"; @@ -104,10 +104,6 @@ function PeopleMultiSelectWithQuery( > {availablePeople.map(person => (