Sumchenko Works
RUРусская версияToggle theme
P—04 · DevelopmentIn progress

Website Health Monitor

A Go service that checks around the clock that my projects are up and actually working — with a web UI, an API and history in PostgreSQL.

Code
Role
Requirements, architecture, Go development with Claude Code
Period
2026.01 → …
Status
In progress
Stack
Go · PostgreSQL · Docker · GitHub Actions · Grafana

Interface

01 / 05
Project overviewDown targets on top, the summary "Down: 1 of 7", last check, response time and 24-hour uptime. The targets are real addresses of this portfolio.

Problem

Links to my pet projects go to employers, and a link must never open a dead service. The projects live on a VPS and free hosting — they fall asleep, respond after a cold start, and a free Supabase database pauses after a week without requests. Learning about an outage from a recruiter is too late.

Solution

The monitor checks every target on a schedule — not just the response code but also a keyword on the page — writes the result to PostgreSQL and shows an "all green / something is down" summary with 24-hour uptime. Targets are added, changed and disabled in the web UI or via the API and are picked up without a restart.

I wrote the first version in January as a Go learning project. In October I came back to it with a new goal — watching the projects in this portfolio — ran an audit, found 10 issues and drew up a 7-stage plan. The code is written with Claude Code along that plan with a decision log; three stages are done.

Goals

  1. 01Learn about an outage before an employer does
  2. 02Check that a project works, not just that it responds
  3. 03Add and disable projects without rebuilding
  4. 04Keep free-tier services awake

Features

Response code and keyword checksPer-target interval, timeout and headersChanges apply on the flyWeb UI with a summary and 24-hour uptimeJSON API for targetsBasic Auth and CSRF protectionEmbedded PostgreSQL migrationsDocker, a healthcheck and CI with tests

Key requirements

IDRequirementPriority
FR-01A target is up if the response has the expected code (any 2xx after redirects by default) and, if set, contains the keyword.Must
FR-02Adding, changing and disabling a target apply without restarting the service.Must
FR-03A target is never checked in parallel with itself.Must
FR-04Interval at least 30 s; timeout at most 120 s and less than the interval.Must
FR-05Telegram alerts on outage and recovery — without spam.Should
NFR-01Stopping or deploying the service produces no false outages.Must
NFR-02UI and API require a password; /healthz is open for external monitoring.Must
NFR-03The DB schema changes only through new migrations; old data is carried over.Must

Scenarios

OwnerA project goes down
  1. 01A check does not find the keyword: the page returned 200 but it is an error stub
  2. 02The result with the reason is written to health_checks
  3. 03In the UI the target moves to the top in red; the summary says "1 down"
  4. 04After stage 5 — a Telegram message, and another on recovery
OwnerA new portfolio project
  1. 01Adds a target in the form: URL, keyword, a timeout for cold starts
  2. 02The server validates the settings and saves the target
  3. 03The scheduler starts checking right away — no restart

Timeline

  1. 2026.01First versionChecks from a list in code, PostgreSQL, Docker, CI with tests, Grafana output.
  2. 2026.10Stage 0: audit and planA new goal — monitoring the portfolio; 10 issues found and a 7-stage plan.
  3. 2026.10Stages 1–2: core and targets in the DBStatus logic, timeouts, migrations, pgx, graceful shutdown; a targets table, keywords, headers, live reload.
  4. 2026.10Stage 3: UI and APIA web UI without JS frameworks, a JSON API, validation, Basic Auth, CSRF protection, /healthz.
  5. NextStages 4–7Grafana as code, Telegram alerts, quality and CI, deployment to the VPS with external monitoring of the checker itself.

Challenges

"Responds" is not "works"A broken app may return 200 with an error page. So a target has a keyword searched for in the first megabyte of the response.
False outages on deployChecks interrupted by a service stop or a target change are discarded, and the processor writes every result before the channel closes.
Target changes without a restartA goroutine per target plus a semaphore instead of a worker pool: the scheduler reconciles the list with the DB and starts, stops or restarts checks precisely.
Basic Auth and CSRFBrowsers attach Basic Auth to requests from other sites by themselves. Forms and the API are guarded by http.CrossOriginProtection from Go 1.25.

Outcome

Three of seven stages are done — about 3,200 lines of Go including 34 tests, integration ones on PostgreSQL among them. The service checks targets, applies changes on the fly and shows a summary with uptime.

Next — a Grafana dashboard from the repository, Telegram alerts and deployment to the VPS next to the projects it watches.

Technologies

Next · P—01Mito