add v2 models
This commit is contained in:
1 parent
b118a321b9
commit
059408f098
9 files changed
+797
No files matched your search
@@ -0,0 +1,50 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
|
||||
export interface IRole extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
description?: string;
|
||||
permissions: string[];
|
||||
isSystem: boolean;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const roleSchema = new Schema<IRole>(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
maxlength: 50,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
trim: true,
|
||||
maxlength: 200,
|
||||
},
|
||||
|
||||
permissions: [
|
||||
{
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
isSystem: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
roleSchema.index({ name: 1 }, { unique: true });
|
||||
|
||||
export const Role = mongoose.model<IRole>("Role_v2", roleSchema);
|
||||
@@ -0,0 +1,108 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
|
||||
export interface ITokenizedUser {
|
||||
sub: string;
|
||||
roles: string[];
|
||||
}
|
||||
export interface IUser extends Document {
|
||||
_id: Types.ObjectId;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
passwordHash: string;
|
||||
roles: Types.ObjectId[];
|
||||
profile: {
|
||||
avatar?: string;
|
||||
bio?: string;
|
||||
timezone: string;
|
||||
locale: string;
|
||||
};
|
||||
preferences: {
|
||||
theme: "light" | "dark" | "system";
|
||||
};
|
||||
lastLoginAt?: Date;
|
||||
isActive: boolean;
|
||||
isVerified: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const userSchema = new Schema<IUser>(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
trim: true,
|
||||
lowercase: true,
|
||||
},
|
||||
firstName: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
maxlength: 50,
|
||||
},
|
||||
lastName: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
maxlength: 50,
|
||||
},
|
||||
passwordHash: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
roles: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Role_v2",
|
||||
},
|
||||
],
|
||||
profile: {
|
||||
avatar: {
|
||||
type: String,
|
||||
},
|
||||
bio: {
|
||||
type: String,
|
||||
maxlength: 200,
|
||||
},
|
||||
timezone: {
|
||||
type: String,
|
||||
default: "UTC",
|
||||
},
|
||||
locale: {
|
||||
type: String,
|
||||
default: "en",
|
||||
},
|
||||
},
|
||||
preferences: {
|
||||
theme: {
|
||||
type: String,
|
||||
enum: ["light", "dark", "system"],
|
||||
default: "system",
|
||||
},
|
||||
},
|
||||
lastLoginAt: {
|
||||
type: Date,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isVerified: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: {
|
||||
transform: function (_doc, ret) {
|
||||
delete ret.passwordHash;
|
||||
return ret;
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const User = mongoose.model<IUser>("User_v2", userSchema);
|
||||
@@ -0,0 +1,297 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
import { MonitorType, MonitorTypes, MonitorStatus, MonitorStatuses } from "../monitors/Monitor.js";
|
||||
import type { Response } from "got";
|
||||
export type GotTimings = Response["timings"];
|
||||
export interface ITimingPhases {
|
||||
wait: number;
|
||||
dns: number;
|
||||
tcp: number;
|
||||
tls: number;
|
||||
request: number;
|
||||
firstByte: number;
|
||||
download: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface ICpuInfo {
|
||||
physical_core: number;
|
||||
logical_core: number;
|
||||
frequency: number;
|
||||
current_frequency: number;
|
||||
temperature: number[]; // per-core temps
|
||||
free_percent: number;
|
||||
usage_percent: number;
|
||||
}
|
||||
|
||||
export interface IMemoryInfo {
|
||||
total_bytes: number;
|
||||
available_bytes: number;
|
||||
used_bytes: number;
|
||||
usage_percent: number;
|
||||
}
|
||||
|
||||
export interface IHostInfo {
|
||||
os?: string;
|
||||
platform?: string;
|
||||
kernel_version?: string;
|
||||
pretty_name?: string;
|
||||
}
|
||||
|
||||
export interface IDiskInfo {
|
||||
device: string;
|
||||
total_bytes: number;
|
||||
free_bytes: number;
|
||||
used_bytes: number;
|
||||
usage_percent: number;
|
||||
total_inodes?: number;
|
||||
free_inodes?: number;
|
||||
used_inodes?: number;
|
||||
inodes_usage_percent?: number;
|
||||
read_bytes?: number;
|
||||
write_bytes?: number;
|
||||
read_time?: number;
|
||||
write_time?: number;
|
||||
}
|
||||
|
||||
export interface INetInfo {
|
||||
name: string;
|
||||
bytes_sent: number;
|
||||
bytes_recv: number;
|
||||
packets_sent: number;
|
||||
packets_recv: number;
|
||||
err_in: number;
|
||||
err_out: number;
|
||||
drop_in: number;
|
||||
drop_out: number;
|
||||
fifo_in: number;
|
||||
fifo_out: number;
|
||||
}
|
||||
|
||||
export interface ICaptureInfo {
|
||||
version?: string;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
export interface ISystemInfo {
|
||||
cpu: ICpuInfo;
|
||||
memory: IMemoryInfo;
|
||||
disk: IDiskInfo[];
|
||||
host: IHostInfo;
|
||||
net: INetInfo[];
|
||||
}
|
||||
|
||||
export interface ILighthouseAudit {
|
||||
id?: string;
|
||||
title?: string;
|
||||
score?: number | null;
|
||||
displayValue?: string;
|
||||
numericValue?: number;
|
||||
numericUnit?: string;
|
||||
}
|
||||
export interface ILighthouseCategories {
|
||||
accessibility?: { score?: number | null };
|
||||
"best-practices"?: { score?: number | null };
|
||||
seo?: { score?: number | null };
|
||||
performance?: { score?: number | null };
|
||||
}
|
||||
|
||||
export interface ILighthouseResult {
|
||||
categories?: ILighthouseCategories;
|
||||
audits?: Record<string, ILighthouseAudit>;
|
||||
}
|
||||
|
||||
export interface ICheckLighthouseFields {
|
||||
accessibility: number;
|
||||
bestPractices: number;
|
||||
seo: number;
|
||||
performance: number;
|
||||
audits: {
|
||||
cls: ILighthouseAudit;
|
||||
si: ILighthouseAudit;
|
||||
fcp: ILighthouseAudit;
|
||||
lcp: ILighthouseAudit;
|
||||
tbt: ILighthouseAudit;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICheck extends Document {
|
||||
_id: Types.ObjectId;
|
||||
monitorId: Types.ObjectId;
|
||||
type: MonitorType;
|
||||
status: MonitorStatus;
|
||||
message: string;
|
||||
responseTime?: number; // in ms
|
||||
timings?: GotTimings;
|
||||
httpStatusCode?: number;
|
||||
errorMessage?: string;
|
||||
ack: boolean;
|
||||
ackAt?: Date;
|
||||
ackBy?: Types.ObjectId;
|
||||
expiry: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
system?: ISystemInfo;
|
||||
capture?: ICaptureInfo;
|
||||
lighthouse?: ICheckLighthouseFields;
|
||||
}
|
||||
|
||||
const CheckSchema = new Schema<ICheck>(
|
||||
{
|
||||
monitorId: { type: Schema.Types.ObjectId, ref: "Monitor_v2", required: true },
|
||||
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: MonitorTypes,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: MonitorStatuses,
|
||||
},
|
||||
message: { type: String, trim: true },
|
||||
responseTime: { type: Number },
|
||||
timings: {
|
||||
start: { type: Date },
|
||||
socket: { type: Date },
|
||||
lookup: { type: Date },
|
||||
connect: { type: Date },
|
||||
secureConnect: { type: Date },
|
||||
response: { type: Date },
|
||||
end: { type: Date },
|
||||
phases: {
|
||||
wait: { type: Number },
|
||||
dns: { type: Number },
|
||||
tcp: { type: Number },
|
||||
tls: { type: Number },
|
||||
request: { type: Number },
|
||||
firstByte: { type: Number },
|
||||
download: { type: Number },
|
||||
total: { type: Number },
|
||||
},
|
||||
},
|
||||
system: {
|
||||
type: {
|
||||
cpu: {
|
||||
physical_core: { type: Number },
|
||||
logical_core: { type: Number },
|
||||
frequency: { type: Number },
|
||||
current_frequency: { type: Number },
|
||||
temperature: [{ type: Number }],
|
||||
free_percent: { type: Number },
|
||||
usage_percent: { type: Number },
|
||||
},
|
||||
memory: {
|
||||
total_bytes: { type: Number },
|
||||
available_bytes: { type: Number },
|
||||
used_bytes: { type: Number },
|
||||
usage_percent: { type: Number },
|
||||
},
|
||||
disk: [
|
||||
{
|
||||
device: { type: String },
|
||||
total_bytes: { type: Number },
|
||||
free_bytes: { type: Number },
|
||||
used_bytes: { type: Number },
|
||||
usage_percent: { type: Number },
|
||||
total_inodes: { type: Number },
|
||||
free_inodes: { type: Number },
|
||||
used_inodes: { type: Number },
|
||||
inodes_usage_percent: { type: Number },
|
||||
read_bytes: { type: Number },
|
||||
write_bytes: { type: Number },
|
||||
read_time: { type: Number },
|
||||
write_time: { type: Number },
|
||||
},
|
||||
],
|
||||
host: {
|
||||
os: { type: String },
|
||||
platform: { type: String },
|
||||
kernel_version: { type: String },
|
||||
pretty_name: { type: String },
|
||||
},
|
||||
net: [
|
||||
{
|
||||
name: { type: String },
|
||||
bytes_sent: { type: Number },
|
||||
bytes_recv: { type: Number },
|
||||
packets_sent: { type: Number },
|
||||
packets_recv: { type: Number },
|
||||
err_in: { type: Number },
|
||||
err_out: { type: Number },
|
||||
drop_in: { type: Number },
|
||||
drop_out: { type: Number },
|
||||
fifo_in: { type: Number },
|
||||
fifo_out: { type: Number },
|
||||
},
|
||||
],
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
|
||||
capture: {
|
||||
type: {
|
||||
version: { type: String },
|
||||
mode: { type: String },
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
lighthouse: {
|
||||
accessibility: { type: Number, required: false },
|
||||
bestPractices: { type: Number, required: false },
|
||||
seo: { type: Number, required: false },
|
||||
performance: { type: Number, required: false },
|
||||
audits: {
|
||||
cls: {
|
||||
type: Object,
|
||||
},
|
||||
si: {
|
||||
type: Object,
|
||||
},
|
||||
fcp: {
|
||||
type: Object,
|
||||
},
|
||||
lcp: {
|
||||
type: Object,
|
||||
},
|
||||
tbt: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
type: {
|
||||
accessibility: { type: Number },
|
||||
bestPractices: { type: Number },
|
||||
seo: { type: Number },
|
||||
performance: { type: Number },
|
||||
audits: {
|
||||
cls: { type: Object },
|
||||
si: { type: Object },
|
||||
fcp: { type: Object },
|
||||
lcp: { type: Object },
|
||||
tbt: { type: Object },
|
||||
},
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
|
||||
httpStatusCode: { type: Number },
|
||||
errorMessage: { type: String, trim: true },
|
||||
ack: { type: Boolean, required: true, default: false },
|
||||
ackAt: { type: Date },
|
||||
ackBy: { type: Schema.Types.ObjectId, ref: "User_v2" },
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 60 * 60 * 24 * 30,
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
CheckSchema.index({ monitorId: 1, createdAt: -1 });
|
||||
CheckSchema.index({ status: 1 });
|
||||
CheckSchema.index({ status: 1, ack: 1 });
|
||||
CheckSchema.index({ ack: 1, ackAt: 1 });
|
||||
CheckSchema.index({ createdAt: -1 });
|
||||
|
||||
export const Check = mongoose.model<ICheck>("Check_v2", CheckSchema);
|
||||
@@ -0,0 +1,33 @@
|
||||
export { User } from "./auth/User.js";
|
||||
export type { IUser } from "./auth/User.js";
|
||||
export type { ITokenizedUser } from "./auth/User.js";
|
||||
export { Role } from "./auth/Role.js";
|
||||
export type { IRole } from "./auth/Role.js";
|
||||
export { connectDatabase, disconnectDatabase } from "../index.js";
|
||||
export { Monitor } from "./monitors/Monitor.js";
|
||||
export { MonitorStatuses } from "./monitors/Monitor.js";
|
||||
export type { IMonitor } from "./monitors/Monitor.js";
|
||||
export { Check } from "./checks/Check.js";
|
||||
export type {
|
||||
ICheck,
|
||||
ISystemInfo,
|
||||
ICaptureInfo,
|
||||
INetInfo,
|
||||
IDiskInfo,
|
||||
IHostInfo,
|
||||
IMemoryInfo,
|
||||
ICpuInfo,
|
||||
ILighthouseAudit,
|
||||
ITimingPhases,
|
||||
ILighthouseCategories,
|
||||
ILighthouseResult,
|
||||
ICheckLighthouseFields,
|
||||
} from "./checks/Check.js";
|
||||
export type { IMonitorStats } from "./monitors/MonitorStats.js";
|
||||
export { MonitorStats } from "./monitors/MonitorStats.js";
|
||||
export type { INotificationChannel } from "./notification-channel/NotificationChannel.js";
|
||||
export { NotificationChannel } from "./notification-channel/NotificationChannel.js";
|
||||
export type { IMaintenance } from "./maintenance/Maintenance.js";
|
||||
export { Maintenance } from "./maintenance/Maintenance.js";
|
||||
export type { IInvite } from "./invite/Invite.js";
|
||||
export { Invite } from "./invite/Invite.js";
|
||||
@@ -0,0 +1,43 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
|
||||
export interface IInvite extends Document {
|
||||
_id: Types.ObjectId;
|
||||
email: string;
|
||||
tokenHash: string;
|
||||
roles: Types.ObjectId[];
|
||||
createdBy: Types.ObjectId;
|
||||
updatedBy: Types.ObjectId;
|
||||
expiry: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const InviteSchema = new Schema<IInvite>(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
trim: true,
|
||||
lowercase: true,
|
||||
},
|
||||
roles: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Role_v2",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
tokenHash: { type: String, required: true, unique: true },
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 60 * 60 * 24,
|
||||
},
|
||||
createdBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
updatedBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export const Invite = mongoose.model<IInvite>("Invite_v2", InviteSchema);
|
||||
@@ -0,0 +1,39 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
|
||||
export interface IMaintenance extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
monitors: Types.ObjectId[];
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
createdBy: Types.ObjectId;
|
||||
updatedBy: Types.ObjectId;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const MaintenanceSchema = new Schema<IMaintenance>(
|
||||
{
|
||||
name: { type: String, required: true, trim: true },
|
||||
isActive: { type: Boolean, required: true, default: true },
|
||||
monitors: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "Monitor_v2",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
startTime: { type: Date, required: true },
|
||||
endTime: { type: Date, required: true },
|
||||
createdBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
updatedBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
MaintenanceSchema.index({ isActive: 1 });
|
||||
MaintenanceSchema.index({ startTime: 1 });
|
||||
MaintenanceSchema.index({ endTime: 1 });
|
||||
|
||||
export const Maintenance = mongoose.model<IMaintenance>("Maintenance_v2", MaintenanceSchema);
|
||||
@@ -0,0 +1,100 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
import { Check, MonitorStats } from "../index.js";
|
||||
|
||||
export const MonitorTypes = ["http", "https", "ping", "infrastructure", "pagespeed"] as const;
|
||||
export type MonitorType = (typeof MonitorTypes)[number];
|
||||
|
||||
export const MonitorStatuses = ["up", "down", "paused", "initializing"] as const;
|
||||
export type MonitorStatus = (typeof MonitorStatuses)[number];
|
||||
export interface IMonitor extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
url: string;
|
||||
secret?: string;
|
||||
type: MonitorType;
|
||||
interval: number; // in ms
|
||||
isActive: boolean;
|
||||
status: MonitorStatus;
|
||||
n: number; // Number of consecutive successes required to change status
|
||||
lastCheckedAt?: Date;
|
||||
latestChecks: {
|
||||
status: MonitorStatus;
|
||||
responseTime: number;
|
||||
checkedAt: Date;
|
||||
}[];
|
||||
notificationChannels?: Types.ObjectId[];
|
||||
createdBy: Types.ObjectId;
|
||||
updatedBy: Types.ObjectId;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const MonitorSchema = new Schema<IMonitor>(
|
||||
{
|
||||
name: { type: String, required: true, trim: true, maxlength: 100 },
|
||||
url: { type: String, required: true, trim: true },
|
||||
secret: { type: String, required: false },
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: MonitorTypes,
|
||||
},
|
||||
interval: { type: Number, required: true, default: 60000 },
|
||||
isActive: { type: Boolean, required: true, default: true },
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "initializing",
|
||||
enum: MonitorStatuses,
|
||||
},
|
||||
n: { type: Number, required: true, default: 1 },
|
||||
lastCheckedAt: { type: Date },
|
||||
latestChecks: {
|
||||
type: [
|
||||
{
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: MonitorStatuses,
|
||||
},
|
||||
responseTime: { type: Number, required: true },
|
||||
checkedAt: { type: Date, required: true },
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
},
|
||||
notificationChannels: [
|
||||
{
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "NotificationChannel_v2",
|
||||
required: false,
|
||||
default: [],
|
||||
},
|
||||
],
|
||||
|
||||
createdBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
updatedBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
MonitorSchema.pre("deleteOne", { document: true, query: false }, async function (next) {
|
||||
try {
|
||||
const monitorId = this._id;
|
||||
await Check.deleteMany({ monitorId });
|
||||
await MonitorStats.deleteMany({ monitorId });
|
||||
next();
|
||||
} catch (error: any) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
MonitorSchema.index({ isActive: 1 });
|
||||
MonitorSchema.index({ status: 1 });
|
||||
MonitorSchema.index({ type: 1 });
|
||||
MonitorSchema.index({ lastCheckedAt: 1 });
|
||||
MonitorSchema.index({ isActive: 1, status: 1 });
|
||||
MonitorSchema.index({ createdBy: 1 });
|
||||
MonitorSchema.index({ updatedBy: 1 });
|
||||
|
||||
export const Monitor = mongoose.model<IMonitor>("Monitor_v2", MonitorSchema);
|
||||
@@ -0,0 +1,77 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
import { MonitorStatus, MonitorStatuses } from "./Monitor.js";
|
||||
|
||||
export interface IMonitorStats extends mongoose.Document {
|
||||
monitorId: mongoose.Types.ObjectId;
|
||||
avgResponseTime: number;
|
||||
maxResponseTime: number;
|
||||
totalChecks: number;
|
||||
totalUpChecks: number;
|
||||
totalDownChecks: number;
|
||||
uptimePercentage: number;
|
||||
lastCheckTimestamp: number;
|
||||
lastResponseTime: number;
|
||||
timeOfLastFailure: number;
|
||||
currentStreak: number;
|
||||
currentStreakStatus: MonitorStatus;
|
||||
currentStreakStartedAt: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const MonitorStatsSchema = new Schema<IMonitorStats>(
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor_v2",
|
||||
immutable: true,
|
||||
index: true,
|
||||
},
|
||||
avgResponseTime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
maxResponseTime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
lastResponseTime: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
totalChecks: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
totalUpChecks: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
totalDownChecks: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
uptimePercentage: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
lastCheckTimestamp: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
timeOfLastFailure: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
currentStreak: { type: Number, required: false, default: 0 },
|
||||
currentStreakStatus: {
|
||||
type: String,
|
||||
required: false,
|
||||
enum: MonitorStatuses,
|
||||
},
|
||||
currentStreakStartedAt: { type: Number, required: false },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export const MonitorStats = mongoose.model<IMonitorStats>("MonitorStats_v2", MonitorStatsSchema);
|
||||
@@ -0,0 +1,50 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
export const ChannelTypes = ["email", "slack", "discord", "webhook"] as const;
|
||||
export type ChannelType = (typeof ChannelTypes)[number];
|
||||
|
||||
export interface INotificationChannelConfig {
|
||||
url?: string; // For webhook, slack, discord
|
||||
emailAddress?: string; // For email
|
||||
}
|
||||
|
||||
export interface INotificationChannel {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
type: ChannelType;
|
||||
config: INotificationChannelConfig;
|
||||
isActive: boolean;
|
||||
createdBy: Types.ObjectId;
|
||||
updatedBy: Types.ObjectId;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const NotificationChannelConfigSchema = new Schema<INotificationChannelConfig>(
|
||||
{
|
||||
url: { type: String, required: false },
|
||||
emailAddress: { type: String, required: false },
|
||||
},
|
||||
{ _id: false, strict: "throw" }
|
||||
);
|
||||
|
||||
const NotificationChannelSchema = new Schema<INotificationChannel>(
|
||||
{
|
||||
name: { type: String, required: true, trim: true },
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: ChannelTypes,
|
||||
},
|
||||
config: { type: NotificationChannelConfigSchema, required: true },
|
||||
isActive: { type: Boolean, required: true, default: true },
|
||||
createdBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
updatedBy: { type: Schema.Types.ObjectId, ref: "User_v2", required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
NotificationChannelSchema.index({ isActive: 1 });
|
||||
NotificationChannelSchema.index({ type: 1 });
|
||||
NotificationChannelSchema.index({ type: 1, isActive: 1 });
|
||||
|
||||
export const NotificationChannel = mongoose.model<INotificationChannel>("NotificationChannel_v2", NotificationChannelSchema);
|
||||
Reference in new issue
Block a user