Pontoporeia 554ba3ee8d fix(admin): stop logging out active long-form work; raise idle timeout to 4h
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.
2026-09-18 16:26:49 +02:00

XAMXAM

(Anciennement Posterg)

Répertoire des travaux de fin d'études de l'ERG (École de Recherche Graphique).

Requirements

  • PHP ≥ 8.4 (with ext-json, ext-openssl, ext-pdo, ext-sqlite3)
  • Composer
  • Node.js / npm
  • nginx (production)

Development

# one-time
composer install
npm ci

# run the dev server (builds assets, applies migrations, opens a browser)
just dev                    # http://127.0.0.1:8000 (public) and /admin/
just stop                   # stop it

Live CSS/JS rebuilds happen automatically via a chokidar watcher while just dev runs. See docs/development.md for the full workflow.

Deployment

Files are pushed to the server with rsync — there is no repo on the remote.

just deploy     # rsync app files → xamxam:/var/www/xamxam/
just deploy-db  # push local xamxam.db → remote (only if remote DB is absent)

deploy-db refuses to run if a database already exists on the server, to avoid accidental overwrites of production data.

First-time server setup

First bootstrap the role/user/dirs with scripts/setup-server.sh, then the one-shot remote provisioning recipe, which deploys code, nginx, and cron jobs:

# 1. role/user/dir bootstrap (creates xamxam group, /var/www/xamxam, perms):
#    equivalent to: ssh -t xamxam "sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh"
rsync scripts/setup-server.sh xamxam:/tmp/setup-server.sh
ssh -t xamxam "sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh"

# 2. full provisioning (env/APP_KEY + deploy + nginx + backup + cleanup cron + logrotate):
just provision-server

Fresh box caveat: provision-server assumes setup-server.sh already ran. On a truly empty /var/www/xamxam, run setup-server.sh (or re-apply deploy-server.sh via just deploy-nginx) first, otherwise the deploy's rsync hits Permission denied on storage/.

just deploy / just deploy-nginx apply code + nginx config:

just deploy
just deploy-nginx   # included in `just deploy` and `just provision-server`

See docs/deployment.md for the full workflow and the podman test environment in test-env/README.md to validate any of this against a fresh throwaway box.

Security notes

  • Admin panel protected by PHP session (AdminAuth) — password-only, no username
  • Uploads stored outside webroot, served via controlled /media (MediaController)
  • Rate limiting on public search (app/src/RateLimit.php)
  • See nginx/docs/SECURITY_HEADERS.md for security headers reference

More docs

See docs/README.md for the full documentation index.

S
Description
Site permettant de consulter la collection de TFE de l'erg
Readme
167 MiB
Languages
PHP 76%
CSS 10%
JavaScript 7.3%
Shell 4.3%
Just 1.6%
Other 0.8%