# CodePress TODO ## ✅ Voltooid (recent) ### Statistieken & GeoIP (v1.9.0) - [x] `GeoIP` class met providerketen: lokaal (DB-IP Lite) → MaxMind `.mmdb` → externe API, met automatische fallback - [x] Eigen pure-PHP MMDB-lezer (`MMDBReader`), geen Composer-afhankelijkheid nodig - [x] `cli/geoip-update.php` — downloadt DB-IP Lite en bouwt compacte binaire index (354k IPv4 + 342k IPv6 records) - [x] Binary search lookup via `fseek` voor IPv4 (10 bytes/record) en IPv6 (34 bytes/record) - [x] Placeholder-landcodes (`ZZ`/`XX`) tellen als onbekend - [x] `cli/generate-world-map.php` — genereert SVG-wereldkaart uit Natural Earth TopoJSON (publiek domein) met ISO alpha-2 id's - [x] `Analytics` class met aggregatie in `admin/storage/stats.json` (LOCK_EX), overleeft het wissen van logs - [x] Admin pagina `/admin/statistics`: KPI's, choropleth wereldkaart met tooltips, landenlijst met vlaggen, top pagina's, dagelijkse grafiek, referrers - [x] Periodefilter 7 / 30 / 90 dagen / alles - [x] GeoIP- en privacy-instellingen in admin (provider, `.mmdb` pad, API URL/sleutel, bewaartermijn) - [x] Knop "GeoIP database bijwerken" en "Statistieken wissen" in admin - [x] IP-anonimisering als schakelaar (`RequestLogger::anonymizeIp()`), standaard uit - [x] Landkolom met vlag in requests log + KPI-kaarten op dashboard - [x] `requests.log` uitgebreid met landcode (9e veld), parser accepteert 7/8/9 velden ### Beveiliging (v1.8.0) - [x] `BotGuard` engine: AI-crawlers, zoekmachines, scrapers en lege user-agents herkennen en blokkeren - [x] Admin pagina `/admin/security` met schakelaars, rate limiting en IP block/allowlist - [x] Rate limiting per IP (HTTP 429 met `Retry-After`) - [x] Dynamische `/robots.txt` en `noai`/`noimageai` meta-tags - [x] Statuskolom met badges in requests log - [x] Echte bezoeker-IP achter HAProxy/PFSense (`RequestLogger::getClientIp()`, 2-pass publiek IP filter) - [x] HAProxy/PFSense handleiding (`docs/haproxy-bot-blocking.md`) - [x] Eén-klik systeemupdate via `/admin/update` met controle op Git-schrijfrechten - [x] `config.json` en `admin/config/admin.json` uit Git, automatisch aangemaakt indien afwezig - [x] **ARIAComponents.php parse error** — opgelost op regels 67, 137 en 262 (`'UTF-8)` → `'UTF-8')`) ### Media & Editor - [x] Media browser modal met upload, thumbnail grid, en size-prompt - [x] Media knop in editor toolbar voor alle modes (md/html/php) - [x] Recursieve scan van `content/` voor media bestanden (ipv alleen `-assets/`) - [x] `/-media/` URL prefix voor media bestanden (consistente routing, geen special cases) - [x] `/-assets/` blijft werken voor backward compatibility - [x] Size prompt voor afbeeldingen: Markdown `![alt](url)`, HTML/PHP `` met width/height - [x] Editor change detectie: `editor.on('change', ...)` werkt nu correct - [x] "Terug" knop verandert naar rode "Annuleren" bij ongewijzigde wijzigingen (content-edit + content-new) - [x] Upload knop disabled tot bestand geselecteerd - [x] "Aanmaken" knop disabled tot bestandsnaam ingevuld - [x] Editor mode switching in content-new werkt via `switchMode()` (mode + toolbar + data-ext) ### Content Management - [x] Inline rename veld in content-edit pagina (geen aparte rename knop) - [x] Bestanden en mappen verplaatsen (content-move) - [x] Breadcrumb toont geen `.` meer (dirname check op PHP niveau) - [x] Verwijderde aparte `content-file-rename` route/handler/template ### Thema's - [x] Thema's in subdirectory `themes/naam/theme.json` (ipv `themes/naam.json`) - [x] Thema CRUD in admin (aanmaken, activeren, bewerken, verwijderen) - [x] File upload voor thema achtergrond afbeeldingen ### Security & Code Quality (docs/TODO.md) - [x] Path traversal fix (`realpath()` + prefix-check) - [x] JWT secret fallback verwijderd - [x] `executePhpFile()` pad-restrictie - [x] IP spoofing fix in MQTTTracker - [x] Debug uitgezet in admin config - [x] Cookie security (Secure/HttpOnly/SameSite) - [x] Dead code verwijderd - [x] `htmlspecialchars()` op bestandspad gecorrigeerd - [x] Ongebruikte methode `scanForPageNames()` verwijderd - [x] Breadcrumb titels geescaped - [x] Taalparameter in zoekresultaat-URLs - [x] Operator precedence bug in MQTTTracker - [x] Hardcoded strings vervangen - [x] HTML lang attribuut dynamisch gemaakt - [x] console.log verwijderd - [x] Sidebar toggle aria attributes ## 🔴 Nog openstaand ### Kritiek - [ ] **Plugin auto-loading** — Elke map in `plugins/` wordt blind geladen zonder allowlist of validatie (`PluginManager.php:40` in docs/TODO.md) ### Hoog - [ ] **autoLinkPageTitles()** — Regex kan geneste `` tags produceren (`CodePressCMS.php`) - [ ] **MQTT wachtwoord** — Credentials in plain text JSON (`MQTTTracker.php`) - [ ] **Markdown editor** — WYSIWYG/split-view Markdown editor integreren in content-edit (bijv. EasyMDE, SimpleMDE, of Toast UI Editor). Live preview, toolbar met opmaakknoppen, drag & drop afbeeldingen - [ ] **Plugin activeren/deactiveren** — Toggle knop per plugin in admin Plugins pagina. Schrijft `enabled: true/false` naar plugin `config.json` - [ ] **Plugin API** — Uitgebreide API voor plugins zodat ze kunnen inhaken op CMS events (hooks/filters): `onPageLoad`, `onBeforeRender`, `onAfterRender`, `onSearch`, `onMenuBuild` ### Medium - [ ] **Taalwisselaar verliest pagina** — Wisselen van taal navigeert altijd naar homepage (`header.mustache`) - [ ] **ctime is geen creatietijd op Linux** — `stat()` ctime is inode-wijzigingstijd (`CodePressCMS.php`) - [ ] **getGuidePage() dupliceert markdown parsing** — Zelfde CommonMark setup als `parseMarkdown()` - [ ] **HTMLBlock ontbrekende ``** — Niet-gesloten tags bij null-check - [ ] **formatDisplayName() redundante logica** — Dubbele checks en overtollige str_replace - [ ] **Plugin configuratie editor** — Per-plugin config.json bewerken vanuit admin panel - [ ] **Admin activity log** — Logboek van alle admin acties (wie deed wat wanneer) met viewer in dashboard - [ ] **Wachtwoord wijzigen eigen account** — Apart formulier voor ingelogde gebruiker om eigen wachtwoord te wijzigen (met huidig wachtwoord verificatie) - [ ] **Admin thema** — Admin sidebar kleur overnemen van site thema config (`header_color`) - [ ] **Map aanmaken/verwijderen** — Directory management in admin Content pagina - [ ] **Bestand uploaden** — Uploaden naar andere mappen dan `-assets/` via admin Content pagina - [ ] **Content preview** — Live preview van Markdown/HTML content naast de editor ### Laag - [ ] **Geen type hints** — Ontbrekende type declarations op properties en methoden - [ ] **Public properties** — `$config`, `$currentLanguage`, `$searchResults` zouden private moeten zijn - [ ] **Inline CSS** — ~250 regels statische CSS in template i.p.v. extern bestand - [ ] **style.css is Bootstrap** — Bestandsnaam is misleidend, Bootstrap wordt mogelijk dubbel geladen - [ ] **Geen error handling op `file_get_contents()`** — Meerdere calls zonder return-check - [ ] **Logger slikt fouten** — `@file_put_contents()` met error suppression - [ ] **Logger tail() leest heel bestand** — Geheugenprobleem bij grote logbestanden - [ ] **Externe links missen `rel="noreferrer"`** - [ ] **Zoekformulier mist aria-label** - [ ] **mobile.css override Bootstrap utilities** met `!important` - [ ] **Content versioning** — Simpele file-based backup bij elke save (bijv. `.bak` bestanden) - [ ] **Zoeken in admin** — Zoekfunctie binnen de admin content browser - [ ] **Drag & drop** — Bestanden herordenen/verplaatsen via drag & drop - [ ] **Keyboard shortcuts** — Ctrl+S om op te slaan in editor, Ctrl+N voor nieuw bestand - [ ] **Dark mode** — Admin panel dark mode toggle - [ ] **Responsive admin** — Admin sidebar inklapbaar op mobiel (nu is het gestacked) - [ ] **stats.json bij hoog verkeer** — Nu één schrijfactie met LOCK_EX per request. Bij veel verkeer eventueel opsplitsen naar dagbestanden of APCu - [ ] **Steden op de kaart** — Nu alleen landniveau; met een City-database ook stippen per stad plotten - [ ] **Statistieken exporteren** — CSV/JSON export van bezoekersstatistieken - [ ] **Automatische GeoIP-update** — Maandelijkse cron/schedule i.p.v. handmatig op de knop drukken