feat: indie status page MVP -- FastAPI + SQLite

- 8 DB models (services, incidents, monitors, subscribers, etc.)
- Full CRUD API for services, incidents, monitors
- Public status page with live data
- Incident detail page with timeline
- API key authentication
- Uptime monitoring scheduler
- 13 tests passing
- TECHNICAL_DESIGN.md with full spec
This commit is contained in:
IndieStatusBot 2026-04-25 05:00:00 +00:00
commit 902133edd3
4655 changed files with 1342691 additions and 0 deletions

View file

@ -0,0 +1,140 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <time.h>
#include <stdint.h>
#include "librt_time.h"
#include "pythoncapi_compat.h"
#include "mypyc_util.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
#ifdef MYPYC_EXPERIMENTAL
// Internal function that returns a C double for mypyc primitives
// Returns high-precision time in seconds (like time.time())
static double
time_time_internal(void) {
#ifdef _WIN32
// Windows: Use GetSystemTimePreciseAsFileTime for ~100ns precision
FILETIME ft;
ULARGE_INTEGER large;
GetSystemTimePreciseAsFileTime(&ft);
large.LowPart = ft.dwLowDateTime;
large.HighPart = ft.dwHighDateTime;
// Windows FILETIME is 100-nanosecond intervals since January 1, 1601
// 116444736000000000 = number of 100-ns intervals between 1601 and 1970
// Convert directly to seconds: 100ns * 1e-9 = 1e-7
int64_t intervals = large.QuadPart - 116444736000000000LL;
return (double)intervals * 1e-7;
#else // Unix-like systems (Linux, macOS, BSD, etc.)
// Try clock_gettime(CLOCK_REALTIME) for nanosecond precision
// This is available on POSIX.1-2001 and later (widely available on modern systems)
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
// Convert seconds and nanoseconds separately to avoid large integer operations
return (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9;
}
// Fall through to gettimeofday if clock_gettime failed
#endif
// Fallback: gettimeofday for microsecond precision
// This is widely available (POSIX.1-2001, BSD, etc.)
struct timeval tv;
if (unlikely(gettimeofday(&tv, NULL) != 0)) {
PyErr_SetFromErrno(PyExc_OSError);
return CPY_FLOAT_ERROR;
}
// Convert seconds and microseconds separately to avoid large integer operations
return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
#endif
}
// Wrapper function for normal Python extension usage
static PyObject*
time_time(PyObject *self, PyObject *const *args, size_t nargs) {
if (nargs != 0) {
PyErr_SetString(PyExc_TypeError, "time() takes no arguments");
return NULL;
}
double result = time_time_internal();
if (result == CPY_FLOAT_ERROR) {
return NULL;
}
return PyFloat_FromDouble(result);
}
#endif
static PyMethodDef librt_time_module_methods[] = {
#ifdef MYPYC_EXPERIMENTAL
{"time", (PyCFunction)time_time, METH_FASTCALL,
PyDoc_STR("Return the current time in seconds since the Unix epoch as a floating point number.")},
#endif
{NULL, NULL, 0, NULL}
};
#ifdef MYPYC_EXPERIMENTAL
static int
time_abi_version(void) {
return LIBRT_TIME_ABI_VERSION;
}
static int
time_api_version(void) {
return LIBRT_TIME_API_VERSION;
}
#endif
static int
librt_time_module_exec(PyObject *m)
{
#ifdef MYPYC_EXPERIMENTAL
// Export mypyc internal C API via capsule
static void *time_api[LIBRT_TIME_API_LEN] = {
(void *)time_abi_version,
(void *)time_api_version,
(void *)time_time_internal,
};
PyObject *c_api_object = PyCapsule_New((void *)time_api, "librt.time._C_API", NULL);
if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
return -1;
}
#endif
return 0;
}
static PyModuleDef_Slot librt_time_module_slots[] = {
{Py_mod_exec, librt_time_module_exec},
#ifdef Py_MOD_GIL_NOT_USED
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
#endif
{0, NULL}
};
static PyModuleDef librt_time_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "time",
.m_doc = "Fast time() function optimized for mypyc",
.m_size = 0,
.m_methods = librt_time_module_methods,
.m_slots = librt_time_module_slots,
};
PyMODINIT_FUNC
PyInit_time(void)
{
return PyModuleDef_Init(&librt_time_module);
}

View file

@ -0,0 +1,62 @@
#ifndef LIBRT_TIME_H
#define LIBRT_TIME_H
#ifndef MYPYC_EXPERIMENTAL
static int
import_librt_time(void)
{
// All librt.time features are experimental for now, so don't set up the API here
return 0;
}
#else // MYPYC_EXPERIMENTAL
#include <Python.h>
#define LIBRT_TIME_ABI_VERSION 1
#define LIBRT_TIME_API_VERSION 1
#define LIBRT_TIME_API_LEN 3
static void *LibRTTime_API[LIBRT_TIME_API_LEN];
#define LibRTTime_ABIVersion (*(int (*)(void)) LibRTTime_API[0])
#define LibRTTime_APIVersion (*(int (*)(void)) LibRTTime_API[1])
#define LibRTTime_time (*(double (*)(void)) LibRTTime_API[2])
static int
import_librt_time(void)
{
PyObject *mod = PyImport_ImportModule("librt.time");
if (mod == NULL)
return -1;
Py_DECREF(mod); // we import just for the side effect of making the below work.
void *capsule = PyCapsule_Import("librt.time._C_API", 0);
if (capsule == NULL)
return -1;
memcpy(LibRTTime_API, capsule, sizeof(LibRTTime_API));
if (LibRTTime_ABIVersion() != LIBRT_TIME_ABI_VERSION) {
char err[128];
snprintf(err, sizeof(err), "ABI version conflict for librt.time, expected %d, found %d",
LIBRT_TIME_ABI_VERSION,
LibRTTime_ABIVersion()
);
PyErr_SetString(PyExc_ValueError, err);
return -1;
}
if (LibRTTime_APIVersion() < LIBRT_TIME_API_VERSION) {
char err[128];
snprintf(err, sizeof(err),
"API version conflict for librt.time, expected %d or newer, found %d (hint: upgrade librt)",
LIBRT_TIME_API_VERSION,
LibRTTime_APIVersion()
);
PyErr_SetString(PyExc_ValueError, err);
return -1;
}
return 0;
}
#endif // MYPYC_EXPERIMENTAL
#endif // LIBRT_TIME_H