mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-11-09 19:20:09 +01:00
docs: keep only reference documentation, archive one-offs
This commit is contained in:
1 parent
8accb88452
commit
d5c1dfb23d
27 files changed
+108
-78
No files matched your search
+5
-3
@@ -10,7 +10,7 @@
|
||||
- **`typography.css`** — type scale
|
||||
- **`utilities.css`** — utility classes and spacing tokens
|
||||
- **`style.css`** — main public entry point (via `@import` chain)
|
||||
- Page-specific: **`public.css`** (home), **`tfe.css`**, **`repertoire.css`**, **`content-page.css`** (about/licences), **`system.css`** (admin system dashboard), **`file-access.css`**, **`admin.css`** (admin section)
|
||||
- Page-specific: **`public.css`** (home), **`tfe.css`**, **`repertoire.css`**, **`content-page.css`** (about/licences), **`system.css`** (admin system dashboard), **`file-access.css`**, **`not-found.css`** (404), **`admin.css`** (admin section)
|
||||
- Form: **`form-base.css`** + **`form-admin.css`** (plus FilePond vendor CSS)
|
||||
|
||||
## Build / bundling
|
||||
@@ -19,9 +19,11 @@ Source CSS is **bundled and minified** by `scripts/build-css.mjs` (lightningcss)
|
||||
into `app/public/assets/dist/*.min.css`:
|
||||
|
||||
- `base.min.css` — resolves the `@import` chain in `style.css` into one file (eliminates ~17 sequential imports)
|
||||
- `admin.min.css` — minified `admin.css`
|
||||
- `admin.min.css` — minified `admin.css` (+ FilePond vendor CSS, for the CSV import dialog)
|
||||
- `form.min.css` — `form-base.css` + `form-admin.css` + FilePond vendor CSS
|
||||
- plus individual `.min.css` for the page-specific files
|
||||
- `form-base.min.css` — `form-base.css` standalone (partage pages without FilePond)
|
||||
- `partage-form.min.css` — `form-base.css` + FilePond vendor CSS (partage pages with FilePond)
|
||||
- plus individual `.min.css` for the page-specific files (`public`, `tfe`, `repertoire`, `content-page`, `not-found`, `system`, `file-access`)
|
||||
|
||||
Run with `just build-css` / `just dev-build`. Never commit hand-edits into
|
||||
`dist/` — they are generated.
|
||||
|
||||
+13
-53
@@ -1,17 +1,16 @@
|
||||
# Documentation index
|
||||
|
||||
This directory separates **current reference** docs, **proposals/plans**, and
|
||||
**historical/archived** analysis (in [`archive/`](archive/)).
|
||||
`docs/` holds **current reference** documentation describing how the system
|
||||
actually works today. Everything else — proposals, plans, incident reports,
|
||||
analyses, original requirements, one-off helpers — is in [`archive/`](archive/).
|
||||
|
||||
> **Note on naming:** XAMXAM was previously *Post-ERG* (and the code was once
|
||||
> organised under `posterg-website/`, `apps/`, `front-backend/`,
|
||||
> `/var/www/posterg/`). References to `posterg`, `apps/public/inc/header.php`,
|
||||
> `posterg.db`, `just serve`, `php-live-reload`, `tests/run-tests.php`, etc. in
|
||||
> historical docs reflect the old layout. The live paths are now `app/`,
|
||||
> **Note on naming:** XAMXAM was previously *Post-ERG* (code once organised
|
||||
> under `posterg-website/`, `apps/`, `front-backend/`, `/var/www/posterg/`).
|
||||
> Historical docs may reference the old layout; the live paths are now `app/`,
|
||||
> `app/public/`, `app/storage/xamxam.db`, `just dev`, PHPUnit, and
|
||||
> `/var/www/xamxam/` on the server.
|
||||
|
||||
## Current reference (kept up to date)
|
||||
## Reference docs
|
||||
|
||||
| Doc | Contents |
|
||||
|-----|----------|
|
||||
@@ -26,50 +25,12 @@ This directory separates **current reference** docs, **proposals/plans**, and
|
||||
| [security.md](security.md) | Current security posture |
|
||||
| [file-uploads.md](file-uploads.md) | Upload surfaces, types, storage layout |
|
||||
| [CSS.md](CSS.md) | CSS architecture + build |
|
||||
| [bookmarklet.md](bookmarklet.md) | Form auto-fill test helper |
|
||||
|
||||
## Proposals / plans (proposed, not all implemented)
|
||||
## Archive
|
||||
|
||||
| Doc | Status |
|
||||
|-----|--------|
|
||||
| [ldap.md](ldap.md) | LDAP login — **not implemented** (merged plan + spec) |
|
||||
| [monolog-plan.md](monolog-plan.md) | Single Monolog logger replacing AppLogger/AdminLogger/ErrorHandler/Audit — **plan** |
|
||||
| [de-librairisation.md](de-librairisation.md) | Replace bespoke SMTP/Markdown/HTTP/crypto with libraries (partly done) |
|
||||
| [refactoring.md](refactoring.md) | Older refactoring proposal |
|
||||
| [ANALYSIS_STRUCTURE_REORG.md](ANALYSIS_STRUCTURE_REORG.md) | Proposed structure reorg |
|
||||
| [ANALYSIS_INLINE_JS_CSS_MINIFY.md](ANALYSIS_INLINE_JS_CSS_MINIFY.md) | Inline JS/CSS/minify analysis (largely actioned by the build system) |
|
||||
| [backup-plan.md](backup-plan.md) | Backup plan — largely implemented (see deployment.md) |
|
||||
| [repertoire-mobile-propositions.md](repertoire-mobile-propositions.md) | Mobile repertoire UI proposals |
|
||||
| [spec-sheet.md](spec-sheet.md) | Original requirements fiche technique (incl. client notes appendix) |
|
||||
|
||||
## Active investigations (unresolved)
|
||||
|
||||
| Doc | Status |
|
||||
|-----|--------|
|
||||
| [filepond-crash-analysis.md](filepond-crash-analysis.md) | FilePond upload crash — **unresolved**, root cause in vendor code (merged race-investigation appendix) |
|
||||
| [peertube-sso-incident.md](peertube-sso-incident.md) | PeerTube `invalid_grant` diagnosis & ownership |
|
||||
| [autosave-system.md](autosave-system.md) | Autosave architecture & HTMX migration assessment |
|
||||
|
||||
## Historical / archived (in [`archive/`](archive/))
|
||||
|
||||
Kept for context — may reference the old codebase. Not maintained.
|
||||
|
||||
| Doc | Contents |
|
||||
|-----|----------|
|
||||
| `vm-crash-incident.md` | VM crash root-cause (merged final report + reports + evidence + fix) |
|
||||
| `CURRENT_ISSUES.md` | Issue log (2026-05-10) — many since resolved |
|
||||
| `LIVRAISONS_PAR_MOIS.md` | Monthly delivery log grouped by functional family |
|
||||
| `migration-history.md` | History of major structural migrations |
|
||||
| `php-vs-flask.md` | Language choice decision |
|
||||
| `orm-assessment.md` | ORM evaluation |
|
||||
| `css.md` | Old Bulma-removal writeup (see CSS.md for current) |
|
||||
| `system-setup.md` | PHP-extension inventory |
|
||||
| `SETUP.md` | Earlier setup snapshot (see development.md) |
|
||||
| `testing.md` | PHP testing best-practices writeup |
|
||||
| `SMTP_550_POSTFIX_FIX.md` | SMTP troubleshooting record |
|
||||
| `cms-migration-plan.html` | CMS migration plan |
|
||||
| `Proposition procédure licences_V2.pdf` | Licence procedure proposal |
|
||||
| `pi-session-2026-05-10T*.html` | Captured session log |
|
||||
Non-documentation material (proposals, plans, incident reports, analyses,
|
||||
requirements, one-off helpers) is preserved read-only in
|
||||
[`archive/`](archive/) for context. It is not maintained.
|
||||
|
||||
## Related documentation elsewhere
|
||||
|
||||
@@ -79,6 +40,5 @@ Kept for context — may reference the old codebase. Not maintained.
|
||||
|
||||
---
|
||||
|
||||
**Maintenance guidance:** when updating code, update the matching *current
|
||||
reference* doc in the table above. Leave *archived* docs untouched (read-only
|
||||
context). Move newly-written analysis into the appropriate section.
|
||||
**Maintenance guidance:** when updating code, update the matching reference doc
|
||||
above. Do not move analysis/proposals into `docs/` — put them in `archive/`.
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+5
-3
@@ -58,7 +58,7 @@ DB so it always reflects the applied set of migrations.
|
||||
|
||||
## Tables
|
||||
|
||||
31 tables. Grouped by purpose:
|
||||
32 tables. Grouped by purpose:
|
||||
|
||||
### Core
|
||||
|
||||
@@ -97,6 +97,7 @@ DB so it always reflects the applied set of migrations.
|
||||
| `file_access_tokens` | One-time access tokens |
|
||||
| `file_access_sessions` | Session tokens for granted access |
|
||||
| `file_access_audit` | Audit trail of access events |
|
||||
| `one_time_tokens` | Generic single-use, expiring tokens (password reset, etc.); only SHA-256 hashes stored |
|
||||
|
||||
### Integrations / settings / content
|
||||
|
||||
@@ -132,7 +133,8 @@ DB so it always reflects the applied set of migrations.
|
||||
| `objet` | TEXT | `'tfe'` default; other objets (`these`, `frart`) gated by site_settings |
|
||||
| `orientation_id` / `ap_program_id` / `finality_id` | INT FK | Lookup refs |
|
||||
| `synopsis` / `context_note` / `remarks` | TEXT | |
|
||||
| `duration_pages`, `duration_minutes` | INT | Combined duration handled at app level |
|
||||
| `duration_value` / `duration_unit` | REAL / TEXT | Normalised duration (`pages` or `minutes`) |
|
||||
| `duration_pages`, `duration_minutes` | INT | Legacy per-unit duration fields (combined handling at app level) |
|
||||
| `has_annexes` | BOOLEAN | |
|
||||
| `access_type_id` | INT FK | Libre / Interne / Interdit |
|
||||
| `license_id` | INT FK | → `license_types` |
|
||||
@@ -141,7 +143,7 @@ DB so it always reflects the applied set of migrations.
|
||||
| `jury_points` | DECIMAL(4,2) | Grade / 20 |
|
||||
| `jury_note_added` | BOOLEAN | |
|
||||
| `contact_visible` | TEXT | `'public'`/`'internal'` control for author contact |
|
||||
| `submitted_at`, `defense_date`, `published_at` | DATETIME | Lifecycle timestamps |
|
||||
| `submitted_at`, `date_depot`, `defense_date`, `published_at` | DATETIME | Lifecycle timestamps (`date_depot` = real deposit date from CSV bulk import; Brussels-local parse → UTC storage) |
|
||||
| `is_published` | BOOLEAN | Public visibility flag |
|
||||
| `status` | TEXT | Default `'active'` |
|
||||
| `baiu_link` | TEXT | Institutional repo link |
|
||||
|
||||
@@ -40,6 +40,22 @@ For a full initial rollout including backup + cleanup cron jobs:
|
||||
just deploy-all-first # deploy + deploy-backup + deploy-cleanup-cron
|
||||
```
|
||||
|
||||
### First-time `APP_KEY` on a brand-new server
|
||||
|
||||
`deploy-env` uploads the **local** `app/.env` only when the remote has none. Do
|
||||
**not** rely on a committed `.env` — generate a fresh key per environment and put
|
||||
it on the server before first `deploy`: create `app/.env` locally (see
|
||||
[development.md](development.md#appkey-and-the-appenv-file)) so `deploy-env`
|
||||
uploads it, or create `/var/www/xamxam/.env` on the server directly:
|
||||
|
||||
```bash
|
||||
ssh xamxam 'sudo -u www-data bash -c "echo APP_KEY=\$(php -r \"echo base64_encode(random_bytes(32));\") > /var/www/xamxam/.env; chmod 640 /var/www/xamxam/.env; chown www-data:xamxam /var/www/xamxam/.env"'
|
||||
```
|
||||
|
||||
If you ever rotate `APP_KEY`, re-encrypt the SMTP password with
|
||||
`just reencrypt-password <new_base64_key>` and push the new key via
|
||||
`just deploy-env`.
|
||||
|
||||
---
|
||||
|
||||
## Deploying
|
||||
|
||||
+33
-1
@@ -29,6 +29,37 @@ just migrate # create/update the SQLite DB from schema + migration
|
||||
not the live-reload watcher. Prefer the explicit `composer install` + `npm ci`
|
||||
above.
|
||||
|
||||
### APP_KEY and the app/.env file
|
||||
|
||||
The app derives DB/storage paths from the filesystem layout, so the public site
|
||||
and admin panel run without any env file. But `Crypto` (decrypting the SMTP
|
||||
password, PeerTube credentials, and Nextcloud WebDAV sync) requires an
|
||||
`app/.env` containing an `APP_KEY`:
|
||||
|
||||
```
|
||||
APP_KEY=<base64-encoded 32 random bytes>
|
||||
```
|
||||
|
||||
Generate one with:
|
||||
|
||||
```bash
|
||||
php -r 'echo "APP_KEY=" . base64_encode(random_bytes(32)) . PHP_EOL;' > app/.env
|
||||
chmod 600 app/.env
|
||||
```
|
||||
|
||||
`app/.env` must **never** be committed. If the file is missing, the public site
|
||||
still runs but any path that reads encrypted credentials throws
|
||||
`RuntimeException: APP_KEY not found`. On a fresh clone, create it before
|
||||
relying on SMTP/PeerTube/Nextcloud features.
|
||||
|
||||
### First admin login
|
||||
|
||||
A brand-new DB seeds `site_settings.admin_password_hash` as an **empty string**,
|
||||
which makes `AdminAuth::requireLogin()` a pass-through — i.e. `/admin/` starts
|
||||
**unauthenticated** until a password is set. To secure it, open
|
||||
`http://127.0.0.1:8000/admin/account` (or the production admin) and set the
|
||||
admin password, which stores the bcrypt hash in `site_settings`.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
@@ -136,7 +167,8 @@ just reset-db # rm DB + init-db
|
||||
just query # open an interactive SQLite shell
|
||||
just backup # SQL dump into app/storage/backup_<timestamp>.sql
|
||||
just backup-snapshot # WAL-safe hot backup + gzip into storage/backups/
|
||||
just cleanup-drafts [--no-dry-run] # remove orphaned drafts > 24h
|
||||
just cleanup-drafts [--no-dry-run] # remove orphaned drafts > 7 days (default)
|
||||
# OLDER_THAN_HOURS=24 to change the threshold
|
||||
```
|
||||
|
||||
See [database.md](database.md) for the full schema reference.
|
||||
|
||||
+2
-3
@@ -1,8 +1,8 @@
|
||||
# Environment / runtime requirements
|
||||
|
||||
The software stack and server environment required to run XAMXAM. This is the
|
||||
machine-facing counterpart to the product spec in
|
||||
[`spec-sheet.md`](spec-sheet.md).
|
||||
machine-facing counterpart to the original product spec (fiche technique,
|
||||
archived at [`spec-sheet.md`](archive/spec-sheet.md)).
|
||||
|
||||
## Production server (`xamxam`)
|
||||
|
||||
@@ -120,4 +120,3 @@ Required on the **dev** machine (and `just` on deploy-from-local):
|
||||
- [`development.md`](development.md) — local dev workflow, structure, builds
|
||||
- [`deployment.md`](deployment.md) — server setup, deploy, backups, rollback
|
||||
- [`security.md`](security.md) — security posture, session GC tuning
|
||||
- [`spec-sheet.md`](spec-sheet.md) — product/feature spec (fiche technique)
|
||||
+26
-11
@@ -56,7 +56,7 @@ Each uploaded file is assigned a `file_type` that controls how it is displayed o
|
||||
|-----------|-----------|---------|
|
||||
| `.mp4` | `video/mp4` | `<video>` |
|
||||
| `.webm` | `video/webm` | `<video>` |
|
||||
| `.mov` | `video/quicktime` | `<video>` (served as `video/mp4`) |
|
||||
| `.mov` | `video/quicktime` | `<video>` (served with Range support) |
|
||||
| `.ogv` | `video/ogg` | `<video>` |
|
||||
|
||||
#### Audio
|
||||
@@ -153,22 +153,37 @@ Labels are stored in `thesis_files.display_label`. If blank, the field falls bac
|
||||
|
||||
## Storage layout
|
||||
|
||||
Files are stored outside the webroot in `app/storage/`.
|
||||
Files are stored outside the webroot in `app/storage/`. Each thesis gets its own
|
||||
folder keyed by object type, year, author slug and a title slug:
|
||||
|
||||
```
|
||||
app/storage/
|
||||
├── covers/
|
||||
│ └── <random-hex>.jpg # cover images
|
||||
└── theses/
|
||||
└── <year>/
|
||||
└── <YEAR>_<AUTHOR_SLUG>/
|
||||
└── <AUTHOR_SLUG>_<sanitized-filename>.<ext>
|
||||
├── {objet}/ # tfe | these | frart (plus legacy theses/, documents/)
|
||||
│ └── <year>/
|
||||
│ └── <YEAR>_<AUTHOR_SLUG>_<TITLE_SLUG>/ # e.g. 2025_EMMA_RENARD_REHABILITATION_..._VERS_UN
|
||||
│ ├── <PREFIX>_TFE_01.pdf # main files: _TFE_<NN>.<ext>
|
||||
│ ├── ..._TFE_02.jpg
|
||||
│ ├── ..._ANNEXE_01.pdf # annexes: _ANNEXE_<NN>.<ext>
|
||||
│ ├── ..._COUVERTURE.png # cover image (_COUVERTURE.<ext>)
|
||||
│ ├── ..._NOTE_INTENTION.pdf # note d'intention (_NOTE_INTENTION.pdf)
|
||||
│ └── ..._TFE_03.vtt # captions share the _TFE_ series
|
||||
└── covers/ # legacy dir — no longer written to
|
||||
```
|
||||
|
||||
Where `<PREFIX>` = `<YEAR>_<AUTHOR_SLUG>_<TITLE_SLUG>` (the folder name), and the
|
||||
object type `{objet}` ∈ `tfe`, `these`, `frart` (older/imported rows may live
|
||||
under legacy `theses/` or `documents/`).
|
||||
|
||||
- Author slug: uppercase ASCII, spaces → underscores, accents stripped (e.g. `EMMA_RENARD`).
|
||||
- Filename: same normalisation applied to the original filename.
|
||||
- If a folder `<YEAR>_<AUTHOR_SLUG>` already exists a numeric suffix is appended (`_1`, `_2`, …).
|
||||
- If a filename already exists in the folder a numeric suffix is appended before the extension.
|
||||
- Title slug: accented chars → ASCII base, other non-alphanumerics → underscores (uppercase).
|
||||
- The cover and note d'intention are stored **inside** the thesis folder using the
|
||||
`_COUVERTURE` / `_NOTE_INTENTION` suffixes, recorded as `file_type='cover'` /
|
||||
`'note_intention'` rows — not in a separate `covers/` directory.
|
||||
- TFE files (and captions) are numbered `_TFE_<NN>` (`_TFE_01`, …); annexes use
|
||||
`_ANNEXE_<NN>` so several files of the same kind coexist in the folder.
|
||||
- If a folder `<PREFIX>` already exists a numeric suffix is appended to the folder
|
||||
(`_1`, `_2`, …); if a filename already exists in the folder a numeric suffix is
|
||||
appended before the extension.
|
||||
|
||||
Files are never served directly from disk. All access goes through `MediaController` (`/media?path=…`), which enforces:
|
||||
- Path traversal prevention (character whitelist + `realpath()` jail)
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
XAMXAM pushes its latest SQLite snapshot to a Nextcloud folder so that a
|
||||
server/disk failure doesn't take the backup history with it. This is the
|
||||
implementation of *Phase 5 — Remote Sync* from [backup-plan.md](backup-plan.md).
|
||||
implementation of *Phase 5 — Remote Sync* from the archived
|
||||
[`backup-plan.md`](archive/backup-plan.md).
|
||||
|
||||
## What it does
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ Single-value filters (`collectSearchParams()`):
|
||||
- `finality` — finality type
|
||||
- `format` — format
|
||||
- `keyword` — tag/keyword
|
||||
- `language` — language
|
||||
|
||||
Results are paginated (`limit = 20` default); the **search bar**
|
||||
(`app/templates/partials/search-bar.php`) submits a GET form to `/search`.
|
||||
|
||||
+3
-3
@@ -29,8 +29,8 @@ Current security posture for XAMXAM.
|
||||
so `session.gc_maxlifetime` must be ≥ the 12 h absolute timeout or PHP would
|
||||
reap active sessions early.
|
||||
- nginx `auth_basic` layer has been removed; the PHP session layer is the only
|
||||
gate. (LDAP-based login is a proposed future enhancement — see
|
||||
[`ldap.md`](ldap.md). It is **not** implemented.)
|
||||
gate. (LDAP-based login is a proposed future enhancement — **not**
|
||||
implemented. See [`ldap.md`](archive/ldap.md).)
|
||||
|
||||
### PHP-FPM session GC configuration
|
||||
|
||||
@@ -130,7 +130,7 @@ spoofing.
|
||||
## Areas to keep monitored
|
||||
|
||||
- Tightening the public CSP (`frame-ancestors 'none'` vs `'self'` on embed
|
||||
routes) is an active topic — see `TODO.md`.
|
||||
routes) is an active topic — tracked in the repo-root `TODO.md`.
|
||||
- Sensitive file downloads and their expiry/token handling are worth periodic
|
||||
review as usage grows.
|
||||
|
||||
|
||||
Reference in new issue
Block a user