Skip to content

Add document archiving#855

Merged
SachaProbo merged 1 commit intomainfrom
SachaProbo/doc-archived-at
Mar 19, 2026
Merged

Add document archiving#855
SachaProbo merged 1 commit intomainfrom
SachaProbo/doc-archived-at

Conversation

@SachaProbo
Copy link
Contributor

@SachaProbo SachaProbo commented Mar 16, 2026

Allow documents to be archived and unarchived via GraphQL, MCP, and
the console UI. Archived documents cannot be edited or published and
are excluded from the trust center. The console displays archived
documents as grayed out in lists and shows the archived date in the
document details drawer.

  • Add archived_at column to documents table
  • Add archive/unarchive mutations in GraphQL and MCP
  • Block update and publish operations on archived documents
  • Exclude archived documents from trust center listings
  • Return not found for archived documents on trust center endpoints
  • Guard title editing form against concurrent archiving
  • Show "Archived on" date in document detail drawer

Summary by cubic

Add document archiving across GraphQL, MCP, and the console with ABAC enforcement. Archived documents are read‑only, can’t be published, are excluded from the trust center, and archiving removes control/risk mappings and resets trust center visibility; the console adds Active/Archived tabs with bulk and per‑document archive/unarchive and toasts.

  • New Features

    • GraphQL: Document.status (ACTIVE/ARCHIVED) and archivedAt; archiveDocument/unarchiveDocument and bulkArchiveDocuments/bulkUnarchiveDocuments; DocumentFilter.status (list); DocumentVersionStatus enum for DocumentVersion.status and DocumentVersionFilter.status; update/publish/version‑update return Conflict if archived; archive/unarchive return Conflict when already/never archived.
    • MCP: New archiveDocument/unarchiveDocument tools; spec includes Document.status and archived_at; version status uses DocumentVersionStatus.
    • Console UI: Active/Archived tabs with tab‑specific bulk actions (Archive/Unarchive or Delete) and per‑document Archive/Unarchive with confirm + toasts; “New document” hidden on Archived tab; permission‑gated actions; edits disabled when archived; “Archived on” date in the details drawer; bulk archive/unarchive/delete remove items immediately via Relay updater; document pickers (LinkedDocumentsDialog, Compliance page) show only ACTIVE documents.
    • Trust Center: Archived documents excluded from listings; detail/PDF/access endpoints return Not Found; archiving resets trust center visibility to NONE.
    • Permissions/ABAC: Added document_status to authorization attributes for Document and DocumentVersion; deny writes when status is ARCHIVED (delete allowed); deny unarchive when status is ACTIVE; new actions core:document:archive and core:document:unarchive.
    • Core behavior: Archiving removes all control and risk mappings; bulk archive applies the same cleanup.
  • Migration

    • Create Postgres enum document_status (ACTIVE/ARCHIVED); add archived_at TIMESTAMPTZ and status document_status NOT NULL DEFAULT 'ACTIVE' to documents, then drop the default. Rename enum policy_status to document_version_status.

Written for commit 1db8e71. Summary will update on new commits.

@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch from 0c53758 to 0aa9b9f Compare March 16, 2026 16:49
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 15 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/console/src/pages/organizations/documents/_components/DocumentTitleForm.tsx">

<violation number="1" location="apps/console/src/pages/organizations/documents/_components/DocumentTitleForm.tsx:112">
P2: This only hides the edit entry point; it does not stop the form from staying editable after the document becomes archived. Guard the editing state as well so archived documents cannot keep showing the title input and save action.</violation>
</file>

<file name="pkg/coredata/document_filter.go">

<violation number="1" location="pkg/coredata/document_filter.go:46">
P1: Archived documents are still directly accessible from trust-center detail and export endpoints because this only filters list queries.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Base automatically changed from fix-deleted-commit to main March 16, 2026 16:56
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch 5 times, most recently from 238fd84 to 70dea02 Compare March 16, 2026 17:14
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch 11 times, most recently from d82171e to bc36c34 Compare March 17, 2026 13:51
@SachaProbo SachaProbo requested review from codenem and gearnode March 17, 2026 14:14
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch 2 times, most recently from c1a151c to 1f1db66 Compare March 17, 2026 14:58
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch from 1f1db66 to 9aa2e98 Compare March 17, 2026 15:16
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch 6 times, most recently from 978ae2a to 8377b8c Compare March 18, 2026 15:42
Copy link
Contributor

