From 371e8cc154c8bf666755331a68661be65877c797 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 11:20:41 -0800 Subject: [PATCH 1/4] purge translationService --- server/src/config/services.ts | 7 -- .../src/service/system/translationService.js | 92 ------------------- 2 files changed, 99 deletions(-) delete mode 100755 server/src/service/system/translationService.js diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 0cf55590b..b48738866 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -1,4 +1,3 @@ -import TranslationService from "../service/system/translationService.js"; import MongoDB from "../db/MongoDB.js"; import NetworkService from "../service/infrastructure/networkService.js"; import EmailService from "../service/infrastructure/emailService.js"; @@ -96,9 +95,7 @@ import { ILogger } from "@/utils/logger.js"; import { EnvConfig } from "@/service/system/settingsService.js"; export type InitializedServices = { - //v1 settingsService: any; - translationService: any; db: any; networkService: any; emailService: any; @@ -138,9 +135,6 @@ export const initializeServices = async ({ envSettings: EnvConfig; settingsService: any; }): Promise => { - const translationService = new TranslationService(logger); - await translationService.initialize(); - // Create DB const inviteModule = new InviteModule({ InviteToken, crypto }); const statusPageModule = new StatusPageModule({ StatusPage, NormalizeData, AppSettings }); @@ -289,7 +283,6 @@ export const initializeServices = async ({ const services = { //v1 settingsService, - translationService, db, networkService, emailService, diff --git a/server/src/service/system/translationService.js b/server/src/service/system/translationService.js deleted file mode 100755 index 0d3893852..000000000 --- a/server/src/service/system/translationService.js +++ /dev/null @@ -1,92 +0,0 @@ -import fs from "fs"; -import path from "path"; - -class TranslationService { - static SERVICE_NAME = "TranslationService"; - constructor(logger) { - this.logger = logger; - this.translations = {}; - this._language = "en"; - this.localesDir = path.join(process.cwd(), "src/locales"); - } - - get serviceName() { - return TranslationService.SERVICE_NAME; - } - - setLanguage(language) { - this._language = language; - } - - get language() { - return this._language; - } - - async initialize() { - try { - await this.loadFromFiles(); - } catch (error) { - this.logger.error({ - message: error.message, - service: "TranslationService", - method: "initialize", - stack: error.stack, - }); - } - } - - async loadFromFiles() { - try { - if (!fs.existsSync(this.localesDir)) { - return false; - } - - const files = fs.readdirSync(this.localesDir).filter((file) => file.endsWith(".json")); - - if (files.length === 0) { - return false; - } - - for (const file of files) { - const language = file.replace(".json", ""); - const filePath = path.join(this.localesDir, file); - const content = fs.readFileSync(filePath, "utf8"); - this.translations[language] = JSON.parse(content); - } - - this.logger.info({ - message: "Translations loaded from files successfully", - service: "TranslationService", - method: "loadFromFiles", - }); - - return true; - } catch (error) { - this.logger.error({ - message: error.message, - service: "TranslationService", - method: "loadFromFiles", - stack: error.stack, - }); - return false; - } - } - - getTranslation(key) { - let language = this._language; - - try { - return this.translations[language]?.[key] || this.translations["en"]?.[key] || key; - } catch (error) { - this.logger.error({ - message: error.message, - service: "TranslationService", - method: "getTranslation", - stack: error.stack, - }); - return key; - } - } -} - -export default TranslationService; From 9fa0113f2b557e2403ca411aba8516150dcc09a5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 11:21:00 -0800 Subject: [PATCH 2/4] remove database.js --- server/src/config/database.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 server/src/config/database.js diff --git a/server/src/config/database.js b/server/src/config/database.js deleted file mode 100644 index e69de29bb..000000000 From 36e02e0a9a09ea2f851465fc64eec5014ceb540e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 11:46:49 -0800 Subject: [PATCH 3/4] team -> ts --- server/src/config/services.ts | 7 ++++ server/src/db/models/Team.js | 14 -------- server/src/db/models/Team.ts | 27 ++++++++++++++ server/src/db/models/index.ts | 3 ++ server/src/repositories/index.ts | 3 ++ .../repositories/teams/ITeamsRepository.ts | 9 +++++ .../teams/MongoTeamsRepository.ts | 36 +++++++++++++++++++ server/src/service/business/userService.ts | 25 +++++++++---- server/src/types/index.ts | 1 + server/src/types/team.ts | 6 ++++ 10 files changed, 110 insertions(+), 21 deletions(-) delete mode 100755 server/src/db/models/Team.js create mode 100755 server/src/db/models/Team.ts create mode 100644 server/src/repositories/teams/ITeamsRepository.ts create mode 100644 server/src/repositories/teams/MongoTeamsRepository.ts create mode 100644 server/src/types/team.ts diff --git a/server/src/config/services.ts b/server/src/config/services.ts index b48738866..8cfcb400b 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -80,6 +80,7 @@ import { MongoSettingsRepository, MongoNotificationsRepository, MongoIncidentRepository, + MongoTeamsRepository, IMonitorsRepository, IChecksRepository, IMonitorStatsRepository, @@ -90,6 +91,7 @@ import { ISettingsRepository, INotificationsRepository, IIncidentsRepository, + ITeamsRepository, } from "@/repositories/index.js"; import { ILogger } from "@/utils/logger.js"; import { EnvConfig } from "@/service/system/settingsService.js"; @@ -124,6 +126,7 @@ export type InitializedServices = { settingsRepository: ISettingsRepository; notificationsRepository: INotificationsRepository; incidentsRepository: IIncidentsRepository; + teamsRepository: ITeamsRepository; }; export const initializeServices = async ({ @@ -171,6 +174,8 @@ export const initializeServices = async ({ const settingsRepository = new MongoSettingsRepository(); const notificationsRepository = new MongoNotificationsRepository(); const incidentsRepository = new MongoIncidentRepository(); + const teamsRepository = new MongoTeamsRepository(); + const networkService = new NetworkService({ axios, got, @@ -254,6 +259,7 @@ export const initializeServices = async ({ invitesRepository, recoveryTokensRepository, settingsRepository, + teamsRepository, }); const diagnosticService = new DiagnosticService(); @@ -311,6 +317,7 @@ export const initializeServices = async ({ settingsRepository, notificationsRepository, incidentsRepository, + teamsRepository, }; return services; diff --git a/server/src/db/models/Team.js b/server/src/db/models/Team.js deleted file mode 100755 index 95337c201..000000000 --- a/server/src/db/models/Team.js +++ /dev/null @@ -1,14 +0,0 @@ -import mongoose from "mongoose"; -const TeamSchema = mongoose.Schema( - { - email: { - type: String, - required: true, - unique: true, - }, - }, - { - timestamps: true, - } -); -export default mongoose.model("Team", TeamSchema); diff --git a/server/src/db/models/Team.ts b/server/src/db/models/Team.ts new file mode 100755 index 000000000..1b177a108 --- /dev/null +++ b/server/src/db/models/Team.ts @@ -0,0 +1,27 @@ +import { Schema, model, type Types } from "mongoose"; + +import type { Team } from "@/types/index.js"; + +interface TeamDocument extends Team { + _id: Types.ObjectId; + createdAt: Date; + updatedAt: Date; +} + +const TeamSchema = new Schema( + { + email: { + type: String, + required: true, + unique: true, + }, + }, + { + timestamps: true, + } +); +const TeamModel = model("Team", TeamSchema); + +export type { TeamDocument }; +export { TeamModel }; +export default TeamModel; diff --git a/server/src/db/models/index.ts b/server/src/db/models/index.ts index 4b71937bb..f762027ec 100644 --- a/server/src/db/models/index.ts +++ b/server/src/db/models/index.ts @@ -27,3 +27,6 @@ export { default as NotificationModel } from "@/db/models/Notification.js"; export * from "@/db/models/Incident.js"; export { default as IncidentModel } from "@/db/models/Incident.js"; + +export * from "@/db/models/Team.js"; +export { default as TeamModel } from "@/db/models/Team.js"; diff --git a/server/src/repositories/index.ts b/server/src/repositories/index.ts index 72dfd2f40..ac5125af9 100644 --- a/server/src/repositories/index.ts +++ b/server/src/repositories/index.ts @@ -27,3 +27,6 @@ export { default as MongoNotificationsRepository } from "@/repositories/notifica export * from "@/repositories/incidents/IIncidentsRepository.js"; export { default as MongoIncidentRepository } from "@/repositories/incidents/MongoIncidentRepository.js"; + +export * from "@/repositories/teams/ITeamsRepository.js"; +export { default as MongoTeamsRepository } from "@/repositories/teams/MongoTeamsRepository.js"; diff --git a/server/src/repositories/teams/ITeamsRepository.ts b/server/src/repositories/teams/ITeamsRepository.ts new file mode 100644 index 000000000..5ba4b36dd --- /dev/null +++ b/server/src/repositories/teams/ITeamsRepository.ts @@ -0,0 +1,9 @@ +import type { Team } from "@/types/index.js"; +export interface ITeamRepository { + // create + create(email: string): Promise; + // fetch + // update + // delete + // other +} diff --git a/server/src/repositories/teams/MongoTeamsRepository.ts b/server/src/repositories/teams/MongoTeamsRepository.ts new file mode 100644 index 000000000..1a2d8ae57 --- /dev/null +++ b/server/src/repositories/teams/MongoTeamsRepository.ts @@ -0,0 +1,36 @@ +import { Team } from "@/types/index.js"; +import { TeamDocument, TeamModel } from "@/db/models/index.js"; +import { ITeamRepository } from "@/repositories/index.js"; +import mongoose from "mongoose"; + +class MongoTeamRepository implements ITeamRepository { + private toStringId = (value?: mongoose.Types.ObjectId | string | null): string => { + if (!value) { + return ""; + } + return value instanceof mongoose.Types.ObjectId ? value.toString() : String(value); + }; + + private toDateString = (value?: Date | string | null): string => { + if (!value) { + return new Date(0).toISOString(); + } + return value instanceof Date ? value.toISOString() : new Date(value).toISOString(); + }; + + private toEntity = (doc: TeamDocument): Team => { + return { + id: this.toStringId(doc._id), + email: doc.email, + createdAt: this.toDateString(doc.createdAt), + updatedAt: this.toDateString(doc.updatedAt), + }; + }; + + create = async (email: string) => { + const team = await TeamModel.create({ email }); + return this.toEntity(team); + }; +} + +export default MongoTeamRepository; diff --git a/server/src/service/business/userService.ts b/server/src/service/business/userService.ts index f6f489b8e..2c31cff9e 100644 --- a/server/src/service/business/userService.ts +++ b/server/src/service/business/userService.ts @@ -1,9 +1,15 @@ -import { IInvitesRepository, IMonitorsRepository, IRecoveryTokensRepository, IUsersRepository, ISettingsRepository } from "@/repositories/index.js"; -import Team from "@/db/models/Team.js"; +import { + IInvitesRepository, + IMonitorsRepository, + IRecoveryTokensRepository, + IUsersRepository, + ISettingsRepository, + ITeamRepository, +} from "@/repositories/index.js"; import type { User } from "@/types/index.js"; import bcrypt from "bcryptjs"; import { AppError } from "@/utils/AppError.js"; -import { ISuperSimpleQueue } from "../infrastructure/SuperSimpleQueue/SuperSimpleQueue.js"; +import { ISuperSimpleQueue } from "@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js"; const SERVICE_NAME = "userService"; @@ -21,6 +27,7 @@ class UserService { private invitesRepository: IInvitesRepository; private recoveryTokensRepository: IRecoveryTokensRepository; private settingsRepository: ISettingsRepository; + private teamsRepository: ITeamRepository; constructor({ crypto, @@ -34,6 +41,7 @@ class UserService { invitesRepository, recoveryTokensRepository, settingsRepository, + teamsRepository, }: { crypto: any; emailService: any; @@ -47,6 +55,7 @@ class UserService { invitesRepository: IInvitesRepository; recoveryTokensRepository: IRecoveryTokensRepository; settingsRepository: ISettingsRepository; + teamsRepository: ITeamRepository; }) { this.emailService = emailService; this.settingsService = settingsService; @@ -59,6 +68,7 @@ class UserService { this.invitesRepository = invitesRepository; this.recoveryTokensRepository = recoveryTokensRepository; this.settingsRepository = settingsRepository; + this.teamsRepository = teamsRepository; } get serviceName() { @@ -85,10 +95,11 @@ class UserService { const jwtSecret = this.crypto.randomBytes(64).toString("hex"); await this.settingsRepository.update({ jwtSecret }); // Create a new team - const team = new Team({ - email: user.email, - }); - user.teamId = team._id; + if (!user.email) { + throw new AppError({ message: "Email is required for first user", service: SERVICE_NAME, method: "registerUser", status: 400 }); + } + const team = await this.teamsRepository.create(user.email); + user.teamId = team.id; } const newUser = await this.usersRepository.create({ ...user }, file); diff --git a/server/src/types/index.ts b/server/src/types/index.ts index b0b6b07c5..9464622ac 100644 --- a/server/src/types/index.ts +++ b/server/src/types/index.ts @@ -11,3 +11,4 @@ export * from "@/types/notification.js"; export * from "@/types/alert.js"; export * from "@/types/incident.js"; export * from "@/types/email.js"; +export * from "@/types/team.js"; diff --git a/server/src/types/team.ts b/server/src/types/team.ts new file mode 100644 index 000000000..1bca943a0 --- /dev/null +++ b/server/src/types/team.ts @@ -0,0 +1,6 @@ +export interface Team { + id: string; + email: string; + createdAt: string; + updatedAt: string; +} From 5b96075c0358854e1849b3e5b97a6b993696fe82 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 21 Jan 2026 11:56:05 -0800 Subject: [PATCH 4/4] build errs --- server/src/db/models/Team.ts | 3 ++- server/src/repositories/teams/ITeamsRepository.ts | 2 +- server/src/repositories/teams/MongoTeamsRepository.ts | 6 +++--- server/src/service/business/userService.ts | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/server/src/db/models/Team.ts b/server/src/db/models/Team.ts index 1b177a108..608f90ad8 100755 --- a/server/src/db/models/Team.ts +++ b/server/src/db/models/Team.ts @@ -2,7 +2,8 @@ import { Schema, model, type Types } from "mongoose"; import type { Team } from "@/types/index.js"; -interface TeamDocument extends Team { +type TeamDocumentBase = Omit & {}; +interface TeamDocument extends TeamDocumentBase { _id: Types.ObjectId; createdAt: Date; updatedAt: Date; diff --git a/server/src/repositories/teams/ITeamsRepository.ts b/server/src/repositories/teams/ITeamsRepository.ts index 5ba4b36dd..9ccdd97fb 100644 --- a/server/src/repositories/teams/ITeamsRepository.ts +++ b/server/src/repositories/teams/ITeamsRepository.ts @@ -1,5 +1,5 @@ import type { Team } from "@/types/index.js"; -export interface ITeamRepository { +export interface ITeamsRepository { // create create(email: string): Promise; // fetch diff --git a/server/src/repositories/teams/MongoTeamsRepository.ts b/server/src/repositories/teams/MongoTeamsRepository.ts index 1a2d8ae57..93a306787 100644 --- a/server/src/repositories/teams/MongoTeamsRepository.ts +++ b/server/src/repositories/teams/MongoTeamsRepository.ts @@ -1,9 +1,9 @@ import { Team } from "@/types/index.js"; import { TeamDocument, TeamModel } from "@/db/models/index.js"; -import { ITeamRepository } from "@/repositories/index.js"; +import { ITeamsRepository } from "@/repositories/index.js"; import mongoose from "mongoose"; -class MongoTeamRepository implements ITeamRepository { +class MongoTeamsRepository implements ITeamsRepository { private toStringId = (value?: mongoose.Types.ObjectId | string | null): string => { if (!value) { return ""; @@ -33,4 +33,4 @@ class MongoTeamRepository implements ITeamRepository { }; } -export default MongoTeamRepository; +export default MongoTeamsRepository; diff --git a/server/src/service/business/userService.ts b/server/src/service/business/userService.ts index 2c31cff9e..b9883f594 100644 --- a/server/src/service/business/userService.ts +++ b/server/src/service/business/userService.ts @@ -4,7 +4,7 @@ import { IRecoveryTokensRepository, IUsersRepository, ISettingsRepository, - ITeamRepository, + ITeamsRepository, } from "@/repositories/index.js"; import type { User } from "@/types/index.js"; import bcrypt from "bcryptjs"; @@ -27,7 +27,7 @@ class UserService { private invitesRepository: IInvitesRepository; private recoveryTokensRepository: IRecoveryTokensRepository; private settingsRepository: ISettingsRepository; - private teamsRepository: ITeamRepository; + private teamsRepository: ITeamsRepository; constructor({ crypto, @@ -55,7 +55,7 @@ class UserService { invitesRepository: IInvitesRepository; recoveryTokensRepository: IRecoveryTokensRepository; settingsRepository: ISettingsRepository; - teamsRepository: ITeamRepository; + teamsRepository: ITeamsRepository; }) { this.emailService = emailService; this.settingsService = settingsService;