diff --git a/apps/status-page/.env.example b/apps/status-page/.env.example
index bcb71e06..13be461d 100644
--- a/apps/status-page/.env.example
+++ b/apps/status-page/.env.example
@@ -11,6 +11,8 @@ DATABASE_AUTH_TOKEN=any-token
NEXT_PUBLIC_SENTRY_DSN=''
+# used for contributions to fill the monitor tracker with data
+NOOP_UPTIME="true"
# https://turbo.build/repo/docs/crafting-your-repository/using-environment-variables#loose-mode
TURBO_ENV_MODE=loose
diff --git a/apps/status-page/src/components/status-page/status-tracker.tsx b/apps/status-page/src/components/status-page/status-tracker.tsx
index d3aab830..81dfbd80 100644
--- a/apps/status-page/src/components/status-page/status-tracker.tsx
+++ b/apps/status-page/src/components/status-page/status-tracker.tsx
@@ -319,9 +319,9 @@ export function StatusTracker({ data }: { data: UptimeData }) {
return (
{content}
diff --git a/packages/api/src/router/statusPage.ts b/packages/api/src/router/statusPage.ts
index 9fdb2b50..0d14a615 100644
--- a/packages/api/src/router/statusPage.ts
+++ b/packages/api/src/router/statusPage.ts
@@ -311,7 +311,10 @@ export const statusPageRouter = createTRPCRouter({
monitorId: m.monitor.id,
});
const rawData = statusDataByMonitorId.get(monitorId) || [];
- const filledData = fillStatusDataFor45Days(rawData, monitorId);
+ const filledData =
+ process.env.NOOP_UPTIME === "true"
+ ? fillStatusDataFor45DaysNoop({ errorDays: [], degradedDays: [] })
+ : fillStatusDataFor45Days(rawData, monitorId);
const processedData = setDataByType({
events,
data: filledData,
@@ -334,7 +337,10 @@ export const statusPageRouter = createTRPCRouter({
// NOTE: used for the theme store
getNoopUptime: publicProcedure.query(async () => {
- const data = fillStatusDataFor45DaysNoop();
+ const data = fillStatusDataFor45DaysNoop({
+ errorDays: [4],
+ degradedDays: [40],
+ });
const processedData = setDataByType({
events: [
{
diff --git a/packages/api/src/router/statusPage.utils.ts b/packages/api/src/router/statusPage.utils.ts
index 9ab04b54..115613de 100644
--- a/packages/api/src/router/statusPage.utils.ts
+++ b/packages/api/src/router/statusPage.utils.ts
@@ -63,15 +63,24 @@ export function fillStatusDataFor45Days(
);
}
-export function fillStatusDataFor45DaysNoop(): Array {
- const data: StatusData[] = Array.from({ length: 45 }, (_, i) => ({
- day: new Date(new Date().setDate(new Date().getDate() - i)).toISOString(),
- count: 1,
- ok: [4, 40].includes(i) ? 0 : 1,
- degraded: i === 40 ? 1 : 0,
- error: i === 4 ? 1 : 0,
- monitorId: "1",
- }));
+export function fillStatusDataFor45DaysNoop({
+ errorDays,
+ degradedDays,
+}: {
+ errorDays: number[];
+ degradedDays: number[];
+}): Array {
+ const issueDays = [...errorDays, ...degradedDays];
+ const data: StatusData[] = Array.from({ length: 45 }, (_, i) => {
+ return {
+ day: new Date(new Date().setDate(new Date().getDate() - i)).toISOString(),
+ count: 1,
+ ok: issueDays.includes(i) ? 0 : 1,
+ degraded: degradedDays.includes(i) ? 1 : 0,
+ error: errorDays.includes(i) ? 1 : 0,
+ monitorId: "1",
+ };
+ });
return fillStatusDataFor45Days(data, "1");
}
diff --git a/packages/db/src/seed.mts b/packages/db/src/seed.mts
index 9219d7a0..7053c3d1 100644
--- a/packages/db/src/seed.mts
+++ b/packages/db/src/seed.mts
@@ -1,5 +1,4 @@
import { createClient } from "@libsql/client";
-import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/libsql";
import { env } from "../env.mjs";
@@ -136,8 +135,8 @@ async function main() {
.values({
id: 1,
workspaceId: 1,
- title: "Test Page",
- description: "hello",
+ title: "Acme Inc.",
+ description: "Get informed about our services.",
icon: "https://www.openstatus.dev/favicon.ico",
slug: "status",
customDomain: "",
@@ -180,82 +179,172 @@ async function main() {
})
.onConflictDoNothing()
.run();
+
await db
.insert(notificationsToMonitors)
.values({ monitorId: 1, notificationId: 1 })
.onConflictDoNothing()
.run();
+ // Status Report 1 - Resolved incident from 7 days ago
+ const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
+ const sevenDaysAgoPlus30Min = new Date(
+ sevenDaysAgo.getTime() + 30 * 60 * 1000,
+ );
+ const sevenDaysAgoPlus90Min = new Date(
+ sevenDaysAgo.getTime() + 90 * 60 * 1000,
+ );
+ const sevenDaysAgoPlus120Min = new Date(
+ sevenDaysAgo.getTime() + 120 * 60 * 1000,
+ );
+
await db
.insert(statusReport)
.values({
id: 1,
workspaceId: 1,
pageId: 1,
- title: "Test Status Report",
- status: "investigating",
- updatedAt: new Date(),
+ title: "API Gateway Degraded Performance",
+ status: "resolved",
+ updatedAt: sevenDaysAgoPlus120Min,
})
.onConflictDoNothing()
.run();
await db
.insert(statusReportUpdate)
- .values({
- id: 1,
- statusReportId: 1,
- status: "investigating",
- message: "Message",
- date: new Date(),
- })
+ .values([
+ {
+ id: 1,
+ statusReportId: 1,
+ status: "investigating",
+ message:
+ "We are investigating reports of slow API response times affecting some customers.",
+ date: sevenDaysAgo,
+ },
+ {
+ id: 2,
+ statusReportId: 1,
+ status: "identified",
+ message:
+ "We have identified the issue as a database connection pool exhaustion and are working on a fix.",
+ date: sevenDaysAgoPlus30Min,
+ },
+ {
+ id: 3,
+ statusReportId: 1,
+ status: "monitoring",
+ message:
+ "A fix has been deployed and we are monitoring the system. Response times are returning to normal.",
+ date: sevenDaysAgoPlus90Min,
+ },
+ {
+ id: 4,
+ statusReportId: 1,
+ status: "resolved",
+ message:
+ "All systems are operating normally. The issue has been fully resolved.",
+ date: sevenDaysAgoPlus120Min,
+ },
+ ])
.onConflictDoNothing()
.run();
+ // Status Report 2 - Ongoing incident from 2 hours ago
+ const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000);
+ const oneHourAgo = new Date(Date.now() - 1 * 60 * 60 * 1000);
+ const twentyMinutesAgo = new Date(Date.now() - 20 * 60 * 1000);
+
await db
.insert(statusReport)
.values({
id: 2,
workspaceId: 1,
pageId: 1,
- title: "Test Status Report",
- status: "investigating",
- updatedAt: new Date(),
+ title: "Increased Error Rates on Monitoring Checks",
+ status: "resolved",
+ updatedAt: oneHourAgo,
})
.onConflictDoNothing()
.run();
await db
.insert(statusReportUpdate)
- .values({
- id: 2,
- statusReportId: 2,
- status: "investigating",
- message: "Message",
- date: new Date(),
- })
+ .values([
+ {
+ id: 5,
+ statusReportId: 2,
+ status: "investigating",
+ message:
+ "We are seeing elevated error rates on some monitoring checks and are investigating the root cause.",
+ date: twoHoursAgo,
+ },
+ {
+ id: 6,
+ statusReportId: 2,
+ status: "monitoring",
+ message:
+ "We have applied a fix and are monitoring the situation. Error rates are decreasing.",
+ date: oneHourAgo,
+ },
+ {
+ id: 7,
+ statusReportId: 2,
+ status: "resolved",
+ message:
+ "Everything is under control, we continue to monitor the situation.",
+ date: twentyMinutesAgo,
+ },
+ ])
.onConflictDoNothing()
.run();
+ // Maintenance windows spread across 30 days
+ const twentyDaysAgo = new Date(Date.now() - 20 * 24 * 60 * 60 * 1000);
+ const twentyDaysAgoPlus2Hours = new Date(
+ twentyDaysAgo.getTime() + 2 * 60 * 60 * 1000,
+ );
+
+ const fiveDaysFromNow = new Date(Date.now() + 5 * 24 * 60 * 60 * 1000);
+ const fiveDaysFromNowPlus4Hours = new Date(
+ fiveDaysFromNow.getTime() + 4 * 60 * 60 * 1000,
+ );
+
await db
.insert(maintenance)
- .values({
- id: 1,
- workspaceId: 1,
- title: "Test Maintenance",
- message: "Test message",
- from: new Date(),
- to: new Date(Date.now() + 1000),
- pageId: 1,
- })
+ .values([
+ {
+ id: 1,
+ workspaceId: 1,
+ title: "Database Migration and Optimization",
+ message:
+ "We will be performing database maintenance to improve performance. Some queries may be slower during this window.",
+ from: twentyDaysAgo,
+ to: twentyDaysAgoPlus2Hours,
+ pageId: 1,
+ },
+ {
+ id: 2,
+ workspaceId: 1,
+ title: "Infrastructure Upgrade",
+ message:
+ "We will be upgrading our monitoring infrastructure to the latest version. Expect brief interruptions in data collection.",
+ from: fiveDaysFromNow,
+ to: fiveDaysFromNowPlus4Hours,
+ pageId: 1,
+ },
+ ])
.onConflictDoNothing()
.run();
await db
.insert(maintenancesToMonitors)
- .values({
- maintenanceId: 1,
- monitorId: 1,
- })
+ .values([
+ {
+ maintenanceId: 1,
+ monitorId: 1,
+ },
+ ])
.onConflictDoNothing()
.run();
@@ -266,51 +355,43 @@ async function main() {
monitorId: 1,
statusReportId: 2,
},
- {
- monitorId: 2,
- statusReportId: 2,
- },
])
.onConflictDoNothing()
.run();
- await db
- .insert(incidentTable)
- .values({
- id: 1,
- workspaceId: 1,
- monitorId: 1,
- createdAt: new Date(),
- startedAt: new Date(),
- })
- .onConflictDoNothing()
- .run();
+ // Incidents - realistic past incidents that were resolved
+ const fifteenDaysAgo = new Date(Date.now() - 15 * 24 * 60 * 60 * 1000);
+ const fifteenDaysAgoPlus2Hours = new Date(
+ fifteenDaysAgo.getTime() + 2 * 60 * 60 * 1000,
+ );
+
+ const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
+ const threeDaysAgoPlus20Min = new Date(
+ threeDaysAgo.getTime() + 20 * 60 * 1000,
+ );
await db
.insert(incidentTable)
- .values({
- id: 2,
- workspaceId: 1,
- monitorId: 1,
- createdAt: new Date(),
- startedAt: new Date(Date.now() + 1000),
- })
- .onConflictDoNothing()
- .run();
- // on status update
- await db
- .update(statusReport)
- .set({ status: "monitoring" })
- .where(eq(statusReport.id, 1));
- await db
- .insert(statusReportUpdate)
- .values({
- id: 3,
- statusReportId: 1,
- status: "monitoring",
- message: "test",
- date: new Date(),
- })
+ .values([
+ {
+ id: 1,
+ workspaceId: 1,
+ monitorId: 1,
+ createdAt: fifteenDaysAgo,
+ startedAt: fifteenDaysAgo,
+ acknowledgedAt: new Date(fifteenDaysAgo.getTime() + 5 * 60 * 1000),
+ resolvedAt: fifteenDaysAgoPlus2Hours,
+ },
+ {
+ id: 2,
+ workspaceId: 1,
+ monitorId: 1,
+ createdAt: threeDaysAgo,
+ startedAt: threeDaysAgo,
+ acknowledgedAt: new Date(threeDaysAgo.getTime() + 2 * 60 * 1000),
+ resolvedAt: threeDaysAgoPlus20Min,
+ },
+ ])
.onConflictDoNothing()
.run();