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;
+}