Files
xamxam/todo/03-system-cache.md
Pontoporeia b981223ff4 admin/system: fetch()-based tab switching, no full-page reload
Add system-fragment.php — a thin authenticated endpoint that returns only
the tab-panel HTML (toolbar + meta + log/nginx-config output) for a given
?tab=&n= combination. No page shell, no status section, no DB queries.

system.php changes:
- Tab <a> elements gain data-tab= attributes used by JS to identify the
  target without parsing hrefs.
- Tab panel content wrapped in <div id=sys-tab-panel data-tab= data-n=>
  which JS uses as both the swap target and its own state store.
- JS rewritten: tab clicks and lines-select changes call loadPanel()
  which fetch()es system-fragment.php, swaps innerHTML, updates active
  tab ARIA attributes, and pushes state via history.pushState.
- Browser back/forward handled via popstate listener.
- bindPanelControls() re-wires the lines-select and copy-to-clipboard
  button after every innerHTML swap (event delegation not feasible here
  because log-output is replaced wholesale).
- fetch() failure falls back to window.location.href (full page load).
- Tabs without JS still work: <a href> links go to system.php?tab=…
  as before.

system-fragment.php:
- Requires AdminAuth::isAuthenticated(); returns 403 on failure.
- Validates tab and n params against the same whitelist as system.php.
- All helper functions namespaced with frag_ prefix to avoid redeclaration
  if PHP ever includes both files in the same process.
- Renders identical HTML to the corresponding section in system.php.

system.css:
- #sys-tab-panel gets min-height:8rem and position:relative to prevent
  layout jump during fetch.
- .sys-panel-loading: opacity 0.4 + pointer-events:none + subtle
  diagonal-stripe ::after overlay with shimmer animation.
2026-04-06 15:32:41 +02:00

2.0 KiB
Raw Blame History

System Page Caching - Database-Backed Status Cache

Problem

The admin system page (/admin/system.php) runs expensive operations on every load:

  • systemctl subprocess calls (~4 checks × ~100ms each)
  • curl HTTP self-check (~200-500ms)
  • disk_total_space()/disk_free_space() (fast but unnecessary per-request)
  • Log file tail + filesize + filemtime (I/O bound)
  • Nginx config file reading

Solution: system_cache table + background refresh

  • Add system_cache table to schema: CREATE TABLE system_cache (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at INTEGER NOT NULL)
  • Add migration storage/migrations/007_system_cache.sql
  • Add SystemCache class (src/SystemCache.php) with methods:
    • get(string $key, int $maxAgeSec = 60): ?array
    • set(string $key, array $data): void
    • isStale(string $key, int $maxAgeSec = 60): bool
  • Refactor system.php status section:
    1. Check SystemCache::get('system_status', 120) — 2-minute TTL
    2. If cache hit → render from cache, show “mis en cache il y a X sec” label
    3. If cache miss → run checks, store in cache, render
    4. Add ?refresh=1 GET param to force-bypass cache
  • Refactor system.php log sections — avoid re-reading on every tab switch; only read the active tabs log
  • Cache disk info separately with 5-minute TTL: SystemCache::get('disk_info', 300)
  • Cache PHP info separately with 1-hour TTL: SystemCache::get('php_info', 3600)

Notes

  • Log caching deliberately omitted: tail output is inherently real-time and caching even 30s would show stale data during the moments it matters most (deploys, errors). The existing tab guard already ensures only the active log file is read.
  • nginx config could be cached but file() on a small static config file is negligible; not worth the added complexity.
  • Log tab switching and line-count changes now use fetch() via system-fragment.php; no full page reload on tab switch.