BareGit

Initial commit

Author: MetroWind <chris.corsair@gmail.com>
Date: Fri Sep 18 13:25:55 2026 -0700
Commit: bf8712a0a79554078d8f81f073127de9caceb818

Changes

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..eb70bf9
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.24)
+
+project(status_tracker LANGUAGES CXX)
+
+add_executable(status_tracker src/main.cpp)
+target_compile_features(status_tracker PRIVATE cxx_std_23)
+set_target_properties(status_tracker PROPERTIES CXX_EXTENSIONS OFF)
diff --git a/prd.md b/prd.md
new file mode 100644
index 0000000..92c542c
--- /dev/null
+++ b/prd.md
@@ -0,0 +1,100 @@
+# Status Tracker
+
+A simple self-hosted service status tracker.
+
+## Requirements
+
+- C++
+- User Cmake to build.
+- All external dependencies should be pulled using `FetchContent`,
+  except for basic ones like OpenSSL, SQLite, etc. `FetchContent`
+  should not pin to specific version of these dependencies. But some
+  dependencies may need a branch specified.
+- No authentication. The web UI is read-only and data-driven.
+- YAML configuration
+- It monitors a bunch of endpoints which are defined in the
+  config file
+- Endpoints may be monitored by one of the following protocols:
+  * HTTP (check it returns 2xx status)
+  * TCP or UDP port open
+  * ICMP
+- Possible config snippet for endpoint:
+
+  ```yaml
+  some-endpoint-id: # A uniq ID
+    name: Blog
+    description: It’s my blog.
+    # User-facing URL
+    url: https://blog.mws.rocks/
+    endpoint:
+      # Different protocols may have different set of fields.
+      protocol: HTTP
+      # This could be different from the user-facing URL. If this is omitted, use the user-facing URL
+      url: https://blog.mws.rocks/
+      timeout_second: 5
+    interval:
+      value: 1
+      unit: minute
+  ```
+
+  Another:
+
+  ```yaml
+  some-endpoint-id: # A uniq ID
+    name: VM host
+    description: My VM host
+    endpoint:
+      protocol: ICMP
+      host: 10.10.10.20
+      timeout_second: 5
+    interval:
+      value: 1
+      unit: minute
+  ```
+
+- In the config file the endpoints are grouped with another level of
+  grouping. This grouping is also shown in the web UI.
+- Stores status history in SQLite db.
+- Endpoint status: There should be four possible status: good, bad,
+  other, and n/a. Right now we can reserve “other” for the case where
+  UDP probe does not get a response. “N/a” is the case where there is
+  no data in the database (which is different from the service being
+  unavailable) or data is staled (the last data point is more than
+  twice the interval old). These status should be indicated on
+  the webpage with a “LED light”. Good is green, bad is red, other is
+  yellow, n/a is dimmed light.
+- In the database, each status update has:
+  * Service ID (the uniq ID defined in the config)
+  * Timestamp with precision to a second (UTC unix timestamp)
+  * Duration in microseconds (the time it takes to finish the status
+    check)
+  * Status (integer)
+
+## Probe scheduling
+
+- Probe workflow:
+  1. A priority queue of tasks, ordered by next due time.
+  2. Each endpoint has an atomic bool `in_flight`.
+  3. The scheduler dequeue a task, If no worker is available, ditch
+     the task. If there is a worker available, if the endpoint is
+     already inflight, ditch the task; otherwise mark the endpoint as
+     inflight, and dispatch it to a worker.
+  4. The scheduler enqueue the next task of that endpoint. Note that
+     if the schedued time of the next task is in the past, we should
+     find the next one that’s in the future.
+  5. The scheduler peeks the queue and wait for the next task to
+     trigger.
+  6. Meanwhile the worker does the probing, and save the result to db
+  7. worker marks the endpoint as not inflight.
+
+- Each worker is a thread in a thread pool with a fixed capacity. The
+  capacity is defined in the config file.
+
+## UI
+
+- Server-rendered HTML
+- No live updates. The user should referesh if they want new data
+- Use Inja for templates
+- Templates and static files are compiled into the binary at build
+  time. In the repository they are individual files in the file
+  system.
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..d4fc6ec
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,8 @@
+#include <iostream>
+
+// Entry point for the status tracker service.
+int main()
+{
+    std::cout << "Status Tracker\n";
+    return 0;
+}