import { InvestigationStatus } from "@typez/investigation/enums";
import { Schema } from "mongoose";
// ============================================================================
// EDITABLE FIELD SCHEMAS
// ============================================================================
/**
* Field History Entry Schema - Schema for a single history entry
* @category Models
*/
const FieldHistoryEntrySchema = new Schema({
value: { type: Schema.Types.Mixed, required: true },
updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
updatedAt: { type: Date, default: Date.now },
}, { _id: false });
/**
* General EditableField Schema - Base schema for all editable fields
* This schema provides the common structure for AI-generated and human-editable content
* @category Models
*/
const EditableFieldSchema = new Schema({
value: { type: Schema.Types.Mixed, default: null },
aiGeneratedValue: { type: Schema.Types.Mixed, default: null },
humanEdited: { type: Boolean, default: false },
aiEditable: { type: Boolean, default: true },
isContradicting: { type: Boolean, default: false },
contradictionReason: { type: String, default: null },
updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
updatedAt: { type: Date, default: Date.now },
createdAt: { type: Date, default: Date.now },
targetFieldName: { type: String, default: null },
history: {
type: [FieldHistoryEntrySchema],
default: [],
},
}, { _id: false });
// const EditableFieldStringSchema = new Schema(
// {
// value: { type: String, default: null },
// aiGeneratedValue: { type: Schema.Types.Mixed, default: null },
// humanEdited: { type: Boolean, default: false },
// aiEditable: { type: Boolean, default: true },
// isContradicting: { type: Boolean, default: false },
// contradictionReason: { type: String, default: null },
// updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
// updatedAt: { type: Date, default: Date.now },
// createdAt: { type: Date, default: Date.now },
// targetFieldName: { type: String, default: null },
// },
// { _id: false },
// );
// ============================================================================
// COMPONENT SCHEMAS
// ============================================================================
/**
* Step Schema - Individual step in an investigation
* Each field is now wrapped with EditableFieldSchema for AI/human editing capabilities
* @category Models
*/
const StepSchema = new Schema({
title: {
type: EditableFieldSchema,
default: null,
},
descriptionEn: {
type: EditableFieldSchema,
default: null,
},
desiredOutcome: {
type: EditableFieldSchema,
default: null,
},
alternativeOutcome: {
type: EditableFieldSchema,
default: null,
},
skippable: {
type: EditableFieldSchema,
default: null,
},
skippable_after_marking: {
type: EditableFieldSchema,
default: null,
},
}, { _id: false });
/**
* Vector3 Schema - 3D vector with x, y, z coordinates
* @category Models
*/
const EditableVector3Schema = new Schema({
x: { type: EditableFieldSchema, default: null },
y: { type: EditableFieldSchema, default: null },
z: { type: EditableFieldSchema, default: null },
}, { _id: false });
/**
* Interaction Schema - Represents an interaction available for a component
* @category Models
*/
// const InteractionSchema = new Schema<IInteraction>(
// {
// name: {
// type: String,
// trim: true,
// maxlength: [100, "Interaction name cannot exceed 100 characters"],
// },
// },
// { _id: false },
// );
/**
* View Component Schema - Mesh, Material, and Texture
* @category Models
*/
// const EditableViewComponentSchema = new Schema(
// {
// mesh: { type: EditableFieldSchema, default: null },
// material: { type: EditableFieldSchema, default: null },
// texture: { type: EditableFieldSchema, default: null },
// },
// { _id: true },
// );
// const ViewComponentSchema2 = new Schema<IViewComponent2>(
// {
// mesh: { type: String },
// material: { type: String },
// texture: { type: String },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* RigidBody Component Schema - Physics body that can be affected by forces
* @category Models
*/
// const RigidBodyComponentSchema = new Schema<IRigidBodyComponent>(
// {
// mass: { type: Number, min: 0 },
// velocity: { type: Vector3Schema },
// angularVelocity: { type: Vector3Schema },
// drag: { type: Number, min: 0 },
// angularDrag: { type: Number, min: 0 },
// useGravity: { type: Boolean },
// isKinematic: { type: Boolean },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Fluid RigidBody Component Schema - Special physics for fluid objects
* @category Models
*/
// const FluidRigidBodyComponentSchema = new Schema<IFluidRigidBodyComponent>(
// {
// density: { type: Number, min: 0 },
// viscosity: { type: Number, min: 0 },
// surfaceTension: { type: Number, min: 0 },
// particleSize: { type: Number, min: 0 },
// simulationMethod: { type: String, enum: ["SPH", "Grid"] },
// maxParticles: { type: Number, min: 1 },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Collision Mesh Component Schema - Defines collision boundaries
* @category Models
*/
// const CollisionMeshComponentSchema = new Schema<ICollisionMeshComponent>(
// {
// type: { type: String, enum: ["Box", "Sphere", "Capsule", "Mesh", "Convex"] },
// size: { type: Vector3Schema },
// isTrigger: { type: Boolean },
// material: { type: String },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Temperature Component Schema - Temperature with value and unit
* @category Models
*/
// const TemperatureComponentSchema = new Schema<ITemperatureComponent>(
// {
// value: { type: Number },
// unit: { type: String, enum: ["C", "F", "K"] },
// conductivity: { type: Number, min: 0 },
// specificHeat: { type: Number, min: 0 },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* State Of Matter Component Schema - Material state based on temperature
* @category Models
*/
// const StateOfMatterComponentSchema = new Schema<IStateOfMatterComponent>(
// {
// currentState: { type: String, enum: ["Solid", "Liquid", "Gas", "Plasma"] },
// meltingPoint: { type: Number },
// boilingPoint: { type: Number },
// sublimationPoint: { type: Number },
// stateChangeObjects: {
// solid: { type: String },
// liquid: { type: String },
// gas: { type: String },
// plasma: { type: String },
// },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Shatter Component Schema - Damage and destruction behavior
* @category Models
*/
// const ShatterComponentSchema = new Schema<IShatterComponent>(
// {
// health: { type: Number, min: 0 },
// maxHealth: { type: Number, min: 0 },
// shatterThreshold: { type: Number, min: 0 },
// shatterEffect: { type: String, enum: ["Visual", "Vaporize", "Fragment"] },
// fragmentCount: { type: Number, min: 0 },
// fragmentObject: { type: String },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Hard-Attach Component Schema - Permanent attachment behavior
* @category Models
*/
// const HardAttachComponentSchema = new Schema<IHardAttachComponent>(
// {
// attachedObjects: [{ type: String }],
// attachmentStrength: { type: Number, min: 0 },
// canDetach: { type: Boolean },
// detachForce: { type: Number, min: 0 },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Fill Component Schema - Container that can be filled with liquids
* @category Models
*/
// const FillComponentSchema = new Schema<IFillComponent>(
// {
// maxVolume: { type: Number, min: 0 },
// currentVolume: { type: Number, min: 0 },
// currentLiquid: { type: String },
// fillRate: { type: Number, min: 0 },
// drainRate: { type: Number, min: 0 },
// hasOverflow: { type: Boolean },
// interactions: [{ type: InteractionSchema }],
// },
// { _id: false },
// );
/**
* Object Schema - 3D object with position, rotation, size, view and components
* @category Models
*/
const ObjectSchema = new Schema({
name: { type: EditableFieldSchema, default: null },
objectId: { type: EditableFieldSchema, default: null },
position: { type: EditableVector3Schema, default: null },
rotation: { type: EditableVector3Schema, default: null },
size: { type: EditableFieldSchema, default: null },
}, { _id: false });
/**
* Object Schema Pre-save hook - Generate object ID from name
* @category Models
*/
ObjectSchema.pre("save", function generateObjectIdFromName(next) {
if (this.name.value) {
this.objectId.value = this.name.value.trim().toLocaleLowerCase().replace(/ /g, "_");
}
if (this.name.aiGeneratedValue) {
this.objectId.aiGeneratedValue = this.name.aiGeneratedValue
.trim()
.toLocaleLowerCase()
.replace(/ /g, "_");
}
next();
});
// const ObjectSchema2 = new Schema<IObject2>(
// {
// id: { type: String },
// name: {
// type: String,
// trim: true,
// maxlength: [200, "Object name cannot exceed 200 characters"],
// },
// position: { type: Vector3Schema },
// rotation: { type: Vector3Schema },
// size: { type: Number, min: 0 },
// view: { type: ViewComponentSchema2 },
//
// // Optional components
// rigidBody: { type: RigidBodyComponentSchema },
// fluidRigidBody: { type: FluidRigidBodyComponentSchema },
// collisionMesh: { type: CollisionMeshComponentSchema },
// temperature: { type: TemperatureComponentSchema },
// stateOfMatter: { type: StateOfMatterComponentSchema },
// shatter: { type: ShatterComponentSchema },
// hardAttach: { type: HardAttachComponentSchema },
// fill: { type: FillComponentSchema },
// },
// { _id: false },
// );
/**
* Investigation Metadata Schema - Metadata for an investigation
* @category Models
*/
const InvestigationMetadataSchema = new Schema({
dateOfDevelopment: { type: Date, default: null },
dateOfDevelopmentDelivery: { type: Date, default: null },
dateOfPublishing: { type: Date, default: null },
author: { type: Schema.Types.ObjectId, ref: "User" }, //todo required later !
editors: [{ type: Schema.Types.ObjectId, ref: "User" }],
views: { type: Number, default: 0, min: 0 },
sourceInvestigation: { type: Schema.Types.ObjectId, ref: "Investigation", default: null },
dateOfCreation: { type: Date, default: Date.now() },
dateModified: { type: Date, default: Date.now() },
}, { _id: false });
const InvestigationVersionSchema = new Schema({
versionNumber: { type: Number, required: true },
snapshot: { type: Schema.Types.Mixed, required: true },
updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
updatedAt: { type: Date, default: Date.now },
isAiGenerated: { type: Boolean, required: true, default: false },
}, { _id: false });
// ============================================================================
// EDITABLE FIELD SCHEMAS
// ============================================================================
/**
* Objects EditableField Schema - For array of 3D objects with full validation
* @category Models
*/
// const ObjectsEditableFieldSchema = new Schema(
// {
// value: { type: [ObjectSchema], default: null },
// aiGeneratedValue: { type: [ObjectSchema], default: null },
// humanEdited: { type: Boolean, default: false },
// aiEditable: { type: Boolean, default: true },
// isContradicting: { type: Boolean, default: false },
// contradictionReason: { type: String, default: null },
// updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
// updatedAt: { type: Date, default: null },
// },
// { _id: false },
// );
// ============================================================================
// MAIN INVESTIGATION SCHEMA
// ============================================================================
/**
* Investigation Schema Definition
* This file contains the main mongoose schema definition for investigations
* @category Models
*/
export const InvestigationSchema = new Schema({
// Lifecycle & locking
status: {
type: String,
enum: Object.values(InvestigationStatus),
default: InvestigationStatus.DRAFT_INCOMPLETE,
},
isLocked: {
type: Boolean,
default: false,
},
lockedBy: {
type: Schema.Types.ObjectId,
ref: "User",
default: null,
},
lockedAt: {
type: Date,
default: null,
},
// Editable content (all wrapped with typed EditableField<T>)
title: {
type: EditableFieldSchema,
},
curriculum: {
type: EditableFieldSchema,
},
unitNumberAndTitle: {
type: EditableFieldSchema,
},
grade: {
type: EditableFieldSchema,
},
lessonNumberAndTitle: {
type: EditableFieldSchema,
},
objectives: {
type: EditableFieldSchema,
},
ngss: {
type: EditableFieldSchema,
},
analyticalFacts: {
type: EditableFieldSchema,
},
goals: {
type: EditableFieldSchema,
},
day: {
type: EditableFieldSchema,
},
steps: {
type: [StepSchema],
default: [],
},
objects: {
type: [ObjectSchema],
},
// Metadata (system/relations)
metadata: {
type: InvestigationMetadataSchema,
},
versions: {
type: [InvestigationVersionSchema],
default: [],
},
currentVersionIndex: {
type: Number,
default: 0,
},
lastChangeWithAI: {
type: Boolean,
default: true,
},
}, {
timestamps: true,
collection: "investigations",
});
Source