Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class ProjectFrameworksModel {
framework_id!: number;
project_id!: number;
is_demo?: boolean;

constructor(data: ProjectFrameworksModel) {
this.framework_id = data.framework_id;
this.project_id = data.project_id;
this.is_demo = data.is_demo;
}

static createNewProjectFrameworks(
data: ProjectFrameworksModel
): ProjectFrameworksModel {
return new ProjectFrameworksModel(data);
}
}
33 changes: 33 additions & 0 deletions Clients/src/domain/models/projectScope/projectScope.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export class ProjectScopeModel {
id?: number;
assessmentId!: number;
describeAiEnvironment!: string;
isNewAiTechnology!: boolean;
usesPersonalData!: boolean;
projectScopeDocuments!: string;
technologyType!: string;
hasOngoingMonitoring!: boolean;
unintendedOutcomes!: string;
technologyDocumentation!: string;
is_demo?: boolean;
created_at?: Date;

constructor(data: ProjectScopeModel) {
this.id = data.id;
this.assessmentId = data.assessmentId;
this.describeAiEnvironment = data.describeAiEnvironment;
this.isNewAiTechnology = data.isNewAiTechnology;
this.usesPersonalData = data.usesPersonalData;
this.projectScopeDocuments = data.projectScopeDocuments;
this.technologyType = data.technologyType;
this.hasOngoingMonitoring = data.hasOngoingMonitoring;
this.unintendedOutcomes = data.unintendedOutcomes;
this.technologyDocumentation = data.technologyDocumentation;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
}

static createNewProjectScope(data: ProjectScopeModel): ProjectScopeModel {
return new ProjectScopeModel(data);
}
}
17 changes: 17 additions & 0 deletions Clients/src/domain/models/projectsMembers/projectsMembers.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class ProjectsMembersModel {
user_id!: number;
project_id!: number;
is_demo?: boolean;

constructor(data: ProjectsMembersModel) {
this.user_id = data.user_id;
this.project_id = data.project_id;
this.is_demo = data.is_demo;
}

static createNewProjectsMembers(
data: ProjectsMembersModel
): ProjectsMembersModel {
return new ProjectsMembersModel(data);
}
}
47 changes: 47 additions & 0 deletions Clients/src/domain/models/question/question.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export class QuestionModel {
id?: number;
order_no?: number;
question!: string;
hint!: string;
priority_level!: "high priority" | "medium priority" | "low priority";
answer_type!: string;
input_type!: string;
evidence_required!: boolean;
is_required!: boolean;
dropdown_options?: any[];
evidence_files?: {
id: string;
fileName: string;
project_id: number;
uploaded_by: number;
uploaded_time: Date;
}[];
answer?: string;
subtopic_id!: number;
is_demo?: boolean;
created_at?: Date;
status?: "Not started" | "In progress" | "Done";

constructor(data: QuestionModel) {
this.id = data.id;
this.order_no = data.order_no;
this.question = data.question;
this.hint = data.hint;
this.priority_level = data.priority_level;
this.answer_type = data.answer_type;
this.input_type = data.input_type;
this.evidence_required = data.evidence_required;
this.is_required = data.is_required;
this.dropdown_options = data.dropdown_options;
this.evidence_files = data.evidence_files;
this.answer = data.answer;
this.subtopic_id = data.subtopic_id;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
this.status = data.status;
}

static createNewQuestion(data: QuestionModel): QuestionModel {
return new QuestionModel(data);
}
}
93 changes: 93 additions & 0 deletions Clients/src/domain/models/risks/risk.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export class RiskModel {
id?: number;
risk_name!: string;
risk_owner!: number;
ai_lifecycle_phase!:
| "Problem definition & planning"
| "Data collection & processing"
| "Model development & training"
| "Model validation & testing"
| "Deployment & integration"
| "Monitoring & maintenance"
| "Decommissioning & retirement";
risk_description!: string;
risk_category!: string[];
impact!: string;
assessment_mapping!: string;
controls_mapping!: string;
likelihood!: "Rare" | "Unlikely" | "Possible" | "Likely" | "Almost Certain";
severity!: "Negligible" | "Minor" | "Moderate" | "Major" | "Catastrophic";
risk_level_autocalculated!:
| "No risk"
| "Very low risk"
| "Low risk"
| "Medium risk"
| "High risk"
| "Very high risk";
review_notes!: string;
mitigation_status!:
| "Not Started"
| "In Progress"
| "Completed"
| "On Hold"
| "Deferred"
| "Canceled"
| "Requires review";
current_risk_level!:
| "Very Low risk"
| "Low risk"
| "Medium risk"
| "High risk"
| "Very high risk";
Comment on lines +36 to +41
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix casing mismatch in risk levels (compile-time inconsistency).

"Very Low risk" vs "Very low risk" will cause type mismatches across the app. Align to a single canonical value.

Apply this diff:

   current_risk_level!:
-    | "Very Low risk"
+    | "Very low risk"
     | "Low risk"
     | "Medium risk"
     | "High risk"
     | "Very high risk";
🤖 Prompt for AI Agents
In Clients/src/domain/models/risks/risk.model.ts around lines 36 to 41, the risk
level string literals have inconsistent casing (e.g. "Very Low risk" vs "Very
high risk"); update them to a single canonical format for all entries to avoid
compile-time mismatches — replace the union with consistent Title Case values:
"Very Low Risk", "Low Risk", "Medium Risk", "High Risk", "Very High Risk".

deadline!: Date;
mitigation_plan!: string;
implementation_strategy!: string;
mitigation_evidence_document!: string;
likelihood_mitigation!:
| "Rare"
| "Unlikely"
| "Possible"
| "Likely"
| "Almost Certain";
risk_severity!: "Negligible" | "Minor" | "Moderate" | "Major" | "Critical";
final_risk_level!: string;
risk_approval!: number;
approval_status!: string;
date_of_assessment!: Date;
is_demo?: boolean;
created_at?: Date;

constructor(data: RiskModel) {
this.id = data.id;
this.risk_name = data.risk_name;
this.risk_owner = data.risk_owner;
this.ai_lifecycle_phase = data.ai_lifecycle_phase;
this.risk_description = data.risk_description;
this.risk_category = data.risk_category;
this.impact = data.impact;
this.assessment_mapping = data.assessment_mapping;
this.controls_mapping = data.controls_mapping;
this.likelihood = data.likelihood;
this.severity = data.severity;
this.risk_level_autocalculated = data.risk_level_autocalculated;
this.review_notes = data.review_notes;
this.mitigation_status = data.mitigation_status;
this.current_risk_level = data.current_risk_level;
this.deadline = data.deadline;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Parse API date strings into Date in the constructor.

Backends generally return ISO strings; assigning directly to Date-typed fields risks Invalid Date or runtime issues when using Date APIs.

Apply this diff:

-    this.deadline = data.deadline;
+    this.deadline =
+      typeof data.deadline === "string" || typeof data.deadline === "number"
+        ? new Date(data.deadline)
+        : data.deadline;

-    this.date_of_assessment = data.date_of_assessment;
+    this.date_of_assessment =
+      typeof data.date_of_assessment === "string" || typeof data.date_of_assessment === "number"
+        ? new Date(data.date_of_assessment)
+        : data.date_of_assessment;

-    this.created_at = data.created_at;
+    this.created_at =
+      data.created_at == null
+        ? undefined
+        : typeof data.created_at === "string" || typeof data.created_at === "number"
+        ? new Date(data.created_at)
+        : data.created_at;

Also applies to: 85-85, 87-87

🤖 Prompt for AI Agents
In Clients/src/domain/models/risks/risk.model.ts around lines 76, 85 and 87 the
constructor assigns API date strings directly to Date-typed fields (e.g.,
this.deadline = data.deadline), which can leave strings or produce Invalid Date
at runtime; update those assignments to parse inputs into Date objects (e.g., if
data.deadline is truthy create new Date(data.deadline) or handle existing Date
instances without re-wrapping) and add minimal input validation (check for
undefined/null and for Invalid Date) before assigning so the class fields are
always real Date objects.

this.mitigation_plan = data.mitigation_plan;
this.implementation_strategy = data.implementation_strategy;
this.mitigation_evidence_document = data.mitigation_evidence_document;
this.likelihood_mitigation = data.likelihood_mitigation;
this.risk_severity = data.risk_severity;
this.final_risk_level = data.final_risk_level;
this.risk_approval = data.risk_approval;
this.approval_status = data.approval_status;
this.date_of_assessment = data.date_of_assessment;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
}

static createNewRisk(data: RiskModel): RiskModel {
return new RiskModel(data);
}
}
19 changes: 19 additions & 0 deletions Clients/src/domain/models/role/role.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export class RoleModel {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Constructor should accept a DTO (not RoleModel) and normalize dates.

Using constructor(data: RoleModel) is tautological and hinders constructing from plain API payloads. Accept a DTO type and coerce created_at to Date. Apply this pattern here (and replicate across the new models).

-export class RoleModel {
+export interface RoleDTO {
+  id?: number;
+  name: string;
+  description: string;
+  is_demo?: boolean;
+  created_at?: string | Date;
+}
+
+export class RoleModel {
   id?: number;
   name!: string;
   description!: string;
   is_demo?: boolean;
   created_at?: Date;

-  constructor(data: RoleModel) {
+  constructor(data: RoleDTO) {
     this.id = data.id;
     this.name = data.name;
     this.description = data.description;
     this.is_demo = data.is_demo;
-    this.created_at = data.created_at;
+    this.created_at = data.created_at
+      ? new Date(data.created_at)
+      : undefined;
   }

-  static createRole(data: RoleModel): RoleModel {
-    return new RoleModel(data);
+  static createRole(data: RoleDTO): RoleModel {
+    return new RoleModel(data);
   }
 }

Note: Consider renaming the factory to fromDTO for clarity and consistency with its purpose.

Also applies to: 6-6, 8-14, 16-18

id?: number;
name!: string;
description!: string;
is_demo?: boolean;
created_at?: Date;

constructor(data: RoleModel) {
this.id = data.id;
this.name = data.name;
this.description = data.description;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
}

static createRole(data: RoleModel): RoleModel {
return new RoleModel(data);
}
}
57 changes: 57 additions & 0 deletions Clients/src/domain/models/subcontrol/subControl.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export class SubControlModel {
id?: number;
title!: string;
description!: string;
order_no?: number;
status?: "Waiting" | "In progress" | "Done";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Status literal consistency

Confirm "In progress" matches other modules (Training Registrar uses "In progress" after fix).


🏁 Script executed:

#!/bin/bash
rg -n -C1 -P '"In progress"|"In Progress"' Clients/src

Length of output: 18542


Status literal consistency
subControl.model.ts defines status?: "Waiting" | "In progress" | "Done", but TrainingRegistrar and most components use "In Progress" (capital “P”). Change to "In Progress" to unify across modules.

🤖 Prompt for AI Agents
Clients/src/domain/models/subcontrol/subControl.model.ts around line 6: the
status union uses "In progress" (lowercase p) which conflicts with other modules
that expect "In Progress"; update the union literal to "Waiting" | "In Progress"
| "Done" and run a project-wide search for "In progress" occurrences to update
any mismatched values or tests to the canonical "In Progress" string so typings
and runtime values are consistent.

approver?: number;
risk_review?: "Acceptable risk" | "Residual risk" | "Unacceptable risk";
owner?: number;
reviewer?: number;
due_date?: Date;
implementation_details?: string;
evidence_description?: string;
feedback_description?: string;
evidence_files?: {
id: string;
fileName: string;
project_id: number;
uploaded_by: number;
uploaded_time: Date;
}[];
feedback_files?: {
id: string;
fileName: string;
project_id: number;
uploaded_by: number;
uploaded_time: Date;
}[];
control_id!: number;
is_demo?: boolean;
created_at?: Date;

constructor(data: SubControlModel) {
this.id = data.id;
this.title = data.title;
this.description = data.description;
this.order_no = data.order_no;
this.status = data.status;
this.approver = data.approver;
this.risk_review = data.risk_review;
this.owner = data.owner;
this.reviewer = data.reviewer;
this.due_date = data.due_date;
this.implementation_details = data.implementation_details;
this.evidence_description = data.evidence_description;
this.feedback_description = data.feedback_description;
this.evidence_files = data.evidence_files;
this.feedback_files = data.feedback_files;
this.control_id = data.control_id;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
}

static createSubControl(data: SubControlModel): SubControlModel {
return new SubControlModel(data);
}
}
27 changes: 27 additions & 0 deletions Clients/src/domain/models/subscription/subscription.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export class SubscriptionModel {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Define SubscriptionDTO, normalize all dates, and type the status.

Current signature requires SubscriptionModel and doesn’t normalize date fields. Also, encode status as a reusable type.

Please confirm backend status literals (is it "canceled" or "cancelled"?). Script to scan the repo:

Proposed changes:

-export class SubscriptionModel {
+export type SubscriptionStatus = "active" | "inactive" | "canceled";
+
+export interface SubscriptionDTO {
+  id?: number;
+  organization_id: number;
+  tier_id: number;
+  stripe_sub_id: string;
+  status: SubscriptionStatus;
+  start_date: string | Date;
+  end_date?: string | Date;
+  created_at: string | Date;
+  updated_at: string | Date;
+}
+
+export class SubscriptionModel {
   id?: number;
   organization_id!: number;
   tier_id!: number;
   stripe_sub_id!: string;
-  status!: "active" | "inactive" | "canceled";
+  status!: SubscriptionStatus;
   start_date!: Date;
   end_date?: Date;
   created_at!: Date;
   updated_at!: Date;

-  constructor(data: SubscriptionModel) {
+  constructor(data: SubscriptionDTO) {
     this.id = data.id;
     this.organization_id = data.organization_id;
     this.tier_id = data.tier_id;
     this.stripe_sub_id = data.stripe_sub_id;
     this.status = data.status;
-    this.start_date = data.start_date;
-    this.end_date = data.end_date;
-    this.created_at = data.created_at;
-    this.updated_at = data.updated_at;
+    this.start_date = new Date(data.start_date);
+    this.end_date = data.end_date ? new Date(data.end_date) : undefined;
+    this.created_at = new Date(data.created_at);
+    this.updated_at = new Date(data.updated_at);
   }

-  static createSubscription(data: SubscriptionModel): SubscriptionModel {
+  static createSubscription(data: SubscriptionDTO): SubscriptionModel {
     return new SubscriptionModel(data);
   }
 }

Also applies to: 2-10, 12-22, 24-26


🏁 Script executed:

#!/bin/bash
# Search for subscription status literals across the repo
rg -nP -C2 '\b(cancelled|canceled|active|inactive)\b' --type-add 'all:*.{ts,tsx,js,py,go,rb,java}'

Length of output: 59


🏁 Script executed:

#!/bin/bash
# Search for subscription status literals across relevant source files
rg -nP -C2 '\b(cancelled|canceled|active|inactive)\b' -g '*.{ts,tsx,js,py,go,rb,java}'

Length of output: 28300


Refactor SubscriptionModel to use SubscriptionDTO and enforce type-safe status

  • Export type SubscriptionStatus = "active" | "inactive" | "canceled" (one ‘l’, matching backend migrations).
  • Add export interface SubscriptionDTO { … } with date fields as string | Date.
  • Change SubscriptionModel to accept SubscriptionDTO in its constructor and convert all date strings via new Date().
🤖 Prompt for AI Agents
In Clients/src/domain/models/subscription/subscription.model.ts around line 1,
refactor the file to export a type alias SubscriptionStatus = "active" |
"inactive" | "canceled" (note single 'l'), add and export an interface
SubscriptionDTO that declares all subscription properties with date fields typed
as string | Date, and update SubscriptionModel so its constructor accepts a
SubscriptionDTO and normalizes any date-string fields by converting them with
new Date(...) to real Date objects while using the SubscriptionStatus type for
the model's status.

id?: number;
organization_id!: number;
tier_id!: number;
stripe_sub_id!: string;
status!: "active" | "inactive" | "canceled";
start_date!: Date;
end_date?: Date;
created_at!: Date;
updated_at!: Date;

constructor(data: SubscriptionModel) {
this.id = data.id;
this.organization_id = data.organization_id;
this.tier_id = data.tier_id;
this.stripe_sub_id = data.stripe_sub_id;
this.status = data.status;
this.start_date = data.start_date;
this.end_date = data.end_date;
this.created_at = data.created_at;
this.updated_at = data.updated_at;
}

static createSubscription(data: SubscriptionModel): SubscriptionModel {
return new SubscriptionModel(data);
}
}
21 changes: 21 additions & 0 deletions Clients/src/domain/models/subtopic/subtopic.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export class SubtopicModel {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Adopt DTO input and normalize created_at.

Same rationale/pattern as TopicModel.

-export class SubtopicModel {
+export interface SubtopicDTO {
+  id?: number;
+  title: string;
+  order_no?: number;
+  topic_id: number;
+  is_demo?: boolean;
+  created_at?: string | Date;
+}
+
+export class SubtopicModel {
   id?: number;
   title!: string;
   order_no?: number;
   topic_id!: number;
   is_demo?: boolean;
   created_at?: Date;

-  constructor(data: SubtopicModel) {
+  constructor(data: SubtopicDTO) {
     this.id = data.id;
     this.title = data.title;
     this.order_no = data.order_no;
     this.topic_id = data.topic_id;
     this.is_demo = data.is_demo;
-    this.created_at = data.created_at;
+    this.created_at = data.created_at ? new Date(data.created_at) : undefined;
   }

-  static createSubtopic(data: SubtopicModel): SubtopicModel {
+  static createSubtopic(data: SubtopicDTO): SubtopicModel {
     return new SubtopicModel(data);
   }
 }

Also applies to: 7-7, 9-16, 18-20

🤖 Prompt for AI Agents
In Clients/src/domain/models/subtopic/subtopic.model.ts around lines 1 and also
affecting 7-7, 9-16, and 18-20, update the class to accept a Subtopic DTO as
input (same shape/pattern used by TopicModel) and normalize the created_at
field: change constructors/factory methods to take the DTO, map DTO properties
to class properties, and convert/validate created_at into a consistent Date (or
ISO string) representation (handle null/undefined and invalid values) before
assigning; update any parameter/return types and tests accordingly to mirror
TopicModel's DTO handling and created_at normalization.

id?: number;
title!: string;
order_no?: number;
topic_id!: number;
is_demo?: boolean;
created_at?: Date;

constructor(data: SubtopicModel) {
this.id = data.id;
this.title = data.title;
this.order_no = data.order_no;
this.topic_id = data.topic_id;
this.is_demo = data.is_demo;
this.created_at = data.created_at;
}

static createSubtopic(data: SubtopicModel): SubtopicModel {
return new SubtopicModel(data);
}
}
33 changes: 33 additions & 0 deletions Clients/src/domain/models/task/task.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { TaskPriority, TaskStatus } from "../../interfaces/i.task";

export class TaskModel {
id?: number;
title!: string;
description?: string;
creator_id!: number;
organization_id!: number;
due_date?: Date;
priority!: TaskPriority;
status!: TaskStatus;
categories?: string[];
created_at?: Date;
updated_at?: Date;

constructor(data: TaskModel) {
this.id = data.id;
this.title = data.title;
this.description = data.description;
this.creator_id = data.creator_id;
this.organization_id = data.organization_id;
this.due_date = data.due_date;
this.priority = data.priority;
this.status = data.status;
this.categories = data.categories;
this.created_at = data.created_at;
this.updated_at = data.updated_at;
}

static createTask(data: TaskModel): TaskModel {
return new TaskModel(data);
}
}
15 changes: 15 additions & 0 deletions Clients/src/domain/models/taskAssignee/taskAssignee.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class TaskAssigneeModel {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Accept DTO and coerce assigned_at to Date.

Mirror the DTO+normalization pattern so callers can pass API payloads safely.

-export class TaskAssigneeModel {
+export interface TaskAssigneeDTO {
+  task_id: number;
+  user_id: number;
+  assigned_at?: string | Date;
+}
+
+export class TaskAssigneeModel {
   task_id!: number;
   user_id!: number;
   assigned_at?: Date;

-  constructor(data: TaskAssigneeModel) {
+  constructor(data: TaskAssigneeDTO) {
     this.task_id = data.task_id;
     this.user_id = data.user_id;
-    this.assigned_at = data.assigned_at;
+    this.assigned_at = data.assigned_at
+      ? new Date(data.assigned_at)
+      : undefined;
   }

-  static createTaskAssignee(data: TaskAssigneeModel): TaskAssigneeModel {
+  static createTaskAssignee(data: TaskAssigneeDTO): TaskAssigneeModel {
     return new TaskAssigneeModel(data);
   }
 }

Also applies to: 4-4, 6-10, 12-14

🤖 Prompt for AI Agents
In Clients/src/domain/models/taskAssignee/taskAssignee.model.ts around lines 1-1
(and similarly for ranges 4-4, 6-10, 12-14), the TaskAssigneeModel must accept a
DTO and normalize fields: add a constructor or static fromDTO(dto) that accepts
the API payload, maps DTO properties to the model fields, and coerces
assigned_at into a JS Date (handle string/number/null safely, e.g. new Date(...)
and validate isFinite date). Ensure any optional fields are normalized to
expected types and throw or return a clear error for invalid dates.

task_id!: number;
user_id!: number;
assigned_at?: Date;

constructor(data: TaskAssigneeModel) {
this.task_id = data.task_id;
this.user_id = data.user_id;
this.assigned_at = data.assigned_at;
}

static createTaskAssignee(data: TaskAssigneeModel): TaskAssigneeModel {
return new TaskAssigneeModel(data);
}
}
Loading