@gearnode gearnode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch 14 times, most recently from dafd881 to 0aa16d8 Compare March 19, 2026 11:52
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="pkg/probo/document_service.go">

<violation number="1" location="pkg/probo/document_service.go:1195">
P1: Archiving now permanently deletes control/risk mappings, and unarchive cannot restore them.</violation>

<violation number="2" location="pkg/probo/document_service.go:1721">
P2: Clearing trust-center visibility on archive is irreversible here because unarchive never restores the previous setting.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

document.Status = coredata.DocumentStatusArchived
document.ArchivedAt = &now
document.UpdatedAt = now
document.TrustCenterVisibility = coredata.TrustCenterVisibilityNone
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Clearing trust-center visibility on archive is irreversible here because unarchive never restores the previous setting.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At pkg/probo/document_service.go, line 1721:

<comment>Clearing trust-center visibility on archive is irreversible here because unarchive never restores the previous setting.</comment>

<file context>
@@ -1695,9 +1705,20 @@ func (s *DocumentService) Archive(
 			document.Status = coredata.DocumentStatusArchived
 			document.ArchivedAt = &now
 			document.UpdatedAt = now
+			document.TrustCenterVisibility = coredata.TrustCenterVisibilityNone
 
 			if err := document.Update(ctx, tx, s.svc.scope); err != nil {
</file context>
Fix with Cubic

@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch from d0e8c78 to d9d4326 Compare March 19, 2026 12:31
Copy link
Contributor

@gearnode gearnode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch from d9d4326 to 26536aa Compare March 19, 2026 13:15
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>
@SachaProbo SachaProbo force-pushed the SachaProbo/doc-archived-at branch from 26536aa to 1db8e71 Compare March 19, 2026 13:16
import type { DocumentListBulkUnarchiveMutation } from "#/__generated__/core/DocumentListBulkUnarchiveMutation.graphql";
import type { DocumentListFragment$key } from "#/__generated__/core/DocumentListFragment.graphql";
import type { DocumentsListQuery, DocumentType } from "#/__generated__/core/DocumentsListQuery.graphql";
import type { DocumentType, DocumentsListQuery } from "#/__generated__/core/DocumentsListQuery.graphql";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint (apps/console)] reported by reviewdog 🐶
DocumentsListQuery import should occur before import of DocumentType import-x/order

{ status: [tab], documentTypes: documentTypeFilter ? [documentTypeFilter] : null },
{ fetchPolicy: "store-and-network" },
);
}, [tab, refetch]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint (apps/console)] reported by reviewdog 🐶
React Hook useEffect has a missing dependency: 'documentTypeFilter'. Either include it or remove the dependency array react-hooks/exhaustive-deps

const canRequestAnySignatures = documents.some(({ canRequestSignatures }) => canRequestSignatures);
const canArchiveAny = documents.some(({ canArchive }) => canArchive);
const canUnarchiveAny = documents.some(({ canUnarchive }) => canUnarchive);
const canSendAnySignatureNotifications = documents.some(({ canSendSigningNotifications }) => canSendSigningNotifications);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint (apps/console)] reported by reviewdog 🐶
This line has a length of 124. Maximum allowed is 120 @stylistic/max-len

const refetchWithFilters: ComponentProps<typeof SortableTable>["refetch"] = ({ order }) => {
pagination.refetch({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
order: order as any,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint (apps/console)] reported by reviewdog 🐶
Unsafe assignment of an any value @typescript-eslint/no-unsafe-assignment

@SachaProbo SachaProbo merged commit 1db8e71 into main Mar 19, 2026
10 of 11 checks passed
@SachaProbo SachaProbo deleted the SachaProbo/doc-archived-at branch March 19, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants