Openstatus www.openstatus.dev
at main 485 lines 12 kB view raw
1import { createClient } from "@libsql/client"; 2import { drizzle } from "drizzle-orm/libsql"; 3 4import { env } from "../env.mjs"; 5import { 6 incidentTable, 7 maintenance, 8 maintenancesToMonitors, 9 maintenancesToPageComponents, 10 monitor, 11 monitorsToPages, 12 monitorsToStatusReport, 13 notification, 14 notificationsToMonitors, 15 page, 16 pageComponent, 17 privateLocation, 18 privateLocationToMonitors, 19 statusReport, 20 statusReportUpdate, 21 statusReportsToPageComponents, 22 user, 23 usersToWorkspaces, 24 workspace, 25} from "./schema"; 26 27async function main() { 28 const db = drizzle( 29 createClient({ url: env.DATABASE_URL, authToken: env.DATABASE_AUTH_TOKEN }), 30 ); 31 console.log("Seeding database "); 32 await db 33 .insert(workspace) 34 .values([ 35 { 36 id: 1, 37 slug: "love-openstatus", 38 stripeId: "stripeId1", 39 name: "test", 40 subscriptionId: "subscriptionId", 41 plan: "team", 42 endsAt: null, 43 paidUntil: null, 44 limits: 45 '{"monitors":50,"synthetic-checks":150000,"periodicity":["30s","1m","5m","10m","30m","1h"],"multi-region":true,"max-regions":35,"data-retention":"24 months","status-pages":20,"maintenance":true,"status-subscribers":true,"custom-domain":true,"password-protection":true,"white-label":true,"notifications":true,"sms":true,"pagerduty":true,"notification-channels":50,"members":"Unlimited","audit-log":true,"regions":["ams","arn","atl","bog","bom","bos","cdg","den","dfw","ewr","eze","fra","gdl","gig","gru","hkg","iad","jnb","lax","lhr","mad","mia","nrt","ord","otp","phx","qro","scl","sea","sin","sjc","syd","waw","yul","yyz"]}', 46 }, 47 { 48 id: 2, 49 slug: "test2", 50 stripeId: "stripeId2", 51 name: "test2", 52 subscriptionId: "subscriptionId2", 53 plan: "free", 54 endsAt: null, 55 paidUntil: null, 56 }, 57 { 58 id: 3, 59 slug: "test3", 60 stripeId: "stripeId3", 61 name: "test3", 62 subscriptionId: "subscriptionId3", 63 plan: "team", 64 endsAt: null, 65 paidUntil: null, 66 }, 67 ]) 68 .onConflictDoNothing() 69 .run(); 70 71 await db 72 .insert(monitor) 73 .values([ 74 { 75 id: 1, 76 workspaceId: 1, 77 active: true, 78 url: "https://www.openstatus.dev", 79 name: "OpenStatus", 80 description: "OpenStatus website", 81 method: "POST", 82 periodicity: "1m", 83 regions: "ams", 84 headers: '[{"key":"key", "value":"value"}]', 85 body: '{"hello":"world"}', 86 }, 87 { 88 id: 2, 89 active: false, 90 workspaceId: 1, 91 periodicity: "10m", 92 url: "https://www.google.com", 93 method: "GET", 94 regions: "gru", 95 public: true, 96 }, 97 { 98 id: 3, 99 workspaceId: 1, 100 active: true, 101 url: "https://www.openstatus.dev", 102 name: "OpenStatus", 103 description: "OpenStatus website", 104 method: "GET", 105 periodicity: "1m", 106 regions: "ams", 107 headers: '[{"key":"key", "value":"value"}]', 108 body: '{"hello":"world"}', 109 }, 110 { 111 id: 4, 112 active: true, 113 workspaceId: 1, 114 periodicity: "10m", 115 url: "https://www.google.com", 116 method: "GET", 117 regions: "gru", 118 public: true, 119 otelEndpoint: "https://otel.com:4337", 120 otelHeaders: '[{"key":"Authorization","value":"Basic"}]', 121 }, 122 { 123 id: 5, 124 active: true, 125 workspaceId: 3, 126 periodicity: "10m", 127 url: "https://openstat.us", 128 method: "GET", 129 regions: "ams", 130 public: true, 131 }, 132 ]) 133 .onConflictDoNothing() 134 .run(); 135 136 await db 137 .insert(page) 138 .values({ 139 id: 1, 140 workspaceId: 1, 141 title: "Acme Inc.", 142 description: "Get informed about our services.", 143 icon: "https://www.openstatus.dev/favicon.ico", 144 slug: "status", 145 customDomain: "", 146 published: true, 147 }) 148 .onConflictDoNothing() 149 .run(); 150 151 await db 152 .insert(user) 153 .values({ 154 id: 1, 155 tenantId: "1", 156 firstName: "Speed", 157 lastName: "Matters", 158 email: "ping@openstatus.dev", 159 photoUrl: "", 160 }) 161 .onConflictDoNothing() 162 .run(); 163 await db 164 .insert(usersToWorkspaces) 165 .values({ workspaceId: 1, userId: 1 }) 166 .onConflictDoNothing() 167 .run(); 168 169 await db 170 .insert(monitorsToPages) 171 .values({ monitorId: 1, pageId: 1 }) 172 .onConflictDoNothing() 173 .run(); 174 175 // Page Components - representing monitors on the status page 176 await db 177 .insert(pageComponent) 178 .values([ 179 { 180 id: 1, 181 workspaceId: 1, 182 pageId: 1, 183 type: "monitor", 184 monitorId: 1, 185 name: "OpenStatus Monitor", 186 description: "Main website monitoring", 187 order: 0, 188 }, 189 { 190 id: 2, 191 workspaceId: 1, 192 pageId: 1, 193 type: "monitor", 194 monitorId: 2, 195 name: "Google Monitor", 196 description: "Google.com monitoring", 197 order: 1, 198 }, 199 ]) 200 .onConflictDoNothing() 201 .run(); 202 203 await db 204 .insert(notification) 205 .values({ 206 id: 1, 207 provider: "email", 208 name: "sample test notification", 209 data: '{"email":"ping@openstatus.dev"}', 210 workspaceId: 1, 211 }) 212 .onConflictDoNothing() 213 .run(); 214 215 await db 216 .insert(notificationsToMonitors) 217 .values({ monitorId: 1, notificationId: 1 }) 218 .onConflictDoNothing() 219 .run(); 220 221 // Status Report 1 - Resolved incident from 7 days ago 222 const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); 223 const sevenDaysAgoPlus30Min = new Date( 224 sevenDaysAgo.getTime() + 30 * 60 * 1000, 225 ); 226 const sevenDaysAgoPlus90Min = new Date( 227 sevenDaysAgo.getTime() + 90 * 60 * 1000, 228 ); 229 const sevenDaysAgoPlus120Min = new Date( 230 sevenDaysAgo.getTime() + 120 * 60 * 1000, 231 ); 232 233 await db 234 .insert(statusReport) 235 .values({ 236 id: 1, 237 workspaceId: 1, 238 pageId: 1, 239 title: "API Gateway Degraded Performance", 240 status: "resolved", 241 updatedAt: sevenDaysAgoPlus120Min, 242 }) 243 .onConflictDoNothing() 244 .run(); 245 246 await db 247 .insert(statusReportUpdate) 248 .values([ 249 { 250 id: 1, 251 statusReportId: 1, 252 status: "investigating", 253 message: 254 "We are investigating reports of slow API response times affecting some customers.", 255 date: sevenDaysAgo, 256 }, 257 { 258 id: 2, 259 statusReportId: 1, 260 status: "identified", 261 message: 262 "We have identified the issue as a database connection pool exhaustion and are working on a fix.", 263 date: sevenDaysAgoPlus30Min, 264 }, 265 { 266 id: 3, 267 statusReportId: 1, 268 status: "monitoring", 269 message: 270 "A fix has been deployed and we are monitoring the system. Response times are returning to normal.", 271 date: sevenDaysAgoPlus90Min, 272 }, 273 { 274 id: 4, 275 statusReportId: 1, 276 status: "resolved", 277 message: 278 "All systems are operating normally. The issue has been fully resolved.", 279 date: sevenDaysAgoPlus120Min, 280 }, 281 ]) 282 .onConflictDoNothing() 283 .run(); 284 285 // Status Report 2 - Ongoing incident from 2 hours ago 286 const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000); 287 const oneHourAgo = new Date(Date.now() - 1 * 60 * 60 * 1000); 288 const twentyMinutesAgo = new Date(Date.now() - 20 * 60 * 1000); 289 290 await db 291 .insert(statusReport) 292 .values({ 293 id: 2, 294 workspaceId: 1, 295 pageId: 1, 296 title: "Increased Error Rates on Monitoring Checks", 297 status: "resolved", 298 updatedAt: oneHourAgo, 299 }) 300 .onConflictDoNothing() 301 .run(); 302 303 await db 304 .insert(statusReportUpdate) 305 .values([ 306 { 307 id: 5, 308 statusReportId: 2, 309 status: "investigating", 310 message: 311 "We are seeing elevated error rates on some monitoring checks and are investigating the root cause.", 312 date: twoHoursAgo, 313 }, 314 { 315 id: 6, 316 statusReportId: 2, 317 status: "monitoring", 318 message: 319 "We have applied a fix and are monitoring the situation. Error rates are decreasing.", 320 date: oneHourAgo, 321 }, 322 { 323 id: 7, 324 statusReportId: 2, 325 status: "resolved", 326 message: 327 "Everything is under control, we continue to monitor the situation.", 328 date: twentyMinutesAgo, 329 }, 330 ]) 331 .onConflictDoNothing() 332 .run(); 333 334 // Maintenance windows spread across 30 days 335 const twentyDaysAgo = new Date(Date.now() - 20 * 24 * 60 * 60 * 1000); 336 const twentyDaysAgoPlus2Hours = new Date( 337 twentyDaysAgo.getTime() + 2 * 60 * 60 * 1000, 338 ); 339 340 const fiveDaysFromNow = new Date(Date.now() + 5 * 24 * 60 * 60 * 1000); 341 const fiveDaysFromNowPlus4Hours = new Date( 342 fiveDaysFromNow.getTime() + 4 * 60 * 60 * 1000, 343 ); 344 345 await db 346 .insert(maintenance) 347 .values([ 348 { 349 id: 1, 350 workspaceId: 1, 351 title: "Database Migration and Optimization", 352 message: 353 "We will be performing database maintenance to improve performance. Some queries may be slower during this window.", 354 from: twentyDaysAgo, 355 to: twentyDaysAgoPlus2Hours, 356 pageId: 1, 357 }, 358 { 359 id: 2, 360 workspaceId: 1, 361 title: "Infrastructure Upgrade", 362 message: 363 "We will be upgrading our monitoring infrastructure to the latest version. Expect brief interruptions in data collection.", 364 from: fiveDaysFromNow, 365 to: fiveDaysFromNowPlus4Hours, 366 pageId: 1, 367 }, 368 ]) 369 .onConflictDoNothing() 370 .run(); 371 372 await db 373 .insert(maintenancesToMonitors) 374 .values([ 375 { 376 maintenanceId: 1, 377 monitorId: 1, 378 }, 379 ]) 380 .onConflictDoNothing() 381 .run(); 382 383 await db 384 .insert(monitorsToStatusReport) 385 .values([ 386 { 387 monitorId: 1, 388 statusReportId: 2, 389 }, 390 ]) 391 .onConflictDoNothing() 392 .run(); 393 394 // Link status reports to page components 395 await db 396 .insert(statusReportsToPageComponents) 397 .values([ 398 { 399 statusReportId: 1, 400 pageComponentId: 1, 401 }, 402 { 403 statusReportId: 2, 404 pageComponentId: 1, 405 }, 406 ]) 407 .onConflictDoNothing() 408 .run(); 409 410 // Link maintenances to page components 411 await db 412 .insert(maintenancesToPageComponents) 413 .values([ 414 { 415 maintenanceId: 1, 416 pageComponentId: 1, 417 }, 418 ]) 419 .onConflictDoNothing() 420 .run(); 421 422 // Incidents - realistic past incidents that were resolved 423 const fifteenDaysAgo = new Date(Date.now() - 15 * 24 * 60 * 60 * 1000); 424 const fifteenDaysAgoPlus2Hours = new Date( 425 fifteenDaysAgo.getTime() + 2 * 60 * 60 * 1000, 426 ); 427 428 const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000); 429 const threeDaysAgoPlus20Min = new Date( 430 threeDaysAgo.getTime() + 20 * 60 * 1000, 431 ); 432 433 await db 434 .insert(incidentTable) 435 .values([ 436 { 437 id: 1, 438 workspaceId: 1, 439 monitorId: 1, 440 createdAt: fifteenDaysAgo, 441 startedAt: fifteenDaysAgo, 442 acknowledgedAt: new Date(fifteenDaysAgo.getTime() + 5 * 60 * 1000), 443 resolvedAt: fifteenDaysAgoPlus2Hours, 444 }, 445 { 446 id: 2, 447 workspaceId: 1, 448 monitorId: 1, 449 createdAt: threeDaysAgo, 450 startedAt: threeDaysAgo, 451 acknowledgedAt: new Date(threeDaysAgo.getTime() + 2 * 60 * 1000), 452 resolvedAt: threeDaysAgoPlus20Min, 453 }, 454 ]) 455 .onConflictDoNothing() 456 .run(); 457 458 await db 459 .insert(privateLocation) 460 .values({ 461 id: 1, 462 name: "My Home", 463 token: "my-secret-key", 464 workspaceId: 3, 465 createdAt: new Date(), 466 }) 467 .onConflictDoNothing() 468 .run(); 469 await db 470 .insert(privateLocationToMonitors) 471 .values({ 472 privateLocationId: 1, 473 monitorId: 5, 474 createdAt: new Date(), 475 }) 476 .onConflictDoNothing() 477 .run(); 478 process.exit(0); 479} 480 481main().catch((e) => { 482 console.error("Seed failed"); 483 console.error(e); 484 process.exit(1); 485});