use repos
This commit is contained in:
1 parent
052b9377bc
commit
61bf2a0dfb
28 files changed
+589
-113
No files matched your search
@@ -1,6 +1,8 @@
|
||||
import mongoose, { Schema, Document, Types } from "mongoose";
|
||||
export const MaintenanceRepeats = ["no repeat", "daily", "weekly"] as const;
|
||||
export type MaintenanceRepeat = (typeof MaintenanceRepeats)[number];
|
||||
import {
|
||||
type MaintenanceRepeat,
|
||||
MaintenanceRepeats,
|
||||
} from "@/types/domain/index.js";
|
||||
export interface IMaintenance extends Document {
|
||||
_id: Types.ObjectId;
|
||||
orgId: Types.ObjectId;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import mongoose, { Schema } from "mongoose";
|
||||
import type { IStatsBase } from "./StatsHourly.js";
|
||||
|
||||
import type {
|
||||
IInfraCpu,
|
||||
IInfraDiskEntry,
|
||||
@@ -6,8 +8,7 @@ import type {
|
||||
IInfraMemory,
|
||||
IInfraNetEntry,
|
||||
IPageSpeedMetrics,
|
||||
IStatsBase,
|
||||
} from "./StatsHourly.js";
|
||||
} from "@/types/domain/index.js";
|
||||
|
||||
export interface IStatsDaily
|
||||
extends mongoose.Document,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import mongoose, { Schema, Types } from "mongoose";
|
||||
import type { MonitorType } from "@/types/domain/index.js";
|
||||
import type {
|
||||
IInfraCpu,
|
||||
IPageSpeedMetrics,
|
||||
IInfraMemory,
|
||||
IInfraDiskEntry,
|
||||
IInfraHost,
|
||||
IInfraNetEntry,
|
||||
MonitorType,
|
||||
} from "@/types/domain/index.js";
|
||||
|
||||
// Common/base metrics across monitor types
|
||||
export interface IStatsBase {
|
||||
@@ -19,74 +27,6 @@ export interface IStatsBase {
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// Pagespeed rollups (averages per window)
|
||||
export interface IPageSpeedMetrics {
|
||||
accessibility?: number;
|
||||
bestPractices?: number;
|
||||
seo?: number;
|
||||
performance?: number;
|
||||
cls?: number;
|
||||
si?: number;
|
||||
fcp?: number;
|
||||
lcp?: number;
|
||||
tbt?: number;
|
||||
}
|
||||
|
||||
// Infrastructure rollups
|
||||
export interface IInfraCpu {
|
||||
physical_core?: number;
|
||||
logical_core?: number;
|
||||
frequency?: number;
|
||||
current_frequency?: number;
|
||||
temperature?: number[]; // averaged per sensor index
|
||||
free_percent?: number;
|
||||
used_percent?: number;
|
||||
}
|
||||
|
||||
export interface IInfraMemory {
|
||||
total_bytes?: number;
|
||||
available_bytes?: number;
|
||||
used_bytes?: number;
|
||||
usage_percent?: number;
|
||||
}
|
||||
|
||||
export interface IInfraDiskEntry {
|
||||
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 IInfraHost {
|
||||
os?: string;
|
||||
platform?: string;
|
||||
kernel_version?: string;
|
||||
pretty_name?: string;
|
||||
}
|
||||
|
||||
export interface IInfraNetEntry {
|
||||
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 IStatsHourly
|
||||
extends mongoose.Document,
|
||||
IStatsBase,
|
||||
|
||||
@@ -38,17 +38,29 @@ import {
|
||||
MongoChecksRepository,
|
||||
MongoMonitorStatsRepository,
|
||||
MongoIncidentsRepository,
|
||||
MongoUserRepository,
|
||||
MongoRoleRepository,
|
||||
MongoTeamRepository,
|
||||
MongoInviteRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import type { CheckEntity } from "@/types/domain/index.js";
|
||||
|
||||
export const initServices = async () => {
|
||||
const monitorRepository = new MongoMonitorRepository();
|
||||
const checksRepository = new MongoChecksRepository();
|
||||
const monitorStatsRepository = new MongoMonitorStatsRepository();
|
||||
const incidentsRepository = new MongoIncidentsRepository();
|
||||
const userRepository = new MongoUserRepository();
|
||||
const roleRepository = new MongoRoleRepository();
|
||||
const teamRepository = new MongoTeamRepository();
|
||||
const inviteRepository = new MongoInviteRepository();
|
||||
|
||||
const checkService = new CheckService(checksRepository, monitorRepository);
|
||||
const inviteService = new InviteService();
|
||||
const inviteService = new InviteService(
|
||||
userRepository,
|
||||
roleRepository,
|
||||
teamRepository,
|
||||
inviteRepository
|
||||
);
|
||||
const maintenanceService = new MaintenanceService();
|
||||
const monitorStatsService = new MonitorStatsService(
|
||||
monitorRepository,
|
||||
|
||||
@@ -12,3 +12,18 @@ export { default as MongoMonitorStatsRepository } from "@/repositories/monitor-s
|
||||
|
||||
export type { IIncidentsRepository } from "@/repositories/incidents/IIncidentsRepository.js";
|
||||
export { default as MongoIncidentsRepository } from "@/repositories/incidents/MongoIncidentsRepository.js";
|
||||
|
||||
export type { IUserRepository } from "@/repositories/user/IUserRepository.js";
|
||||
export { default as MongoUserRepository } from "@/repositories/user/MongoUserRepository.js";
|
||||
|
||||
export type { IInviteRepository } from "@/repositories/invites/IInviteRepository.js";
|
||||
export { default as MongoInviteRepository } from "@/repositories/invites/MongoInviteRepository.js";
|
||||
|
||||
export type { IRoleRepository } from "@/repositories/role/IRoleRepository.js";
|
||||
export { default as MongoRoleRepository } from "@/repositories/role/MongoRoleRepository.js";
|
||||
|
||||
export type { ITeamRepository } from "@/repositories/team/ITeamRepository.js";
|
||||
export { default as MongoTeamRepository } from "@/repositories/team/MongoTeamRepository.js";
|
||||
|
||||
export type { ITeamMembershipRepository } from "@/repositories/team-membership/ITeamMembershipRepository.js";
|
||||
export { default as MongoTeamMembershipRepository } from "@/repositories/team-membership/MongoTeamMembershipRepository.js";
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Invite } from "@/types/domain/index.js";
|
||||
|
||||
export interface IInviteRepository {
|
||||
// create
|
||||
create(inviteData: Partial<Invite>): Promise<Invite | null>;
|
||||
// single fetch
|
||||
findByEmail(email: string, teamId: string): Promise<Invite | null>;
|
||||
findByHash(tokenHash: string): Promise<Invite | null>;
|
||||
// collection fetch
|
||||
findAll(): Promise<Invite[]>;
|
||||
// update
|
||||
// delete
|
||||
deleteById(id: string): Promise<boolean>;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { type IInvite, Invite } from "@/db/models/index.js";
|
||||
import type { IInviteRepository } from "@/repositories/index.js";
|
||||
import { Invite as InviteEntity } from "@/types/domain/index.js";
|
||||
import ApiError from "@/utils/ApiError.js";
|
||||
|
||||
class MongoInviteRepository implements IInviteRepository {
|
||||
private toEntity = (doc: IInvite): InviteEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
orgId: doc.orgId.toString(),
|
||||
orgRoleId: doc.orgRoleId?.toString(),
|
||||
teamId: doc.teamId.toString(),
|
||||
teamRoleId: doc.teamRoleId.toString(),
|
||||
email: doc.email,
|
||||
tokenHash: doc.tokenHash,
|
||||
createdBy: doc.createdBy.toString(),
|
||||
updatedBy: doc.updatedBy.toString(),
|
||||
expiry: doc.expiry,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
create = async (inviteData: Partial<InviteEntity>) => {
|
||||
const {
|
||||
orgId,
|
||||
orgRoleId,
|
||||
teamId,
|
||||
teamRoleId,
|
||||
email,
|
||||
tokenHash,
|
||||
createdBy,
|
||||
updatedBy,
|
||||
} = inviteData;
|
||||
const invite = await Invite.create({
|
||||
orgId,
|
||||
...(orgRoleId && { orgRoleId }),
|
||||
teamId,
|
||||
teamRoleId,
|
||||
email,
|
||||
tokenHash,
|
||||
createdBy,
|
||||
updatedBy,
|
||||
});
|
||||
if (!invite) {
|
||||
return null;
|
||||
}
|
||||
return this.toEntity(invite);
|
||||
};
|
||||
|
||||
findByEmail = async (email: string, teamId: string) => {
|
||||
const invite = await Invite.findOne({
|
||||
email,
|
||||
teamId,
|
||||
});
|
||||
if (!invite) {
|
||||
return null;
|
||||
}
|
||||
return this.toEntity(invite);
|
||||
};
|
||||
|
||||
findByHash = async (tokenHash: string) => {
|
||||
const invite = await Invite.findOne({ tokenHash });
|
||||
if (!invite) return null;
|
||||
return this.toEntity(invite);
|
||||
};
|
||||
|
||||
findAll = async () => {
|
||||
const invites = await Invite.find();
|
||||
return invites.map(this.toEntity);
|
||||
};
|
||||
deleteById = async (id: string) => {
|
||||
const result = await Invite.deleteOne({ _id: id });
|
||||
|
||||
if (!result.deletedCount) {
|
||||
throw new ApiError("Invite not found", 404);
|
||||
}
|
||||
return result.deletedCount === 1;
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoInviteRepository;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Role } from "@/types/domain/index.js";
|
||||
|
||||
export interface IRoleRepository {
|
||||
// create
|
||||
// single fetch
|
||||
findById(roleId: string, orgId: string): Promise<Role | null>;
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { IRoleRepository } from "./IRoleRepository.js";
|
||||
import { Role } from "@/db/models/index.js";
|
||||
import type { IRole } from "@/db/models/index.js";
|
||||
import { Role as RoleEntity } from "@/types/domain/index.js";
|
||||
class MongoRoleRepository implements IRoleRepository {
|
||||
private toEntity = (doc: IRole): RoleEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
organizationId: doc.organizationId.toString(),
|
||||
name: doc.name,
|
||||
scope: doc.scope,
|
||||
permissions: doc.permissions,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
findById = async (roleId: string, orgId: string) => {
|
||||
const role = await Role.findOne({
|
||||
_id: roleId,
|
||||
organizationId: orgId,
|
||||
});
|
||||
if (!role) {
|
||||
return null;
|
||||
}
|
||||
return this.toEntity(role);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoRoleRepository;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { TeamMembership } from "@/types/domain/index.js";
|
||||
export interface ITeamMembershipRepository {
|
||||
// create
|
||||
// single fetch
|
||||
findByUserId(userId: string, teamId: string): Promise<TeamMembership | null>;
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { type ITeamMembership, TeamMembership } from "@/db/models/index.js";
|
||||
import type { ITeamMembershipRepository } from "@/repositories/index.js";
|
||||
import { TeamMembership as TeamMembershipEntity } from "@/types/domain/index.js";
|
||||
class MongoTeamMembershipRepository implements ITeamMembershipRepository {
|
||||
private toEntity = (doc: ITeamMembership): TeamMembershipEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
orgId: doc.orgId.toString(),
|
||||
teamId: doc.teamId.toString(),
|
||||
userId: doc.userId.toString(),
|
||||
roleId: doc.roleId.toString(),
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
findByUserId = async (userId: string, teamId: string) => {
|
||||
const membership = await TeamMembership.findOne({
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
if (!membership) return null;
|
||||
return this.toEntity(membership);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoTeamMembershipRepository;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Team } from "@/types/domain/index.js";
|
||||
|
||||
export interface ITeamRepository {
|
||||
// create
|
||||
// single fetch
|
||||
findById(teamId: string, orgId: string): Promise<Team | null>;
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { ITeamRepository } from "@/repositories/index.js";
|
||||
import { type ITeam, Team } from "@/db/models/index.js";
|
||||
import { Team as TeamEntity } from "@/types/domain/index.js";
|
||||
class MongoTeamRepository implements ITeamRepository {
|
||||
private toEntity = (doc: ITeam): TeamEntity => {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
orgId: doc.orgId.toString(),
|
||||
name: doc.name,
|
||||
description: doc.description,
|
||||
isSystem: doc.isSystem,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
findById = async (teamId: string, orgId: string) => {
|
||||
const team = await Team.findOne({
|
||||
_id: teamId,
|
||||
orgId,
|
||||
});
|
||||
if (!team) {
|
||||
return null;
|
||||
}
|
||||
return this.toEntity(team);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoTeamRepository;
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { User } from "@/types/domain/index.js";
|
||||
export interface IUserRepository {
|
||||
// create
|
||||
// single fetch
|
||||
findByEmail: (email: string) => Promise<User | null>;
|
||||
// collection fetch
|
||||
// update
|
||||
// delete
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { User as UserEntity } from "@/types/domain/index.js";
|
||||
import { IUserRepository } from "@/repositories/index.js";
|
||||
import { User } from "@/db/models/index.js";
|
||||
import type { IUser } from "@/db/models/index.js";
|
||||
|
||||
class MongoUserRepository implements IUserRepository {
|
||||
private toEntity = (user: IUser): UserEntity => {
|
||||
return {
|
||||
id: user._id.toString(),
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
email: user.email,
|
||||
passwordHash: user.passwordHash,
|
||||
lastLoginAt: user.lastLoginAt,
|
||||
createdAt: user.createdAt,
|
||||
updatedAt: user.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
findByEmail = async (email: string) => {
|
||||
const user = await User.findOne({ email });
|
||||
if (!user) return null;
|
||||
return this.toEntity(user);
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoUserRepository;
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Incident, Monitor } from "@/db/models/index.js";
|
||||
import type { ResolutionType } from "@/types/domain/index.js";
|
||||
import { getChildLogger } from "@/logger/Logger.js";
|
||||
import { ThresholdEvaluationResult } from "@/services/infrastructure/StatusService.js";
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import crypto from "node:crypto";
|
||||
import {
|
||||
IInvite,
|
||||
Invite,
|
||||
User,
|
||||
IUser,
|
||||
Role,
|
||||
Team,
|
||||
TeamMembership,
|
||||
} from "@/db/models/index.js";
|
||||
import ApiError from "@/utils/ApiError.js";
|
||||
import type {
|
||||
IUserRepository,
|
||||
IRoleRepository,
|
||||
ITeamRepository,
|
||||
IInviteRepository,
|
||||
ITeamMembershipRepository,
|
||||
} from "@/repositories/index.js";
|
||||
import { User } from "@/types/domain/index.js";
|
||||
import { Invite } from "@/types/domain/index.js";
|
||||
|
||||
const SERVICE_NAME = "InviteService";
|
||||
export interface IInviteService {
|
||||
@@ -20,15 +20,31 @@ export interface IInviteService {
|
||||
teamId: string,
|
||||
teamRoleId: string
|
||||
) => Promise<string>;
|
||||
getAll: () => Promise<IInvite[]>;
|
||||
get: (tokenHash: string) => Promise<{ user: IUser | null; invite: IInvite }>;
|
||||
getAll: () => Promise<Invite[]>;
|
||||
get: (tokenHash: string) => Promise<{ user: User | null; invite: Invite }>;
|
||||
delete: (id: string) => Promise<boolean>;
|
||||
}
|
||||
|
||||
class InviteService implements IInviteService {
|
||||
public SERVICE_NAME: string;
|
||||
constructor() {
|
||||
private userRepository: IUserRepository;
|
||||
private roleRepository: IRoleRepository;
|
||||
private teamRepository: ITeamRepository;
|
||||
private inviteRepository: IInviteRepository;
|
||||
private teamMembershipRepository: ITeamMembershipRepository;
|
||||
constructor(
|
||||
userRepository: IUserRepository,
|
||||
roleRepository: IRoleRepository,
|
||||
teamRepository: ITeamRepository,
|
||||
inviteRepository: IInviteRepository,
|
||||
teamMembershipRepository: ITeamMembershipRepository
|
||||
) {
|
||||
this.SERVICE_NAME = SERVICE_NAME;
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.teamRepository = teamRepository;
|
||||
this.inviteRepository = inviteRepository;
|
||||
this.teamMembershipRepository = teamMembershipRepository;
|
||||
}
|
||||
|
||||
create = async (
|
||||
@@ -40,40 +56,36 @@ class InviteService implements IInviteService {
|
||||
teamRoleId: string
|
||||
) => {
|
||||
try {
|
||||
const role = await Role.findOne({
|
||||
_id: teamRoleId,
|
||||
organizationId: orgId,
|
||||
});
|
||||
const role = await this.roleRepository.findById(teamRoleId, orgId);
|
||||
|
||||
if (!role) {
|
||||
throw new ApiError("Role not found", 404);
|
||||
}
|
||||
|
||||
const team = await Team.findOne({
|
||||
_id: teamId,
|
||||
orgId,
|
||||
});
|
||||
const team = await this.teamRepository.findById(teamId, orgId);
|
||||
|
||||
if (!team) {
|
||||
throw new ApiError("Team not found", 404);
|
||||
}
|
||||
|
||||
// Check if already a team member
|
||||
const user = await User.findOne({ email });
|
||||
const existingMembership = await TeamMembership.findOne({
|
||||
userId: user?._id,
|
||||
teamId,
|
||||
});
|
||||
const user = await this.userRepository.findByEmail(email);
|
||||
|
||||
const existingMembership =
|
||||
await this.teamMembershipRepository.findByUserId(
|
||||
user?.id || "",
|
||||
teamId
|
||||
);
|
||||
|
||||
if (existingMembership) {
|
||||
throw new ApiError("User is already a team member", 409);
|
||||
}
|
||||
|
||||
// Check if inivite already exists
|
||||
const existingInvite = await Invite.findOne({
|
||||
const existingInvite = await this.inviteRepository.findByEmail(
|
||||
email,
|
||||
teamId,
|
||||
});
|
||||
teamId
|
||||
);
|
||||
|
||||
if (existingInvite) {
|
||||
throw new ApiError("An invite already exists for this email", 409);
|
||||
@@ -82,7 +94,7 @@ class InviteService implements IInviteService {
|
||||
const token = crypto.randomBytes(32).toString("hex");
|
||||
const tokenHash = crypto.createHash("sha256").update(token).digest("hex");
|
||||
|
||||
const invite = await Invite.create({
|
||||
const invite = await this.inviteRepository.create({
|
||||
orgId,
|
||||
...(orgRoleId && { orgRoleId }),
|
||||
teamId,
|
||||
@@ -104,24 +116,21 @@ class InviteService implements IInviteService {
|
||||
|
||||
get = async (token: string) => {
|
||||
const tokenHash = crypto.createHash("sha256").update(token).digest("hex");
|
||||
const invite = await Invite.findOne({ tokenHash });
|
||||
const invite = await this.inviteRepository.findByHash(tokenHash);
|
||||
if (!invite) {
|
||||
throw new ApiError("Invite not found", 404);
|
||||
}
|
||||
const user = await User.findOne({ email: invite.email });
|
||||
const user = await this.userRepository.findByEmail(invite.email);
|
||||
|
||||
return { user, invite };
|
||||
};
|
||||
|
||||
getAll = async () => {
|
||||
return Invite.find();
|
||||
return await this.inviteRepository.findAll();
|
||||
};
|
||||
|
||||
delete = async (id: string) => {
|
||||
const result = await Invite.deleteOne({ _id: id });
|
||||
if (!result.deletedCount) {
|
||||
throw new ApiError("Invite not found", 404);
|
||||
}
|
||||
return result.deletedCount === 1;
|
||||
return await this.inviteRepository.deleteById(id);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,3 +2,12 @@ export * from "@/types/domain/monitor.js";
|
||||
export * from "@/types/domain/check.js";
|
||||
export * from "@/types/domain/monitorStats.js";
|
||||
export * from "@/types/domain/incident.js";
|
||||
export * from "@/types/domain/user.js";
|
||||
export * from "@/types/domain/role.js";
|
||||
export * from "@/types/domain/team.js";
|
||||
export * from "@/types/domain/teamMembership.js";
|
||||
export * from "@/types/domain/invite.js";
|
||||
export * from "@/types/domain/org.js";
|
||||
export * from "@/types/domain/orgMembership.js";
|
||||
export * from "@/types/domain/maintenance.js";
|
||||
export * from "@/types/domain/statsHourly.js";
|
||||
@@ -0,0 +1,14 @@
|
||||
export interface Invite {
|
||||
id: string;
|
||||
orgId: string;
|
||||
orgRoleId?: string;
|
||||
teamId: string;
|
||||
teamRoleId: string;
|
||||
email: string;
|
||||
tokenHash: string;
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
expiry: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export const MaintenanceRepeats = ["no repeat", "daily", "weekly"] as const;
|
||||
export type MaintenanceRepeat = (typeof MaintenanceRepeats)[number];
|
||||
|
||||
export interface Maintenance {
|
||||
id: string;
|
||||
orgId: string;
|
||||
teamId: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
repeat: MaintenanceRepeat;
|
||||
monitors: string[];
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { PlanKey } from "@/types/entitlements.js";
|
||||
export type SubscriptionStatus =
|
||||
| "active"
|
||||
| "trialing"
|
||||
| "past_due"
|
||||
| "canceled"
|
||||
| "incomplete";
|
||||
|
||||
export interface Org {
|
||||
id: string;
|
||||
name: string;
|
||||
ownerId: string;
|
||||
|
||||
// Entitlements & plan
|
||||
planKey: "free" | "pro" | "business" | "enterprise";
|
||||
|
||||
// Billing
|
||||
billingCustomerId?: string;
|
||||
subscriptionId?: string;
|
||||
priceId: string;
|
||||
priceIds?: string[];
|
||||
subscriptionStatus?: SubscriptionStatus;
|
||||
currentPeriodStart?: Date;
|
||||
currentPeriodEnd?: Date;
|
||||
|
||||
// Cached entitlements
|
||||
entitlements: {
|
||||
plan: PlanKey;
|
||||
monitorsMax: number;
|
||||
notificationChannelsMax: number;
|
||||
statusPagesMax: number;
|
||||
checksIntervalMsMin: number;
|
||||
teamsMax: number;
|
||||
notificationsEnabled: boolean;
|
||||
retentionDays: number;
|
||||
};
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface OrgMembership extends Document {
|
||||
id: string;
|
||||
orgId: string;
|
||||
userId: string;
|
||||
roleId?: string;
|
||||
role: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export const ScopeTypes = ["organization", "team"] as const;
|
||||
export type ScopeType = (typeof ScopeTypes)[number];
|
||||
|
||||
export interface Role {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
scope: ScopeType;
|
||||
permissions: string[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { IStatsBase } from "@/types/domain/index.js";
|
||||
|
||||
import type {
|
||||
IInfraCpu,
|
||||
IInfraDiskEntry,
|
||||
IInfraHost,
|
||||
IInfraMemory,
|
||||
IInfraNetEntry,
|
||||
IPageSpeedMetrics,
|
||||
} from "@/types/domain/index.js";
|
||||
|
||||
export interface IStatsDaily extends IStatsBase, IPageSpeedMetrics {
|
||||
cpu?: IInfraCpu;
|
||||
memory?: IInfraMemory;
|
||||
disk?: IInfraDiskEntry[];
|
||||
host?: IInfraHost;
|
||||
net?: IInfraNetEntry[];
|
||||
// Docker rollups
|
||||
dockerRunningPercent?: number;
|
||||
dockerHealthyPercent?: number;
|
||||
dockerRunningContainers?: number;
|
||||
dockerHealthyContainers?: number;
|
||||
dockerTotalContainers?: number;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import type { MonitorType } from "@/types/domain/index.js";
|
||||
|
||||
// Common/base metrics across monitor types
|
||||
export interface IStatsBase {
|
||||
monitorId: string;
|
||||
teamId: string;
|
||||
type: MonitorType;
|
||||
windowStart: Date; // inclusive
|
||||
windowEnd: Date; // exclusive
|
||||
finalized: boolean;
|
||||
count: number; // number of checks in window
|
||||
avgResponseTime: number; // ms
|
||||
upChecks?: number;
|
||||
downChecks?: number;
|
||||
avgResponseTimeUp?: number;
|
||||
avgResponseTimeDown?: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// Pagespeed rollups (averages per window)
|
||||
export interface IPageSpeedMetrics {
|
||||
accessibility?: number;
|
||||
bestPractices?: number;
|
||||
seo?: number;
|
||||
performance?: number;
|
||||
cls?: number;
|
||||
si?: number;
|
||||
fcp?: number;
|
||||
lcp?: number;
|
||||
tbt?: number;
|
||||
}
|
||||
|
||||
// Infrastructure rollups
|
||||
export interface IInfraCpu {
|
||||
physical_core?: number;
|
||||
logical_core?: number;
|
||||
frequency?: number;
|
||||
current_frequency?: number;
|
||||
temperature?: number[]; // averaged per sensor index
|
||||
free_percent?: number;
|
||||
used_percent?: number;
|
||||
}
|
||||
|
||||
export interface IInfraMemory {
|
||||
total_bytes?: number;
|
||||
available_bytes?: number;
|
||||
used_bytes?: number;
|
||||
usage_percent?: number;
|
||||
}
|
||||
|
||||
export interface IInfraDiskEntry {
|
||||
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 IInfraHost {
|
||||
os?: string;
|
||||
platform?: string;
|
||||
kernel_version?: string;
|
||||
pretty_name?: string;
|
||||
}
|
||||
|
||||
export interface IInfraNetEntry {
|
||||
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 IStatsHourly extends IStatsBase, IPageSpeedMetrics {
|
||||
cpu?: IInfraCpu;
|
||||
memory?: IInfraMemory;
|
||||
disk?: IInfraDiskEntry[];
|
||||
host?: IInfraHost;
|
||||
net?: IInfraNetEntry[];
|
||||
dockerRunningPercent?: number;
|
||||
dockerHealthyPercent?: number;
|
||||
dockerRunningContainers?: number;
|
||||
dockerHealthyContainers?: number;
|
||||
dockerTotalContainers?: number;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface Team {
|
||||
id: string;
|
||||
orgId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
isSystem?: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface TeamMembership {
|
||||
id: string;
|
||||
orgId: string;
|
||||
teamId: string;
|
||||
userId: string;
|
||||
roleId: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface User {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email: string;
|
||||
passwordHash: string;
|
||||
lastLoginAt?: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
Reference in new issue
Block a user