mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
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.
102 lines
8.8 KiB
Markdown
102 lines
8.8 KiB
Markdown
# 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`)
|