Bobril is a component-based TypeScript framework with a virtual DOM and built-in state management, widely used in the Czech enterprise ecosystem. Its strict typing and high performance make it a solid choice for large-scale apps — but none of that matters when your app is unreachable or a background job has been silently failing. Vigilmon gives you continuous uptime monitoring, heartbeat checks, and instant alerts to email or Slack.
What You'll Build
- A health endpoint for your Bobril app's backend
- Vigilmon HTTP monitors covering your SPA and API
- A heartbeat for scheduled background jobs
- Alert channels (email and Slack)
- An uptime badge component in your Bobril UI
Prerequisites
- A Bobril project (with a Node/Express API backend)
- A free Vigilmon account
Step 1: Add a Health Endpoint
Bobril apps are typically served as static SPAs backed by a Node/Express API. Add a /health route to your backend:
// server.ts
import express from "express";
const app = express();
app.get("/health", async (_req, res) => {
const checks: Record<string, string> = {};
let degraded = false;
// Database connectivity check
try {
// await db.execute("SELECT 1");
checks.database = "ok";
} catch (err) {
checks.database = `error: ${(err as Error).message}`;
degraded = true;
}
// External dependency check
try {
const response = await fetch("https://api.example.com/ping", {
signal: AbortSignal.timeout(3000),
});
checks.externalApi = response.ok ? "ok" : `http_${response.status}`;
} catch {
checks.externalApi = "unreachable";
degraded = true;
}
res.status(degraded ? 503 : 200).json({
status: degraded ? "degraded" : "ok",
timestamp: new Date().toISOString(),
checks,
});
});
app.listen(process.env.PORT ?? 3000);
Test it locally:
curl http://localhost:3000/health | jq .
# {"status":"ok","timestamp":"2026-07-03T...","checks":{"database":"ok","externalApi":"ok"}}
Step 2: Configure Vigilmon HTTP Monitors
Log in to Vigilmon → Monitors → New Monitor.
Monitor 1: Bobril SPA
| Field | Value |
|---|---|
| URL | https://yourapp.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | A stable string from your HTML (e.g. app title) |
| Check interval | 1 minute |
Monitor 2: Health API
| Field | Value |
|---|---|
| URL | https://yourapp.com/health |
| Method | GET |
| Expected status | 200 |
| Check interval | 1 minute |
Two monitors cover two distinct failure classes: static file serving and backend data layer failures.
Step 3: Heartbeat for Background Jobs
Bobril enterprise apps often run scheduled tasks — cache warming, data export, report generation. Use a Vigilmon heartbeat to detect silent failures.
npm install node-cron
// scheduler.ts
import cron from "node-cron";
const VIGILMON_HEARTBEAT_URL = process.env.VIGILMON_HEARTBEAT_URL ?? "";
async function pingHeartbeat(): Promise<void> {
if (!VIGILMON_HEARTBEAT_URL) return;
try {
await fetch(VIGILMON_HEARTBEAT_URL, { signal: AbortSignal.timeout(5000) });
} catch {
// Never let monitoring crash the job
}
}
cron.schedule("*/10 * * * *", async () => {
try {
await runDataExport();
await pingHeartbeat();
} catch (err) {
console.error("[scheduler] Data export failed:", err);
// Vigilmon fires after the heartbeat window expires with no ping
}
});
async function runDataExport(): Promise<void> {
// Your scheduled task logic here
}
Create the heartbeat in Vigilmon:
- Monitors → New Heartbeat Monitor
- Set Expected interval to 20 minutes (2× the cron interval)
- Copy the ping URL into your environment:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Step 4: Display an Uptime Badge in Your Bobril Component
Bobril's component model makes it straightforward to embed a live status badge:
// src/components/StatusBadge.ts
import * as b from "bobril";
interface IStatusBadgeData {}
interface IStatusBadgeCtx extends b.IBobrilCtx {
data: IStatusBadgeData;
}
const BADGE_URL = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL = "https://vigilmon.online/status/your-monitor-slug";
export const StatusBadge = b.createComponent<IStatusBadgeData>({
render(ctx: IStatusBadgeCtx, me: b.IBobrilNode) {
me.children = b.styledDiv(
b.anchor(
{
href: STATUS_URL,
target: "_blank",
rel: "noopener noreferrer",
"aria-label": "Service uptime status",
},
b.image({ src: BADGE_URL, alt: "Uptime", width: 120, height: 20 })
),
{}
);
},
});
Add it to your root layout:
// src/app.ts
import * as b from "bobril";
import { StatusBadge } from "./components/StatusBadge";
b.init(() =>
b.styledDiv(
[
// ... your main content
b.create(StatusBadge, {}),
],
{ display: "flex", flexDirection: "column", minHeight: "100vh" }
)
);
Step 5: Configure Alert Channels
In Vigilmon's Alert Channels settings:
- Alert Channels → Email → add your on-call address
- Attach to both HTTP monitors and the heartbeat
Slack
- Create a Slack Incoming Webhook for
#alerts - Alert Channels → Webhook → paste the webhook URL
- Payload template:
{
"text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}
Step 6: Verify Everything Works
# 1. Confirm the health endpoint
curl -s https://yourapp.com/health | jq .
# 2. Simulate a DB failure → confirm health returns 503
# Expected: Vigilmon alert within ~2 minutes
# 3. Remove VIGILMON_HEARTBEAT_URL and let the scheduler run
# Expected: heartbeat alert after the grace window
# 4. Vigilmon → "Test Alert" → confirm delivery to Slack/email
Summary
| Monitor | What It Catches | |---|---| | HTTP SPA check | CDN failures, broken static deploys | | HTTP health API | Database, external API, and service failures | | Heartbeat | Silent scheduler failures, broken background jobs |
Next Steps
- Create separate monitors for staging and production environments
- Use Vigilmon's response time graphs to catch latency regressions across releases
- Route critical alerts to Slack, low-severity alerts to email
Ready to get started? Sign up for Vigilmon free — have your first monitor running in under 5 minutes.