lexguard-backend / src /models /Contract.js
github-actions[bot]
Deploy to Hugging Face
b921752
Raw
History Blame Contribute Delete
4.99 kB
const mongoose = require('mongoose');
const { CONTRACT_CATEGORIES, CONTRACT_STATUSES, RISK_LEVELS } = require('../config/constants');
const agentMetadataSchema = new mongoose.Schema(
{
preFlightExtractedAt: { type: Date, default: null },
isPreFlightComplete: { type: Boolean, default: false },
extractedAt: { type: Date, default: null },
analysedAt: { type: Date, default: null },
advocatedAt: { type: Date, default: null },
complianceCheckedAt: { type: Date, default: null },
},
{ _id: false }
);
const crossRefFindingSchema = new mongoose.Schema(
{
type: { type: String, enum: ['undefined_term', 'broken_reference', 'circular_definition', 'conflict'] },
severity: { type: String, enum: ['low', 'medium', 'high'] },
issue_text: { type: String },
location_hint: { type: String },
recommendation: { type: String }
},
{ _id: false }
);
const contractSchema = new mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true,
},
parentContractId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Contract',
default: null,
index: true,
},
originalFileName: {
type: String,
required: [true, 'Original file name is required'],
trim: true,
},
uploadedAt: {
type: Date,
default: Date.now,
},
status: {
type: String,
enum: CONTRACT_STATUSES,
default: 'processing',
},
contractCategory: {
type: String,
enum: CONTRACT_CATEGORIES,
required: [true, 'Contract category is required'],
},
executionDate: {
type: Date,
default: null,
description: 'The date the contract was executed or goes into effect'
},
financial_obligations: [{
amount: { type: Number },
currency: { type: String, default: 'INR' },
description: { type: String },
clause_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Clause' }
}],
total_financial_exposure: { type: Number, default: 0 },
rawText: {
type: String,
default: '',
},
lifecycle_events: [{
event_type: String, // e.g., "RENEWAL", "EXPIRATION", "NOTICE_PERIOD"
date: Date,
description: String,
notified: { type: Boolean, default: false }
}],
totalClauses: {
type: Number,
default: 0,
},
// V3 Architecture: Dynamic Global Context Payload
globalContext: {
type: mongoose.Schema.Types.Mixed,
default: null,
},
// Populated in Phase 2+ by Agent 2.
// NOTE: null is a valid default — Mongoose enum doesn't support null natively,
// so we use a custom validator that passes null through and validates strings.
overallRiskLevel: {
type: String,
default: null,
validate: {
validator: (v) => v === null || RISK_LEVELS.includes(v),
message: (props) => `${props.value} is not a valid risk level.`,
},
},
// Timestamps set by each agent in Phase 2–4
agentMetadata: {
type: agentMetadataSchema,
default: () => ({}),
},
// ── Phase 3: Agent 9 (Cross-Reference Auditor) ──────────────────────
crossRefFindings: { type: [crossRefFindingSchema], default: [] },
crossRefAuditSummary: { type: String, default: null },
// ── Citation Statistics (Categorical Breakdown) ───────────────────
citationStats: {
totalCitations: { type: Number, default: 0 },
verified: { type: Number, default: 0 },
notFound: { type: Number, default: 0 },
avgAccuracy: { type: Number, default: 0 },
strong: { type: Number, default: 0 },
weak: { type: Number, default: 0 },
hallucinated: { type: Number, default: 0 },
unverifiable: { type: Number, default: 0 },
hallucinationRate: { type: Number, default: 0 },
},
},
{ timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } }
);
contractSchema.virtual('clauses', {
ref: 'Clause',
localField: '_id',
foreignField: 'contractId'
});
contractSchema.virtual('risk_summary').get(function() {
if (!this.clauses) return null; // Only works if clauses are populated
const breakdown = { low: 0, medium: 0, high: 0, critical: 0 };
const compBreakdown = { low: 0, medium: 0, high: 0 };
let hrRecommended = 0;
for (const c of this.clauses) {
const risk = c.risk_level || 'low';
if (breakdown[risk] !== undefined) breakdown[risk]++;
const compRisk = c.compliance_risk_level || 'low';
if (compBreakdown[compRisk] !== undefined) compBreakdown[compRisk]++;
if (c.human_review_strongly_recommended) {
hrRecommended++;
}
}
return {
riskBreakdown: breakdown,
complianceBreakdown: compBreakdown,
complianceReviewRecommendedCount: hrRecommended
};
});
module.exports = mongoose.model('Contract', contractSchema);