Charles N Wyble ed34a28c89 WIP: uncommitted changes before archiving
💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
2026-01-13 20:14:07 -05:00

Website Monitor

A comprehensive website monitoring application built with ReasonML, OCaml, and server-reason-react. Monitor multiple websites for HTTP status deviations and receive alerts via email or webhooks.

Features

  • Real-time Monitoring: Continuously monitor websites for HTTP 200 status deviations
  • Alert System: Send alerts via email or webhooks when websites go down or recover
  • Admin Dashboard: Beautiful, responsive web interface for managing websites and alerts
  • REST API: Full CRUD API for programmatic access
  • History Tracking: Keep detailed history of all website checks
  • Docker Support: Fully containerized with Docker and Docker Compose
  • Resource-Constrained Builds: Docker builds limited to 1 CPU core

Technology Stack

  • Language: OCaml 5.0+ with ReasonML
  • Web Framework: Dream (OCaml web framework)
  • Frontend: server-reason-react (server-side React with ReasonML)
  • Database: PostgreSQL with Caqti (OCaml database interface)
  • Async: Lwt (OCaml's cooperative threading library)
  • Container: Docker & Docker Compose

Quick Start

Prerequisites

  • Docker 20.10+
  • Docker Compose 2.0+

Installation

  1. Clone the repository:
git clone <repository-url>
cd test3
  1. Create environment file:
cp .env.example .env
  1. Edit .env with your configuration (especially SMTP settings for alerts)

  2. Start the application:

docker-compose up -d
  1. Access the dashboard at http://localhost:8080

Configuration

Environment Variables

Variable Description Default
DB_PASSWORD PostgreSQL database password changeme
SMTP_HOST SMTP server hostname smtp.gmail.com
SMTP_PORT SMTP server port 587
SMTP_USER SMTP username -
SMTP_PASSWORD SMTP password -
ADMIN_EMAIL Email to receive all alerts admin@example.com
SECRET_KEY Secret key for sessions -
ENVIRONMENT Environment (development/production) production

API Documentation

Websites

List all websites

GET /api/websites

Get website by ID

GET /api/websites/:id

Create website

POST /api/websites
Content-Type: application/json

{
  "name": "Example Site",
  "url": "https://example.com",
  "expected_status": 200,
  "timeout": 30,
  "check_interval": 300
}

Update website

PUT /api/websites/:id
Content-Type: application/json

{
  "name": "Updated Name",
  "active": true
}

Delete website

DELETE /api/websites/:id

Check website now

POST /api/websites/:id/check

Get website history

GET /api/websites/:id/history?limit=100

Get website status

GET /api/websites/:id/status

Alerts

List all alerts

GET /api/alerts

Get alert by ID

GET /api/alerts/:id

Create alert

POST /api/alerts
Content-Type: application/json

{
  "website_id": 1,
  "alert_type": "email",
  "config": {
    "to_email": "admin@example.com",
    "cc_email": "client@example.com",
    "subject_prefix": "[Monitor]"
  }
}

Update alert

PUT /api/alerts/:id
Content-Type: application/json

{
  "enabled": true
}

Delete alert

DELETE /api/alerts/:id

Stats

Get summary statistics

GET /api/stats/summary

Alert Types

Email Alerts

Configuration:

{
  "to_email": "recipient@example.com",
  "cc_email": "cc@example.com",  // optional
  "subject_prefix": "[Monitor]"    // optional
}

Webhook Alerts

Configuration:

{
  "url": "https://hooks.slack.com/services/...",
  "method": "POST",
  "headers": {
    "Content-Type": "application/json"
  },
  "body_template": ""
}

Development

Local Development

  1. Install dependencies:
opam install . --deps-only
  1. Build the project:
dune build
  1. Run tests:
dune test
  1. Run the application:
dune exec bin/main.exe

Docker Development

Build with CPU constraint (1 core):

docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t website_monitor .

Run with Docker Compose:

docker-compose up

Project Structure

test3/
├── bin/
│   ├── dune              # Binary build configuration
│   └── main.ml           # Application entry point
├── lib/
│   ├── dune              # Library build configuration
│   ├── database.ml       # Database models and queries
│   ├── monitor.ml        # Website monitoring logic
│   ├── alert.ml          # Alerting system
│   ├── api.ml            # REST API handlers
│   ├── ui.ml             # Server-side React UI
│   └── scheduler.ml      # Background monitoring scheduler
├── docker/
│   └── Dockerfile
├── docker-compose.yml
├── dune-project
├── website_monitor.opam
├── .env.example
└── README.md

Monitoring Behavior

  • Websites are checked at their configured check_interval (default: 5 minutes)
  • Failed checks trigger alerts to configured endpoints
  • Recovery alerts are sent when a website returns to normal
  • Check history is retained for 30 days (configurable)
  • The scheduler runs every minute to check due websites

CPU Constraints

The Docker build is configured to use only 1 CPU core:

ENV OPAMJOBS=1

In docker-compose.yml:

cpus: '1.0'
cpuset: '0'

Security Considerations

  1. Environment Variables: Never commit .env files to version control
  2. Secrets: Use strong random strings for SECRET_KEY
  3. SMTP: Use app-specific passwords, not your main password
  4. Database: Change default passwords in production
  5. HTTPS: Use a reverse proxy (nginx, Traefik) for HTTPS

Troubleshooting

Database Connection Issues

docker-compose logs postgres

SMTP Issues

  • Check SMTP credentials in .env
  • Verify SMTP host and port
  • Use app-specific passwords for Gmail

High CPU Usage

  • Increase check_interval for less frequent checks
  • Reduce number of active websites
  • The build is already limited to 1 CPU core

License

MIT License - see LICENSE file for details

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Write tests
  5. Submit a pull request

Support

For issues and questions, please open an issue on the GitHub repository.

Description
No description provided
Readme MIT 76 KiB
Languages
OCaml 91.1%
Shell 3.8%
Dockerfile 2.2%
Makefile 2.1%
Dune 0.8%