feat: status page schema, licence feature and indexes

This commit is contained in:
2026-08-24 14:00:00 +00:00
parent 383b763a66
commit 1c15961309
6 changed files with 190 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
package models
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)
// A status page entry kind. Incidents and maintenance share one document
// because they share a timeline, an impact and a set of affected components.
const (
StatusKindIncident = "incident"
StatusKindMaintenance = "maintenance"
)
const (
ImpactNone = "none"
ImpactMinor = "minor"
ImpactMajor = "major"
ImpactCritical = "critical"
)
// Incident statuses.
const (
IncidentInvestigating = "investigating"
IncidentIdentified = "identified"
IncidentMonitoring = "monitoring"
IncidentResolved = "resolved"
)
// Maintenance statuses.
const (
MaintenanceScheduled = "scheduled"
MaintenanceInProgress = "in_progress"
MaintenanceCompleted = "completed"
)
// StatusPageEntry names one monitor on one page.
//
// DisplayName overrides the monitor's own name for this page only. A monitor's
// internal name is frequently not a name anybody wants published, and the same
// monitor may need different words on a customer page and a partner page.
type StatusPageEntry struct {
MonitorID string `bson:"monitor_id" json:"monitor_id"`
DisplayName string `bson:"display_name,omitempty" json:"display_name,omitempty"`
}
// StatusPageSection is page-local and unrelated to Monitor.Group, which labels
// rows on the authenticated monitors list.
type StatusPageSection struct {
Name string `bson:"name" json:"name"`
Entries []StatusPageEntry `bson:"entries" json:"entries"`
}
// StatusPageBanner is three fields on the page rather than a collection,
// because it is one string with no lifecycle.
type StatusPageBanner struct {
Enabled bool `bson:"enabled" json:"enabled"`
Level string `bson:"level,omitempty" json:"level,omitempty"`
Text string `bson:"text,omitempty" json:"text,omitempty"`
}
// StatusPage is read whole, always, which is why its structure is embedded
// rather than joined: one page is one read is one cache fill.
type StatusPage struct {
ID bson.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
InstanceID string `bson:"instance_id" json:"instance_id"`
PageID string `bson:"page_id" json:"page_id"`
Title string `bson:"title" json:"title"`
Description string `bson:"description,omitempty" json:"description,omitempty"`
LogoURL string `bson:"logo_url,omitempty" json:"logo_url,omitempty"`
Published bool `bson:"published" json:"published"`
Banner StatusPageBanner `bson:"banner" json:"banner"`
Sections []StatusPageSection `bson:"sections" json:"sections"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}
type StatusIncidentUpdate struct {
At time.Time `bson:"at" json:"at"`
Status string `bson:"status" json:"status"`
Body string `bson:"body" json:"body"`
Author string `bson:"author" json:"author"`
}
// StatusIncident is operator-authored. Monitor-detected outages stay in the
// incidents collection and are derived at assembly time; copying them here
// would be a second writer for the same fact.
//
// PageIDs is explicit rather than derived from AffectedMonitors: deriving it
// would mean adding a monitor to a page retroactively republishes old
// incidents to a new audience.
type StatusIncident struct {
ID bson.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
InstanceID string `bson:"instance_id" json:"instance_id"`
IncidentID string `bson:"incident_id" json:"incident_id"`
PageIDs []string `bson:"page_ids" json:"page_ids"`
Kind string `bson:"kind" json:"kind"`
Title string `bson:"title" json:"title"`
Impact string `bson:"impact" json:"impact"`
AffectedMonitors []string `bson:"affected_monitors,omitempty" json:"affected_monitors,omitempty"`
Status string `bson:"status" json:"status"`
ScheduledStart *time.Time `bson:"scheduled_start,omitempty" json:"scheduled_start,omitempty"`
ScheduledEnd *time.Time `bson:"scheduled_end,omitempty" json:"scheduled_end,omitempty"`
Updates []StatusIncidentUpdate `bson:"updates" json:"updates"`
StartedAt time.Time `bson:"started_at" json:"started_at"`
ResolvedAt *time.Time `bson:"resolved_at,omitempty" json:"resolved_at,omitempty"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}