Central history server + plugin write-through sync (epic hc-0p1)
Adds a PHP/SQLite history server in server/ and refactors the plugin to write every session change through it. Healthcheck history now survives plugin uninstall and groups across dev + live URLs for the same engagement via an editable site_key (defaults to the normalised host). Server (server/): - Front controller + hand-rolled autoloader, no framework, no composer - SQLite default DSN; swap to MySQL by changing config.php - Schema: healthchecks (PK id, UNIQUE (site_key, started_at)) + step_updates (PK (healthcheck_id, step_id)) + request_log; auto-migration runner - 8 endpoints: POST/GET/PUT healthchecks, PUT/GET step rows, GET step history with exclude_id, GET /sites (recent), GET /step-counts (badge data) - Bearer auth via hash_equals; HTTPS expected (plugin enforces client-side) - DEPLOY.md with Apache/nginx vhosts, Let's Encrypt, SQLite backup cron, and the /home/www/ perm gotcha - dev-router.php works around PHP -S 405-ing dotted uniqid paths Plugin: - ATT_HC_Api HTTP client reads ATT_HC_API_URL/ATT_HC_API_KEY constants from wp-config.php; refuses non-HTTPS with a loopback dev exception - ATT_HC_Session is now write-through: every start/update_step/finish/ set_autocheck POSTs or PUTs to the server first, then updates the local WP option cache. No drift possible — failures throw ATT_HC_Api_Exception - previous() now reads from /healthchecks?include=steps and reconstructs; the old att_hc_previous_session local option is gone - ATT_HC_Session::resume(id) hydrates a server session into the local cache - Start screen: editable site_key (defaults to normalise_site_url()), datalist of recent engagements, table of in-progress sessions for the chosen key with Resume buttons. Double-click guard on start + resume handlers short-circuits if a session is already active - Per-step <details> disclosure shows "Previous notes (N)" badge from /step-counts; lazy-loads detail rows on first expand via admin-ajax, caches via data-loaded, resets on error so user can retry - All admin handlers catch ATT_HC_Api_Exception and surface via att_hc_api_error transient → admin notice - Hard config-error gate at the top of the admin page blocks the UI when ATT_HC_API_URL/ATT_HC_API_KEY are missing or malformed Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
40
server/src/bootstrap.php
Normal file
40
server/src/bootstrap.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace AttHc\Server;
|
||||
|
||||
// Hand-rolled PSR-4-ish autoloader. No composer dependency.
|
||||
spl_autoload_register(static function (string $class): void {
|
||||
$prefix = 'AttHc\\Server\\';
|
||||
if (strncmp($class, $prefix, strlen($prefix)) !== 0) return;
|
||||
$relative = substr($class, strlen($prefix));
|
||||
$path = __DIR__ . '/' . str_replace('\\', '/', $relative) . '.php';
|
||||
if (is_file($path)) require $path;
|
||||
});
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '1');
|
||||
|
||||
set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
|
||||
if (!(error_reporting() & $severity)) return false;
|
||||
throw new \ErrorException($message, 0, $severity, $file, $line);
|
||||
});
|
||||
|
||||
set_exception_handler(static function (\Throwable $e): void {
|
||||
error_log('[att-hc-server] ' . $e::class . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine());
|
||||
if (!headers_sent()) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
}
|
||||
echo json_encode(['error' => 'internal server error', 'code' => 'internal']);
|
||||
});
|
||||
|
||||
$configPath = __DIR__ . '/../config.php';
|
||||
if (!is_file($configPath)) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'server not configured: missing config.php', 'code' => 'no_config']);
|
||||
exit;
|
||||
}
|
||||
Config::load(require $configPath);
|
||||
Reference in New Issue
Block a user