# Agent Instructions for CodePress CMS

## AI Model
- **Huidig model**: `claude-opus-4-6` (OpenCode / `opencode/claude-opus-4-6`)
- Sessie gestart: 16 feb 2026

## Build & Run
- **Run Server**: `php -S localhost:8080 cms/router.php` (router nodig voor clean URLs)
- **Lint PHP**: `find . -name "*.php" -not -path "./vendor/*" -exec php -l {} \;`
- **Dependencies**: Composer vereist voor CommonMark. Geen NPM.
- **Admin Console**: Toegankelijk op `/admin.php` (standaard login: `admin` / `admin`)

## Project Structuur
```
codepress/
├── cms/                            # Core CMS engine
│   ├── core/
│   │   ├── class/
│   │   │   ├── CodePressCMS.php    # Hoofd CMS class
│   │   │   ├── Logger.php          # Logging systeem
│   │   │   └── SimpleTemplate.php  # Mustache-style template engine
│   │   ├── plugin/
│   │   │   ├── PluginManager.php   # Plugin loader
│   │   │   └── CMSAPI.php          # API voor plugins
│   │   ├── config.php              # Config loader (leest config.json)
│   │   └── index.php               # Bootstrap (autoloader, requires)
│   ├── lang/                       # Taalbestanden (nl.php, en.php)
│   ├── templates/                  # Mustache templates
│   │   ├── layout.mustache         # Hoofd layout (bevat inline CSS)
│   │   ├── assets/
│   │   │   ├── header.mustache
│   │   │   ├── navigation.mustache
│   │   │   └── footer.mustache
│   │   ├── markdown_content.mustache
│   │   ├── php_content.mustache
│   │   └── html_content.mustache
│   └── router.php                  # PHP dev server router
├── admin/                          # Admin paneel
│   ├── config/
│   │   ├── app.php                # Admin app configuratie
│   │   └── admin.json             # Gebruikers & security (file-based)
│   ├── src/
│   │   └── AdminAuth.php          # Authenticatie (sessies, bcrypt, CSRF, lockout)
│   ├── templates/
│   │   ├── login.php              # Login pagina
│   │   ├── layout.php             # Admin layout met sidebar
│   │   └── pages/
│   │       ├── dashboard.php
│   │       ├── content.php
│   │       ├── content-edit.php
│   │       ├── content-new.php
│   │       ├── content-dir-form.php
│   │       ├── config.php
│   │       ├── plugins.php
│   │       ├── plugin-config.php
│   │       └── users.php
│   └── storage/logs/              # Admin logs
├── cli/                            # CLI scripts & tests
│   └── test/
│       ├── accessibility.sh        # WCAG 2.1 AA test suite
│       ├── enhanced-suite.sh       # Enhanced test suite
│       ├── functional/             # Functionele testen
│       └── pentest/                # Penetratietesten
├── plugins/                        # CMS plugins
│   ├── HTMLBlock/
│   └── MQTTTracker/
├── public/                         # Web root
│   ├── assets/css/js/
│   ├── index.php                  # Website entry point
│   └── admin.php                  # Admin entry point + router
├── content/                        # Content bestanden
├── guide/                          # Handleidingen (nl/en)
├── docs/                           # Documentatie
├── config.json                     # Site configuratie
└── AGENTS.md                       # Dit bestand
```

## Code Style & Conventions
- **PHP Standards**: Follow PSR-12. Use 4 spaces for indentation.
- **Naming**: Classes `PascalCase` (e.g., `CodePressCMS`), methods `camelCase` (e.g., `renderMenu`), variables `camelCase`, config keys `snake_case`.
- **Architecture**: 
  - Core CMS logic in `cms/core/class/CodePressCMS.php`
  - Bootstrap/requires in `cms/core/index.php`
  - Configuration loaded from `config.json` via `cms/core/config.php`
  - Public website entry point: `public/index.php`
  - Admin entry point + routing: `public/admin.php`
  - Admin authenticatie: `admin/src/AdminAuth.php`
- **Content**: Stored in `content/`. Supports `.md` (Markdown), `.php` (Dynamic), `.html` (Static).
- **Templating**: Mustache-style `{{placeholder}}` in `templates/layout.mustache` via `SimpleTemplate.php`.
- **Navigation**: Auto-generated from directory structure. Folders require an index file to be clickable in breadcrumbs.
- **Security**: 
  - Always use `htmlspecialchars()` for outputting user/content data
  - Use `realpath()` + prefix-check for path traversal prevention
  - Admin forms require CSRF tokens via `AdminAuth::verifyCsrf()`
  - Passwords stored as bcrypt hashes in `admin.json`
- **Git**: `main` is the clean CMS core. `development` is de actieve development branch. `e.noorlander` bevat persoonlijke content. Niet mixen.

## Admin Console
- **File-based**: Geen database. Gebruikers opgeslagen in `admin/config/admin.json`
- **Routing**: Via `?route=` parameter in `public/admin.php`
- **Routes**: `login`, `logout`, `dashboard`, `content`, `content-edit`, `content-new`, `content-delete`, `config`, `plugins`, `plugins-new`, `plugins-edit`, `plugins-config`, `plugins-toggle`, `plugins-delete`, `users`
- **Auth**: Session-based. `AdminAuth` class handelt login, logout, CSRF, brute-force lockout af
- **Templates**: Pure PHP templates in `admin/templates/pages/`. Layout in `layout.php`

## Important: Title vs File/Directory Name Logic
- **CRITICAL**: When user asks for "title" corrections, they usually mean **FILE/DIRECTORY NAME WITHOUT LANGUAGE PREFIX AND EXTENSIONS**, not the HTML title from content!
- **Examples**:
  - `nl.test.md` → display as "Test" (not content title)
  - `nl.test/` directory → display as "Test" (not H1 content)
  - `en.php-testen` → display as "Php Testen" (not "ICT")
- **Method**: Use `formatDisplayName()` to process file/directory names correctly
- **Priority**: Directory names take precedence over file names when both exist
- **Language prefixes**: Dynamisch verwijderd op basis van beschikbare talen via `getAvailableLanguages()`

## Bekende aandachtspunten
- LSP errors over "Undefined function" in PHP files zijn vals-positief (standaard PHP functies worden niet herkend door de LSP). Negeer deze.
- Zie `TODO.md` voor alle openstaande verbeteringen en nieuwe features.
- `vendor/` map bevat Composer dependencies (CommonMark, Mustache). Niet handmatig wijzigen.
- `admin/config/admin.json` bevat wachtwoord-hashes. Niet committen met echte productie-wachtwoorden.
