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 <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-03-27 17:22:54 +01:00
parent 4a2d308da0
commit 999171a626
78 changed files with 6483 additions and 1600 deletions

View File

@@ -370,7 +370,6 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
controlID := createControlResult.CreateControl.ControlEdge.Node.ID
// Create a document
profileID := factory.CreateUser(owner)
var createDocumentResult struct {
CreateDocument struct {
DocumentEdge struct {
@@ -395,7 +394,6 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(),
"title": "Document for Control Mapping",
"content": "Document content",
"approverIds": []string{profileID},
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -760,7 +758,6 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID
// Create a document
profileID := factory.CreateUser(owner)
var createDocumentResult struct {
CreateDocument struct {
DocumentEdge struct {
@@ -785,7 +782,6 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(),
"title": "Document for Risk Mapping",
"content": "Document content",
"approverIds": []string{profileID},
"documentType": "POLICY",
"classification": "INTERNAL",
},