562 lines
13 KiB
TypeScript
562 lines
13 KiB
TypeScript
/**
|
|
* @file contract.ts
|
|
* @description Enhanced portable contract interface
|
|
* The main contract data structure that ties all modules together
|
|
*/
|
|
|
|
import * as plugins from './plugins.js';
|
|
import type {
|
|
TContractCategory,
|
|
TContractType,
|
|
TContractStatus,
|
|
TPartyRole,
|
|
TSigningDependency,
|
|
TLegalCapacity,
|
|
TSectionType,
|
|
TVariableType,
|
|
TConditionOperator,
|
|
TConditionCombine,
|
|
TLegalReferenceType,
|
|
TDisputeResolution,
|
|
TSignatureType,
|
|
TSignatureLegalLevel,
|
|
TConfidentialityLevel,
|
|
} from './types.js';
|
|
import type {
|
|
IFinancialTerms,
|
|
ITimeTerms,
|
|
IObligationTerms,
|
|
createEmptyFinancialTerms,
|
|
createEmptyTimeTerms,
|
|
createEmptyObligationTerms,
|
|
} from './terms.js';
|
|
import type { ISignature, ISignatureFieldPlacement, ISignatureFieldRequirements, ISignatureDependency } from './signature.js';
|
|
import type { IIdentityVerificationResult } from './identity.js';
|
|
import type { ILegalComplianceProof } from './legal.js';
|
|
import type { IVersionHistory, IVersion } from './versioning.js';
|
|
import type { ICollaborator, ICommentThread, ISuggestion } from './collaboration.js';
|
|
import type { IDocumentLifecycle, IAuditLog } from './lifecycle.js';
|
|
import type { IContractAttachment, IPriorContractReference } from './attachments.js';
|
|
import type { IPdfGenerationConfig } from './pdf.js';
|
|
|
|
// ============================================================================
|
|
// METADATA
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Governing law and jurisdiction
|
|
*/
|
|
export interface IGoverningLaw {
|
|
country: string;
|
|
state?: string;
|
|
applicableLaws: string[];
|
|
disputeJurisdiction?: string;
|
|
disputeResolution: TDisputeResolution;
|
|
arbitrationInstitution?: string;
|
|
arbitrationRules?: string;
|
|
arbitrationSeat?: string;
|
|
numberOfArbitrators?: number;
|
|
proceedingsLanguage?: string;
|
|
}
|
|
|
|
/**
|
|
* Contract metadata
|
|
*/
|
|
export interface IContractMetadata {
|
|
contractNumber?: string;
|
|
category: TContractCategory;
|
|
contractType: TContractType;
|
|
language: string;
|
|
additionalLanguages: string[];
|
|
bindingLanguage?: string;
|
|
governingLaw: IGoverningLaw;
|
|
tags: string[];
|
|
internalReference?: string;
|
|
externalReference?: string;
|
|
templateId?: string;
|
|
parentContractId?: string;
|
|
relatedContractIds: string[];
|
|
confidentialityLevel: TConfidentialityLevel;
|
|
customFields: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================================================
|
|
// ROLES AND PARTIES
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Role definition
|
|
*/
|
|
export interface IRole {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
category: 'party' | 'witness' | 'notary' | 'guarantor' | 'beneficiary';
|
|
signatureRequired: boolean;
|
|
defaultSigningOrder: number;
|
|
legalCapacity?: TLegalCapacity;
|
|
notifyOnChanges: boolean;
|
|
notifyOnComments: boolean;
|
|
displayColor?: string;
|
|
icon?: string;
|
|
minParties?: number;
|
|
maxParties?: number;
|
|
}
|
|
|
|
/**
|
|
* Legal proxy information
|
|
*/
|
|
export interface ILegalProxy {
|
|
type: 'self' | 'company_representative' | 'power_of_attorney' | 'guardian' | 'other';
|
|
representedEntity: plugins.tsclass.business.TContact;
|
|
position?: string;
|
|
poaDocumentId?: string;
|
|
authorityScope?: string;
|
|
}
|
|
|
|
/**
|
|
* Party signature status
|
|
*/
|
|
export interface IPartySignature {
|
|
status: 'pending' | 'viewed' | 'signed' | 'declined' | 'voided';
|
|
signedAt?: number;
|
|
signature?: ISignature;
|
|
declinedAt?: number;
|
|
declineReason?: string;
|
|
}
|
|
|
|
/**
|
|
* Involved party in contract
|
|
*/
|
|
export interface IInvolvedParty {
|
|
partyId: string;
|
|
roleId: string;
|
|
contact: plugins.tsclass.business.TContact;
|
|
partyRole: TPartyRole;
|
|
signingOrder: number;
|
|
signingDependency: TSigningDependency;
|
|
dependsOnParties: string[];
|
|
signature: IPartySignature;
|
|
identityVerification?: IIdentityVerificationResult;
|
|
legalComplianceProof?: ILegalComplianceProof;
|
|
actingAsProxy: boolean;
|
|
legalProxy?: ILegalProxy;
|
|
deliveryEmail?: string;
|
|
deliveryPhone?: string;
|
|
preferredLanguage?: string;
|
|
internalNotes?: string;
|
|
invitationSentAt?: number;
|
|
remindersSent: number;
|
|
lastReminderAt?: number;
|
|
firstViewedAt?: number;
|
|
lastViewedAt?: number;
|
|
totalViews: number;
|
|
metadata: Record<string, unknown>;
|
|
}
|
|
|
|
// ============================================================================
|
|
// CONTENT STRUCTURE
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Variable validation rules
|
|
*/
|
|
export interface IVariableValidation {
|
|
pattern?: string;
|
|
minLength?: number;
|
|
maxLength?: number;
|
|
min?: number;
|
|
max?: number;
|
|
options?: string[];
|
|
}
|
|
|
|
/**
|
|
* Variable format specification
|
|
*/
|
|
export interface IVariableFormat {
|
|
dateFormat?: string;
|
|
numberFormat?: string;
|
|
currencyFormat?: string;
|
|
}
|
|
|
|
/**
|
|
* Variable source configuration
|
|
*/
|
|
export interface IVariableSource {
|
|
type: 'party_field' | 'contract_field' | 'calculated' | 'external' | 'manual';
|
|
path?: string;
|
|
formula?: string;
|
|
externalSource?: string;
|
|
}
|
|
|
|
/**
|
|
* Variable/placeholder definition
|
|
*/
|
|
export interface IVariable {
|
|
variableId: string;
|
|
name: string;
|
|
type: TVariableType;
|
|
value?: unknown;
|
|
defaultValue?: unknown;
|
|
required: boolean;
|
|
source?: IVariableSource;
|
|
validation?: IVariableValidation;
|
|
format?: IVariableFormat;
|
|
}
|
|
|
|
/**
|
|
* Condition for conditional content
|
|
*/
|
|
export interface ICondition {
|
|
conditionId: string;
|
|
field: string;
|
|
operator: TConditionOperator;
|
|
value: unknown;
|
|
combine?: TConditionCombine;
|
|
nestedConditions: ICondition[];
|
|
}
|
|
|
|
/**
|
|
* Legal reference annotation
|
|
*/
|
|
export interface ILegalReference {
|
|
type: TLegalReferenceType;
|
|
citation: string;
|
|
url?: string;
|
|
jurisdiction?: string;
|
|
effectiveDate?: number;
|
|
}
|
|
|
|
/**
|
|
* Paragraph translation
|
|
*/
|
|
export interface IParagraphTranslation {
|
|
title: string;
|
|
content: string;
|
|
}
|
|
|
|
/**
|
|
* Paragraph/section in contract
|
|
*/
|
|
export interface IParagraph {
|
|
uniqueId: string;
|
|
parentId: string | null;
|
|
title: string;
|
|
content: string;
|
|
sectionType: TSectionType;
|
|
numbering?: string;
|
|
order: number;
|
|
depth: number;
|
|
required: boolean;
|
|
isEditable: boolean;
|
|
variables: IVariable[];
|
|
conditions: ICondition[];
|
|
legalReferences: ILegalReference[];
|
|
language?: string;
|
|
translations: Record<string, IParagraphTranslation>;
|
|
crossReferences: string[];
|
|
attachmentReferences: string[];
|
|
jurisdictions: string[];
|
|
tags: string[];
|
|
aiGenerated: boolean;
|
|
templateSourceId?: string;
|
|
lastEditedBy?: string;
|
|
lastEditedAt?: number;
|
|
lockedBy?: string;
|
|
lockedAt?: number;
|
|
}
|
|
|
|
// ============================================================================
|
|
// SIGNATURE FIELDS
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Signer assignment to signature field
|
|
*/
|
|
export interface ISignerAssignment {
|
|
id: string;
|
|
partyId?: string;
|
|
email: string;
|
|
phone?: string;
|
|
signingOrder: number;
|
|
invitationStatus: 'not_sent' | 'sent' | 'delivered' | 'opened' | 'bounced';
|
|
invitationSentAt?: number;
|
|
deliveredAt?: number;
|
|
openedAt?: number;
|
|
remindersSent: number;
|
|
lastReminderAt?: number;
|
|
accessTokenHash?: string;
|
|
tokenExpiresAt?: number;
|
|
}
|
|
|
|
/**
|
|
* Signature field in contract
|
|
*/
|
|
export interface ISignatureField {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
placement: ISignatureFieldPlacement;
|
|
requirements: ISignatureFieldRequirements;
|
|
dependencies: ISignatureDependency[];
|
|
assignedSigner?: ISignerAssignment;
|
|
status: 'pending' | 'ready' | 'in_progress' | 'completed' | 'declined' | 'expired' | 'voided';
|
|
signature?: ISignature;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
// ============================================================================
|
|
// MAIN CONTRACT INTERFACE
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Complete portable contract interface
|
|
* All fields are required - use empty arrays/objects where no data
|
|
*/
|
|
export interface IPortableContract {
|
|
// Core Identity
|
|
id: string;
|
|
title: string;
|
|
context: string;
|
|
metadata: IContractMetadata;
|
|
|
|
// Parties and Roles
|
|
availableRoles: IRole[];
|
|
involvedParties: IInvolvedParty[];
|
|
|
|
// Content Structure
|
|
paragraphs: IParagraph[];
|
|
variables: IVariable[];
|
|
signatureFields: ISignatureField[];
|
|
|
|
// Structured Terms
|
|
financialTerms: IFinancialTerms;
|
|
timeTerms: ITimeTerms;
|
|
obligationTerms: IObligationTerms;
|
|
|
|
// Documents
|
|
priorContracts: IPriorContractReference[];
|
|
attachments: IContractAttachment[];
|
|
|
|
// Versioning
|
|
versionHistory: IVersionHistory;
|
|
|
|
// Collaboration
|
|
collaborators: ICollaborator[];
|
|
commentThreads: ICommentThread[];
|
|
suggestions: ISuggestion[];
|
|
|
|
// Lifecycle and Audit
|
|
lifecycle: IDocumentLifecycle;
|
|
auditLog: IAuditLog;
|
|
|
|
// PDF Generation (optional)
|
|
pdfConfig?: IPdfGenerationConfig;
|
|
finalDocument?: plugins.tsclass.business.IPdf;
|
|
renderTemplateId?: string;
|
|
renderOptions?: Record<string, unknown>;
|
|
|
|
// Timestamps
|
|
createdAt: number;
|
|
createdBy: string;
|
|
updatedAt: number;
|
|
updatedBy?: string;
|
|
|
|
// Organization
|
|
organizationId?: string;
|
|
visibility: 'private' | 'organization' | 'public';
|
|
|
|
// Integrations
|
|
integrations: {
|
|
crmId?: string;
|
|
erpId?: string;
|
|
customIntegrations: Record<string, string>;
|
|
};
|
|
}
|
|
|
|
// ============================================================================
|
|
// FACTORY FUNCTIONS
|
|
// ============================================================================
|
|
|
|
import {
|
|
createEmptyFinancialTerms as _createEmptyFinancialTerms,
|
|
createEmptyTimeTerms as _createEmptyTimeTerms,
|
|
createEmptyObligationTerms as _createEmptyObligationTerms,
|
|
} from './terms.js';
|
|
import { createInitialVersion, createEmptyVersionHistory } from './versioning.js';
|
|
import { createInitialLifecycle, createEmptyAuditLog } from './lifecycle.js';
|
|
|
|
/**
|
|
* Create default governing law
|
|
*/
|
|
export function createDefaultGoverningLaw(): IGoverningLaw {
|
|
return {
|
|
country: '',
|
|
applicableLaws: [],
|
|
disputeResolution: 'litigation',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create default contract metadata
|
|
*/
|
|
export function createDefaultMetadata(
|
|
category: TContractCategory,
|
|
contractType: TContractType,
|
|
language: string = 'en'
|
|
): IContractMetadata {
|
|
return {
|
|
category,
|
|
contractType,
|
|
language,
|
|
additionalLanguages: [],
|
|
governingLaw: createDefaultGoverningLaw(),
|
|
tags: [],
|
|
relatedContractIds: [],
|
|
confidentialityLevel: 'internal',
|
|
customFields: {},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create a new empty contract
|
|
*/
|
|
export function createEmptyContract(
|
|
title: string,
|
|
category: TContractCategory,
|
|
contractType: TContractType,
|
|
createdBy: string,
|
|
language: string = 'en'
|
|
): IPortableContract {
|
|
const id = crypto.randomUUID();
|
|
const now = Date.now();
|
|
const initialVersion = createInitialVersion(createdBy);
|
|
|
|
return {
|
|
id,
|
|
title,
|
|
context: '',
|
|
metadata: createDefaultMetadata(category, contractType, language),
|
|
availableRoles: [],
|
|
involvedParties: [],
|
|
paragraphs: [],
|
|
variables: [],
|
|
signatureFields: [],
|
|
financialTerms: _createEmptyFinancialTerms(),
|
|
timeTerms: _createEmptyTimeTerms(),
|
|
obligationTerms: _createEmptyObligationTerms(),
|
|
priorContracts: [],
|
|
attachments: [],
|
|
versionHistory: createEmptyVersionHistory(id, initialVersion),
|
|
collaborators: [],
|
|
commentThreads: [],
|
|
suggestions: [],
|
|
lifecycle: createInitialLifecycle(id),
|
|
auditLog: createEmptyAuditLog(id),
|
|
createdAt: now,
|
|
createdBy,
|
|
updatedAt: now,
|
|
visibility: 'private',
|
|
integrations: {
|
|
customIntegrations: {},
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create a new role
|
|
*/
|
|
export function createRole(
|
|
id: string,
|
|
name: string,
|
|
description: string,
|
|
options: Partial<IRole> = {}
|
|
): IRole {
|
|
return {
|
|
id,
|
|
name,
|
|
description,
|
|
category: 'party',
|
|
signatureRequired: true,
|
|
defaultSigningOrder: 1,
|
|
notifyOnChanges: true,
|
|
notifyOnComments: true,
|
|
...options,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create an involved party
|
|
*/
|
|
export function createInvolvedParty(
|
|
roleId: string,
|
|
contact: plugins.tsclass.business.TContact,
|
|
signingOrder: number = 1
|
|
): IInvolvedParty {
|
|
return {
|
|
partyId: crypto.randomUUID(),
|
|
roleId,
|
|
contact,
|
|
partyRole: 'signer',
|
|
signingOrder,
|
|
signingDependency: 'none',
|
|
dependsOnParties: [],
|
|
signature: {
|
|
status: 'pending',
|
|
},
|
|
actingAsProxy: false,
|
|
remindersSent: 0,
|
|
totalViews: 0,
|
|
metadata: {},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create a paragraph
|
|
*/
|
|
export function createParagraph(
|
|
title: string,
|
|
content: string,
|
|
sectionType: TSectionType = 'clause',
|
|
order: number = 0
|
|
): IParagraph {
|
|
return {
|
|
uniqueId: crypto.randomUUID(),
|
|
parentId: null,
|
|
title,
|
|
content,
|
|
sectionType,
|
|
order,
|
|
depth: 0,
|
|
required: true,
|
|
isEditable: true,
|
|
variables: [],
|
|
conditions: [],
|
|
legalReferences: [],
|
|
translations: {},
|
|
crossReferences: [],
|
|
attachmentReferences: [],
|
|
jurisdictions: [],
|
|
tags: [],
|
|
aiGenerated: false,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create a variable
|
|
*/
|
|
export function createVariable(
|
|
variableId: string,
|
|
name: string,
|
|
type: TVariableType,
|
|
required: boolean = true
|
|
): IVariable {
|
|
return {
|
|
variableId,
|
|
name,
|
|
type,
|
|
required,
|
|
};
|
|
}
|