Add document archiving

Documents can be archived and unarchived. Archived documents are
read-only, excluded from the trust center, and moved to a dedicated
Archived tab in the document list.

- Add archived_at timestamp and status (ACTIVE/ARCHIVED) PG enum column
- Rename DocumentStatus → DocumentVersionStatus, introduce DocumentStatus
- Archive/unarchive mutations in GraphQL, MCP, and CLI
- Bulk archive/unarchive mutations with Active/Archived tabs in the list
- ABAC policies: write actions denied on archived docs, unarchive denied
  on active docs
- Remove control/risk mappings and reset trust center visibility on archive
- Exclude archived documents from mapping dialogs and trust center tab

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-03-19 14:15:16 +01:00
parent 2e12c11c0c
commit 1db8e7133e
29 changed files with 1194 additions and 199 deletions

View File

@@ -69,15 +69,26 @@ enum EvidenceState
@goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceStateRequested")
}
enum DocumentStatus
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentStatus") {
DRAFT @goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentStatusDraft")
enum DocumentVersionStatus
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatus") {
DRAFT
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatusDraft"
)
PUBLISHED
@goEnum(
value: "go.probo.inc/probo/pkg/coredata.DocumentStatusPublished"
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionStatusPublished"
)
}
enum DocumentStatus
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentStatus") {
ACTIVE
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentStatusActive")
ARCHIVED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.DocumentStatusArchived")
}
enum EvidenceType
@goModel(model: "go.probo.inc/probo/pkg/coredata.EvidenceType") {
FILE @goEnum(value: "go.probo.inc/probo/pkg/coredata.EvidenceTypeFile")
@@ -1569,7 +1580,7 @@ input ApplicabilityStatementOrder
}
input DocumentVersionFilter {
status: DocumentStatus
status: DocumentVersionStatus
}
# Input Types for Filtering
@@ -1580,6 +1591,7 @@ input ControlFilter {
input DocumentFilter {
query: String
documentTypes: [DocumentType!]
status: [DocumentStatus!]
}
input MeasureFilter {
@@ -2402,6 +2414,9 @@ type Document implements Node {
filter: ControlFilter
): ControlConnection! @goField(forceResolver: true)
status: DocumentStatus!
archivedAt: Datetime
createdAt: Datetime!
updatedAt: Datetime!
@@ -3657,6 +3672,8 @@ type Mutation {
# Document mutations
createDocument(input: CreateDocumentInput!): CreateDocumentPayload!
updateDocument(input: UpdateDocumentInput!): UpdateDocumentPayload!
archiveDocument(input: ArchiveDocumentInput!): ArchiveDocumentPayload!
unarchiveDocument(input: UnarchiveDocumentInput!): UnarchiveDocumentPayload!
deleteDocument(input: DeleteDocumentInput!): DeleteDocumentPayload!
# Meeting mutations
createMeeting(input: CreateMeetingInput!): CreateMeetingPayload!
@@ -3694,6 +3711,12 @@ type Mutation {
bulkDeleteDocuments(
input: BulkDeleteDocumentsInput!
): BulkDeleteDocumentsPayload!
bulkArchiveDocuments(
input: BulkArchiveDocumentsInput!
): BulkArchiveDocumentsPayload!
bulkUnarchiveDocuments(
input: BulkUnarchiveDocumentsInput!
): BulkUnarchiveDocumentsPayload!
bulkExportDocuments(
input: BulkExportDocumentsInput!
): BulkExportDocumentsPayload!
@@ -4367,6 +4390,14 @@ input ExportTransferImpactAssessmentsPDFInput {
filter: TransferImpactAssessmentFilter
}
input ArchiveDocumentInput {
documentId: ID!
}
input UnarchiveDocumentInput {
documentId: ID!
}
input DeleteDocumentInput {
documentId: ID!
}
@@ -5086,6 +5117,14 @@ type UpdateDocumentPayload {
document: Document!
}
type ArchiveDocumentPayload {
document: Document!
}
type UnarchiveDocumentPayload {
document: Document!
}
type DeleteDocumentPayload {
deletedDocumentId: ID!
}
@@ -5197,7 +5236,7 @@ type DeleteMeasurePayload {
type DocumentVersion implements Node {
id: ID!
document: Document! @goField(forceResolver: true)
status: DocumentStatus!
status: DocumentVersionStatus!
version: Int!
content: String!
changelog: String!
@@ -5326,6 +5365,22 @@ input BulkDeleteDocumentsInput {
documentIds: [ID!]!
}
input BulkArchiveDocumentsInput {
documentIds: [ID!]!
}
type BulkArchiveDocumentsPayload {
documents: [Document!]!
}
input BulkUnarchiveDocumentsInput {
documentIds: [ID!]!
}
type BulkUnarchiveDocumentsPayload {
documents: [Document!]!
}
input BulkExportDocumentsInput {
documentIds: [ID!]!
withWatermark: Boolean!