feat: migrate templates and documents to envelope model

This commit is contained in:
David Nguyen
2025-09-11 18:23:38 +10:00
parent eec2307634
commit bf89bc781b
234 changed files with 8677 additions and 6054 deletions

View File

@ -642,7 +642,7 @@ export const ZDocumentAuditLogEventDocumentMovedToTeamSchema = z.object({
export const ZDocumentAuditLogBaseSchema = z.object({
id: z.string(),
createdAt: z.date(),
documentId: z.number(),
envelopeId: z.string(),
name: z.string().optional().nullable(),
email: z.string().optional().nullable(),
userId: z.number().optional().nullable(),

View File

@ -1,11 +1,11 @@
import type { z } from 'zod';
import { z } from 'zod';
import { DocumentDataSchema } from '@documenso/prisma/generated/zod/modelSchema/DocumentDataSchema';
import { DocumentMetaSchema } from '@documenso/prisma/generated/zod/modelSchema/DocumentMetaSchema';
import { DocumentSchema } from '@documenso/prisma/generated/zod/modelSchema/DocumentSchema';
import { FolderSchema } from '@documenso/prisma/generated/zod/modelSchema/FolderSchema';
import { TeamSchema } from '@documenso/prisma/generated/zod/modelSchema/TeamSchema';
import { UserSchema } from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
import { LegacyDocumentSchema } from '@documenso/prisma/types/document-legacy-schema';
import { ZFieldSchema } from './field';
import { ZRecipientLiteSchema } from './recipient';
@ -15,7 +15,7 @@ import { ZRecipientLiteSchema } from './recipient';
*
* Mainly used for returning a single document from the API.
*/
export const ZDocumentSchema = DocumentSchema.pick({
export const ZDocumentSchema = LegacyDocumentSchema.pick({
visibility: true,
status: true,
source: true,
@ -25,15 +25,17 @@ export const ZDocumentSchema = DocumentSchema.pick({
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
folderId: true,
}).extend({
// Which "Template" the document was created from. Legacy field for backwards compatibility.
// The actual field is now called `createdFromDocumentId`.
templateId: z.number().nullish(),
// Todo: Maybe we want to alter this a bit since this returns a lot of data.
documentData: DocumentDataSchema.pick({
type: true,
@ -48,9 +50,7 @@ export const ZDocumentSchema = DocumentSchema.pick({
subject: true,
message: true,
timezone: true,
password: true,
dateFormat: true,
documentId: true,
redirectUrl: true,
typedSignatureEnabled: true,
uploadSignatureEnabled: true,
@ -82,7 +82,7 @@ export type TDocument = z.infer<typeof ZDocumentSchema>;
/**
* A lite version of the document response schema without relations.
*/
export const ZDocumentLiteSchema = DocumentSchema.pick({
export const ZDocumentLiteSchema = LegacyDocumentSchema.pick({
visibility: true,
status: true,
source: true,
@ -92,15 +92,17 @@ export const ZDocumentLiteSchema = DocumentSchema.pick({
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
folderId: true,
useLegacyFieldInsertion: true,
}).extend({
// Which "Template" the document was created from. Legacy field for backwards compatibility.
// The actual field is now called `createdFromDocumentId`.
templateId: z.number().nullish(),
});
export type TDocumentLite = z.infer<typeof ZDocumentLiteSchema>;
@ -108,7 +110,7 @@ export type TDocumentLite = z.infer<typeof ZDocumentLiteSchema>;
/**
* A version of the document response schema when returning multiple documents at once from a single API endpoint.
*/
export const ZDocumentManySchema = DocumentSchema.pick({
export const ZDocumentManySchema = LegacyDocumentSchema.pick({
visibility: true,
status: true,
source: true,
@ -118,16 +120,18 @@ export const ZDocumentManySchema = DocumentSchema.pick({
authOptions: true,
formValues: true,
title: true,
documentDataId: true,
createdAt: true,
updatedAt: true,
completedAt: true,
deletedAt: true,
teamId: true,
templateId: true,
folderId: true,
useLegacyFieldInsertion: true,
}).extend({
// Which "Template" the document was created from. Legacy field for backwards compatibility.
// The actual field is now called `createdFromDocumentId`.
templateId: z.number().nullish(),
user: UserSchema.pick({
id: true,
name: true,

View File

@ -15,11 +15,11 @@ import { FieldSchema } from '@documenso/prisma/generated/zod/modelSchema/FieldSc
* - ./templates.ts
*/
export const ZFieldSchema = FieldSchema.pick({
envelopeId: true,
envelopeItemId: true,
type: true,
id: true,
secondaryId: true,
documentId: true,
templateId: true,
recipientId: true,
page: true,
positionX: true,
@ -29,6 +29,10 @@ export const ZFieldSchema = FieldSchema.pick({
customText: true,
inserted: true,
fieldMeta: true,
}).extend({
// Todo: Migration - Backwards compatibility.
documentId: z.number().nullish(),
templateId: z.number().nullish(),
});
export const ZFieldPageNumberSchema = z

View File

@ -1,3 +1,5 @@
import { z } from 'zod';
import { RecipientSchema } from '@documenso/prisma/generated/zod/modelSchema/RecipientSchema';
import { TeamSchema } from '@documenso/prisma/generated/zod/modelSchema/TeamSchema';
import { UserSchema } from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
@ -10,13 +12,12 @@ import { ZFieldSchema } from './field';
* Mainly used for returning a single recipient from the API.
*/
export const ZRecipientSchema = RecipientSchema.pick({
envelopeId: true,
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
@ -28,19 +29,22 @@ export const ZRecipientSchema = RecipientSchema.pick({
rejectionReason: true,
}).extend({
fields: ZFieldSchema.array(),
// Todo: Migration - Backwards compatibility.
documentId: z.number().nullish(),
templateId: z.number().nullish(),
});
/**
* A lite version of the recipient response schema without relations.
*/
export const ZRecipientLiteSchema = RecipientSchema.pick({
envelopeId: true,
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
@ -50,19 +54,22 @@ export const ZRecipientLiteSchema = RecipientSchema.pick({
authOptions: true,
signingOrder: true,
rejectionReason: true,
}).extend({
// Todo: Migration - Backwards compatibility.
documentId: z.number().nullish(),
templateId: z.number().nullish(),
});
/**
* A version of the recipient response schema when returning multiple recipients at once from a single API endpoint.
*/
export const ZRecipientManySchema = RecipientSchema.pick({
envelopeId: true,
role: true,
readStatus: true,
signingStatus: true,
sendStatus: true,
id: true,
documentId: true,
templateId: true,
email: true,
name: true,
token: true,
@ -83,4 +90,8 @@ export const ZRecipientManySchema = RecipientSchema.pick({
id: true,
url: true,
}).nullable(),
// Todo: Migration - Backwards compatibility.
documentId: z.number().nullish(),
templateId: z.number().nullish(),
});

View File

@ -5,8 +5,8 @@ import { DocumentMetaSchema } from '@documenso/prisma/generated/zod/modelSchema/
import { FolderSchema } from '@documenso/prisma/generated/zod/modelSchema/FolderSchema';
import TeamSchema from '@documenso/prisma/generated/zod/modelSchema/TeamSchema';
import { TemplateDirectLinkSchema } from '@documenso/prisma/generated/zod/modelSchema/TemplateDirectLinkSchema';
import { TemplateSchema } from '@documenso/prisma/generated/zod/modelSchema/TemplateSchema';
import { UserSchema } from '@documenso/prisma/generated/zod/modelSchema/UserSchema';
import { TemplateSchema } from '@documenso/prisma/types/template-legacy-schema';
import { ZFieldSchema } from './field';
import { ZRecipientLiteSchema } from './recipient';
@ -25,7 +25,6 @@ export const ZTemplateSchema = TemplateSchema.pick({
userId: true,
teamId: true,
authOptions: true,
templateDocumentDataId: true,
createdAt: true,
updatedAt: true,
publicTitle: true,
@ -51,13 +50,12 @@ export const ZTemplateSchema = TemplateSchema.pick({
drawSignatureEnabled: true,
allowDictateNextSigner: true,
distributionMethod: true,
templateId: true,
redirectUrl: true,
language: true,
emailSettings: true,
emailId: true,
emailReplyTo: true,
}).nullable(),
}),
directLink: TemplateDirectLinkSchema.nullable(),
user: UserSchema.pick({
id: true,
@ -94,7 +92,6 @@ export const ZTemplateLiteSchema = TemplateSchema.pick({
userId: true,
teamId: true,
authOptions: true,
templateDocumentDataId: true,
createdAt: true,
updatedAt: true,
publicTitle: true,
@ -103,6 +100,8 @@ export const ZTemplateLiteSchema = TemplateSchema.pick({
useLegacyFieldInsertion: true,
});
export type TTemplateLite = z.infer<typeof ZTemplateLiteSchema>;
/**
* A version of the template response schema when returning multiple template at once from a single API endpoint.
*/
@ -115,7 +114,6 @@ export const ZTemplateManySchema = TemplateSchema.pick({
userId: true,
teamId: true,
authOptions: true,
templateDocumentDataId: true,
createdAt: true,
updatedAt: true,
publicTitle: true,
@ -138,3 +136,5 @@ export const ZTemplateManySchema = TemplateSchema.pick({
enabled: true,
}).nullable(),
});
export type TTemplateMany = z.infer<typeof ZTemplateManySchema>;

View File

@ -1,10 +1,11 @@
import type { Document, DocumentMeta, Recipient, WebhookTriggerEvents } from '@prisma/client';
import type { DocumentMeta, Envelope, Recipient, WebhookTriggerEvents } from '@prisma/client';
import {
DocumentDistributionMethod,
DocumentSigningOrder,
DocumentSource,
DocumentStatus,
DocumentVisibility,
EnvelopeType,
ReadStatus,
RecipientRole,
SendStatus,
@ -12,6 +13,8 @@ import {
} from '@prisma/client';
import { z } from 'zod';
import { mapSecondaryIdToDocumentId, mapSecondaryIdToTemplateId } from '../utils/envelope';
/**
* Schema for recipient data in webhook payloads.
*/
@ -42,7 +45,6 @@ export const ZWebhookDocumentMetaSchema = z.object({
subject: z.string().nullable(),
message: z.string().nullable(),
timezone: z.string(),
password: z.string().nullable(),
dateFormat: z.string(),
redirectUrl: z.string().nullable(),
signingOrder: z.nativeEnum(DocumentSigningOrder),
@ -67,7 +69,6 @@ export const ZWebhookDocumentSchema = z.object({
visibility: z.nativeEnum(DocumentVisibility),
title: z.string(),
status: z.nativeEnum(DocumentStatus),
documentDataId: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
completedAt: z.date().nullable(),
@ -94,16 +95,54 @@ export type WebhookPayload = {
webhookEndpoint: string;
};
export const mapDocumentToWebhookDocumentPayload = (
document: Document & {
export const mapEnvelopeToWebhookDocumentPayload = (
envelope: Envelope & {
recipients: Recipient[];
documentMeta: DocumentMeta | null;
},
): TWebhookDocument => {
const { recipients, documentMeta, ...trimmedDocument } = document;
const { recipients: rawRecipients, documentMeta } = envelope;
const legacyId =
envelope.type === EnvelopeType.DOCUMENT
? mapSecondaryIdToDocumentId(envelope.secondaryId)
: mapSecondaryIdToTemplateId(envelope.secondaryId);
const mappedRecipients = rawRecipients.map((recipient) => ({
id: recipient.id,
documentId: envelope.type === EnvelopeType.DOCUMENT ? legacyId : null,
templateId: envelope.type === EnvelopeType.TEMPLATE ? legacyId : null,
email: recipient.email,
name: recipient.name,
token: recipient.token,
documentDeletedAt: recipient.documentDeletedAt,
expired: recipient.expired,
signedAt: recipient.signedAt,
authOptions: recipient.authOptions,
signingOrder: recipient.signingOrder,
rejectionReason: recipient.rejectionReason,
role: recipient.role,
readStatus: recipient.readStatus,
signingStatus: recipient.signingStatus,
sendStatus: recipient.sendStatus,
}));
return {
...trimmedDocument,
id: legacyId,
externalId: envelope.externalId,
userId: envelope.userId,
authOptions: envelope.authOptions,
formValues: envelope.formValues,
visibility: envelope.visibility,
title: envelope.title,
status: envelope.status,
createdAt: envelope.createdAt,
updatedAt: envelope.updatedAt,
completedAt: envelope.completedAt,
deletedAt: envelope.deletedAt,
teamId: envelope.teamId,
templateId: envelope.templateId,
source: envelope.source,
documentMeta: documentMeta
? {
...documentMeta,
@ -112,7 +151,7 @@ export const mapDocumentToWebhookDocumentPayload = (
dateFormat: 'yyyy-MM-dd hh:mm a',
}
: null,
Recipient: recipients,
recipients,
Recipient: mappedRecipients,
recipients: mappedRecipients,
};
};