feat(api, web): enhance health check and domain management features
Build, Test, and Push CFDM Docker Image / test (push) Successful in 3m3s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Successful in 1m48s
Build, Test, and Push CFDM Docker Image / update-wiki (push) Successful in 6s
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped

- Integrated domain monitoring routes and bulk update functionality for domains in the API.
- Improved health check service to include domain monitoring and logging of health status changes.
- Updated web components to reflect health status with new HealthCheckBadge and enhanced domain filtering options.
- Refactored domain service to support bulk updates and improved domain management capabilities.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
DenozordecandCursor committed 2026-07-17 02:25:12 +07:00
1 parent dd167a4fec
commit 64585ccd47
38 files changed
+4199 -677

No files matched your search

+77 -1
View File
@@ -7,9 +7,15 @@ export type CertMonitoring = z.infer<typeof certMonitoringSchema>
export const lbModeSchema = z.enum(['round_robin', 'failover', 'weighted'])
export type LbMode = z.infer<typeof lbModeSchema>
export const healthCheckTypeSchema = z.enum(['tcp', 'http'])
export const healthCheckTypeSchema = z.enum(['tcp', 'http', 'ping', 'dns'])
export type HealthCheckType = z.infer<typeof healthCheckTypeSchema>
export const domainEnvironmentSchema = z.enum(['prod', 'staging', 'dev'])
export type DomainEnvironment = z.infer<typeof domainEnvironmentSchema>
export const domainMonitorTypeSchema = z.enum(['http', 'ping', 'dns'])
export type DomainMonitorType = z.infer<typeof domainMonitorTypeSchema>
export const ipHealthStateSchema = z.enum(['up', 'down', 'degraded', 'unknown'])
export type IpHealthState = z.infer<typeof ipHealthStateSchema>
@@ -144,6 +150,7 @@ export const domainSchema = z.object({
cf_zone_id: z.string(),
status: z.string(),
cert_monitoring: certMonitoringSchema.default('auto'),
environment: domainEnvironmentSchema.nullable().optional().default(null),
last_synced_at: z.string().nullable(),
created_at: z.string(),
updated_at: z.string(),
@@ -152,6 +159,9 @@ export const domainSchema = z.object({
export const domainListItemSchema = domainSchema.extend({
group_name: z.string().nullable(),
service_count: z.number(),
health_status: ipHealthStateSchema.default('unknown'),
health_latency_ms: z.number().nullable().default(null),
tags: z.array(z.string()).default([]),
})
export const serviceBindingSchema = z
@@ -361,8 +371,74 @@ export const updateDomainSchema = z.object({
group_id: z.number().nullable().optional(),
status: z.string().optional(),
cert_monitoring: certMonitoringSchema.optional(),
environment: domainEnvironmentSchema.nullable().optional(),
tags: z.array(z.string().min(1).max(64)).max(20).optional(),
})
export const bulkUpdateDomainsSchema = z.object({
ids: z.array(z.number().int().positive()).min(1),
group_id: z.number().nullable().optional(),
environment: domainEnvironmentSchema.nullable().optional(),
tags_add: z.array(z.string().min(1).max(64)).max(20).optional(),
})
export type BulkUpdateDomainsInput = z.infer<typeof bulkUpdateDomainsSchema>
export const domainMonitorSchema = z.object({
id: z.number(),
domain_id: z.number(),
hostname: z.string(),
type: domainMonitorTypeSchema,
enabled: z.coerce.boolean(),
interval_sec: z.number(),
timeout_ms: z.number(),
path: z.string().nullable(),
expected_status: z.number().nullable(),
last_status: ipHealthStateSchema.default('unknown'),
last_latency_ms: z.number().nullable(),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable(),
created_at: z.string(),
updated_at: z.string(),
})
export type DomainMonitor = z.infer<typeof domainMonitorSchema>
export const createDomainMonitorSchema = z.object({
hostname: z.string().min(1),
type: domainMonitorTypeSchema,
enabled: z.boolean().optional().default(true),
interval_sec: z.number().int().min(10).max(3600).optional().default(60),
timeout_ms: z.number().int().min(500).max(30000).optional().default(5000),
path: z.string().nullable().optional(),
expected_status: z.number().int().min(100).max(599).nullable().optional(),
})
export type CreateDomainMonitorInput = z.infer<typeof createDomainMonitorSchema>
export const domainMonitorResultSchema = z.object({
id: z.number(),
monitor_id: z.number(),
status: ipHealthStateSchema,
latency_ms: z.number().nullable(),
error: z.string().nullable(),
checked_at: z.string(),
})
export type DomainMonitorResult = z.infer<typeof domainMonitorResultSchema>
export const notificationLogSchema = z.object({
id: z.number(),
kind: z.string(),
ref_type: z.string(),
ref_id: z.number().nullable(),
title: z.string(),
message: z.string(),
created_at: z.string(),
})
export type NotificationLog = z.infer<typeof notificationLogSchema>
export type CreateSubdomainInput = z.infer<typeof createSubdomainSchema>
export type UpdateSubdomainInput = z.infer<typeof updateSubdomainSchema>
export type UpdateDomainInput = z.infer<typeof updateDomainSchema>
+9 -1
View File
@@ -55,6 +55,7 @@ export interface Domain {
cf_zone_id: string;
status: string;
cert_monitoring: string;
environment: DomainEnvironment | null;
last_synced_at: string | null;
created_at: string;
updated_at: string;
@@ -193,6 +194,9 @@ export interface GroupWithStats extends Group {
export interface DomainListItem extends Domain {
group_name: string | null;
service_count: number;
health_status: IpHealthState;
health_latency_ms: number | null;
tags: string[];
}
export interface SyncJob {
@@ -246,7 +250,11 @@ export interface JwtClaims {
export type LbMode = "round_robin" | "failover" | "weighted";
export type HealthCheckType = "tcp" | "http";
export type HealthCheckType = "tcp" | "http" | "ping" | "dns";
export type DomainEnvironment = "prod" | "staging" | "dev";
export type DomainMonitorType = "http" | "ping" | "dns";
export type IpHealthState = "up" | "down" | "degraded" | "unknown";