Files
xamxam/TODO.md
Pontoporeia a5ee9b162f Replace site-search BEM classes with semantic header form[role="search"] selectors
CSS: .site-search → header form[role="search"],
     .site-search__icon → header form[role="search"] svg,
     .site-search__input → header form[role="search"] input,
     .site-search__input::placeholder → header form[role="search"] input::placeholder

HTML: Removed class="site-search", class="site-search__icon", and
class="site-search__input" from header.php and search-bar.php.
The form already uses role="search" and contains a single svg + input,
so the semantic selectors are unambiguous.
2026-04-01 15:55:12 +02:00

102 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TODO
## Template Simplification — Remove Custom Classes Where Semantic HTML Suffices
### CSS class audit: replace with semantic selectors
- [ ] **`admin.css`**: Replace `.admin-main` with `.admin-body main` — only one `<main>` per page
- [ ] **`admin.css`**: Replace `.admin-page-title` with `.admin-body main > h1` — always the first `h1` in `<main>`
- [ ] **`admin.css`**: Replace `.admin-alert` / `.admin-alert--error` / `.admin-alert--success` with `[role="alert"]` or `.admin-body main > .alert` using `data-type="error|success"` attribute instead of modifier classes
- [ ] **`admin.css`**: Replace `.admin-form-row` with `.admin-body form > div` or `.admin-body form > .row` — form rows are always direct `<div>` children of `<form>`
- [ ] **`admin.css`**: Replace `.admin-label` with `.admin-body form label` — every label in admin forms
- [ ] **`admin.css`**: Replace `.admin-input` / `.admin-select` / `.admin-textarea` with `.admin-body form input[type="text"]`, `.admin-body form select`, `.admin-body form textarea` — leverage native element selectors
- [ ] **`admin.css`**: Replace `.admin-hint` with `.admin-body form small` — use `<small>` instead of `<p class="admin-hint">`
- [ ] **`admin.css`**: Replace `.admin-table` with `.admin-body table` — only one table per admin page
- [ ] **`admin.css`**: Replace `.admin-fieldset` / `.admin-fieldset-legend` with `.admin-body fieldset` / `.admin-body legend`
- [ ] **`main.css`**: Replace `.card__caption` with `.home-body .cards-container li p` or target `li > a > p` directly
- [ ] **`main.css`**: Replace `.card__media` with `.home-body figure` — already uses `<figure>` elements
- [ ] **`tfe.css`**: Replace `.tfe-meta-list` selectors with `article dl`, `article dt`, `article dd` — already using `<dl>` inside `<article>`
- [ ] **`tfe.css`**: Replace `.tfe-media-block` with `aside figure` — already wrapped in `<figure>` inside `<aside>`
- [ ] **`tfe.css`**: Replace `.tfe-file-caption` with `aside figcaption` — native `<figcaption>` element
- [ ] **`search.css`**: Replace `.repertoire-col > h2` styling — already targets `section > h2`, can use `.repertoire-index section > h2`
- [x] **`common.css`**: Replace `.site-search__icon` with `header form[role="search"] svg`
- [x] **`common.css`**: Replace `.site-search__input` with `header form[role="search"] input`
- [x] **`common.css`**: Replace `.site-search` with `header form[role="search"]`
- [ ] **`system.php`**: Move inline `<style>` block to `system.css` (already in TODO, reinforced here)
### Template HTML changes to match
- [ ] In all admin templates, replace `<p class="admin-hint">` with `<small>` elements
- [ ] In `tfe.php`, remove `class="tfe-meta-list"` — target via `article dl`
- [ ] In `tfe.php`, remove `class="tfe-media-block"` — target via `aside figure`
- [ ] In `tfe.php`, remove `class="tfe-file-caption"` — target via `aside figcaption`
- [ ] In `index.php`, remove `class="card__caption"` — target via `li > a > p`
- [x] In `search-bar.php` and `header.php`, remove `class="site-search"`, `class="site-search__icon"` and `class="site-search__input"`
## PHP Components (Reusable Partials/Includes)
PHP has no component system, but `include`/`require` with variable scoping works as partials. These are already used (`head.php`, `header.php`, `footer.php`, `flash-messages.php`). New partials to extract:
### Form field partials — `templates/partials/form/`
- [ ] **`text-field.php`** — accepts `$name`, `$label`, `$value`, `$required`, `$placeholder`, `$hint`; renders the `<div>…<label>…<input>…<small>` pattern used ~15 times across `add.php` and `edit.php`
- [ ] **`select-field.php`** — accepts `$name`, `$label`, `$options[]`, `$selected`, `$required`; renders `<div>…<label>…<select>…</div>` pattern used ~6 times
- [ ] **`checkbox-list.php`** — accepts `$name`, `$label`, `$options[]`, `$checked[]`; renders the checkbox group pattern (languages, formats) used ~4 times across `add.php` and `edit.php`
- [ ] **`file-field.php`** — accepts `$name`, `$label`, `$accept`, `$hint`, `$multiple`; renders file input pattern used 3 times
- [ ] **`jury-fieldset.php`** — the entire jury composition fieldset + JS is duplicated verbatim between `add.php` and `edit.php`; extract into one partial accepting `$juryPresident`, `$juryPromoteur`, `$juryPromoteurExt`, `$juryLecteurs[]`
### Shared UI partials — `templates/partials/`
- [ ] **`pagination.php`** — pagination nav is duplicated between `index.php` and `search.php` with minor variations; unify into one partial accepting `$page`, `$totalPages`, `$baseParams[]`
- [ ] **`status-badge.php`** — the published/pending badge + access badge pattern is repeated in `index.php` admin table rows; extract into a partial
- [ ] **`admin-alert.php`** — rename/merge `flash-messages.php` to also handle the 3 different legacy flash key patterns (`$_SESSION['error']`, `$_SESSION['admin_error']`, `$_SESSION['edit_error']`, etc.) that pages still consume manually instead of via `App::consumeFlash()`
## 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)` — stores JSON-encoded status snapshots keyed by section
- [ ] **Add migration** `storage/migrations/007_system_cache.sql` to create the table
- [ ] **Add `SystemCache` class** (`src/SystemCache.php`) with methods:
- `get(string $key, int $maxAgeSec = 60): ?array` — returns cached JSON data if fresh, null if stale
- `set(string $key, array $data): void` — upserts cache row
- `isStale(string $key, int $maxAgeSec = 60): bool`
- [ ] **Refactor `system.php` status section** to:
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** to not cache (logs should always be live) but avoid re-reading on every tab switch — only read the active tab's 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)` — PHP config doesn't change at runtime
## In Progress (from previous plan)
- [ ] Extract `SearchController` — most complex public page (§2 step 4)
- [ ] Extract `SystemController` — biggest single-file win, 500→8 lines (§2 step 3, §5)
- [ ] Extract `ThesisEditController` — merges edit.php + actions/edit.php, deduplicate jury fieldset (§2 step 5)
- [ ] Extract remaining controllers one by one (§2 step 6)
- [ ] Consolidate action handlers into controller methods (§4)
- [ ] Introduce pagination partial `templates/partials/pagination.php` (§6)
- [ ] Introduce admin form partials: select-field, checkbox-list, jury-fieldset (§6)
- [ ] Unify flash message keys project-wide to `_flash_error` / `_flash_success` (§7)
- [ ] Move OG tag construction into controller logic (§8)
- [ ] Extract inline CSS/JS from `system.php` into separate assets (§5)
## Completed
- [x] Create `src/App.php` — boot, adminGuard, verifyCsrf, rotateCsrf, redirect, flash, consumeFlash, render
- [x] Auto-load `App.php` from `config/bootstrap.php`
- [x] Create `templates/partials/flash-messages.php` — unified flash partial with legacy key drain
- [x] Merge public and admin head/nav templates into unified `templates/head.php` and `templates/header.php`
- `templates/head.php` — outputs `<!DOCTYPE html>…</head><body class="…">`, reads `$bodyClass`, `$isAdmin`; handles admin title suffix, admin.css prepend, and OG tag suppression internally
- `templates/header.php` — outputs `<header>…</header>` with public nav + search bar or admin nav depending on `$isAdmin`
- Deleted: `templates/public/head.php`, `templates/admin/head.php`, `templates/nav.php`, `templates/admin/nav.php`
- All 11 admin pages and 5 public pages updated to set `$bodyClass` / `$isAdmin` and include new templates
- [x] Replace nav/header BEM custom classes with semantic HTML targeting in CSS
- `common.css`: `.site-nav``header nav`, `.site-nav__logo``header nav > a`, etc.
- `admin.css`: `.admin-nav``.admin-body header nav`, logout via `[data-nav-logout]` attribute
- [x] PHP vs Flask architecture analysis (`ANALYSIS_PHP_VS_FLASK.md`)
- [x] Refactoring recommendations for controller/template separation (`REFACTORING_RECOMMENDATIONS.md`)