import { Model } from "mongoose"; import * as uuid from "uuid"; import { mongooseLeanVirtuals } from "mongoose-lean-virtuals"; import { currentDate, MongooseModule, } from "../helpers"; import { DataSharingAgreementActions, DataSharingAgreementType, DataSharingVendorConsentType, } from "../types/data-sharing-agreement"; export interface DataSharingAgreement extends DataSharingAgreementType, Record { } // Append-only legal record of data sharing sign-offs. Every signature, change and // revocation inserts a new document; the collection IS the revision history. // // - No TTL index: records must never auto-purge. Removal only happens on a verified // legal request, as a manual engineer-run operation never via an API. // - Record fields are `immutable` so a loaded document cannot be re-saved with // different content. This gives us a static timeline of events as they happen export default async function DataSharingAgreementModule(mongoose: MongooseModule) { const { Schema } = mongoose; const DataSharingVendorConsent = new Schema({ key: { type: String, required: true, }, label: { type: String, default: "", }, checked: { type: Boolean, default: false, }, }, { _id: false, id: false, }); const modelSchema = new Schema({ _id: { type: Schema.Types.ObjectId, auto: true, }, uuid: { type: String, required: true, default: uuid.v4, immutable: true, }, // Who / where departmentId: { type: String, required: true, immutable: true, }, // Department.department at signing time (Using the value and not id on purpose) departmentName: { type: String, default: "", immutable: true, }, // Unset for account-wide signatures agencyId: { type: Schema.Types.ObjectId, ref: "Agency", default: null, immutable: true, }, agencyName: { type: String, default: "", immutable: true, }, userId: { type: String, required: true, immutable: true, }, email: { type: String, required: true, immutable: true, }, // User.name at signing time signerName: { type: String, default: "", immutable: true, }, // What they signed agreementTitle: { type: String, required: true, immutable: true, }, // Versioned in service code and rolled out with deploys agreementVersion: { type: String, required: true, immutable: true, }, // FULL text as displayed to the signer, stored verbatim, never a reference agreementText: { type: String, required: true, immutable: true, }, action: { type: String, enum: DataSharingAgreementActions, required: true, immutable: true, }, // Full checkbox state after this action consents: { type: [DataSharingVendorConsent], default: [], immutable: true, }, // Evidence remoteAddress: { type: String, default: "", immutable: true, }, userAgent: { type: String, default: "", immutable: true, }, appVersion: { type: String, default: "", immutable: true, }, // Signing timestamp, server-side createdAt: { type: Date, default: currentDate, immutable: true, }, modified: { type: Date, default: currentDate, }, }, { autoIndex: false, toJSON: { virtuals: true, versionKey: false, }, }); // History (newest first) and "latest record" lookups per account modelSchema.index({ departmentId: 1, createdAt: -1, _id: -1, }, { name: "departmentId_1_createdAt_-1__id_-1", }); modelSchema.virtual("id").get(function(this: DataSharingAgreement) { return this._id.toHexString(); }); modelSchema.plugin(mongooseLeanVirtuals); return mongoose.model("DataSharingAgreement", modelSchema, "massive_data_sharing_agreement", { overwriteModels: true }); } export interface DataSharingAgreementModel extends Model { }