Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
14 kB ยท 551 lines
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552import { createClient } from "@libsql/client";import { drizzle } from "drizzle-orm/libsql";
import { env } from "../env.mjs";import { externalService, incident, incidentEvent, monitorIncidentTable, maintenance, maintenancesToPageComponents, monitor, notification, notificationsToMonitors, page, pageComponent, privateLocation, privateLocationToMonitors, statusReport, statusReportUpdate, statusReportsToPageComponents, user, usersToWorkspaces, workspace,} from "./schema";import { externalServicesSeed } from "./seed/external-services";import { TEAM_WORKSPACE_LIMITS } from "./seed/limits";
async function main() { if ( !env.DATABASE_URL.includes("localhost") && !env.DATABASE_URL.includes("127.0.0.1") ) { throw new Error( `Refusing to wipe non-local database: DATABASE_URL=${env.DATABASE_URL}`, ); }
const client = createClient({ url: env.DATABASE_URL, authToken: env.DATABASE_AUTH_TOKEN, }); const db = drizzle(client);
// Fresh slate: wipe every table so re-seeding is idempotent and tests never // inherit residue from a previous run. `defer_foreign_keys` lets us delete in // any order within the transaction (all tables end empty, so FKs hold at commit). const tables = await client.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != '__drizzle_migrations'", ); await client.batch( [ "PRAGMA defer_foreign_keys=ON", ...tables.rows.map((row) => `DELETE FROM "${row.name}"`), ], "write", );
console.log("Seeding database "); await db .insert(workspace) .values([ { id: 1, slug: "love-openstatus", stripeId: "stripeId1", name: "test", subscriptionId: "subscriptionId", plan: "team", endsAt: null, paidUntil: null, limits: TEAM_WORKSPACE_LIMITS, }, { id: 2, slug: "test2", stripeId: "stripeId2", name: "test2", subscriptionId: "subscriptionId2", plan: "free", endsAt: null, paidUntil: null, }, { id: 3, slug: "test3", stripeId: "stripeId3", name: "test3", subscriptionId: "subscriptionId3", plan: "team", endsAt: null, paidUntil: null, }, ]) .onConflictDoNothing() .run();
await db .insert(monitor) .values([ { id: 1, workspaceId: 1, active: true, url: "https://www.openstatus.dev", name: "OpenStatus", description: "OpenStatus website", method: "POST", periodicity: "1m", regions: "ams", headers: '[{"key":"key", "value":"value"}]', body: '{"hello":"world"}', }, { id: 2, active: false, workspaceId: 1, periodicity: "10m", url: "https://www.google.com", method: "GET", regions: "gru", public: true, }, { id: 3, workspaceId: 1, active: true, url: "https://www.openstatus.dev", name: "OpenStatus", description: "OpenStatus website", method: "GET", periodicity: "1m", regions: "ams", headers: '[{"key":"key", "value":"value"}]', body: '{"hello":"world"}', }, { id: 4, active: true, workspaceId: 1, periodicity: "10m", url: "https://www.google.com", method: "GET", regions: "gru", public: true, otelEndpoint: "https://otel.com:4337", otelHeaders: '[{"key":"Authorization","value":"Basic"}]', }, { id: 5, active: true, workspaceId: 3, periodicity: "10m", url: "https://openstat.us", method: "GET", regions: "ams", public: true, }, ]) .onConflictDoNothing() .run();
await db .insert(page) .values({ id: 1, workspaceId: 1, title: "Acme Inc.", description: "Get informed about our services.", icon: "https://www.openstatus.dev/favicon.ico", slug: "status", customDomain: "", published: true, }) .onConflictDoNothing() .run();
await db .insert(page) .values({ id: 2, workspaceId: 1, title: "Acme Inc.", description: "Get informed about our services.", icon: "https://www.openstatus.dev/favicon.ico", slug: "acme", customDomain: "status.acme.com", published: true, }) .onConflictDoNothing() .run();
await db .insert(user) .values({ id: 1, tenantId: "1", firstName: "Speed", lastName: "Matters", email: "ping@openstatus.dev", photoUrl: "", }) .onConflictDoNothing() .run(); await db .insert(usersToWorkspaces) .values({ workspaceId: 1, userId: 1 }) .onConflictDoNothing() .run();
// Page Components - representing monitors on the status page await db .insert(pageComponent) .values([ { id: 1, workspaceId: 1, pageId: 1, type: "monitor", monitorId: 1, name: "OpenStatus Monitor", description: "Main website monitoring", order: 0, }, { id: 2, workspaceId: 1, pageId: 1, type: "monitor", monitorId: 2, name: "Google Monitor", description: "Google.com monitoring", order: 1, }, ]) .onConflictDoNothing() .run();
await db .insert(notification) .values({ id: 1, provider: "email", name: "sample test notification", data: '{"email":"ping@openstatus.dev"}', workspaceId: 1, }) .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: "API Gateway Degraded Performance", status: "resolved", updatedAt: sevenDaysAgoPlus120Min, }) .onConflictDoNothing() .run();
await db .insert(statusReportUpdate) .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: "Increased Error Rates on Monitoring Checks", status: "resolved", updatedAt: oneHourAgo, }) .onConflictDoNothing() .run();
await db .insert(statusReportUpdate) .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: "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();
// Link status reports to page components await db .insert(statusReportsToPageComponents) .values([ { statusReportId: 1, pageComponentId: 1, }, { statusReportId: 2, pageComponentId: 1, }, ]) .onConflictDoNothing() .run();
// Link maintenances to page components await db .insert(maintenancesToPageComponents) .values([ { maintenanceId: 1, pageComponentId: 1, }, ]) .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(monitorIncidentTable) .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();
await db .insert(incident) .values({ id: 1, workspaceId: 1, title: "Elevated API error rates", severity: "major", status: "mitigated", summary: "Increased 5xx responses on the public API.", commanderId: 1, declaredBy: 1, declaredAt: twoHoursAgo, startedAt: new Date(twoHoursAgo.getTime() - 10 * 60 * 1000), mitigatedAt: new Date(twoHoursAgo.getTime() + 45 * 60 * 1000), statusReportId: 2, }) .onConflictDoNothing() .run(); await db .insert(incidentEvent) .values([ { incidentId: 1, type: "declared", message: "Incident declared", createdBy: 1, createdAt: twoHoursAgo, }, { incidentId: 1, type: "note", message: "Rolling back the latest API deploy.", createdBy: 1, createdAt: new Date(twoHoursAgo.getTime() + 20 * 60 * 1000), }, { incidentId: 1, type: "mitigated", message: "Rollback done, error rate back to baseline.", createdBy: 1, createdAt: new Date(twoHoursAgo.getTime() + 45 * 60 * 1000), }, ]) .run();
await db .insert(privateLocation) .values({ id: 1, name: "My Home", token: "my-secret-key", workspaceId: 3, createdAt: new Date(), }) .onConflictDoNothing() .run(); await db .insert(privateLocationToMonitors) .values({ privateLocationId: 1, monitorId: 5, createdAt: new Date(), }) .onConflictDoNothing() .run();
await db .insert(externalService) .values(externalServicesSeed) .onConflictDoNothing() .run();
process.exit(0);}
main().catch((e) => { console.error("Seed failed"); console.error(e); process.exit(1);});