Move document classification from document to document version

Classification now lives exclusively on DocumentVersion. The field is
removed from the Document model, all SQL queries, GraphQL Document
type, SignableDocument type, UpdateDocumentInput, and MCP Document
schema.

New documents still accept classification in CreateDocumentInput,
applied to the first version. New drafts inherit classification from
the previous version. PDF generation uses the version classification.

The drawer allows editing classification on draft versions via the
updateDocumentVersion mutation. Classification is read-only on
published versions.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-03-27 16:04:38 +01:00
parent 851e585b9b
commit 5d6d0bdd7f
16 changed files with 155 additions and 151 deletions

View File

@@ -16,19 +16,18 @@ import { documentClassifications, documentTypes, formatDate, getDocumentClassifi
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Badge, Button, Drawer, IconCheckmark1, IconCrossLargeX, IconPencil, PropertyRow } from "@probo/ui"; import { Badge, Button, Drawer, IconCheckmark1, IconCrossLargeX, IconPencil, PropertyRow } from "@probo/ui";
import { useState } from "react"; import { useState } from "react";
import { useFragment } from "react-relay"; import { useFragment, useMutation } from "react-relay";
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import { z } from "zod"; import { z } from "zod";
import type { DocumentLayoutDrawer_documentFragment$key } from "#/__generated__/core/DocumentLayoutDrawer_documentFragment.graphql"; import type { DocumentLayoutDrawer_documentFragment$key } from "#/__generated__/core/DocumentLayoutDrawer_documentFragment.graphql";
import type { DocumentLayoutDrawer_updateClassificationMutation } from "#/__generated__/core/DocumentLayoutDrawer_updateClassificationMutation.graphql";
import type { DocumentLayoutDrawer_versionFragment$key } from "#/__generated__/core/DocumentLayoutDrawer_versionFragment.graphql"; import type { DocumentLayoutDrawer_versionFragment$key } from "#/__generated__/core/DocumentLayoutDrawer_versionFragment.graphql";
import type { DocumentLayoutDrawerMutation } from "#/__generated__/core/DocumentLayoutDrawerMutation.graphql"; import type { DocumentLayoutDrawerMutation } from "#/__generated__/core/DocumentLayoutDrawerMutation.graphql";
import { ControlledField } from "#/components/form/ControlledField"; import { ControlledField } from "#/components/form/ControlledField";
import { DocumentClassificationOptions } from "#/components/form/DocumentClassificationOptions"; import { DocumentClassificationOptions } from "#/components/form/DocumentClassificationOptions";
import { DocumentTypeOptions } from "#/components/form/DocumentTypeOptions"; import { DocumentTypeOptions } from "#/components/form/DocumentTypeOptions";
import { useFormWithSchema } from "#/hooks/useFormWithSchema"; import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
const documentFragment = graphql` const documentFragment = graphql`
fragment DocumentLayoutDrawer_documentFragment on Document { fragment DocumentLayoutDrawer_documentFragment on Document {
id id
@@ -57,6 +56,16 @@ const updateDocumentMutation = graphql`
document { document {
id id
documentType documentType
}
}
}
`;
const updateClassificationMutation = graphql`
mutation DocumentLayoutDrawer_updateClassificationMutation($input: UpdateDocumentVersionInput!) {
updateDocumentVersion(input: $input) {
documentVersion {
id
classification classification
} }
} }
@@ -65,6 +74,9 @@ const updateDocumentMutation = graphql`
const schema = z.object({ const schema = z.object({
documentType: z.enum(documentTypes), documentType: z.enum(documentTypes),
});
const classificationSchema = z.object({
classification: z.enum(documentClassifications), classification: z.enum(documentClassifications),
}); });
@@ -90,47 +102,56 @@ export function DocumentLayoutDrawer(props: {
{ {
defaultValues: { defaultValues: {
documentType: document.documentType, documentType: document.documentType,
},
},
);
const {
control: classificationControl,
handleSubmit: handleClassificationSubmit,
reset: resetClassification,
} = useFormWithSchema(
classificationSchema,
{
defaultValues: {
classification: version.classification, classification: version.classification,
}, },
}, },
); );
const [updateDocument, isUpdatingDocument] const [updateDocument, isUpdatingDocument]
= useMutationWithToasts<DocumentLayoutDrawerMutation>( = useMutation<DocumentLayoutDrawerMutation>(updateDocumentMutation);
updateDocumentMutation,
{
successMessage: __("Document updated successfully."),
errorMessage: __("Failed to update document"),
},
);
const handleUpdateDocumentType = async (data: { const [updateClassification, isUpdatingClassification]
= useMutation<DocumentLayoutDrawer_updateClassificationMutation>(updateClassificationMutation);
const handleUpdateDocumentType = (data: {
documentType: (typeof documentTypes)[number]; documentType: (typeof documentTypes)[number];
}) => { }) => {
await updateDocument({ updateDocument({
variables: { variables: {
input: { input: {
id: document.id, id: document.id,
documentType: data.documentType, documentType: data.documentType,
}, },
}, },
onSuccess: () => { onCompleted: () => {
setIsEditingType(false); setIsEditingType(false);
}, },
}); });
}; };
const handleUpdateClassification = async (data: { const handleUpdateClassification = (data: {
classification: (typeof documentClassifications)[number]; classification: (typeof documentClassifications)[number];
}) => { }) => {
await updateDocument({ updateClassification({
variables: { variables: {
input: { input: {
id: document.id, documentVersionId: version.id,
classification: data.classification, classification: data.classification,
}, },
}, },
onSuccess: () => { onCompleted: () => {
setIsEditingClassification(false); setIsEditingClassification(false);
}, },
}); });
@@ -176,16 +197,16 @@ export function DocumentLayoutDrawer(props: {
{isEditingClassification {isEditingClassification
? ( ? (
<EditablePropertyContent <EditablePropertyContent
onSave={() => void handleSubmit(handleUpdateClassification)()} onSave={() => void handleClassificationSubmit(handleUpdateClassification)()}
onCancel={() => { onCancel={() => {
setIsEditingClassification(false); setIsEditingClassification(false);
reset(); resetClassification();
}} }}
disabled={isUpdatingDocument} disabled={isUpdatingClassification}
> >
<ControlledField <ControlledField
name="classification" name="classification"
control={control} control={classificationControl}
type="select" type="select"
> >
<DocumentClassificationOptions /> <DocumentClassificationOptions />
@@ -195,13 +216,10 @@ export function DocumentLayoutDrawer(props: {
: ( : (
<ReadOnlyPropertyContent <ReadOnlyPropertyContent
onEdit={() => setIsEditingClassification(true)} onEdit={() => setIsEditingClassification(true)}
canEdit={canEdit} canEdit={canEdit && isDraft}
> >
<div className="text-sm text-txt-secondary"> <div className="text-sm text-txt-secondary">
{getDocumentClassificationLabel( {getDocumentClassificationLabel(__, version.classification)}
__,
version.classification,
)}
</div> </div>
</ReadOnlyPropertyContent> </ReadOnlyPropertyContent>
)} )}

View File

@@ -15,12 +15,11 @@
import { formatDate, getDocumentClassificationLabel, getDocumentTypeLabel, sprintf } from "@probo/helpers"; import { formatDate, getDocumentClassificationLabel, getDocumentTypeLabel, sprintf } from "@probo/helpers";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { ActionDropdown, Badge, Checkbox, DropdownItem, IconTrashCan, Td, Tr, useConfirm } from "@probo/ui"; import { ActionDropdown, Badge, Checkbox, DropdownItem, IconTrashCan, Td, Tr, useConfirm } from "@probo/ui";
import { useFragment } from "react-relay"; import { useFragment, useMutation } from "react-relay";
import { type DataID, graphql } from "relay-runtime"; import { type DataID, graphql } from "relay-runtime";
import type { DocumentListItem_deleteMutation } from "#/__generated__/core/DocumentListItem_deleteMutation.graphql"; import type { DocumentListItem_deleteMutation } from "#/__generated__/core/DocumentListItem_deleteMutation.graphql";
import type { DocumentListItemFragment$key } from "#/__generated__/core/DocumentListItemFragment.graphql"; import type { DocumentListItemFragment$key } from "#/__generated__/core/DocumentListItemFragment.graphql";
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
import { useOrganizationId } from "#/hooks/useOrganizationId"; import { useOrganizationId } from "#/hooks/useOrganizationId";
const fragment = graphql` const fragment = graphql`
@@ -28,7 +27,6 @@ const fragment = graphql`
id id
title title
documentType documentType
classification
updatedAt updatedAt
canDelete: permission(action: "core:document:delete") canDelete: permission(action: "core:document:delete")
recentVersions: versions(first: 2 orderBy: { field: CREATED_AT direction: DESC }) { recentVersions: versions(first: 2 orderBy: { field: CREATED_AT direction: DESC }) {
@@ -38,6 +36,7 @@ const fragment = graphql`
status status
major major
minor minor
classification
approvalQuorums(first: 1, orderBy: { field: CREATED_AT, direction: DESC }) { approvalQuorums(first: 1, orderBy: { field: CREATED_AT, direction: DESC }) {
edges { edges {
node { node {
@@ -117,23 +116,21 @@ export function DocumentListItem(props: {
PUBLISHED: __("Published"), PUBLISHED: __("Published"),
} as const; } as const;
const [deleteDocument] = useMutationWithToasts<DocumentListItem_deleteMutation>( const [deleteDocument] = useMutation<DocumentListItem_deleteMutation>(deleteDocumentMutation);
deleteDocumentMutation,
{
successMessage: __("Document deleted successfully."),
errorMessage: __("Failed to delete document"),
},
);
const confirm = useConfirm(); const confirm = useConfirm();
const handleDelete = () => { const handleDelete = () => {
confirm( confirm(
() => () =>
new Promise<void>((resolve, reject) => {
deleteDocument({ deleteDocument({
variables: { variables: {
connections: [connectionId], connections: [connectionId],
input: { documentId: document.id }, input: { documentId: document.id },
}, },
onCompleted: () => resolve(),
onError: err => reject(err),
});
}), }),
{ {
message: sprintf( message: sprintf(
@@ -171,7 +168,7 @@ export function DocumentListItem(props: {
{getDocumentTypeLabel(__, document.documentType)} {getDocumentTypeLabel(__, document.documentType)}
</Td> </Td>
<Td className="w-32"> <Td className="w-32">
{getDocumentClassificationLabel(__, document.classification)} {getDocumentClassificationLabel(__, lastVersion.classification)}
</Td> </Td>
<Td className="w-60"> <Td className="w-60">
{(() => { {(() => {

View File

@@ -28,9 +28,15 @@ const fragment = graphql`
id id
title title
documentType documentType
classification
approvalState approvalState
updatedAt updatedAt
lastVersion: versions(first: 1 orderBy: { field: CREATED_AT direction: DESC }) {
edges {
node {
classification
}
}
}
} }
`; `;
@@ -42,6 +48,7 @@ export function ApprovableDocumentRow({
organizationId: string; organizationId: string;
}) { }) {
const document = useFragment<ApprovableDocumentRowFragment$key>(fragment, fKey); const document = useFragment<ApprovableDocumentRowFragment$key>(fragment, fKey);
const lastVersion = document.lastVersion.edges[0].node;
const { __ } = useTranslate(); const { __ } = useTranslate();
const stateVariant = document.approvalState === "APPROVED" const stateVariant = document.approvalState === "APPROVED"
@@ -64,7 +71,7 @@ export function ApprovableDocumentRow({
</Td> </Td>
<Td className="w-36"> <Td className="w-36">
<Badge variant="neutral"> <Badge variant="neutral">
{getDocumentClassificationLabel(__, document.classification)} {getDocumentClassificationLabel(__, lastVersion.classification)}
</Badge> </Badge>
</Td> </Td>
<Td className="w-40">{formatDate(document.updatedAt)}</Td> <Td className="w-40">{formatDate(document.updatedAt)}</Td>

View File

@@ -28,9 +28,15 @@ const fragment = graphql`
id id
title title
documentType documentType
classification
signed signed
updatedAt updatedAt
lastVersion: versions(first: 1 orderBy: { field: CREATED_AT direction: DESC }) {
edges {
node {
classification
}
}
}
} }
`; `;
@@ -42,6 +48,7 @@ export function DocumentRow({
organizationId: string; organizationId: string;
}) { }) {
const document = useFragment<DocumentRowFragment$key>(fragment, fKey); const document = useFragment<DocumentRowFragment$key>(fragment, fKey);
const lastVersion = document.lastVersion.edges[0].node;
const { __ } = useTranslate(); const { __ } = useTranslate();
return ( return (
@@ -52,7 +59,7 @@ export function DocumentRow({
</Td> </Td>
<Td className="w-36"> <Td className="w-36">
<Badge variant="neutral"> <Badge variant="neutral">
{getDocumentClassificationLabel(__, document.classification)} {getDocumentClassificationLabel(__, lastVersion.classification)}
</Badge> </Badge>
</Td> </Td>
<Td className="w-40">{formatDate(document.updatedAt)}</Td> <Td className="w-40">{formatDate(document.updatedAt)}</Td>

View File

@@ -104,7 +104,6 @@ func TestDocument_Create(t *testing.T) {
id id
title title
documentType documentType
classification
} }
} }
} }
@@ -123,7 +122,6 @@ func TestDocument_Create(t *testing.T) {
ID string `json:"id"` ID string `json:"id"`
Title string `json:"title"` Title string `json:"title"`
DocumentType string `json:"documentType"` DocumentType string `json:"documentType"`
Classification string `json:"classification"`
} `json:"node"` } `json:"node"`
} `json:"documentEdge"` } `json:"documentEdge"`
} `json:"createDocument"` } `json:"createDocument"`

View File

@@ -34,7 +34,6 @@ type (
OrganizationID gid.GID `db:"organization_id"` OrganizationID gid.GID `db:"organization_id"`
Title string `db:"title"` Title string `db:"title"`
DocumentType DocumentType `db:"document_type"` DocumentType DocumentType `db:"document_type"`
Classification DocumentClassification `db:"classification"`
CurrentPublishedMajor *int `db:"current_published_major"` CurrentPublishedMajor *int `db:"current_published_major"`
CurrentPublishedMinor *int `db:"current_published_minor"` CurrentPublishedMinor *int `db:"current_published_minor"`
TrustCenterVisibility TrustCenterVisibility `db:"trust_center_visibility"` TrustCenterVisibility TrustCenterVisibility `db:"trust_center_visibility"`
@@ -128,7 +127,6 @@ SELECT
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -182,7 +180,6 @@ SELECT
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -237,7 +234,6 @@ SELECT
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -321,7 +317,6 @@ SELECT
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -374,7 +369,6 @@ SELECT
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -441,7 +435,6 @@ SELECT
organization_id, organization_id,
COALESCE(published_title, title) AS title, COALESCE(published_title, title) AS title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -491,7 +484,6 @@ INSERT INTO
organization_id, organization_id,
title, title,
document_type, document_type,
classification,
current_published_major, current_published_major,
current_published_minor, current_published_minor,
trust_center_visibility, trust_center_visibility,
@@ -506,7 +498,6 @@ VALUES (
@organization_id, @organization_id,
@title, @title,
@document_type, @document_type,
@classification,
@current_published_major, @current_published_major,
@current_published_minor, @current_published_minor,
@trust_center_visibility, @trust_center_visibility,
@@ -523,7 +514,6 @@ VALUES (
"organization_id": p.OrganizationID, "organization_id": p.OrganizationID,
"title": p.Title, "title": p.Title,
"document_type": p.DocumentType, "document_type": p.DocumentType,
"classification": p.Classification,
"current_published_major": p.CurrentPublishedMajor, "current_published_major": p.CurrentPublishedMajor,
"current_published_minor": p.CurrentPublishedMinor, "current_published_minor": p.CurrentPublishedMinor,
"trust_center_visibility": p.TrustCenterVisibility, "trust_center_visibility": p.TrustCenterVisibility,
@@ -586,7 +576,6 @@ SET
current_published_major = @current_published_major, current_published_major = @current_published_major,
current_published_minor = @current_published_minor, current_published_minor = @current_published_minor,
document_type = @document_type, document_type = @document_type,
classification = @classification,
trust_center_visibility = @trust_center_visibility, trust_center_visibility = @trust_center_visibility,
status = @status, status = @status,
archived_at = @archived_at, archived_at = @archived_at,
@@ -605,7 +594,6 @@ WHERE
"current_published_major": p.CurrentPublishedMajor, "current_published_major": p.CurrentPublishedMajor,
"current_published_minor": p.CurrentPublishedMinor, "current_published_minor": p.CurrentPublishedMinor,
"document_type": p.DocumentType, "document_type": p.DocumentType,
"classification": p.Classification,
"trust_center_visibility": p.TrustCenterVisibility, "trust_center_visibility": p.TrustCenterVisibility,
"status": p.Status, "status": p.Status,
"archived_at": p.ArchivedAt, "archived_at": p.ArchivedAt,
@@ -678,7 +666,6 @@ SELECT
scoped_documents.organization_id, scoped_documents.organization_id,
scoped_documents.title, scoped_documents.title,
scoped_documents.document_type, scoped_documents.document_type,
scoped_documents.classification,
scoped_documents.current_published_major, scoped_documents.current_published_major,
scoped_documents.current_published_minor, scoped_documents.current_published_minor,
scoped_documents.trust_center_visibility, scoped_documents.trust_center_visibility,
@@ -770,7 +757,6 @@ SELECT
scoped_documents.organization_id, scoped_documents.organization_id,
scoped_documents.title, scoped_documents.title,
scoped_documents.document_type, scoped_documents.document_type,
scoped_documents.classification,
scoped_documents.current_published_major, scoped_documents.current_published_major,
scoped_documents.current_published_minor, scoped_documents.current_published_minor,
scoped_documents.trust_center_visibility, scoped_documents.trust_center_visibility,

View File

@@ -0,0 +1,2 @@
-- TODO: drop the classification column from documents.
ALTER TABLE documents ALTER COLUMN classification SET DEFAULT 'SECRET';

View File

@@ -85,14 +85,14 @@ type (
UpdateDocumentRequest struct { UpdateDocumentRequest struct {
DocumentID gid.GID DocumentID gid.GID
Title *string Title *string
Classification *coredata.DocumentClassification
DocumentType *coredata.DocumentType DocumentType *coredata.DocumentType
TrustCenterVisibility *coredata.TrustCenterVisibility TrustCenterVisibility *coredata.TrustCenterVisibility
} }
UpdateDocumentVersionRequest struct { UpdateDocumentVersionRequest struct {
ID gid.GID ID gid.GID
Content string Content *string
Classification *coredata.DocumentClassification
} }
RequestSignatureRequest struct { RequestSignatureRequest struct {
@@ -133,7 +133,6 @@ func (udr *UpdateDocumentRequest) Validate() error {
v.Check(udr.DocumentID, "document_id", validator.Required(), validator.GID(coredata.DocumentEntityType)) v.Check(udr.DocumentID, "document_id", validator.Required(), validator.GID(coredata.DocumentEntityType))
v.Check(udr.Title, "title", validator.SafeTextNoNewLine(TitleMaxLength)) v.Check(udr.Title, "title", validator.SafeTextNoNewLine(TitleMaxLength))
v.Check(udr.Classification, "classification", validator.OneOfSlice(coredata.DocumentClassifications()))
v.Check(udr.DocumentType, "document_type", validator.OneOfSlice(coredata.DocumentTypes())) v.Check(udr.DocumentType, "document_type", validator.OneOfSlice(coredata.DocumentTypes()))
v.Check(udr.TrustCenterVisibility, "trust_center_visibility", validator.OneOfSlice(coredata.TrustCenterVisibilities())) v.Check(udr.TrustCenterVisibility, "trust_center_visibility", validator.OneOfSlice(coredata.TrustCenterVisibilities()))
@@ -144,7 +143,8 @@ func (udvr *UpdateDocumentVersionRequest) Validate() error {
v := validator.New() v := validator.New()
v.Check(udvr.ID, "id", validator.Required(), validator.GID(coredata.DocumentVersionEntityType)) v.Check(udvr.ID, "id", validator.Required(), validator.GID(coredata.DocumentVersionEntityType))
v.Check(udvr.Content, "content", validator.Required(), validator.NotEmpty(), validator.MaxLen(documentMaxLength)) v.Check(udvr.Content, "content", validator.NotEmpty(), validator.MaxLen(documentMaxLength))
v.Check(udvr.Classification, "classification", validator.OneOfSlice(coredata.DocumentClassifications()))
return v.Error() return v.Error()
} }
@@ -509,7 +509,6 @@ func (s *DocumentService) Create(
Title: req.Title, Title: req.Title,
DocumentType: req.DocumentType, DocumentType: req.DocumentType,
TrustCenterVisibility: coredata.TrustCenterVisibilityNone, TrustCenterVisibility: coredata.TrustCenterVisibilityNone,
Classification: req.Classification,
Status: coredata.DocumentStatusActive, Status: coredata.DocumentStatusActive,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
@@ -763,8 +762,12 @@ func (s *DocumentService) UpdateVersion(
} }
documentVersion.Title = document.Title documentVersion.Title = document.Title
documentVersion.Classification = document.Classification if req.Content != nil {
documentVersion.Content = req.Content documentVersion.Content = *req.Content
}
if req.Classification != nil {
documentVersion.Classification = *req.Classification
}
documentVersion.UpdatedAt = time.Now() documentVersion.UpdatedAt = time.Now()
if err := documentVersion.Update(ctx, conn, s.svc.scope); err != nil { if err := documentVersion.Update(ctx, conn, s.svc.scope); err != nil {
@@ -1002,7 +1005,7 @@ func (s *DocumentService) CreateDraft(
draftVersion.Title = document.Title draftVersion.Title = document.Title
draftVersion.Major = latestVersion.Major draftVersion.Major = latestVersion.Major
draftVersion.Minor = latestVersion.Minor + 1 draftVersion.Minor = latestVersion.Minor + 1
draftVersion.Classification = document.Classification draftVersion.Classification = latestVersion.Classification
draftVersion.Content = latestVersion.Content draftVersion.Content = latestVersion.Content
draftVersion.Status = coredata.DocumentVersionStatusDraft draftVersion.Status = coredata.DocumentVersionStatusDraft
draftVersion.CreatedAt = now draftVersion.CreatedAt = now
@@ -1533,10 +1536,6 @@ func (s *DocumentService) Update(
document.Title = *req.Title document.Title = *req.Title
} }
if req.Classification != nil {
document.Classification = *req.Classification
}
if req.DocumentType != nil { if req.DocumentType != nil {
document.DocumentType = *req.DocumentType document.DocumentType = *req.DocumentType
} }
@@ -1559,7 +1558,6 @@ func (s *DocumentService) Update(
err := draftVersion.LoadLatestVersion(ctx, tx, s.svc.scope, req.DocumentID) err := draftVersion.LoadLatestVersion(ctx, tx, s.svc.scope, req.DocumentID)
if err == nil && draftVersion.Status == coredata.DocumentVersionStatusDraft { if err == nil && draftVersion.Status == coredata.DocumentVersionStatusDraft {
draftVersion.Title = document.Title draftVersion.Title = document.Title
draftVersion.Classification = document.Classification
draftVersion.UpdatedAt = now draftVersion.UpdatedAt = now
if err := draftVersion.Update(ctx, tx, s.svc.scope); err != nil { if err := draftVersion.Update(ctx, tx, s.svc.scope); err != nil {
@@ -1934,7 +1932,7 @@ func exportDocumentPDF(
} }
classification := docgen.ClassificationSecret classification := docgen.ClassificationSecret
switch document.Classification { switch version.Classification {
case coredata.DocumentClassificationPublic: case coredata.DocumentClassificationPublic:
classification = docgen.ClassificationPublic classification = docgen.ClassificationPublic
case coredata.DocumentClassificationInternal: case coredata.DocumentClassificationInternal:

View File

@@ -2440,7 +2440,6 @@ type Document implements Node {
title: String! title: String!
description: String description: String
documentType: DocumentType! documentType: DocumentType!
classification: DocumentClassification!
currentPublishedMajor: Int currentPublishedMajor: Int
currentPublishedMinor: Int currentPublishedMinor: Int
trustCenterVisibility: TrustCenterVisibility! trustCenterVisibility: TrustCenterVisibility!
@@ -2481,7 +2480,6 @@ type EmployeeDocument
title: String! title: String!
description: String description: String
documentType: DocumentType! documentType: DocumentType!
classification: DocumentClassification!
signed: Boolean @goField(forceResolver: true) signed: Boolean @goField(forceResolver: true)
approvalState: DocumentVersionApprovalDecisionState @goField(forceResolver: true) approvalState: DocumentVersionApprovalDecisionState @goField(forceResolver: true)
@@ -2505,6 +2503,7 @@ type EmployeeDocumentVersion
major: Int! major: Int!
minor: Int! minor: Int!
status: DocumentVersionStatus! status: DocumentVersionStatus!
classification: DocumentClassification!
signed: Boolean! @goField(forceResolver: true) signed: Boolean! @goField(forceResolver: true)
approvalDecision: DocumentVersionApprovalDecision @goField(forceResolver: true) approvalDecision: DocumentVersionApprovalDecision @goField(forceResolver: true)
publishedAt: Datetime publishedAt: Datetime
@@ -4482,7 +4481,6 @@ input UpdateDocumentInput {
title: String title: String
content: String content: String
documentType: DocumentType documentType: DocumentType
classification: DocumentClassification
trustCenterVisibility: TrustCenterVisibility trustCenterVisibility: TrustCenterVisibility
} }
@@ -5738,7 +5736,8 @@ input DeleteDraftDocumentVersionInput {
input UpdateDocumentVersionInput { input UpdateDocumentVersionInput {
documentVersionId: ID! documentVersionId: ID!
content: String! content: String
classification: DocumentClassification
} }
input CancelSignatureRequestInput { input CancelSignatureRequestInput {

View File

@@ -81,7 +81,6 @@ func NewDocument(document *coredata.Document) *Document {
ID: document.OrganizationID, ID: document.OrganizationID,
}, },
DocumentType: document.DocumentType, DocumentType: document.DocumentType,
Classification: document.Classification,
CurrentPublishedMajor: document.CurrentPublishedMajor, CurrentPublishedMajor: document.CurrentPublishedMajor,
CurrentPublishedMinor: document.CurrentPublishedMinor, CurrentPublishedMinor: document.CurrentPublishedMinor,
TrustCenterVisibility: document.TrustCenterVisibility, TrustCenterVisibility: document.TrustCenterVisibility,

View File

@@ -46,7 +46,6 @@ type (
Title string Title string
Description *string Description *string
DocumentType coredata.DocumentType DocumentType coredata.DocumentType
Classification coredata.DocumentClassification
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
@@ -69,6 +68,7 @@ type (
Major int Major int
Minor int Minor int
Status coredata.DocumentVersionStatus Status coredata.DocumentVersionStatus
Classification coredata.DocumentClassification
PublishedAt *time.Time PublishedAt *time.Time
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time

View File

@@ -1664,6 +1664,7 @@ func (r *employeeDocumentResolver) Versions(ctx context.Context, obj *types.Empl
Major: v.Major, Major: v.Major,
Minor: v.Minor, Minor: v.Minor,
Status: v.Status, Status: v.Status,
Classification: v.Classification,
PublishedAt: v.PublishedAt, PublishedAt: v.PublishedAt,
CreatedAt: v.CreatedAt, CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt, UpdatedAt: v.UpdatedAt,
@@ -4669,7 +4670,6 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat
probo.UpdateDocumentRequest{ probo.UpdateDocumentRequest{
DocumentID: input.ID, DocumentID: input.ID,
Title: input.Title, Title: input.Title,
Classification: input.Classification,
DocumentType: input.DocumentType, DocumentType: input.DocumentType,
TrustCenterVisibility: input.TrustCenterVisibility, TrustCenterVisibility: input.TrustCenterVisibility,
}, },
@@ -5412,6 +5412,7 @@ func (r *mutationResolver) UpdateDocumentVersion(ctx context.Context, input type
probo.UpdateDocumentVersionRequest{ probo.UpdateDocumentVersionRequest{
ID: input.DocumentVersionID, ID: input.DocumentVersionID,
Content: input.Content, Content: input.Content,
Classification: input.Classification,
}, },
) )
if err != nil { if err != nil {
@@ -10246,7 +10247,6 @@ func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewe
ID: doc.ID, ID: doc.ID,
Title: doc.Title, Title: doc.Title,
DocumentType: doc.DocumentType, DocumentType: doc.DocumentType,
Classification: doc.Classification,
CreatedAt: doc.CreatedAt, CreatedAt: doc.CreatedAt,
UpdatedAt: doc.UpdatedAt, UpdatedAt: doc.UpdatedAt,
FilterMode: types.EmployeeDocumentFilterModeSignature, FilterMode: types.EmployeeDocumentFilterModeSignature,
@@ -10283,7 +10283,6 @@ func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer
ID: document.ID, ID: document.ID,
Title: document.Title, Title: document.Title,
DocumentType: document.DocumentType, DocumentType: document.DocumentType,
Classification: document.Classification,
CreatedAt: document.CreatedAt, CreatedAt: document.CreatedAt,
UpdatedAt: document.UpdatedAt, UpdatedAt: document.UpdatedAt,
FilterMode: types.EmployeeDocumentFilterModeSignature, FilterMode: types.EmployeeDocumentFilterModeSignature,
@@ -10327,7 +10326,6 @@ func (r *viewerResolver) ApprovableDocuments(ctx context.Context, obj *types.Vie
ID: doc.ID, ID: doc.ID,
Title: doc.Title, Title: doc.Title,
DocumentType: doc.DocumentType, DocumentType: doc.DocumentType,
Classification: doc.Classification,
CreatedAt: doc.CreatedAt, CreatedAt: doc.CreatedAt,
UpdatedAt: doc.UpdatedAt, UpdatedAt: doc.UpdatedAt,
FilterMode: types.EmployeeDocumentFilterModeApproval, FilterMode: types.EmployeeDocumentFilterModeApproval,
@@ -10364,7 +10362,6 @@ func (r *viewerResolver) ApprovableDocument(ctx context.Context, obj *types.View
ID: document.ID, ID: document.ID,
Title: document.Title, Title: document.Title,
DocumentType: document.DocumentType, DocumentType: document.DocumentType,
Classification: document.Classification,
CreatedAt: document.CreatedAt, CreatedAt: document.CreatedAt,
UpdatedAt: document.UpdatedAt, UpdatedAt: document.UpdatedAt,
FilterMode: types.EmployeeDocumentFilterModeApproval, FilterMode: types.EmployeeDocumentFilterModeApproval,

View File

@@ -2106,7 +2106,6 @@ func (r *Resolver) UpdateDocumentTool(ctx context.Context, req *mcp.CallToolRequ
probo.UpdateDocumentRequest{ probo.UpdateDocumentRequest{
DocumentID: input.ID, DocumentID: input.ID,
Title: input.Title, Title: input.Title,
Classification: input.Classification,
DocumentType: input.DocumentType, DocumentType: input.DocumentType,
TrustCenterVisibility: input.TrustCenterVisibility, TrustCenterVisibility: input.TrustCenterVisibility,
}, },
@@ -2185,6 +2184,7 @@ func (r *Resolver) UpdateDocumentVersionTool(ctx context.Context, req *mcp.CallT
probo.UpdateDocumentVersionRequest{ probo.UpdateDocumentVersionRequest{
ID: input.DocumentVersionID, ID: input.DocumentVersionID,
Content: input.Content, Content: input.Content,
Classification: input.Classification,
}, },
) )
if err != nil { if err != nil {

View File

@@ -5186,7 +5186,6 @@ components:
- organization_id - organization_id
- title - title
- document_type - document_type
- classification
- trust_center_visibility - trust_center_visibility
- status - status
- created_at - created_at
@@ -5204,9 +5203,6 @@ components:
document_type: document_type:
$ref: "#/components/schemas/DocumentType" $ref: "#/components/schemas/DocumentType"
description: Document type description: Document type
classification:
$ref: "#/components/schemas/DocumentClassification"
description: Document classification
current_published_major: current_published_major:
type: type:
- integer - integer
@@ -5459,9 +5455,6 @@ components:
title: title:
type: string type: string
description: Document title description: Document title
classification:
$ref: "#/components/schemas/DocumentClassification"
description: Document classification
document_type: document_type:
$ref: "#/components/schemas/DocumentType" $ref: "#/components/schemas/DocumentType"
description: Document type description: Document type
@@ -5580,7 +5573,6 @@ components:
type: object type: object
required: required:
- document_version_id - document_version_id
- content
properties: properties:
document_version_id: document_version_id:
$ref: "#/components/schemas/GID" $ref: "#/components/schemas/GID"
@@ -5588,6 +5580,9 @@ components:
content: content:
type: string type: string
description: Document content description: Document content
classification:
$ref: "#/components/schemas/DocumentClassification"
description: Document classification
UpdateDocumentVersionOutput: UpdateDocumentVersionOutput:
type: object type: object

View File

@@ -25,7 +25,6 @@ func NewDocument(d *coredata.Document) *Document {
OrganizationID: d.OrganizationID, OrganizationID: d.OrganizationID,
Title: d.Title, Title: d.Title,
DocumentType: d.DocumentType, DocumentType: d.DocumentType,
Classification: d.Classification,
CurrentPublishedMajor: d.CurrentPublishedMajor, CurrentPublishedMajor: d.CurrentPublishedMajor,
CurrentPublishedMinor: d.CurrentPublishedMinor, CurrentPublishedMinor: d.CurrentPublishedMinor,
TrustCenterVisibility: d.TrustCenterVisibility, TrustCenterVisibility: d.TrustCenterVisibility,

View File

@@ -219,12 +219,14 @@ func (s *DocumentService) exportPDFData(
return nil, err return nil, err
} }
classification := docgen.ClassificationInternal classification := docgen.ClassificationSecret
switch document.DocumentType { switch version.Classification {
case coredata.DocumentTypePolicy: case coredata.DocumentClassificationPublic:
classification = docgen.ClassificationPublic
case coredata.DocumentClassificationInternal:
classification = docgen.ClassificationInternal
case coredata.DocumentClassificationConfidential:
classification = docgen.ClassificationConfidential classification = docgen.ClassificationConfidential
case coredata.DocumentTypeGovernance:
classification = docgen.ClassificationSecret
} }
horizontalLogoBase64 := "" horizontalLogoBase64 := ""