The admin idle timeout (30 min) was refreshed only by navigations and HTMX requests. During long encoding sessions on an open form there are none, so an actively-typing admin was logged out mid-work after ~30-45 min. Add an activity-driven keepalive: - /admin/session-keepalive.php: 204 when authenticated (refreshes admin_last_activity via AdminAuth::isAuthenticated()), 401 otherwise. - admin-session-keepalive.js: marks activity only on real user input (pointer/keyboard/input/scroll/wheel/touch/focus) and pings at most once per 5 min while the tab is visible. A genuinely idle tab never pings, so the idle timeout still applies. Raise the idle window 30 min -> 4 h: for a single-/few-admin back-office whose main workflow is data entry, 30 min still kicked admins who stepped away mid-form. With the keepalive in place, 4 h means "no interaction at all", not "no navigation". Absolute timeout stays 12 h. Also fix session ID rotation, which never fired: it used `$absolute % IDLE_TIMEOUT_SECONDS === 0`, i.e. required a request to land exactly on a multiple of the interval relative to login time. Replaced with an explicit admin_last_rotation timestamp and a ROTATION_INTERVAL_SECONDS (30 min) constant decoupled from the idle timeout, so raising the idle window does not widen the fixation/replay window. Refactor AdminAuth::enforceSessionTimeout() to return bool instead of redirecting/exiting, so the keepalive endpoint can report 401 cleanly rather than letting fetch follow a redirect to the login page. Smoke test (just smoke-session-keepalive) covers activity refresh, 2 h idle accepted, rotation firing, idle rejection+destruction, and unauthenticated rejection. Docs updated.
4.0 KiB
Admin Panel Structure
This directory and app/templates/admin/ contain the admin panel for managing
the XAMXAM TFE database.
Entry points (app/public/admin/)
| File | Purpose |
|---|---|
index.php |
List all theses (main page; hosts the inline CSV import + tabs for list/trash) |
add.php |
Add new thesis form |
edit.php |
Existing thesis form |
recapitulatif.php |
Post-submission recap |
cleanup.php |
Cleanup page (Corbeille — restore/delete trashed files) |
system.php |
System dashboard (logs, SMTP/PeerTube status) |
contenus.php |
Editable content (pages, contacts) |
contenus-edit.php |
Edit a content page |
acces.php |
Share-link management |
file-access.php |
Restricted-file access requests |
media.php |
Admin file viewer — opens files of 'Interdit' (access_type_id=3) theses; session-gated (AdminAuth::requireLogin), delegates to MediaController::handle(adminBypass: true) |
media-viewer.php |
HTML wrapper that opens a thesis file with a reliable tab title (original file name); embeds the file via media.php in a full-viewport iframe |
account.php |
Admin account / password |
session-keepalive.php |
Lightweight 204/401 liveness ping that refreshes admin_last_activity while an open admin page is being actively used (see docs/security.md) |
login.php |
Login (session) |
import.php |
Redirects to /admin/ (CSV import is inline in index.php) |
status.php, markdown-cheatsheet-fragment.php, *fragment.php |
HTMX fragments / helpers |
Backend actions (app/public/admin/actions/)
Process forms and redirect (no HTML output):
formulaire.php— thesis create submission (ThesisCreateController::submit())edit.php— thesis edit submission (ThesisEditController::save())export-csv.php,export-db.php,export-files.php— seedocs/export.mdfilepond/— FilePond async upload endpoints- many others:
publish,delete,corbeille(trash),draft,visibility,tag,language,form-help*,page,apropos,smtp-test,peertube-*,maintenance,settings,account,access-request,acces-etudiante,cleanup-*
Templates
View templates live under app/templates/admin/ (not in public/):
app/templates/admin/*.php— page layoutsapp/templates/admin/partials/— shared fragments (toasts, dialogs, toc, …)
The public/partage and form partials live in app/templates/partials/ and
app/templates/partage/.
Auth
- PHP session auth (
src/AdminAuth.php) viaAdminAuth::requireLogin()is the only authentication layer. The old nginxauth_basiclayer has been removed — seedocs/security.mdandnginx/docs/PHP_AUTH_LAYER.md. - All forms include a CSRF token from
$_SESSION['csrf_token']. - Inputs use PDO prepared statements; uploads validated and stored outside the
webroot (
app/storage/).
Bootstrap / routing
Entry pages bootstrap the app and set up the environment:
require_once __DIR__ . '/../../bootstrap.php'; // defines APP_ROOT, autoload, config
require_once APP_ROOT . '/src/AdminAuth.php';
AdminAuth::requireLogin();
APP_ROOT is the app/ directory. Database access is via
app/src/Database.php; form logic lives in app/src/Controllers/ and
app/src/Form/.
URL structure
/admin/— list theses (index.php)/admin/add.php— add thesis/admin/edit.php?id=N— edit thesis/admin/cleanup.php,/admin/system.php,/admin/acces.php, etc./admin/actions/…— backend processors
Development guide
Add a page: create app/templates/admin/yourpage.php, add a thin
app/public/admin/yourpage.php entry that bootstraps + requires the template,
and add navigation in app/templates/admin/partials/admin-toc.php.
Add an action: create app/public/admin/actions/youraction.php that
bootstraps, requires login, verifies the CSRF token, performs the work, and
redirects back to the referring admin page.
See docs/development.md for the general workflow (dev server, builds,
tests, linting).