Pontoporeia
bfde71caaa
style: fix biome check errors (import order + formatting)
...
npx biome check reported 14 errors on app/public/assets/css/,
app/public/assets/js/app/ and scripts/:
- assist/source/organizeImports: scripts/css-content-sources.mjs,
scripts/css-unused-report.mjs
- format: 9 CSS files + 3 JS files
Fixed via biome check --write. Verified: npx biome check clean,
npm run build succeeds, PHPUnit 316 tests / 628 assertions pass.
2026-09-18 16:26:49 +02:00
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
Pontoporeia
b1715b210d
fix(deploy): restore www-data ownership after deploy-code to prevent HTTP 500
2026-09-18 16:26:49 +02:00
Pontoporeia
3f352b0d26
feat(admin): cleanup page — remove 'Fichiers temporaires' level, promote sections to h2 TOC entries
2026-09-18 16:26:49 +02:00
Pontoporeia
1ed69a2c1a
refactor(justfile): de-dup deploy-code, move nginx/setup to deploy-nginx
2026-09-18 16:26:48 +02:00
Pontoporeia
fc66b37801
feat(home): htmx lazy-load cover images
...
Replace the eager <img> on the home page with an htmx placeholder <figure>
that fetches a /cover-fragment endpoint when it scrolls into view
(hx-trigger="revealed"), so heavy cover bytes load only on demand.
Add spinner + settle-fade transition CSS, and load htmx.min.js on home.
2026-09-18 16:26:36 +02:00
Pontoporeia
541470b9bb
feat(provision): idempotent setup for local dev and remote server
2026-09-18 16:26:36 +02:00
Pontoporeia
8accb88452
update: CSS per-page split and lightningcss unusedSymbols report
...
docs: record CSS template inventory + decide unusedSymbols-before-split ordering
feat(css): add content-source collector + dynamic-class safelist for unusedSymbols report
- scripts/css-content-sources.mjs: buildCorpus() gathers templates/public/src
PHP + first-party js/app JS (vendor excluded), returns {corpus, sources,
totalBytes, safelist, prefixes}
- Mined 22 exact runtime classes + 5 DB/state-derived suffix prefixes from
status-badge.php, SystemController statusClass/logLineClass, and class=<?=?>
ternaries
- docs/css-split-analysis.md notes content-corpus section
- td: #11 collect-content-sources done; feeds #12 report script
feat(css): unusedSymbols report script + just css-report recipe
- scripts/css-unused-report.mjs: per-bundle class/id extraction vs buildCorpus()
corpus + safelists; measures reclaimable bytes via lightningcss transform
unusedSymbols (report-only, no stripping to disk)
- just css-report: rebuild CSS then run the report
- css-content-sources.mjs: add VENDOR_CLASS_PREFIXES (filepond--*, htmx-*)
- RESULT: 216,383B total, ~6.2KB (2.9%) reclaimable; FilePond/HTMX exclusion
corrected inflated 26% (56KB) false-positive down to honest 2.9%
- docs/css-split-analysis.md findings table + TODO 12/13 done
docs(css): record go/no-go decision — split NO-GO, pruning conditional-go
- Decision analysis in docs/css-split-analysis.md
- ~6.2KB (2.9%) reclaimable of 216KB; base.min.css only 484B (2.3%)
- SPLIT NO-GO: base.css already well-used; parked u/w/x/y(/z) as deferred
- PRUNING conditional-go on hand-verifiable dead selers from source, never dist;
re-run just css-report after each edit; keep needs-review + vendor-prefix cls
- td: task 14 done; split stream 41 tasks -> 2 pending / 32 done / 7 deferred
todo: defer CSS pruning stream (10/u/w/x/y/z), context updated
2026-09-18 16:26:36 +02:00
Pontoporeia
307988eb3c
feat: enforce idle + absolute timeouts on admin session
2026-09-18 16:26:36 +02:00
Pontoporeia
30a16f9e9e
fix: display db timestamps in Brussels time
...
(heure de dépôt was showing UTC)
- feat: add date_depot column (real TFE deposit date)
with CSV round-trip + Brussels→UTC sanitization
- fix: keep PHP default tz at UTC to preserve token/share-link
expiry consistency; convert to Brussels only in db_datetime()
2026-09-18 16:26:36 +02:00
Pontoporeia
e4b48867aa
Add sso-diagnose.sh: verify all peertube-sso-incident claims into a log
...
- docs: record the open identity-forwarding question, auth contracts, and responsibility boundary
2026-08-24 11:36:02 +02:00
Pontoporeia
f31addb6bc
add password-reset smoke test + AdminAuth DI + OneTimeToken empty-context redeem fix
2026-08-24 11:36:02 +02:00
Pontoporeia
fb5e856288
admin: backup logs via parameters.php, nextcloud secondary backup
...
- surface backup/cleanup cron logs + backup freshness status
- email xamxam@erg.be when SQLite backups go stale (backup watchdog)
- sync SQLite snapshots to Nextcloud WebDAV + remote-freshness watchdog
- precise retention pruning, manual sync in check recipe, and Nextcloud-sync docs
2026-08-24 11:34:57 +02:00
Pontoporeia
d2cef85966
logs: standardise log filenames to xamxam-{service}-{date}.log
2026-08-24 11:34:34 +02:00
Pontoporeia
7b6d79c133
diag: invalid_grant is SSO auth-method mismatch, not bad creds
...
- feat: creds-test.sh gum probe for SMTP vs PeerTube auth + PeerTubeService::probeAuth()
- feat: app-token.sh gum probe for long-lived PeerTube app token (client_credentials)
- docs: add copy-paste proof commands to demonstrate the SSO break to admins
2026-08-24 11:33:34 +02:00
Pontoporeia
7938ab39c0
feat: add custom 404 page rendered via the site layout
2026-08-24 11:32:02 +02:00
Pontoporeia
c1a05efcda
fix: bypass /tmp tmpfs for file uploads by redirecting PHP upload_tmp_dir to storage partition
2026-07-10 15:42:07 +02:00
Pontoporeia
22a49f7cb6
fix: unify CSV import/export columns, fix import JS error, fix createThesis VALUES
...
- Fix createThesis SQL: extra ? placeholder in VALUES (27 values for 26 columns)
- Add createThesis integration tests to catch column/value mismatches
- Add CSV_COLUMNS as single source of truth in ExportController, deriving
csvHeaders() and positional fallback from it
- Add missing columns to export query + CSV: duration_pages, duration_minutes,
has_annexes, license_custom, contact_visible, objet
- Add missing columns to import INSERT: license_id, license_custom, cc2r,
exemplaire_baiu, exemplaire_erg, objet, contact_visible, duration_pages,
duration_minutes, has_annexes
- Resolve license name → license_id during import
- Fix XamxamInitFilePonds: add file-upload-filepond.js to admin-entry.js
so FilePond initialization code is available on the admin list page
- Add FilePond vendor CSS to admin.min.css bundle (import dialog styling)
- Generate .admin-file-hint from csvHeaders() instead of hardcoded stale list
- Use positional fallback from CSV_COLUMNS for import cell parsing
2026-07-10 11:56:27 +02:00
Pontoporeia
912b38583b
Add --quiet flag to build.mjs for cleaner 'just dev' output
2026-07-08 13:50:03 +02:00
Pontoporeia
3e93150c76
justfile: standardise test recipes to lint-php/lint-css/lint-js/test + add fix recipe
...
- Removed ambiguous aliases: phpstan, cs-check, syntax
- Split lint-biome into lint-css and lint-js with correct paths
- Added lint meta-recipe and fix recipe (biome --unsafe + php-cs-fixer)
- Fixed FormBootstrap dead null check, CSS shorthand override bug
- Updated phpstan baseline, suppressed noDescendingSpecificity/noInnerDeclarations
- Applied ~74 biome auto-fixes across CSS/JS
2026-07-05 11:07:41 +02:00
Pontoporeia
6ecd3d4540
Fix biome lint errors: remove duplicate CSS properties, apply safe auto-fixes
...
CSS:
- Remove duplicate 'background' fallbacks in base.css, header.css, search.css
(solid color declared before gradient — gradient always wins)
- Remove duplicate 'padding' in admin.css .admin-import-log
JS (biome --write safe fixes applied):
- function() → arrow functions in all IIFEs and callbacks
- forEach/callback → arrow functions
- evaluePtrn → parseInt(x, 10) in admin-contacts-form.js
- Cleaned label text in build.mjs lint step
Remaining warnings are intentional: !important overrides, descending
specificity (admin.css cascade), noUnusedVariables (functions exported
to window/onclick), useTemplate style preference.
2026-06-24 13:57:00 +02:00
Pontoporeia
20fe4b6c8c
Add biome + rolldown + lightningcss build pipeline for JS/CSS bundling & minification
...
- package.json with biome, rolldown, lightningcss devDependencies
- biome.json: add CSS formatter support
- scripts/build-css.mjs: lightningcss resolves @import chain, bundles/minifies CSS
- scripts/build-js.mjs: rolldown per-entry JS bundling (no code splitting)
- scripts/build.mjs: orchestrator for both CSS + JS
- scripts/check-build.mjs: staleness checker for CI/deploy guard
- justfile: add build, build-css, build-js, build-install, build-check recipes
- justfile: deploy recipe now runs build before deploy-code
- head.php + form-page.php: use dist/base.min.css instead of style.css
- All controllers + FormBootstrap: reference dist/*.min.{css,js}
- admin footer: load admin.min.js for all admin pages
- repertoire: use public.min.js instead of individual app JS files
- Fix stray '}' syntax error in admin.css line 305
- .gitignore: add app/public/assets/dist/
2026-06-24 13:09:50 +02:00
Pontoporeia
03c9c3566f
Add SQLite indexes for contenus page language/tag queries + WIP: Peertube orphans, dialogs, contact decoupling, context note, finality types
2026-06-21 16:36:34 +02:00
Pontoporeia
d588ae004d
Reintroduce TFE duration metadata: DB columns, form fields, controllers, views, and migration
...
Add 'unsafe-eval' to CSP script-src directives (htmx requires Function())
2026-06-15 15:56:52 +02:00
Pontoporeia
00fed5f0e3
Add periodic cleanup of orphaned drafts: cleanup job, just command, deploy cron
2026-06-11 13:05:34 +02:00
Pontoporeia
defc919cd0
cleanup modal: list stale files to remove; storage restructure: documents/ → {objet}/
2026-05-19 23:58:51 +02:00
Pontoporeia
31ccbd195b
add syntaqlite SQL validation to migrate.sh before applying schema.sql
2026-05-19 00:08:06 +02:00
Pontoporeia
cb6394e119
add incremental migration runner to deploy recipe — execute whole SQL files (not semicolon-split), catch 'no such column' for idempotent re-runs, merge into migrate.sh
2026-05-19 00:08:06 +02:00
Pontoporeia
c1960d224b
fix deploy: multiple deploy recipe fixes — upload xamxam.conf before deploy-server.sh, sudo rsync for chown, migrate.sh via sqlite3, chmod WAL/SHM sidecar files, deploy-verify-permissions awk fix, .env sudo perms
2026-05-19 00:08:06 +02:00
Pontoporeia
28ef35dce5
fix: make schema.sql fully idempotent — add IF NOT EXISTS to all CREATE INDEX, CREATE TRIGGER, and CREATE VIEW statements
2026-05-19 00:08:06 +02:00
Pontoporeia
973444bdbb
feat(backup): deploy cron-based SQLite backups to production
...
- Create deploy/xamxam-backup.cron with hourly (30d) and daily (90d) jobs
- Add just recipes for deploying backup infrastructure:
- deploy-backup-script: upload backup-sqlite.sh to /usr/local/bin
- deploy-backup-cron: install cron.d file, create /var/backups/xamxam + log
- deploy-backup: one-shot convenience (script + cron)
- deploy-check-backup-log: tail the backup log
- deploy-list-backups: ls remote backup directory
- trigger-backup: manually invoke backup on server
- test-restore: scp, gunzip, verify a remote snapshot
- Add reminder to run deploy-backup after first deploy
- Replace 'Contenu (Markdown)' label with 'Syntax Markdown' link (cheatsheet)
2026-05-19 00:08:06 +02:00
Pontoporeia
72f7192156
feat(deploy): add deploy-verify-permissions recipe + upload/run deploy-server.sh before verification + run migrations in deploy
2026-05-19 00:08:06 +02:00
Pontoporeia
926659087f
feat: implement SQLite backup & data integrity plan (Phases 2-4)
2026-05-19 00:08:06 +02:00
Pontoporeia
8db7b6e9eb
feat: FilePond production hardening — extension-based validation, server-side size limits (2GB), annexe validation, drop accept attributes, FilePond file styling
2026-05-19 00:08:05 +02:00
Pontoporeia
95fcbc919a
Remove required from all admin add/edit form inputs
...
- Skip required-field validation for orientation/ap/finality/licence/jury in admin add+edit
2026-05-13 17:59:13 +02:00
Pontoporeia
ca5983075d
feat: admin audit logging across all admin actions
...
- AdminLogger: JSON-lines → /var/log/xamxam.log (prod) / storage/logs/admin.log (dev)
+ best-effort DB mirror to admin_audit_log table
- DB: admin_audit_log table, share_links.is_archived column
- ShareLink: archive() replaces delete(), toggleActive() returns new state,
listActive()/listArchived() split, validateLink blocks archived slugs
- All action handlers wired: publish, unpublish, visibility, delete, csv/db export,
tfe add/edit, tags, pages, apropos, form-help, access-request, maintenance,
settings (formulaire toggles, objet types, smtp update), smtp-test
- acces.php: archive button replaces delete; collapsible archived links section
- setup-server.sh: provision /var/log/xamxam.log (www-data:xamxam 640)
2026-05-05 11:04:52 +02:00
Pontoporeia
cb883ab33f
fix: deploy-server.sh migrates posterg.db → xamxam.db and cleans legacy nginx configs
2026-05-05 11:04:52 +02:00
Pontoporeia
ab51bf3a66
fix: deploy-server.sh cleans up legacy posterg configs and prunes old xamxam backups
2026-05-05 11:04:52 +02:00
Pontoporeia
68e30abb56
fix: remove Post-ERG branding → XAMXAM; drop legacy posterg nginx symlink in deploy script; rename posterg.db → xamxam.db
2026-05-05 11:04:52 +02:00
Pontoporeia
c949cf9481
rename posterg → xamxam throughout: nginx conf, scripts, PHP source, docs
2026-05-05 11:04:52 +02:00
Pontoporeia
18a02a0018
deploy: rename deploy path from /var/www/posterg to /var/www/xamxam
2026-04-28 22:21:09 +02:00
Théophile Gervreau-Mercier
7e26351f4b
refactor: remove test.db, use only posterg.db for all environments
...
- Simplified Database.php determineDatabasePath to always use posterg.db
- Removed test.db auto-detection based on php_sapi_name
- Removed test.db targets from justfile (migrate-test removed)
- Removed CreateTestDatabase.php fixture script
- Updated migrate.sh to only init posterg.db
- Updated setup-dev.sh to init posterg.db
- Updated run-tests.php (removed DB_ENV=test env var)
- Updated deploy-db to use posterg.db
- Removed test.db file
refactor: remove empty fixtures directory
2026-04-27 18:07:20 +02:00
Pontoporeia
dbaabaf8a0
merge all migrations into schema.sql
2026-04-24 23:03:49 +02:00
Pontoporeia
75f808bee4
feat: extract MediaController, wire into Dispatcher, delete media.php
2026-04-20 12:32:00 +02:00
Pontoporeia
6f04514aa2
fix: add structural guard for migration 008 in migrate.sh
2026-04-15 14:24:44 +02:00
Théophile Gervreau-Mercier
5c5054d744
Investigating VM crash
2026-04-13 11:12:12 +02:00
Pontoporeia
b45e6c50cc
fix: admin CSP allow inline scripts
...
script-src 'self' 'unsafe-inline' added to admin Content-Security-Policy.
default-src 'self' was blocking OverType editor init block and
the dev live-reload poller. Admin section is auth-gated so
unsafe-inline is acceptable.
2026-04-08 14:14:37 +02:00
Pontoporeia
e6960f0c9c
fix: RateLimit permission denied — code + deploy scripts
...
RateLimit.php:
- Silence mkdir() with @ operator
- Guard file_put_contents with is_writable() check (graceful degrade)
scripts/deploy-server.sh + setup-server.sh:
- mkdir -p storage/cache/rate_limit on every deploy
- chown www-data:posterg + chmod 2775 on storage/cache/
so php-fpm can always write rate limit files
2026-04-06 16:45:14 +02:00
Pontoporeia
756ddb5765
fix: RateLimit graceful degradation on permission denied
...
Silence mkdir() with @ operator; guard file_put_contents with
is_writable() check. When storage/cache/rate_limit is not writable
by php-fpm, requests are allowed through instead of throwing
warnings that flood the nginx error log.
2026-04-06 16:40:55 +02:00
Pontoporeia
a88e5562f8
fix(config): auto-route test.db locally, posterg.db on production
...
- config.php: getDatabasePath() detects php built-in CLI server
(php_sapi_name() === 'cli-server') and routes to test.db; all
other SAPIs (nginx/fpm) get posterg.db. DB_ENV env-var still
overrides either way.
- migrate.sh: auto-initialise the target DB from storage/schema.sql
when the file is absent or has no tables yet. Existing DBs with
data are left completely untouched (table_count check, no re-run
of schema on populated DB). Idempotent: safe to run repeatedly.
- justfile: serve still calls migrate (which now handles init too),
no DB_ENV prefix needed since sapi detection handles routing.
2026-04-01 15:55:12 +02:00