Release History
coreX
Changelog
All versions, new features and bug fixes of coreX at a glance.
v0.10.0
Current
08. June 2026
NEW: FormBuilder + Changes
New
- **System: Secure Dynamic Form Builder (Phases 1–10)**
- A fully independent subsystem (`Admin → Content → Forms`) for managing dynamic forms that can subsequently be used as flexible CMS blocks.
- The system supports 15 essential field types (such as text, phone, whitelisted select/checkbox fields, consent fields, and protected file uploads).
- Security-optimized: All uploaded documents are stored encrypted outside the webroot under `storage/private/form_uploads` and are streamed exclusively through CSRF-token-protected one-time access patterns within the admin area (secured GET downloads).
- Integrated mailbox-style inbox for reviewing every form submission, including processing history, status changes, read automation, and private notes.
- Performance: AJAX-based frontend submission with automatic client-side AbortController request timeouts (15 seconds) to prevent browser freezes during network stalls.
- GDPR-compliant: Optional fully automated probabilistic housekeeping regularly removes expired submissions, including physical cleanup of associated file attachments based on the configured `retention_days` timer.
- Export: Privacy-friendly CSV exporter (protected by the `admin.forms.export` permission) with Byte Order Mark (UTF-8 BOM) to ensure correct display of special characters directly in Microsoft Excel.
- Fully translatable: Seamless integration of all field labels and help texts into the MLS translation board while preserving all technical validation rules.
Changed
- **Legal: Privacy & Security Information Updated**
- The English privacy policy template has been updated to reflect the modern coreX subsystem architecture.
- The documentation now covers the integrated local visitor statistics system (without third-party services), strict referrer-domain anonymization, flexible data retention management with automatic housekeeping, the modernized two-factor / selector-hashed `cx_remember` cookie logic including active session management in user profiles, as well as the mailbox-style admin inbox for contact form requests.
v0.9.9
06. June 2026
NEW: Backup System + Changes + Fixes
New
- **System: Database Backups**
- The admin area now includes a dedicated backup page for database backups.
- Backup scope, retention settings, and optional statistics/log data can be managed intentionally.
- Backups can be securely downloaded, verified, and restored with additional confirmation.
- The Security Diagnostics page now also displays the detected backup status and recommendations for complementary file backups.
Changed
- **Contact Page: Headline Updated**
- The contact page now features a stronger two-line headline with highlighted accent text.
Fixed
- **Contact Page: Header Image from Content Manager**
- The page-specific header background image is now correctly applied on the contact page again.
- Existing contact header settings remain available as a fallback.
- **Page Headers: Alignment and Background Images**
- Blog and Privacy Policy headers now align their headlines vertically again.
- The Privacy Policy page now uses the header image configured in the Content Manager as well as the configured header height.
v0.9.8
05. June 2026
NEU: Viele Neuheiten + Änderungen + Fixes
New
- **System: Security Diagnostics**
- Added a new admin area under System that evaluates recognizable security and environment aspects in read-only mode.
- The diagnostics show status, context and concrete recommendations without exposing sensitive configuration values or making automatic changes.
- Checks include transport, PHP/session settings, HTTP security headers and important file system boundaries.
- **After Setup Guide**
- The admin help now includes a clear starter checklist for new installations.
- The dashboard links directly to the guide so new users can configure settings, branding, design, navigation, media and content in a sensible order.
- **Design Options Made Clearer**
- The design options are now split into tabs for base colors, Bootstrap colors, sections, form fields, mobile and custom CSS/JS.
- The existing save logic remains unchanged, while maintaining larger designs becomes much easier.
- **Admin Inbox Reworked**
- Contact form messages are now displayed in a mailbox-like inbox with message list, preview and detail area.
- Opening a message stores its read status, so the topbar counter only shows truly new messages.
- The admin help describes the new inbox and the read-status behavior.
- **Logo Page Extended with Favicon**
- The website browser icon can now also be uploaded and removed under Logo & Favicon.
- The frontend automatically uses the configured favicon or falls back to the existing default icon.
- **Loading Layer Configurable in Admin**
- Design & Layout now contains its own Loading Layer page.
- Loading image, image height and background color can be maintained independently from the regular website logo.
- The loading image can be selected directly from the media library or uploaded separately.
- Without a custom loading image, coreX continues to use the configured logo or the previous fallback.
- **Content Manager: Per-Page Header Height**
- PHP-file pages with a header background image can now receive their own header height in the Content Manager.
- Fixed heights and fullscreen mode are supported, similar to existing hero/contact settings.
- The setting applies to existing header areas such as blog, newsletter, profile, changelog and technical pages.
- **Content Manager: Page Visibility by Access Level**
- CMS pages can now define per page whether they are public, only visible to logged-in users, visible to editors or only visible to admins.
- Protected pages disappear from the public navigation and are checked against the current session when accessed directly.
- Public sitemap entries continue to include only freely visible CMS pages.
- **Content Manager: Advanced Block Extended**
- The advanced HTML block now offers separate CodeMirror fields for HTML, CSS and JavaScript.
- Block-specific code is placed more cleanly: markup in the page content, CSS in the page head and JavaScript at the end of the page.
- Page-level special solutions can now be maintained more precisely without using global design options for every single page.
- **Translations: Hero Texts Managed More Centrally**
- Hero texts can now be maintained in the translation area under Website.
- The hero editor shows translation status and links to the central maintenance area, while layout, media and design remain in the hero editor.
- **Translations: Dashboard Added**
- The translation area now starts with an overview per language and area.
- Filters and direct links help find missing translations faster.
- **Content Manager: Translation Duplication Reduced**
- Page translations for navigation, slug and SEO now clearly lead to the central translation page.
- The Content Manager shows status and direct links per language, while remaining the place for base/DE page data.
- Block translations are marked as a quick access shortcut in the Content Manager; central maintenance remains under Translations.
- **News / Blog: Translations Managed More Centrally**
- The news form remains the place for DE base posts and now shows translation status plus direct links.
- Post translations including SEO metadata are maintained centrally under Translations.
- Existing news translation paths use the same save logic so the form and the central page do not drift apart.
- **Translations: JSON System Texts Better Structured**
- Language files in the JSON area are grouped by system messages, JavaScript/UI, frontend content, layout parts and forum.
- Filters and status indicators show more quickly which files or keys are still missing per language.
- The save logic checks language file paths more defensively and continues to write only inside the intended language area.
- **Translations: Legal Content Visible**
- The translation area now contains a read-only section for legal language content.
- Privacy status and direct maintenance links are visible per language.
- Legally relevant texts deliberately remain in the privacy area and are not automatically mixed with regular translations.
- **Translations: Module Language Files Visible**
- The translation area now shows module language files read-only by module and language.
- Missing locale files are marked without automatically generating or changing module files.
- Write functions for module i18n remain a conscious later step.
- **Translations: Central Maintenance Protected**
- The most important translation areas now follow shared status and save logic.
- An automated policy check protects central translation maintenance against unintended regressions.
- **Translations: coreY Coverage Extended**
- coreY can now also support footer labels for column and flat footers in the central translation area.
- **Footer Manager: External Links**
- Footer links can now store external web, mail and phone targets in addition to internal paths.
- Internal and external targets are rendered correctly in the frontend; new tabs receive appropriate protection attributes.
- **Statistics: Aggregated Long-Term Analytics**
- Historical statistics (visitors, pages, referrers, browser/OS/device, performance) are now stored as compact daily values instead of keeping raw data permanently.
- Long-term analytics in the admin area are therefore significantly faster and more resource-friendly.
- **Statistics: Manual Database Management in Admin**
- Admin → Statistics now offers buttons to aggregate and clean up immediately, with feedback about processed records.
- **Performance Tracking: Configurable Recording Rate**
- The rate at which performance measurements are recorded can be configured in the admin area, from every request to sample-based recording.
- **Statistics Data Retention Configurable in Admin**
- Retention periods for visitor, bot, performance and Web Vitals raw data, as well as the performance sampling rate, can be maintained directly in the statistics area.
- **Automatic Housekeeping for Security and Session Data**
- Expired login-attempt entries and inactive sessions are now cleaned up automatically in the background, without requiring a cron job.
- **Retention: Web Vitals Measurements**
- Web Vitals samples now have their own configurable retention period and are cleaned up automatically.
Changed
- Design-related card styles and global table styles now live more consistently in the `corex/parts` area.
- Background cleanup for raw data now runs more frequently to limit database growth more proactively.
- The retention notice in Admin → Statistics now mentions all configurable retention periods.
- Performance evaluations in the dashboard now use a clearly defined time window and are less affected by older outliers.
- Statistics reset, long-term aggregates and raw-data cleanup now work together more consistently so historical values are not accidentally lost before aggregation.
- Performance sampling is now labeled more clearly as sampling in the dashboard and statistics.
Fixed
- **Media Library Selection: More Consistent WebP Filenames**
- Media picker and header image fields now prefer the actually stored WebP filename for automatically converted images.
- **Forum: Topbar and Fixed Navigation Accounted For**
- Forum pages now also load the frontend topbar.
- Forum content receives a central offset so topbar and fixed navigation no longer cover the page header.
- **Contact Form: Feedback After Submit Repaired**
- Success and error messages after contact form submission are rendered correctly again.
- Captcha errors now lead back to the normal form message instead of causing a page failure.
- **Content Manager: Quill CDN Corrected**
- The shared Quill editor now loads version 1.3.7 through the stable jsDelivr URL.
- SRI and CORS attributes remain in place so the block editor starts again without CDN redirect/hash errors.
- **Content Manager: Admin Fetch Base More Robust**
- Shared admin fetch preparation now loads without an additional asset request.
- This keeps the block editor stable even on language-prefixed admin URLs.
- **Configuration: OAuth Saving More Clearly Separated**
- Saving social login data no longer changes general website/coreY description fields.
- **Cookie Settings: Fallback Notice**
- If a browser add-on blocks the cookie settings, the footer link now shows an understandable notice instead of silently doing nothing.
- Unused legacy database structure without active usage was cleaned up.
- Referrers in visitor statistics are stored more sparingly as domains instead of permanently keeping full paths or query parameters.
v0.9.7
01. June 2026
Changes
Changed
- **Media processing hardened**
- Upload, media and image-derivation paths now validate files earlier and more consistently before further processing begins.
- Invalid or unusually large media files are rejected more clearly instead of unnecessarily stressing admin actions.
- The media library now displays upload limits and relevant server capabilities more transparently in the admin area.
- An automated regression test validates the most important media rules in Composer and CI.
- **Redirect behavior stabilized**
- Content redirects now apply only to normal page requests; form and API requests reliably reach their intended endpoints.
- The redirect manager explains the new rule in the admin area and protects technical system paths from accidental redirect rules.
- An automated regression test validates the most important redirect rules in Composer and CI.
- **External frontend and admin resources more clearly secured**
- Active external libraries are now integrated more consistently using pinned versions, integrity validation and CORS attributes.
- The frontend CSP remains nonce-based for internal scripts; the current admin transition state and further reduction of legacy inline patterns are documented.
- Custom JavaScript is now more clearly labeled in the design options as intentionally trusted frontend code.
- An automated regression test validates the most important CSP/SRI rules in Composer and CI.
- **Statistics data retention made more transparent**
- Visitor, bot and performance raw data now use centralized retention policies and are cleaned up fault-tolerantly.
- The admin area now more clearly displays which data period statistics and performance information refer to.
- Tracking boundaries for technical requests and admin areas were tightened; IP displays are now anonymized more consistently.
- An automated regression test validates the most important tracking/retention rules in Composer and CI.
- **Module package preview made more informative**
- Package validation now compactly displays which technical extensions a module introduces before installation or update.
- Origin verification, dev/recovery notices and technical impact are now presented more clearly and separately.
- Unverified packages with extensive impact now require more deliberate confirmation; audit entries remain abstract and contain no package details.
- An automated regression test validates the most important preview rules in Composer and CI.
- **Architecture hotspots reduced**
- Reused layout and admin views now obtain smaller data points more consistently through services, managers or view models.
- Front controller, routing and admin JavaScript follow-up paths are now documented more clearly so future refactorings remain targeted and testable.
- An automated regression test protects the new architectural boundaries in Composer and CI.
- **Automated test network expanded**
- Stable security and architecture validations are now grouped into dedicated Composer test suites.
- CI executes validation, linting, policy tests and isolated smoke tests without requiring production services or real databases.
- Manual and release-near checks are now documented separately from automated tests.
v0.9.6
30. May 2026
NEW: Secure Package Processing + Changes + Fixes
New
- **Asset versioning prepared**
- New centralized `AssetVersionService` plus global `cx_asset()` helper now generate versioned internal asset URLs using `filemtime()` and the correct `APP_BASE`.
- Existing query strings are preserved; external URLs and special URLs remain untouched.
- Frontend/admin layout assets, loading logo and module assets now use centralized versioning; generated part CSS files still keep `css_parts_version` as their functional version.
- Generated part CSS versions are monotonically incremented; button palette files additionally receive a random suffix in the filename so rapid consecutive saves never reuse the same cache URL.
- `.htaccess` now sets explicit long-term Cache-Control headers for static assets; dynamic design CSS/JS PHP endpoints revalidate instead of being blindly cached long-term.
- New regression test `.tests/asset-versioning-policy-test.php` integrated into Composer and CI as `composer test:fund10`.
- **Secure Package Processing — Staging and Rollback**
- Core update ZIPs are extracted into an isolated staging area outside the webroot; files are only deployed into the target tree after full validation.
- If deployment fails, an automatic rollback restores the previous state. A snapshot of the original state is retained for manual inspection.
- ZIP validation detects symlinks, path traversal attempts and invalid archive entries.
- **Hardened module upload path**
- Temporary files during module uploads are stored in a directory outside the webroot — never reachable via HTTP regardless of web server configuration.
- Temporary directories are reliably cleaned up after installation or errors.
- **ManifestVersion consistency guaranteed**
- The manifest version number is now correctly persisted after every generation process; monotonic growth is guaranteed.
- **Admin UI: Manifest status**
- The manifest management page displays the version number and key ID of the current manifest.
- **Ed25519-signed package manifest**
- All official packages are authorized through a cryptographically signed manifest.
- Both core updates and modules pass through the same verification chain — no separate signature logic exists.
- The private signing key is not part of the web server distribution and must be kept offline.
- **Admin UI: Generate Manifest** (`/admin/updates/manifest`)
- Status overview (key, manifest date, package count) and signing workflow via form; accessible only to authorized users.
- **Strict package path for modules**
- Modules are accepted in the normal installation path only if their SHA-256 hash is registered in a valid signed manifest.
- A separately permission-protected recovery path allows manual recovery installations when required. Such installations are visibly marked in the audit log.
- **Replay and downgrade protection**
- Previously accepted manifest versions are stored locally; older signed manifests are detected as replay attempts and rejected.
- Core and module downgrades are blocked in the normal installation path.
- **Key ring for manifest verification**
- Manifests include a key ID; the verifier supports active, deprecated and revoked keys. Revoked or unknown key IDs are rejected. Future key rotation is prepared.
Changed
- **Hardened update distribution**
- Package manifests are distributed publicly as signed artifacts; ZIP packages are trusted only through hash verification against the valid signed manifest.
Fix
- **Module Installer**: Package preview incorrectly displayed both buttons (Install + Update) when a module was already installed — fixed.
v0.9.5
28. May 2026
Change: Security Hardening
Changed
- **Security hardening** — Internal security audit completed; multiple preventive improvements implemented across authentication, encryption and input validation.
v0.9.4
28. May 2026
Change: Migration Path
Changed
- **Unified migration path**
- There is now exactly one migration service and one migration history table; legacy entries are automatically imported.
- The migration service is now isolated and fully testable without a real database connection.
v0.9.3
27. May 2026
NEW: Profile Panel + Changes
New
- **Profile Panel "Active Logins"**
- The user profile now displays all active remember-me sessions including device/user-agent, login date and expiration date.
- The current session is highlighted with a “This Device” badge.
- “Log out all other devices” terminates all other sessions with a single click. Fully translated (DE/EN).
- **Hardened Remember-Me Tokens**
- Tokens are now stored in a dedicated database table using selector/hash separation instead of a single value inside the user record.
- Tokens rotate on every auto-login; the previous cookie value becomes invalid immediately.
- **Logout cleans up all sessions**
- Logging out now removes all active remember-me tokens for the user.
Changed
- **`cx_remember` cookie attributes**
- SameSite=Lax, HttpOnly and Secure (when HTTPS is active) are now correctly applied.
- **Efficient token lookup**
- Tokens are now looked up directly via database index; expired tokens are opportunistically cleaned up.
v0.9.2
26. May 2026
NEW: CSRF Regression Test + Changes + Fixes
New
- **CSRF regression testing for admin mutations**
- Automated regression tests validate hardened admin write actions using missing and invalid tokens.
- Additional manual test matrix documents reversible save checks with valid admin tokens.
- **HTML/CSS professional block with strict JavaScript boundary**
- `raw_html` remains available as a flexible block for HTML, Bootstrap classes, inline styles and `<style>` blocks.
- The editor labels it as **HTML/CSS (Professional)** and displays a direct warning when JavaScript input is detected, referring users to the centralized Custom JavaScript section.
- Automated policy tests cover allowed HTML/CSS content, forbidden JavaScript vectors and legacy content rendering.
- **Secure management of external service credentials**
- OAuth, PSI and coreY credentials are managed through a shared secret management system.
- A guided admin flow supports the secure migration of already stored service credentials.
- Automated policy tests validate encryption, admin masking, migrations and failure scenarios.
- **Intentional OAuth account linking**
- New OAuth mapping differentiates between existing provider logins, new OAuth registrations and intentional linking from an authenticated profile.
- The profile page displays connected Google/Facebook login methods and provides secure connect/disconnect actions.
- Added metadata for account origin and last usage.
- Automated policy tests validate provider trust, profile linking, conflict handling and metadata consistency.
Changed
- **Centralized protection for mutating admin routes**
- `Router::dispatch()` now enforces valid CSRF tokens for all `POST`, `PUT`, `PATCH` and `DELETE` requests under `admin/*` before handler execution.
- Existing route-level and controller-level checks remain as additional defense layers.
- Permission checks across all admin sections have been completed.
- **Clear separation of custom code**
- Custom JavaScript continues to be managed centrally under *Design Options → Custom JavaScript*; the admin UI now explicitly explains this separation from content blocks.
- Rejected JavaScript save attempts from professional blocks and their translations are logged in the audit log without storing the submitted code itself.
- **Centralized and masked service credentials**
- Stored external credentials are no longer exposed in admin views and can be selectively replaced or removed.
- Changes and secure migrations remain traceable in the audit log without exposing confidential values.
- **Encapsulated OAuth login logic**
- `OAuthProviderProfile` normalizes provider data including email trust status.
- `OAuthAccountService` centrally decides about existing links, new accounts, profile linking and conflicts.
- OAuth actions are logged in the audit log in a traceable manner, but without tokens, secrets, provider IDs or unnecessary profile data.
- **Profile page as a dynamic account area**
- `PageRenderer` now prepares the profile context centrally, regardless of whether `/profile` is rendered as a special page or as a CMS `php_file`.
- Profile views, OAuth connections and active sessions now share the same prepared user context.
Fix
- **Unified CSRF protection for all admin write actions**
- All mutating admin actions (settings, content, configuration, migrations) now enforce valid CSRF tokens.
- Newsletter management and contact request status actions now use CSRF-protected POST requests.
- **`raw_html` block restricted to HTML/CSS**
- The professional block now only accepts pure HTML and CSS; disallowed content is rejected server-side and existing content is defensively sanitized.
- **Profile page reliably displays user data again**
- When the profile page is integrated as a CMS `php_file`, avatar, username, email and role status are now rendered again using the prepared profile context instead of empty view defaults.
v0.9.1
25. May 2026
NEW: Mobile First Settings + Fixes + Changes
New
- **Mobile Background Images for CMS Blocks (Phase 1)**
- All 5 block types with background image support (hero, text, two_col, cards, cta) now include an optional **Mobile BG (9:16)** field.
- In the admin block editor (`block-forms.js`), a second media library slot now appears below the desktop background: “Mobile BG · 9:16 · optional · <768px” including URL input, media library button, and clear button.
- In the frontend, when `mobile_bg_image` is set, an inline `<style nonce>` with `@media (max-width: 767px)` is generated to override the desktop background image — no JS or DB schema change required (block JSON).
- `ContentController::extractBlockData()` now persists `mobile_bg_image` for all 5 block types.
- **Mobile Background Images for News Detail Pages and Homepage Hero (Phase 1b)**
- **News/Blog Post**: New DB field `cms_news.mobile_hero_image` (migration `2026_05_27_000057_news_mobile_hero_image.sql`). A mobile background picker now appears below the desktop hero in the admin form. `views/content/blog-post.php` outputs a `@media (max-width: 767px)` override for `.cx-bpost-header-pb` when set.
- **Homepage Hero**: Each hero slot can now define a **Mobile BG** below the desktop background image (`hero{1|2|3}_mobile_bg_src` in `site_settings`). `HeroSettingsService` stores the value, and `views/parts/hero.php` outputs the `@media` override CSS for all 3 layout variants (Cinematic, Split, Centered). In the admin panel (`views/admin/hero.php`), each slot now includes a dedicated media library slot for the mobile image.
- **Mobile / Responsive Settings (Phase 2)**
- New admin section in *Design Options* with 4 sliders + 2 toggles: Mobile Hero Height (vh), Mobile Section Padding (px), Mobile H1 Font Size (px), Mobile H2 Font Size (px), Full Width CTA Buttons, Hide Topbar.
- `DesignSettingsService::MOBILE_KEYS` — typed constant array with validation rules (int/bool, min/max).
- `saveDesignOptions()` now persists all 6 mobile keys via `DesignSettingsRepository::upsert()` into `design_settings`.
- Migration `2026_05_27_000058_mobile_settings.sql` — INSERT IGNORE for the 6 default values into `design_settings`.
- **Generated Mobile CSS (Phase 3)**
- New `MobileCssGenerator` based on `CssPartInterface` generates `public/assets/css/corex/parts/mobile.css` using the active design settings.
- The generated stylesheet applies mobile hero heights, section spacing, and fluid-limited H1/H2 sizes; CTA full-width mode and optional topbar hiding including fixed-navbar spacing reset are enabled when configured.
- `DesignSettingsService::saveDesignOptions()` regenerates the file on save; `views/parts/header.php` loads it globally using the existing `css_parts_version` cache busting.
- **Mobile Polish & Performance (Phase 4, without PSI)**
- Hero LCP: real hero images are now prioritized for loading; homepage and news heroes can output separate desktop/mobile preloads via media queries in the document head.
- `ResponsiveImageService` generates WebP variants with 640 px and 1200 px widths under `assets/img/uploads/responsive/`; new uploads and pasted images are processed instantly, while the media library scanner upgrades existing images automatically.
- Blog, blog post, CMS text, and two-column images now use `<picture>`/`srcset` when variants are available; the lightbox opens the actually active image source.
- Design options now include a 390 px mobile preview of the saved homepage, and the block editor displays live warnings when a desktop background is set without a mobile replacement image.
- Mobile background images now correctly override active hero/text background videos on small viewports.
- **News/Blog — Multilingual SEO Metas**
- The news form now displays a language tab for non-DE locales on existing posts, similar to the Content Manager.
- Per language, blog title, blog slug, meta title, meta description, and meta keywords can now be maintained directly inside the post.
- New route `/admin/news/i18n/{id}` stores translated news meta data with CSRF and `admin.news.edit`.
- Migration `2026_05_23_000056_news_i18n_meta_fields.sql`: adds `cms_news_i18n.meta_title`, `meta_description`, and `meta_keywords`.
- **Central Mobile Settings (Phase 5–6)**
- The existing `/admin/mobile-nav` page has been expanded into the central **Mobile Settings** page; all mobile sliders from the general design options are now managed centrally there.
- Added design values: Mobile body font size, line height, container gutter, hero text alignment, and an intentional exception for decorative videos when a mobile fallback image exists.
- `MobileSettingsService` continues separating navigation-related `site_settings` from design-related `mobile_*` values and synchronizes the generated `mobile.css`.
- Migration `2026_05_27_000059_extended_mobile_settings.sql` creates the extended mobile design defaults.
- **Core Mobile Baseline & Content Robustness (Phase 5 and 7)**
- Fullscreen mobile heroes now use robust `vh`/`svh`/`dvh` heights, safe-area spacing, and centrally aligned touch targets with a minimum size of 44 px.
- Mobile navigation now supports visible keyboard focus, Escape closing, focus return, and proper ARIA states.
- `prefers-reduced-motion` reduces unnecessary animations; slider autoplay, parallax, and decorative videos are softened for reduced motion users.
- Parallax is disabled by default on smaller displays; CMS tables, embeds, long links, and media placeholders are now more robust on narrow viewports.
- The block editor additionally warns when background videos are missing a suitable mobile fallback image.
- **Responsive Preview & Mobile Release Check (Phase 8)**
- The admin preview now supports viewport presets `320`, `360`, `390`, `430`, and `768 px` in portrait and landscape mode.
- Homepage, published CMS pages, and news detail pages can now be selected as preview targets.
- The preview highlights missing mobile images, videos without fallback images, and horizontal overflow; a manual mobile release checklist is documented directly inside the settings.
- **Configurable Breakpoint for Mobile Background Images**
- Mobile settings now provide a Bootstrap breakpoint selector up to `xl` (`max-width: 1199.98px`) for alternative mobile background images.
- Homepage hero, CMS block backgrounds, news hero sources, preloads, and decorative video fallbacks all use the shared content-wide value `mobile_bg_breakpoint`.
- Migration `2026_05_27_000060_mobile_background_breakpoint.sql` adds the new `site_settings` default.
- **Mobile Navigation — Link and Button Display**
- Mobile settings now allow switching navigation links between **Buttons / Tiles** and **Text Only** mode.
- In button mode, background color, border color, and border radius can be configured; link, hover, and accent colors remain globally editable.
- In text mode, the hover accent color uses a text glow effect without showing backgrounds or borders.
- Migration `2026_05_27_000061_mobile_nav_link_style.sql` adds the new display defaults.
Changed
- **CMS Block Styles**
- Built-in CMS block sections now include stable `data-cx-block="<type>"` attributes so global and block-specific frontend styles can be targeted precisely.
- **Mobile CSS Pipeline**
- `mobile.css` is now regenerated from persisted values whenever the central Mobile Settings page is opened/saved or when another design is activated.
- Configurable mobile values are now output exactly as defined; H1/H2 no longer receive an additional hidden `clamp()` reduction.
- CSS file generation errors are now visibly reported in the admin panel instead of pretending the save was successful.
Fix
- **Hero Height in Frontend**
- The `/admin/hero` setting for `Fullscreen (100 vh)` is now explicitly output for all homepage hero layouts and uses `svh`/`dvh` support instead of depending on arbitrary layout CSS heights.
- In Split Hero Layout 2, mobile CSS now neutralizes the fixed desktop height so the separate mobile hero height truly takes priority.
- **Mobile Navigation — Stored Colors**
- Link and hover colors of the mobile sidebar are now output using dedicated `#mobile-nav` rules and are no longer overridden by generic design dynamic CSS link colors.
v0.9.0
21. May 2026
NEW: Media Library 2.0 & coreZ & Quill Image Resize + Fixes + Changes
New
- **Media Library 2.0 — Folder Workflow**
- Media grid expanded with a two-column layout; a folder sidebar appears on the right grouped by folder assignment.
- Folders are displayed as ~120x120px tiles showing name, file count and total size.
- Added “Unassigned Images” filter button between “All” and “Images”; displays only images without folder assignment.
- Image cards can now be dragged & dropped onto folder tiles; videos remain non-draggable.
- Folder tiles filter the media library on click and provide visual drop feedback during drag-over.
- Drag & drop assignments use the existing AJAX endpoint `/admin/media/meta` with CSRF token and existing permission checks.
- Folders can be created directly in the sidebar and renamed inline via pencil icon.
- Bulk cleanup: Multi-selection in the media grid with toolbar dropdown and folder assignment via sidebar click or “Assign” button.
- New admin route `/admin/media/bulk-assign-folder` for bulk assignments with CSRF token and `admin.media.upload`.
- Convenience features: URL copy button directly on media cards, sorting by name/image size/file size/date and switchable grid sizes.
- Images without alt text now display an `ALT` badge in the media library as a quick SEO/accessibility hint.
- `MediaUsageService`: usage tracking for media files in CMS pages, blocks, translations, news and settings.
- Detail modal displays “Used in” with source, field and link to the related admin section.
- New admin route `/admin/media/usage` for usage tracking with `admin.media.view`.
- New database field for hash-based duplicate detection during uploads and sync imports.
- New table for persistent empty folders; existing folder assignments are migrated automatically.
- **Design & Layout — General**
- New admin page `/admin/design-general` under “Design & Layout” for global body typography and the image scrolling toggle.
- Per-design defaults for `body_font_family`, `body_font_size`, `body_line_height`, `body_font_weight` and `parallax_scroll_enabled`.
- **Translations — Footer Links**
- New “Footer Links” tab under `/admin/translations` for managing `footer_links_i18n` and `footer_flat_links_i18n`.
- New route `/admin/translations/footer-links/save` stores label and URL translations per language with CSRF protection and `admin.mls.edit`.
- **Admin Help**
- New static help page `/admin/help` with search, sticky topic navigation and sections covering content, Quill, media library, MLS, design, SEO, system and keyboard shortcuts.
- Added “Help” sidebar entry before logout.
- **coreZ — Module Concept**
- New architecture paper `coreX-coreZ.md` for an installable module docking system including manifest, registry, installer, permissions, CSRF, CSP, assets, routes and pilot module proposal.
- Added architectural decisions/explanations for Composer dependencies, packaging, coreZ module hub, marketplace and core hooks.
- Implementation roadmap updated for the coreZ module manager with package validation, separated coreX/coreZ updates, content targets and direct SEO/media/dashboard hooks.
- Phase 0 completed: `modules/` established as the official module directory, manifest-v1 finalized and registry/permission/package-validation foundations documented.
- Phase 1 completed: `ModuleManager` and `ModuleEvents` introduced as registry/hook foundation; module manifests are scanned/validated and active modules can provide autoloading, admin/frontend routes, content targets, assets and SEO/media/dashboard hooks.
- Added `corex_modules`, `corex_module_migrations` and permissions `admin.modules.view` and `admin.modules.manage`.
- Phase 2 completed: New admin page `/admin/modules` with registry status, system sidebar entry, ZIP upload area, temporary package extraction, `module.json` validation and SHA-256 package verification.
- `ModulePackageInspector` intentionally prepares RAR support only as a later format; actual installation/activation/updates remain separated for Phase 3.
- Phase 3 completed: `ModuleInstaller` installs local modules and verified ZIP packages, registers module permissions, executes module migrations, tracks them in `corex_module_migrations` and stores activation state in `corex_modules`.
- coreZ updates back up existing module directories before updating and automatically roll back module files on failure.
- Activation/deactivation is available in the module manager; deactivation does not delete files or module data.
- Phase 4 completed: Module assets are securely delivered via `/module-asset`, admin/frontend CSS and JS from active modules are automatically included and manifest CSP rules are merged into the existing Content Security Policy.
- Content Manager: The “PHP File” select box now displays active module targets as a separate group; active modules can optionally provide custom views or routes.
- Phase 5 completed: `seo.urls.collect` connected to sitemap and SEO overview; module content targets with routes appear as module URLs and can be opened directly.
- `media.usage.collect` integrated into `MediaUsageService` so modules can report media usage for delete warnings and “Used in”.
- `dashboard.widgets.collect` integrated into the admin dashboard; optional widget permissions are checked before rendering.
- Phase 6 completed: Pilot module `modules/faq` created with manifest, migration, admin/frontend routes, repository, controllers, glass-style admin view, frontend accordion, JSON-LD `FAQPage`, dashboard widget and MediaUsage hook.
- Module i18n is mandatory: `module.json` must declare `i18n`; local modules and package validation require DE/EN JSON files.
- Admin sidebar renders module menu entries from `admin.menu.collect` inside a dedicated “Modules” group.
- Phase 7 completed: `content.blocks.collect` integrates module content blocks into the Content Manager; module blocks are stored as `module:slug:key`, edited/sanitized via manifest schema and rendered in the frontend through module render views.
- The FAQ pilot module provides the first module block `FAQ Teaser` for existing CMS pages including translatable fields, limits, category badges and a button linking to the FAQ page.
- Added prepared convenience hooks: `search.index.collect` for future global search, `module.backup.collect` for module exports/backups and `module.registry.collect` as the foundation for registry/marketplace functionality.
- `SeoAnalyzerService` can evaluate module block fields as static SEO context.
- coreZ package validation: Official module hashes are validated outside the ZIP; known official packages appear as success notices in the admin.
- **Quill — Image Resize in Editor**
- Images inside the editor can now be resized via drag handles; adjusted widths are saved and rendered responsively in the frontend.
- **GLightbox in the Public Frontend**
- CDN integration (CSS in `views/parts/header.php`, JS in `views/parts/footer.php`) with CSP nonce.
- Auto-wrap script: Finds all `<img>` elements inside `.blog-content` and `section[data-cx-cms-block="text"]` that are not already wrapped in `<a>` tags and wraps them as `<a class="glightbox">`. Initialization via `GLightbox({ touchNavigation: true, loop: false })`.
- `views/blocks/text.php`: `<section>` now includes `data-cx-cms-block="text"` — extensible for future block types.
- `public/assets/css/cx-global.css`: Added `section[data-cx-cms-block] img { max-width:100%; height:auto; }`.
Changed
- **Media Library**
- Folder dropdown, datalist and sidebar are now synchronized in-browser after meta changes, delete actions or drag & drop assignments.
- On smaller screens, the folder sidebar moves below the grid while remaining compact and usable.
- Unified active-state handling for media library filters.
- The special filter “Unassigned Images” automatically clears the folder filter; selecting a folder later exits the special filter.
- In the “Unassigned Images” filter, assigned image cards disappear from the grid immediately after assignment.
- Folder renaming updates all existing file assignments in `media_files.folder`.
- Media library selection state is now robustly reset after filter/search changes, delete actions and successful bulk assignments; added basic keyboard support for cards and folder tiles.
- The detail modal updates alt-text status, folder badges, sidebar and active filters immediately in-browser after saving.
- Single and bulk deletion now warn before removal if files are still referenced in content, news or settings.
- Upload, paste-upload and sync import store SHA-256 hashes once the new hash migration is installed; duplicates are reported to the UI as notices.
- Video files are now displayed as real HTML5 video elements in the grid and detail modal; the detail modal plays videos directly with controls while keeping the preview box layout stable.
- Media library header displays whether `ffmpeg`/`ffprobe` are available via PHP or whether `exec()` is disabled.
- Content media picker (`Select image from media library`) now additionally supports folder filtering alongside search.
- **Frontend Design**
- Dynamic CSS of all designs now outputs shared `--cx-body-*` variables and applies them to `body`.
- Parallax JS reads `--cx-parallax-scroll-enabled`; when image scrolling is disabled, only JS position movement is stopped while the background image remains fixed via `background-attachment: fixed`.
- **Admin Interface**
- The new help page uses the existing Glass Mode with `var(--admin-card-bg)` and blur instead of custom standalone backgrounds.
- The new “Footer Links” translation tab has been visually adapted to the admin Glass Mode; Bootstrap default backgrounds in accordions and tables were overridden.
Fix
- **Frontend — Parallax**
- Parallax JS now sets `background-position-y` with `!important` so it overrides the existing `.parallax-section` CSS rule.
- AOS initialization in the coreX design is now fault-tolerant so missing AOS does not stop the remaining frontend initialization.
- Design JS from manifests and `assets/js/corex/main.js` are now versioned using `filemtime()` so frontend JS changes no longer remain stuck in browser cache.
- **Media Library — Usage Tracking**
- `MediaUsageService` now checks text/JSON fields server-side using normalized variants (`\/` → `/`, HTML entities decoded) so CMS hero block data and other JSON references are detected reliably.
- Upload filenames are additionally extracted from normalized text/JSON fields and compared via basename, ensuring CMS block references work even with different URL formats.
- CMS block data is now JSON-decoded before scanning and recursively searched for string values; `bg_image` references in Hero/Cards/Text blocks are now detected reliably.
- Table/column detection in the usage service was changed from fragile `SHOW ... LIKE ?` checks to `information_schema` with secure fallback behavior so sources are no longer silently skipped.
- **Quill — Tables disappearing on save**
- Table content inside the editor was removed during save due to an internal browser timing conflict — fixed.
v0.8.9
20. May 2026
NEW: Quill WYSIWYG + Changes
New
- **Quill WYSIWYG — Unified Rich Text Editor**
- All text fields in the admin area (pages, blocks, news, translations) now use the same editor with a unified toolbar and media library integration.
- Screenshots can be pasted directly into the editor via Ctrl+V — automatic upload as WebP into the media library.
Changed
- **DB Query Optimization — Frontend page load significantly reduced**
- `src/Models/SiteSettings::getAll()`: Request-scoped static cache — `SELECT site_settings` is now executed only once per request, regardless of how often `getAll()` is called.
- `src/Repositories/DesignSettingsRepository::getAllByDesign()`: Request-scoped static cache per design slug — prevents duplicate `design_settings` queries.
- `src/Controllers/ContentController::getBlocksForPage()`: Fixed N+1 problem for non-DE locales — instead of 1 query per block, a single `cms_blocks_i18n WHERE block_id IN (...)` batch query is now used (saves N-1 queries for N blocks).
- `src/Models/FooterManager`: `getFooterData()`, `getActiveSocials()`, `getTopbarSocials()`, `getFlatLinks()` and new `getRevisionVersion()` now use request-scoped static caches.
- `src/Controllers/SettingsController`: New public delegator methods `getActiveSocials()`, `getTopbarSocials()`, `getFlatLinks()`, `getRevisionVersion()`.
- `views/parts/footer.php`: All 4–6 inline queries removed. Socials, revision version, footer columns/links and flat links are now loaded via `$page->settingsCtrl->*()` (cached). Klaro services: `new SettingsController()` replaced with `$page->settingsCtrl->getKlaroServices()` — no redundant controller bootstrap anymore.
- `views/parts/topbar.php`: Removed inline query for `footer_socials`, now uses `$page->settingsCtrl->getTopbarSocials()` (cached).
- `views/parts/navi.php`: Removed inline query `SELECT value FROM site_settings WHERE key='available_languages'` — value is now read directly from the already loaded `$siteSettings` array.
- **Result**: Frontend page load queries reduced by ~50% for both DE and non-DE locales (including block-i18n batching).
v0.8.8
19. May 2026
NEW: Brute-Force Login Protection and more + Changes + Fixes
New
- **Brute-force protection for login**
- `BruteForceService`: IP-based attempt tracking — ≥3 attempts = captcha, ≥5 = 15 min block, ≥10 = 60 min block
- Login view automatically shows the captcha block based on `$_cx_brute['show_captcha']`
- `AuthController::login()` checks block → captcha → logs success/failure via `AuditService`
- Admin view `views/admin/users/ip-locks.php`: table of all IP locks, unlock via AJAX
- New permission `admin.users.ip-locks`
- **Audit Log**
- `AuditService`: two-layer logging — layer 1: automatic router hook for all POST routes, layer 2: `AuditService::log()` in controllers/services for before/after values
- `AuthController`: login success/failure + logout are explicitly logged
- `UserController::save()` + `delete()`: logs `user.create` / `user.save` / `user.delete`
- Admin view `views/admin/system/audit-log.php`: DataTables server-side, color-coded action badge, JSON old/new values in expandable modal
- Route `admin/system/audit-log` + AJAX `admin/audit-log/data`
- New permission `admin.audit.view`
- Probabilistic cleanup (1% of writes delete entries older than `audit_retention_days` days, default 90)
- **DataTableService** (`src/Services/DataTableService.php`): Generic server-side endpoint — unified `respond()` for all DataTables endpoints in the admin
- **MailService with SMTP** (`src/Services/MailService.php`)
- Native SMTP via PHP streams — no Composer/PHPMailer required
- Supports STARTTLS (port 587), SSL (port 465), AUTH LOGIN and native `mail()` fallback
- HTML + plain-text multipart emails
- `.env` variables: `MAIL_HOST`, `MAIL_PORT`, `MAIL_ENCRYPTION`, `MAIL_USER`, `MAIL_PASS`, `MAIL_FROM`, `MAIL_FROM_NAME`
- **Password reset via email** fully enabled
- Routes `/forgot-password` + `/reset-password` (views + controller logic + i18n were already prepared)
- SMTP delivery via `MailService`, branded HTML email template with reset button
- **Admin → System: Test Mail**
- Form for sending a test email to verify SMTP configuration
- Displays the current delivery mode (SMTP host or native `mail()`)
- **coreY: model select box**
- Dropdown instead of free-text input for all cloud providers (Gemini, OpenAI, Groq, Mistral, Anthropic)
- Deprecated models marked with ⚠ warning, recommended models marked with ★
- Free-text fallback for ollama/custom + manual entry via `✏ Enter custom model…`
- **DataTables CSP-compliant (MLS Phase 6 ✅)**
- Admin CSP detection is locale-prefix-aware: correctly detects `/de/admin/...` as an admin request
- `cdn.datatables.net` whitelisted in admin CSP; i18n files via CDN
- `views/admin/parts/datatables-defaults.php`: global defaults (stateSave, lengthMenu, processing logo), locale-change-detection IIFE
Changed
- `UserController::data()`: now uses `DataTableService::respond()`
- Router: `AuditService::autoLog()` is called before every `call_user_func` (POST only)
- Admin sidebar: Audit Log entry added under System (permission-protected)
- `public/index.php`: admin detection now checks the first 2 URL segments (locale-prefix support)
- `views/admin/parts/top-navbar.php`: DataTables state is cleared via click handler when switching locale
Fix
- `siteBase()` in `AuthController` used a hardcoded `/corex` path instead of `APP_BASE` — password reset link pointed to the wrong URL
v0.8.7
18. May 2026
NEW: Invitation Code System + Changes + Fixes
New
- **Invitation Code System for Registration**
- New registration mode `invite`: Admin generates invitation codes (32 characters, cryptographically secure), receives a copyable invitation link to share with the invited person
- Invitation links: `/register?invite=CODE` — Code is pre-filled in the form
- Codes are individual and single-use: marked as `used_by` / `used_at` after use
- Optional note (name/email) and optional expiration date (1–365 days) per code
- Unused codes can be revoked
- `database/migrations/2026_05_18_000049_invitations.sql`: Table `cx_invitations` + Setting `registration_mode` + Permission `admin.invitations.manage`
- `src/Controllers/InvitationController.php`: `index()`, `generate()`, `revoke()`
- `views/admin/invitations.php`: Admin overview with code list, copy button, status badges
- Admin Sidebar: "Invitations" entry under Users (permission-secured)
Changed
- **Registration Mode** — `registration_enabled` (0/1) replaced by `registration_mode` (`disabled` / `open` / `invite`) in `site_settings`
- `src/Services/ConfigSettingsService.php`: saves new `registration_mode` setting
- `views/admin/config.php`: Toggle replaced by 3-way select; in `invite` mode, direct link to invitation codes
- `views/content/auth.php`: Registration form shows invitation code field only in `invite` mode; login page shows registration link only in `open` mode
- `views/parts/navi.php`: Registration link in nav only in `open` mode
- `src/Config/Routes.php`: new routes `admin/invitations`, `admin/invitations/generate`, `admin/invitations/revoke`
Fix
- **MLS Block Counter (Top Card)**: `TranslationService::getMissingI18n()` now also filters with `blockHasTranslatableFields()` — the number in the top overview box now matches the list
- **coreY: `<translation>` tag in output**: Fallback path now removes `<translation>`/`</translation>` from the raw text before it is saved (occurred when the model did not provide a closing tag)
- **cx-global.css for all designs**: Nav avatar/pill classes (`cx-nav-pill`, `cx-nav-avatar*`, `cx-logo-img`, `cx-mn-*`) moved from `corex-custom.css` to `cx-global.css` so all designs automatically receive these classes
- **Button palette invisible in Block Editor**: Generated `buttons-{timestamp}.css` was previously only loaded in the frontend header, not in the admin header. `views/admin/parts/header.php` now reads `buttons_css_file` via DB query and loads the file — button previews in all CMS block editors are now displayed correctly
v0.8.6
18. May 2026
NEW: coreY: Cloud Provider Support + Fixes
New
- **coreY: Cloud Provider Support (Google Gemini, OpenAI, Groq, Mistral, Anthropic, Custom)**
- `CoreYProviderInterface` (`src/Contracts/`): Unified interface `chat()`, `stream()`, `ping()` for all providers
- `OpenAiProvider` (`src/Services/CoreY/`): Full implementation for all OpenAI-compatible APIs including SSE streaming; Google Gemini uses the same provider via `generativelanguage.googleapis.com/v1beta/openai`
- Sensitive credentials (API keys) are stored encrypted in the database and displayed masked in admin views
- `CoreYService` refactored: Provider factory `makeCloudProvider()`, `chat()` / `streamChat()` / `pingWithError()` automatically route to the active provider; Ollama path remains fully supported
- Global admin system prompt: when filled, it completely replaces the built-in coreY base prompt
- Admin page “coreY Settings”: New sections “Provider & API” (provider dropdown, endpoint, encrypted API key) and “Persona & System Prompt” (2000-character textarea); Ollama URL/model fields are dynamically shown/hidden depending on the selected provider (JS)
- 4 new keys in `site_settings` (`corey_provider`, `corey_api_key`, `corey_api_endpoint`, `corey_system_prompt`)
- **coreY: DB-based chat history + multi-turn context**
- New table `corey_chats`: stores all user and AI messages per user
- Chat history is loaded from the database when opening the panel (`GET /admin/corey/history`)
- Multi-turn context: the last 20 messages are passed as conversation history to the AI provider (Gemini/OpenAI-compatible)
- Welcome message is stored only once — it no longer reappears after page navigation
- New endpoints: `clear-history` (POST), `save-message` (POST), `history` (GET)
- **coreY: Streaming toggle in settings**
- “Enable Streaming” switch in the coreY settings
- **coreY: Persistent panel state via localStorage**
- The panel remains open while navigating between admin pages
Fix
- Chat now reliably scrolls to the bottom after loading history and after new messages
- Close button in the panel header now works correctly at all viewport sizes (`.coreY-debug` was incorrectly positioned above the button)
- User messages stored in the database now contain the actual user input instead of the action prompt
- CSS structure updated: `corey-response-area` is now a flex container, while `corey-chat-list` acts as the actual scroll container
v0.8.5
14. May 2026
NEW: coreX SEO Analyzer + Fixes + Changes
New
- **coreX SEO Analyzer (Admin → System):** Complete SEO analysis tool for all CMS pages and blog posts
- **Overview Page** (`/admin/seo`): Table of all pages with score badge, latest scan date, quick scan button (AJAX), and PSI link; tab for global SEO settings (Twitter handle, author, Google/Bing verification, PSI API key, default meta description)
- **Detail Page** (`/admin/seo/{type}/{id}`): 4 score cards (Overall, On-Page, Technical, Content), expandable issue/warning list with priority, Core Web Vitals (LCP/INP/CLS via PageSpeed Insights API), scan history as sparkline chart
- **`SeoAnalyzerService`:** 13 checks (meta title/description, canonical, hreflang, H1, image alt tags, robots, Open Graph, Twitter Card, JSON-LD, HTTPS, loading time), 100-point scoring system
- **`SeoFetcherService`:** Live frontend URL fetching via cURL, DOM parsing with DOMDocument
- **`SeoPageSpeedService`:** Integration of the Google PageSpeed Insights API v5 (Mobile, LCP/INP/CLS)
- **`SeoSnapshotService`:** Stores scan results in the `seo_snapshots` table, history queries, site overview
- **`SeoController`:** 7 new routes (`/admin/seo`, `/admin/seo/scan`, `/admin/seo/detail`, `/admin/seo/settings`, `/admin/seo/history`, `/admin/seo/snapshot`, `/admin/seo/site-overview`)
- **News/Blog SEO Fields:** `meta_title`, `meta_description`, `meta_canonical` are now editable for blog posts in the editor; `NewsController` stores and reads these fields
- **PSI API Key:** Configurable under Admin → Configuration; managed via `ConfigSettingsService`
- **Nav Link:** SEO Analyzer under Admin → System → “coreX SEO Analyzer” (`bi-graph-up-arrow`)
- **coreY Integration (Phase 7):** “Ask coreY” button in the detail view — passes page title, URL, score, and all detected issues as context; new `seo_expert` action mode in `CoreYController` and `CoreYService`; global function `window.coreyOpenWith()` for programmatic panel opening
- **Migrations:** `seo_snapshots` table, news SEO fields, `admin.seo.view`/`admin.seo.edit` permissions, `psi_api_key` in `site_settings`
- **Social Icons — Centralized Management:** URLs and icon classes for all platforms are now managed exclusively under *Administration → Configuration → Social Media*. The `footer_socials` table is now the single source of truth for all platforms.
- **Social Icons — Topbar Control:** New `show_in_topbar` column in `footer_socials` controls which platforms appear in the topbar. Admin page *Topbar → Social Icons* now displays toggles instead of URL fields.
- **New Social Platforms:** Facebook, Xing, Telegram, Threads, WhatsApp, and Bluesky added as default platforms in `footer_socials`.
Changed
- **Frontend / Topbar:** `<style>` block moved from `<body>` into `<head>` — CSS variables and marquee keyframes are now correctly rendered in `<head>` via `header.php` (no more FOUC possible)
- **Frontend / Desktop Navigation:** `<style>` block for navbar colors/blur/shadow moved from `navi.php` (`<body>`) into `<head>` (`header.php`); complete `$_dn*` calculation block removed from `navi.php`
- **Frontend / Parallax:** `corex-init.js` extended with JS-based scroll handler for `.parallax-section` (updates `backgroundPositionY` on scroll, similar to `light_blue-init.js`); `background-attachment: fixed` removed from `corex-custom.css` because it conflicts with JS parallax and fails in certain contexts (transform ancestors, iOS)
- **Performance / `.htaccess`:** gzip compression (`mod_deflate`) and browser caching (`mod_expires`, 1 year for static assets) enabled
- **Admin / Footer → Social Icons:** Tab now only displays on/off toggles (footer visibility), no more URL/icon input fields. Link to centralized configuration added.
- **Admin / Topbar → Social Icons:** Section now displays toggles for `show_in_topbar` instead of URL input fields. Live preview reacts to toggles.
- **Frontend / Topbar:** Social icons are now dynamically loaded from `footer_socials WHERE show_in_topbar=1 AND url != ''` instead of individual `site_settings` keys.
- **`TopbarSettingsService`:** No longer stores `topbar_social_*` keys in `site_settings`.
Fix
- **SEO / hreflang Homepage:** hreflang tags pointed to `/de/home` instead of `/de/` — slug `home` is now treated like an empty slug in `SeoService::hreflangForCmsPage()`
- **SEO / Canonical URL:** Canonical URL did not contain a locale prefix (`/kontakt/`) and therefore did not match any hreflang tag — canonical URLs are now built with locale prefix (`/de/kontakt`) so canonical and hreflang exactly match for the current language; applies to CMS pages and blog posts
- **SEO / Twitter Cards (Blog Posts):** `twitter:site` was missing on blog post pages — `$twHandle` was not loaded from `$siteSettings` inside `buildBlogPostContext()` and therefore not added to the Twitter array
Migration
- `2026_05_15_000041_social_centralize.sql` — `show_in_topbar` column, new platforms, cleanup of old `site_settings` social keys.
v0.8.4
13. May 2026
NEW: Error Log DataTables + Fixes
New
- **Admin / Error Log:** DataTables 2.x integration — removed server-side pagination, all entries are now paginated, sorted and searchable client-side via DataTables (25 entries per page, configurable); level filter badges remain server-side via GET parameters; detail modal opens on click
Fix
- **Admin / Error Log:** Invalid function call prevented the error log content from rendering — fixed
- **Admin / Error Log:** DataTables scripts blocked by missing CSP whitelist — `cdn.datatables.net` added to `script-src`, `style-src` and `connect-src` of the admin CSP in `public/index.php`
- **Admin / Error Log:** `jQuery is not defined` / `DataTable is not defined` — DataTables v2 requires jQuery; jQuery 3.7.1 is now dynamically loaded before DataTables
- **Translations / Content Blocks:** Block type was displayed as `?` and “No translatable text fields” appeared even though the block contained text — `TranslationService::getBlockDeData()` only loaded the `data` JSON column, while `block_type` is a separate DB column; it is now loaded and injected into the array
- **Translations / Content Blocks:** Semantic text fields (`text`, `content`, `description`) with short DE content (<80 characters) were incorrectly rendered as single-line `<input>` fields instead of `<textarea>` — fix: field keys are now additionally checked (`text`, `content`, `description` suffixes → always textarea)
- **Smooth Scroll:** `scroll-behavior: smooth` in CSS (`corex`, `universe`, `light_blue`) conflicted with the JS-based `window.scrollTo({ behavior: 'smooth' })` — browser animation became too fast/uncontrolled; CSS property removed and replaced with a custom `cxSmoothScrollTo()` function using 700ms EaseInOutCubic easing
- **Translations / JSON Tab:** Progress badge displayed file existence (`1/1`) instead of the actual key translation ratio; badge now shows translated/total (e.g. `8/10`)
v0.8.3
12. May 2026
NEW: Redirect-Manager; Newsletter-System + Fixes
Neu
- **Newsletter / Subscriber-System**
- Tabelle `cx_newsletter_subscribers` (email, name, confirm_token, confirmed_at, unsubscribe_token, is_active) + Permission `admin.newsletter.edit`
- `src/Repositories/NewsletterRepository.php` — `all()`, `count()`, `countConfirmed()`, `findByEmail()`, `findByConfirmToken()`, `findByUnsubscribeToken()`, `insert()`, `confirm()`, `deactivate()`, `toggleActive()`, `delete()`, `allConfirmed()`
- `src/Services/NewsletterService.php` — `subscribe()` (Doppel-Anmeldeschutz, Re-Aktivierung), `confirm()` (Token-basiert), `unsubscribe()` (Token-basiert), `sendConfirmMail()` (UTF-8 encoded subject, PHP `mail()`)
- `src/Controllers/NewsletterController.php` — Admin: `index()`, `delete()`, `toggle()`, `export()` (CSV mit UTF-8 BOM)
- `src/Controllers/NewsletterPublicController.php` — Public: `subscribe()` (AJAX + Fallback), `confirm()` (GET), `unsubscribe()` (GET) mit eigenem Render-Page
- `views/admin/newsletter/index.php` — Übersicht mit Bestätigt/Ausstehend/Abgemeldet-Badge, Toggle, AJAX-Delete, CSV-Export-Button
- `views/parts/newsletter-form.php` — wiederverwendbares Anmeldeformular-Snippet (AJAX, Flash-Message, Spinner)
- Routen: `newsletter/subscribe`, `newsletter/confirm`, `newsletter/unsubscribe` (public) + `admin/newsletter/**` (auth + permission)
- Navi-Eintrag unter Verwaltung → Newsletter (`bi-envelope-at`)
- **Geplantes Veröffentlichen (Scheduled Publishing)** für Blog-Posts
- `src/Controllers/NewsController.php`: `getPublished()` + `getBySlug()` filtern jetzt `AND published_at <= NOW()` — Posts mit Zukunftsdatum bleiben unsichtbar bis zum Zeitpunkt
- `views/admin/news/index.php`: Neues "Geplant"-Badge (warning/clock) wenn `is_published=1` und `published_at` in der Zukunft; Datum zeigt Uhrzeit für geplante Posts
- `views/admin/news/form.php`: Datetime-Feld mit Hint-Box "Der Beitrag wird automatisch zum gewählten Zeitpunkt sichtbar" + JS-Toggle; kein Cron-Job nötig — rein query-basiert
- **Redirect-Manager** (`/admin/redirects`) — 301/302-Weiterleitungen verwalten
- Tabelle `cx_redirects` + Permission `admin.redirects.edit`
- `src/Repositories/RedirectRepository.php` — `findByPath()`, `all()`, `upsert()`, `update()`, `toggleActive()`, `delete()`, `incrementHit()`
- `src/Controllers/RedirectController.php` — `index()`, `save()`, `toggle()`, `delete()`
- `views/admin/redirects.php` — Übersicht-Tabelle mit Hit-Counter, Modal für Neu/Bearbeiten, Inline-Toggle, AJAX-Delete
- Weiterleitungen werden zentral vor dem normalen Routing ausgewertet.
- Navi-Eintrag unter Verwaltung → Redirects (`bi-sign-turn-right`)
Fix
- **Parallax-Bug (Text-Block, Two-Col, Blog-Post-Hero)**: Alle drei Blöcke nutzten einen veralteten JS+inner-Div-Ansatz (`data-parallax="0.5"` mit `top:-650px;bottom:-650px`) — jetzt einheitlich auf CSS `parallax-section` + `background-attachment:fixed` umgestellt (wie `cards.php`)
- **Blog-Listing Teaser**: Fallback-Teaser nutzte `strip_tags()` mit erlaubten HTML-Tags — wird jetzt sauber durch `$blogWordPreview()` als Plaintext gerendert
- **Übersetzungseditor (`views/admin/translations.php`)**: Quill WYSIWYG durch einfache Monospace-Textarea + Toolbar ersetzt (identisches Konzept wie News-Editor); Quill-CDN-Einbindung entfernt; `cx-corey-quill-field`-Sonderfall im coreY-Handler entfernt
v0.8.2
11. May 2026
NEW: coreY SSE-Streaming + Settings-Page
New
- **Phase 8c — coreY SSE Streaming + Settings Page**
- `src/Services/CoreYService.php`: `streamChat()` — streams Ollama responses token-by-token as Server-Sent Events; `getAvailableModels()` — loads available models from the Ollama server; `sanitizeInputPublic()` — public access to the internal sanitizer; new properties: `$tone`, `$responseLength`, `$responseLang`, `$personality` from `site_settings`; new getters; `buildSystemPrompt()` now considers tone, length, language, and personality
- `src/Controllers/CoreYController.php`: `stream()` (GET, SSE), `settings()` (GET, View), `settingsSave()` (POST, DB write)
- `src/Config/Routes.php`: added routes `corey/stream`, `corey/settings`, `corey/settings/save`
- `views/admin/corey-settings.php` — new settings page with connection test, model selection, tone/length/language option cards, and personality textarea
- `public/assets/admin/js/corey.js`: `sendRequest()` rebuilt for SSE streaming (fetch + ReadableStream) — token-by-token rendering instead of full JSON text
- `views/admin/parts/aside-navi-left.php`: added coreY link under Administration → Configuration (only when `COREY_ENABLED` + permission)
- `database/migrations/2026_05_11_000037_corey_behavior_settings.sql` — added `corey_tone`, `corey_response_length`, `corey_response_lang`, `corey_personality` to `site_settings`
v0.8.1
10. May 2026
Changes + Fixes
New
- `src/Services/Parts/FooterCssGenerator.php` — generates `public/assets/css/corex/parts/footer.css` with DB-dynamic footer padding (5rem for columns, 2rem for flat/none) as well as optional link color, hover color, text shadow, and font size from the footer settings
- `public/assets/css/corex/parts/footer.css` — new generated part CSS file (default: `padding-top:5rem`)
Changed
- **Sprint F — Footer Inline Style Cleanup**
- `src/Models/FooterManager.php`: `saveSettings()` triggers `FooterCssGenerator::generate()` after each save; added `use` imports for `CssGeneratorService` + `FooterCssGenerator`
- `views/parts/header.php`: `footer.css` included globally (as the second line after `navi.css`)
- `views/parts/footer.php`: `<style>` block (static + DB-dynamic rules) completely removed; PHP variables for color interpolation removed; `style="padding-top:..."` on `<footer>` → `class="cx-footer"`; inline opacities/cursor → CSS classes (`cx-foot-slogan`, `cx-foot-divider`, `cx-foot-copyright`, `cx-foot-sep`, `cx-foot-copyright-dim`, `cx-cursor-pointer`)
- `public/assets/css/corex/corex-custom.css`: added Sprint F section with 9 new utility classes
- **Sprint E — Content Inline Style Cleanup**
- `views/content/datenschutz.php`: `padding-bottom:3rem` → `pb-5`; divider → `.cx-divider-line`; `line-height:1.8` → `.cx-lh-18`; all `color:var(--eyecatcher)` on h2 → `.text-eyecatcher`; `color:var(--neon-blue)` on links → `.text-neon-blue`
- `views/content/technical.php`: header section padding+position → `pb-5 position-relative`; background image wrapper → `.cx-hero-bg-wrapper` / `.cx-hero-bg-video`; video height → `.cx-hvb-427`; kicker span → `.cx-section-kicker`; divider (×3) → `.cx-divider-line`; lead text → `.cx-lead-narrow`; DB-dynamic colors remain inline
- `views/content/changelog.php`: analogous to technical.php + subtitle span → `.cx-changelog-subtitle`; lead max-width → `.cx-lead-narrow`; container → `.cx-content-narrow`; current badge → `.cx-badge-current`
- `views/content/profile.php`: section position → `position-relative`; bg wrapper/video → `.cx-hero-bg-wrapper/.cx-hero-bg-video`; divider → `.cx-divider-line`; avatar image → `.cx-avatar-lg`; avatar initial div → `.cx-avatar-lg-initial`; cards → `.cx-card-glass`
- `views/content/blog.php`: sections position → `position-relative`/`pb-5 position-relative`; bg wrapper/video → classes; video heights → `.cx-hvb-300` / `.cx-hvb-300-mt`; divider → `.cx-divider-line`; blog section padding → `.cx-py-4rem`; card image → `.cx-blog-card-img`
- `views/content/blog-post.php`: header padding/overflow → `.cx-bpost-header-pb` + `overflow-hidden` class (conditional); parallax wrapper → `.cx-bpost-parallax-bg`; bg wrapper/video → classes; layer overlays → `.cx-overlay-55` / `.cx-overlay-light-35`; container z-index → `.cx-rel-z2`; featured image → `.cx-blogpost-featured-img`; back section padding → `.cx-bpost-footer-section`
- `views/content/features.php`: summary card → `.cx-card-surface`; done icons (×5) → `.cx-table-check`; feature card → `.cx-feat-card`; num/icon/title/desc → `.cx-feat-num/.cx-feat-icon-sm/.cx-feat-title/.cx-feat-desc`
- `views/content/contact.php`: textarea → `.cx-textarea-constrained`; captcha wrapper (×2) → `.cx-captcha-wrapper/.cx-captcha-wrapper-rounded`; captcha images → `.cx-captcha-img-sm/.cx-captcha-img-lg`; refresh buttons → `.cx-captcha-refresh-btn`; `margin-top:unset` → `mt-0`; divider (×2) → `.cx-divider-line`; `padding-bottom:3rem` → `pb-5`; `z-index:2;padding:2rem` → `.cx-z2-pad`; all DB-dynamic styles remain inline
- `public/assets/css/corex/corex-custom.css`: added Sprint E section with ~35 new utility classes
- **Sprint B — Blocks Inline Style Cleanup**
- `views/blocks/slider.php`: section height → CSS custom property `--sl-height` + `.cx-sl-section`; Swiper height, slide overflow, overlay z-index, content z-index → CSS classes (`.cx-sl-section > .swiper`, `.cx-sl-content`, `.cx-sl-bg-fallback`, `.cx-sl-text`, `.cx-sl-lead`); `.sl-bg` structural properties → CSS (only `background-image:url()` remains inline)
- `views/blocks/hero.php` (Block): structural CSS (position, display, align, color) → `.cx-blk-hero`; `.hero-container` padding → CSS; description max-width → `.cx-blk-hero-desc`; dynamic background/height remains inline
- `views/blocks/cta.php`: `color:#fff` → `.cx-blk-cta`; `background-size:cover;background-position:center` → `.cx-blk-cta-cover`; dynamic background color/image remains inline
- `public/assets/css/corex/corex-custom.css`: added Sprint B section with all classes above
- **Sprint D — Parts Inline Style Cleanup**
- `views/parts/navi.php`: all hardcoded `style=""` attributes (nav pills, avatars, mobile nav, language divider) replaced with new CSS classes (`cx-nav-pill`, `cx-nav-avatar`, `cx-nav-avatar-initial`, `cx-nav-avatar-guest`, `cx-nav-lang-code`, `cx-mn-overlay-light`, `cx-mn-video-wrapper`, `cx-mn-lang-divider`, `cx-mn-lang-active`, `cx-mn-lang-muted`)
- Logo height: `style="width:auto;max-height:Xpx"` in navi.php + header.php → CSS class `cx-logo-img` + CSS variable `--cx-logo-height` (written by `NaviCssGenerator`)
- `views/parts/header.php`: loading layer logo styles → `cx-logo-img`
- `views/parts/hero.php`: `<style>` block with `.hero-layout-1/2/3` structural CSS moved to `corex-custom.css`; DB-dynamic section backgrounds remain until the HeroCssGenerator sprint
- `src/Services/Parts/NaviCssGenerator.php`: now writes `:root{--cx-logo-height:Xpx}` into the generated `navi.css`
- `public/assets/css/corex/corex-custom.css`: new Sprint D CSS section with all classes above + hero layout CSS
v0.8.0
02. May 2026
NEW: coreX MLS; coreX ErrorLog + Fixes + Changes
New
- **coreX MLS Phase 5 — URL Structure with Language Prefix** (Option A, Breaking Change)
- All frontend URLs now include the language prefix: `/de/contact`, `/en/contact`, `/de/forum`, etc.
- `CX_SUPPORTED_LANGS` constant — comma-separated list of supported languages derived from `$__cxSupported`
- `CX_BASE` constant — `APP_BASE . '/' . CX_LOCALE`, e.g. `/corex/en` — base for all frontend links
- `cx_url(string $path = ''): string` helper function in `CoreXMLS.php` — generates locale-prefixed URLs; external URLs (`https://`, `//`) and anchors (`#`) are passed through unchanged
- **Canonical Redirect**: GET requests without a language prefix are redirected via 301 to `APP_BASE/{locale}/{path}`. Exceptions: `admin/*`, `captcha`, `robots.txt`, `sitemap.xml`, `install/*`, `auth/*`, `lang/*`. POST requests are never redirected.
- **Router** (`src/Core/Router.php`): Strips the language prefix after APP_BASE stripping — `de/login` → `login`, `en/forum` → `forum`
- **`PageRenderer::resolveSlug()`**: Also strips the locale prefix after APP_BASE stripping — fixes 404 errors for all CMS pages under `/de/...`
- **Maintenance Check**: now also considers the language prefix during path matching
- `<html lang="...">` in `views/parts/header.php` dynamically generated from `CX_LOCALE`
- Admin area remains without language prefix: `APP_BASE/admin/...`
- **`cx_url()` integrated into all link sources** — Breaking Change fully resolved:
- `views/parts/navi.php` — Logo, CMS slugs, Profile/Login/Logout/Register → `cx_url()` / `CX_BASE`; Admin link remains `APP_BASE`
- `views/parts/footer.php` — `$pageroot` switched to `CX_BASE`; flat links via `cx_url()`
- `views/blocks/hero.php`, `cta.php`, `text.php`, `slider.php` — button URLs via `cx_url()`
- `src/Core/BasePage.php` + `PageRenderer.php` — home redirects and 404 links now use `CX_BASE` instead of `APP_BASE`
- **coreX MLS — Frontend Language Switcher**
- **Globe dropdown** (`bi-globe2`) in the desktop navigation (left of the user avatar) — displays active locale code, checkmark for active language
- Same language links in the **mobile nav sidebar** (with separator, at the top of the user section)
- Only rendered if `available_languages` in `site_settings` contains more than 1 language
- **`MlsController::switchLanguage()`** — sets session + cookie and redirects to the equivalent URL of the new language (replaces locale segment: `/de/contact` → `/en/contact`)
- **Route `GET /lang/switch?to=en&back={url}`** — registered outside the `admin` group, before the catch-all
- **coreX MLS Phase 3 — Frontend Views Migrated** — all frontend pages with UI strings now use `coreX_mls()`
- `views/parts/navi.php` — navigation (Login, Register, Profile, Admin Panel, Logout, menu labels)
- `views/content/auth.php` — Login, Registration, Forgot Password, Reset Password
- `views/content/blog.php` + `blog-post.php` — empty-state texts, Read More, error page
- `views/content/contact.php` — headline, form fields, placeholders, submit button, address block
- `views/content/maintenance.php` — maintenance page (title, headline, default message)
- `views/content/profile.php` — profile form (all labels, buttons, JS password validation)
- `views/content/changelog.php` — page headline, “Current” badge, empty-state text
- `views/forum/*.php` — forum index, thread list, thread view, new topic, forbidden page
- 20+ new language files in `lang/de/` and `lang/en/`
- Static content pages (`privacy.php`, `technical.php`, `features.php`) will be handled as CMS content in Phase 4
- **coreX Error Log** — DB-based error logging system; captures all PHP errors (Warnings, Notices, Exceptions, Fatals) via `set_error_handler`, `set_exception_handler`, and `register_shutdown_function`
- **`ErrorLogger`** (`src/Core/ErrorLogger.php`) — Singleton, writes to `cx_error_log`; stack trace sanitization, fallback to native `error_log()`
- **Admin UI** under *System → Error Log* — table with level filtering, free-text search, pagination, detail modal, clear-log button (with CSRF)
- **coreX MLS Phase 1 — Core Infrastructure** — MultiLanguage System foundation
- `src/Core/Translator.php` — Singleton, lazy-loading JSON, dotted-key notation, plural support, 6-level fallback chain (URL → Session → Cookie → Accept-Language → DB → `de`)
- `src/Helpers/CoreXMLS.php` — global functions `coreX_mls()`, `coreX_mls_group()`, `cx_locale()`
- Locale detection in `public/index.php` directly after APP_BASE; dev mode logs missing keys
- Initial language files: `lang/de/parts/footer.json` + `lang/en/parts/footer.json`
- **coreX MLS Phase 2 — Admin Configuration** — Administration → coreX MLS
- `src/Services/LanguageSettingsService.php` — reads/writes language configuration, calculates translation progress in %
- `src/Controllers/MlsController.php` — GET page + POST save, permission `admin.mls.edit`
- `views/admin/mls.php` — default language, active languages (DE always fallback), progress bars per language
- Migrations: `2026_05_02_000030_error_log.sql`, `2026_05_02_000031_mls_settings.sql`
- **coreX MLS Phase 4 — Database i18n (Multilingual DB Content)**
- **3 new i18n tables** via migration `2026_05_02_000032_mls_i18n_tables.sql`:
- `cms_pages_i18n` `(page_id, lang, nav_label, slug, page_title, meta_description, meta_keywords)` — translates page metadata and URL slugs per language
- `cms_news_i18n` `(news_id, lang, title, slug, excerpt, content)` — translates news/blog posts; `content = NULL` = DE fallback
- `cms_blocks_i18n` `(block_id, lang, data JSON)` — translates block content; `data = NULL` = DE fallback
- **EN seed data** directly inside the migration: 15 page slugs + titles in EN, 4 news entries with EN titles/slugs/excerpts
- Main tables (`cms_pages`, `cms_news`, `cms_blocks`) remain **unchanged** — they act as the hardcoded DE fallback
- **`ContentController` i18n-aware** (`src/Controllers/ContentController.php`):
- `getPageBySlug()`: For non-DE locales, first checks `cms_pages_i18n WHERE slug=? AND lang=CX_LOCALE` via JOIN, fallback to `cms_pages.slug` (DE)
- `resolvePage()`: Automatically merges i18n metadata (`nav_label`, `page_title`, `meta_description`, `meta_keywords`) from `cms_pages_i18n` into the page array after slug lookup
- `getBlocksForPage()`: After loading blocks, checks `cms_blocks_i18n WHERE block_id=? AND lang=CX_LOCALE` for each block — if `data` JSON exists, it is merged over the DE data via `array_merge` (structural keys like `bg_image` remain from DE)
- **`NewsController` i18n-aware** (`src/Controllers/NewsController.php`):
- `getBySlug()`: For non-DE locales, first JOIN on `cms_news_i18n` via translated slug; fallback to DE slug with LEFT JOIN; `COALESCE` for title/slug/excerpt/content
- `getPublished()`: LEFT JOIN `cms_news_i18n` — `COALESCE(NULLIF(i.title,''), n.title)` etc. — lists automatically display translated titles/slugs/excerpts; `content = NULL` = DE
- **Admin UI: Page Translations** (in `views/admin/content/page_form.php`):
- New card “Page Translations” at the end of each edit page (only when `$isEdit`)
- Tab per active non-DE language with fields: Nav Label, URL Slug, Browser Title, Meta Description, Meta Keywords
- Saves via `POST /admin/content/i18n/{id}` → upsert into `cms_pages_i18n` (slug uniqueness ensured)
- New route `admin/content/i18n/{id}` + `ContentController::savePageI18n()`
- **Admin UI: Block Translations** (in `views/admin/content/page_form.php`):
- New translate button (`btn-outline-info`, `bi-translate`) per block in the block list
- Modal “Translate Block” with tab per non-DE language
- Shows only translatable text fields per block type: `headline`, `content`, `description`, `btn_text`, etc.
- Also supports Cards arrays (title + text per card) and Slider slides (headline, text, button)
- Loads existing i18n data via AJAX `GET /admin/content/block/i18n/get?block_id=X&lang=en`
- Saves via AJAX `POST /admin/content/block/i18n/save` → upsert into `cms_blocks_i18n`; leaf values sanitized server-side
- New routes: `admin/content/block/i18n/get` + `admin/content/block/i18n/save`
- New controller methods: `getBlockI18n()`, `saveBlockI18n()`, `getPageI18nAll()` (private: `sanitizeI18nData()`)
- **`hreflang` tags in `<head>`** (`views/parts/header.php`) — SEO requirement for multilingual websites:
- For CMS pages: reads `cms_pages_i18n` per `page_id` → generates `<link rel="alternate" hreflang="{lang}" href="...">` for all configured languages
- For blog posts: reads `cms_news_i18n` per `news_id` → same schema using `/blog/{slug}` path
- `x-default` always points to the first language (DE)
- `og:locale` and `inLanguage` in Schema.org blocks are now dynamically generated from `CX_LOCALE` (instead of hardcoded `de_DE`)
- Locale-to-OG-Locale map: `de → de_DE`, `en → en_US`, `fr → fr_FR`, `es → es_ES`
- **coreX MLS — Phase 3 Additions + Phase 1 Completion**
- **`views/parts/hero.php`** — fallback strings for subtitle, title, and button text now come from `coreX_mls('parts.hero.*')` instead of hardcoded DE — `/lang/de/parts/hero.json` + `/lang/en/parts/hero.json` created
- **Klaro Cookie Banner i18n** — Klaro’s `translations` object is now filled with DE + EN language blocks from `/lang/de/parts/klaro.json` + `/lang/en/parts/klaro.json`; `lang` key in the Klaro config object dynamically set to `CX_LOCALE`; admin-configured texts (Notice, Accept, Decline) flow into both language blocks
- **New helper function `coreX_mls_for(string $key, array $vars, string $locale): string`** — translates a key for a specific locale independently of the active locale (useful for multi-locale rendering in the same request, e.g. Klaro, hreflang labels)
- As global function in `src/Helpers/CoreXMLS.php`
- As `getFor(string $key, array $vars, string $locale): string` method in `src/Core/Translator.php`
- **`window.CX_TRANS` — JS Translation Object** — server renders a global JS object with all translated JS strings into the `<head>`:
- Frontend: `views/parts/header.php` — `window.CX_TRANS = <?= json_encode(coreX_mls_group('js')) ?>;`
- Admin: `views/admin/parts/header.php` — same object, locale-aware
- Language files: `/lang/de/js.json` + `/lang/en/js.json` (flat, all JS-visible strings)
- Migrated JS strings in: `corey.js` (modeLabels, Copy/Copied!, error messages), `cx-admin.js` (Saved, Error, Network Error, Close), `block-helpers.js` (blockLabels, edit suffix, no form), `block-forms.js` (Left/Right Column, Left/Right, No Effect, Card-style labels, Timeline defaults)
- All JS strings use `(window.CX_TRANS && CX_TRANS.key || 'DE fallback')` for backwards compatibility
- **Flash/System Message Infrastructure** — `/lang/de/messages.json` + `/lang/en/messages.json` created with all common system message keys (`saved`, `deleted`, `error_generic`, `invalid_token`, `fill_required`, `upload_success`, etc.); incremental replacement of controller strings with `coreX_mls('messages.key')` ongoing
Note
- **Breaking Change resolved**: All internally linked views now use `cx_url()` or `CX_BASE`. External links and anchors remain untouched. CMS block content with stored DB paths (e.g. `/contact`) automatically receives the locale prefix during rendering via `cx_url()`.
Fix
- **Visitor Tracking**: Admin routes (`/admin/*`) are no longer counted in `visitor_tracking`
New (Addendum 2026-05-02 / 2026-05-03)
- **MLS Phase 4 — DB i18n Starter Translations (EN)**
- Migration `000033`: EN translations for all CMS blocks on 5 pages (Home, About, Imprint, Team, Download) in `cms_blocks_i18n`
- Migration `000034`: EN content for 3 news articles in `cms_news_i18n`
- Migration `000035`: `footer_links_i18n` + `footer_flat_links_i18n` tables + EN entries for all footer navigation items
- Migration `000036`: `revisions_i18n` table + EN translations for all 27 changelog entries (0.3.6 – 0.7.5); label + full markdown changelog per version
- Migration `000037`: `site_settings_i18n` table (generic, key-value with locale) + EN hero texts (`hero_subtitle`, `hero_title`, `hero_description`, `hero_btn_text`, all highlight word keys)
- **`ContentController::getNavTree()` i18n-aware** — merges `nav_label` + `slug` from `cms_pages_i18n` for non-DE locales in a single query; DE fallback remains in the main fields
- **`views/parts/footer.php` i18n-aware** — footer links (column mode) and flat links read labels + URLs from `footer_links_i18n` / `footer_flat_links_i18n` with COALESCE fallback
- **`views/content/changelog.php` i18n-aware** — LEFT JOIN on `revisions_i18n` with COALESCE(i.label, r.label) + COALESCE(i.changelog, r.changelog); DE query remains unchanged
- **`views/parts/hero.php` i18n-aware** — for locale ≠ `de`, all matching `site_settings_i18n` entries are loaded in a single query and directly overwrite `$siteSettings[$key]`; all subsequent hero variables (subtitle, title, description, button, highlight words) automatically use the translated version
- **Captcha: Design-Adaptive Styling**
- `src/Core/Captcha.php`: Reads `input_bg_color`, `input_text_color`, `input_border_color` from `design_settings` (active design via `site_settings`) — captcha image automatically adapts to the active design; new private `hexToRgb()` helper (supports `#rgb`, `#rrggbb`, `#rrggbbaa`); fallback to previous defaults if DB is unavailable
- `views/content/contact.php`: Both captcha wrappers now use `var(--input-bg)` + `var(--input-border)` + `var(--input-text)` instead of hardcoded `bg-dark` / `#dee2e6` / `#333` — consistent layout with form inputs across all designs
v0.7.5
02. May 2026
NEW: coreY — The AI Assistant for coreX
New
- **coreY AI Assistant** — integrated AI assistant based on [Ollama](https://ollama.com/) (self-hosted, no cloud dependency required)
- **`CoreYService`** (`src/Services/CoreYService.php`) — Ollama HTTP client, reads configuration from DB, builds a system prompt with website context (`site_name`, `site_description`, `site_language`), injection protection via `sanitizeInput()`
- **`CoreYController`** (`src/Controllers/CoreYController.php`) — 3 AJAX endpoints: `POST /admin/corey/chat`, `GET /admin/corey/ping`, `GET /admin/corey/context`; authentication + permission checks + CSRF protection on every endpoint
- **5 AI modes**: Improve, SEO, Generate Meta Data, Summarize, Generate Ideas
- **Right Aside Panel** (`views/admin/parts/corey-aside.php`) — expandable right-side admin panel with mode tabs, textarea, character counter, copy button and live status indicator (Ping)
- **Welcome message** on first panel open: coreY reads `site_name` + `site_description` from the DB and displays a personalized welcome message
- **Toggle button in the admin topbar** (purple circle with “C” + label “coreY”) — will later be replaced with the official coreY icon
- **`corey.css`** + **`corey.js`** — standalone assets, only loaded when coreY is enabled
- **Permission** `admin.corey.use`
- **`site_description` field** in Administration → Configuration — short website description used for coreY context
- **Migration**
Infrastructure
- coreY runs on a secured self-hosted server.
v0.7.0
30. April 2026
NEW: Forum System + Changes
New
- **Forum System** completely new: Categories → Forums → Threads → Posts (classic 4-level structure)
- **`forum_categories`**, **`forum_forums`**, **`forum_threads`**, **`forum_posts`**, **`forum_user_bans`** — 5 new DB tables
- **Forum Permissions**: `admin.forum.manage`, `forum.post`, `forum.threads.close`, `forum.posts.delete`, `forum.threads.move`, `forum.threads.pin`, `forum.users.ban`
- **New Role: `forum_moderator` (Forum Moderator)** with permissions: `forum.post`, `forum.threads.close`, `forum.posts.delete`, `forum.threads.move`, `forum.threads.pin`, `forum.users.ban`
- **`ForumAdminController`** — CRUD for categories and forums (incl. order, read permissions, toggle, delete)
- **`ForumFrontendController`** — overview, thread list, thread view, reply, moderation actions
- **Admin View `views/admin/forum.php`** — management page with modals, inline editing
- **Frontend Views** (`views/forum/`): `index.php`, `threads.php`, `thread.php`, `new-thread.php`, `forbidden.php`
- **Frontend Routes** `/forum`, `/forum/f/{id}`, `/forum/t/{id}`, `/forum/t/{id}/reply`, moderation endpoints
- **Migration** `database/migrations-webserver/2026_04_30_000028_forum.sql`
- **FileScanner** — improved exclusion rules: `database/migrations-webserver/` explicitly whitelisted, root files completely excluded, `IGNORE_PATHS` for developer-only views/controllers introduced
Changed
- Role `moderator` → renamed to **`Blog-Moderator`** (DB label)
- Admin Sidebar: Forum entry in Content submenu (visible with `admin.forum.manage`)
- `public/index.php`: `ForumAdminController` + `ForumFrontendController` instantiated and passed to routing
v0.6.94
30. April 2026
Changes + Fixes
Changed
- **`public/robots.txt`**: Physical file in `public/` with clean structure — all search engines, SEO tools and AI assistants allowed; known malicious scrapers, scanners, email harvesters and exploit tools blocked (`nikto`, `sqlmap`, `HTTrack`, `EmailCollector` etc.)
- **`LogoUploadService` → `ImageUploadService`**: Class, file (`src/Services/ImageUploadService.php`) and all references in `SettingsController` renamed — the service manages not only the logo but also admin background images
- **`ImageUploadService::saveAdminBackground()`**: Regex extended from `\.png` to `\.(png|jpg|jpeg|webp)` — admin background images can now be stored in all common formats
Fix
- **CSP `script-src-attr` Violations** (aiqia.de): Footer links (flat mode) and social icons had `onmouseover="this.style.opacity='1'"` / `onmouseout="this.style.opacity='.75'"` as inline HTML attributes — replaced by CSS classes `cx-foot-link` / `cx-foot-social` with `:hover` rules
- **CSP `script-src-attr` Violations** (maintenance page): Admin login link in `views/content/maintenance.php` also had `onmouseover`/`onmouseout` — replaced by CSS class `cx-maint-admin-link`
Result — Mozilla Observatory Score — before → after
- Mozilla Observatory Score: from 0/100 → 130/100
v0.6.93
30. April 2026
NEW: HTTP Security Headers + Fixes
New
- **HTTP Security Headers**: `public/index.php` now sends the following headers on every request: `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: strict-origin-when-cross-origin`, `Cross-Origin-Resource-Policy: same-origin`, `Permissions-Policy: geolocation=(), microphone=(), camera=()`
- **HSTS**: `Strict-Transport-Security: max-age=63072000; includeSubDomains` is now automatically enabled when HTTPS is detected (disabled in local environments)
- **Content Security Policy**: Complete CSP allowlist for all used CDNs (Bootstrap, Font Awesome, Animate.css, AOS, Swiper, CodeMirror, Klaro, Leaflet/OpenStreetMap, Google Fonts, reCAPTCHA). Was tested using `Content-Security-Policy-Report-Only` before enforcement
- **Subresource Integrity (SRI)**: All 24 external CDN resources in `views/parts/header.php`, `views/parts/footer.php`, `views/admin/parts/header.php` and `views/admin/parts/footer.php` now include `integrity="sha384-..."` + `crossorigin="anonymous"` attributes — prevents manipulation through compromised CDNs
- **Swiper pinned to an exact version**, required for stable Subresource Integrity hashes
Fix
- **`cookie_secure`**: Session cookies now dynamically set the `Secure` flag when HTTPS is active
v0.6.92
24. April 2026
NEW: WebP Conversion on Upload + Fixes
New
- **WebP conversion on upload**: `MediaController::upload()` now automatically converts JPEG/PNG images to WebP (quality 82) and removes the original file. Result: ~78% less transferred data and nearly half the loading time (670 ms → 322 ms)
- **Automatic resize to 1920px**: Images wider than 1920px are proportionally downscaled to Full HD — prevents inexperienced users from uploading uncompressed high-resolution photos (6–10 MB)
- **Upload limit increased to 20 MB**: Since originals shrink significantly after WebP conversion, the limit was raised to allow large RAW photos to be uploaded successfully
Fix
- **`file_size` in DB**: Now determined after WebP conversion via `filesize()` — reflects the actual final file size instead of the original upload size
- **Media Library showing 0 files**: A naming conflict of an internal variable prevented the media library from displaying correctly — fixed
- **Media Library Sync Button**: New “Sync” button in the media library toolbar. Scans `public/assets/img/uploads/` and imports files copied via FTP/direct upload that are not yet registered in `media_files` (`MediaController::scan()`, route `admin/media/scan`)
- **Blog Header Image**: Empty-state branch (`empty($posts)`) ignored `$page['header_image']` — both branches (empty + with posts) now support the header image from the Content Manager
- **Profile Page Header Image**: `PageRenderer` loaded `profile.php` without setting `$page`. Now loaded analogously to `technical` and `changelog` via `$cmsCtrl->getPageBySlug('profile')`. Hardcoded background image removed, `$page['header_image']` is now used
v0.6.91
23. April 2026
Fixes
Fix
- **Button Palette: Buttons not displayed** — `ButtonPaletteController::index()` did not pass `$buttons` to view. `$buttons ?? []` fell back to empty array. Fixed: `$buttons = $this->manager->getAll($theme)` is now loaded before the view include
- **Button Palette: Timestamp filename** — Generated CSS file now named `buttons-{timestamp}.css` instead of fixed `buttons-generated.css`. Filename saved in `site_settings` (`buttons_css_file`), `header.php` reads it dynamically. Old file is automatically deleted on next save → updates can no longer overwrite the file
- **Parallax Blocks (text, two_col, blog-post)**: Background div had `inset:0` — on `translateY()` shift, edges were exposed. Fixed with `top:-120px; bottom:-120px` instead of percentage values (percentages did not work with `height:auto` sections)
- **Footer `REQUEST_URI`**: `basename($_SERVER['SCRIPT_NAME'])` always returns `index.php` (single entry point router). Replaced by `$_currentPath = strtok($_SERVER['REQUEST_URI'], '?')` for correct page detection
- **Versions Admin**: Version number input field was `col-md-2` (too narrow), `pattern` attribute added (`[0-9]+\.[0-9]+(\.[0-9]+)*`) — now allows 4-digit versions like `0.6.91`
v0.6.9
23. April 2026
Cards Admin Page + Changes
New
- **Cards Admin Page** (`/admin/cards`): New admin module under Layout → Cards for setting all card effects per theme. Configurable: background transparency, border opacity, border radius, padding, backdrop blur, hover effects (TranslateY, rotation, shadow), transition duration and easing curve. Live preview in admin
- **`corex-cards.css`**: New design-dependent CSS file with all card styles (extracted from `corex-custom.css`). All effects controlled via CSS variables (`--card-*`) which `corex-dynamic.php` reads from `design_settings`
- **12 new `card_*` keys** in `design_settings` for all 4 themes. Migration `2026_04_22_000027_card_settings.sql`
Changed
- **`corex-custom.css`**: All card-related styles commented out (moved to `corex-cards.css`)
- **`corex-dynamic.php`**: Now reads all 12 `card_*` keys and writes CSS variables to `:root`
- **Inline styles commented out** in `features.php`, `technical.php`, `changelog.php` (preparation for global stylesheet)
v0.6.89
23. April 2026
Button Palette + Changes
New
- **Button Palette** (`/admin/buttons`): New admin module for creating, editing and deleting custom CSS buttons per theme. Properties: background color + gradient, text color, font size, border, border radius, shadow, glow, glassmorphism, hover effect, padding for sm/md/lg. Saving writes `public/assets/css/buttons-generated.css` (static file, included in frontend)
- **Extended `.btn-eyecatcher` Control**: All 4 theme dynamic CSS files (`corex`, `universe`, `light_blue`, `solaris`) now read `btn_ec_*` keys from `design_settings` and render the complete `.btn-eyecatcher` block incl. `:hover`, `btn-sm`, `btn-lg`, shadow, glow, glassmorphism and padding
- **New DB Table `button_palette`**: Stores custom buttons per theme as JSON. Migration `2026_04_21_000020_button_palette.sql`
- **New `design_settings` Keys** (`btn_ec_*`): Defaults for all 4 themes in migration `2026_04_21_000021_btn_ec_defaults.sql`
Changed
- `views/parts/header.php`: Includes `assets/css/buttons-generated.css` in frontend
- `.btn-outline-eyecatcher` + `.btn-futuristic`: Removed from `*-custom.css` and `*-dynamic.php` files — now managed exclusively via the Button Palette
v0.6.88
23. April 2026
Content Manager: Block Layer Selection + Changes + Fixes
New
- **Content Manager: Block Layer Selection**: Hero banner, cards and slider blocks now have their own layer option (Dark / Light / No Layer). Previously, a dark layer was always hardcoded when a background image was set. New radio buttons in admin, validation in `ContentController::extractBlockData()`, output in `views/blocks/hero.php` and `views/blocks/cards.php` dynamically via `overlay-dark` / `overlay-light` class
- **Content Manager: Card Animation Effect per Card**: Each card in the cards block now has its own animation dropdown (AOS: ↑ Fade Up, ↓ Fade Down, ← Fade Left, → Fade Right, Fade In, Zoom In/Out, Flip Left/Right, Slide Up/Down, No Animation). The select appears to the left of the delete button in each card row. `syncCards()` serializes the `animation` field, frontend reads it in all 3 card styles
Changed
- **`ContentController::extractBlockData()`**: `hero` case extended with `bg_layer`, `cards` case extended with `bg_layer`, `slider` case extended with `layer` (was already present in admin UI but was never saved)
- **`views/blocks/hero.php`**: `$hasOverlay` + hardcoded `overlay-dark` replaced by `$bgLayer` variable (default `'dark'` for backward compatibility)
- **`views/blocks/cards.php`**: Analogous to hero — dynamic layer, all 3 card styles read `$card['animation']` with allowlist validation, fallback `fade-up`
- **`views/admin/content/page_form.php`**: Layer radios in hero form and cards form (parallax row + new layer row, both togglable via `oninput`); `cardRow()` + `syncCards()` extended with `animation` field
Fix
- **Slider Layer**: The layer select in the slider form was displayed but the value was not saved in `extractBlockData()` — fixed
v0.6.83
21. April 2026
Hero Editor: Text Colors + Changes + Fixes
New
- **Hero Editor: Text Colors**: An individual text color can be set in the Hero Editor for kicker, title and description (`hero_subtitle_color`, `hero_title_color`, `hero_desc_color`). The color is output as inline `style="color:…"` directly on the respective element — combined with an optionally set font size in a single `style` attribute
- **Hero Editor: Highlight Words**: For kicker, title and description, a comma-separated list of words can be specified that are automatically highlighted in the frontend in a selectable color (`hero_subtitle_highlight_words`, `hero_subtitle_highlight_color` etc.). The words are searched in the already HTML-encoded string via regex and wrapped in `<span style="color:…">`. Default highlight color: `#e87b00`
- **Colorpicker: Alpha/Transparency Support**: All `<input type="color">` fields in admin are now fully alpha-capable. `cxAddAlphaSupport()` in `cx-admin.js` builds a slider with checkerboard background below each chip. The saved value is 8-digit hex (`#rrggbbaa`). All 4 theme dynamic PHP files and nav/mobile nav files accept the new format
- **Colorpicker: Viewport Detection**: Color chips near the bottom of the page open the popup upward instead of downward — prevents the picker from being cut off
- **Admin `cx-admin.js` Cache Busting**: Script tag in `views/admin/parts/footer.php` now uses `filemtime()` as query string — browser always loads the current version
Changed
- **`HeroSettingsService::save()`**: 9 new keys — `hero_subtitle_color`, `hero_subtitle_highlight_words`, `hero_subtitle_highlight_color` and equivalents for `title` + `desc`. Colors via `SettingsSanitizer::sanitizeColor()`, texts via `sanitizeText()` (max. 500 characters)
- **`views/parts/hero.php`**: `$_heroSubtitleFs` / `$_heroTitleFs` / `$_heroDescFs` (pure size style strings) replaced by `$_buildStyle($px, $color)` — combines `font-size` and `color` in one attribute. `$_titleHtml()` closure receives additionally `$highlightWords`, `$highlightColor` and `$_applyHighlight` as parameters and returns the finished HTML string with embedded highlight spans
- **Colorpicker: Native OS Dialog Fix**: `cxEnhanceColorPicker()` removes Bootstrap classes `form-control`, `form-control-color`, `w-100` from input — prevented opening the native OS picker on nav/mobile nav pages
Fix
- **Colorpicker: Alpha Slider Covered**: `.c-chip input[type=color]` had `inset:0` as positioning, which overlaid the alpha slider below the chip. Fix: rule split into `.c-chip > input[type=color]` (pre-JS fallback, swatch height only) and `.c-chip .c-swatch input[type=color]` (after JS rebuild, `inset:0` correctly scoped)
- **Colorpicker: Alpha Value on Save**: Submit-time sync loop in `cxAttachAjax` (cx-admin.js) ensures the 8-digit hex value of the hidden input is recalculated from current RGB + alpha slider position directly before submitting — prevents stale values on quick submit
v0.6.8
21. April 2026
Extensions + Changes + Fixes
New
- **Content Manager: Block Layer Selection**: Hero banner, cards and slider blocks now have their own layer option (Dark / Light / No Layer). Previously, a dark layer was always hardcoded when a background image was set. New radio buttons in admin, validation in `ContentController::extractBlockData()`, output in `views/blocks/hero.php` and `views/blocks/cards.php` dynamically via `overlay-dark` / `overlay-light` class
- **Content Manager: Card Animation Effect per Card**: Each card in the cards block now has its own animation dropdown (AOS: ↑ Fade Up, ↓ Fade Down, ← Fade Left, → Fade Right, Fade In, Zoom In/Out, Flip Left/Right, Slide Up/Down, No Animation). The select appears to the left of the delete button in each card row. `syncCards()` serializes the `animation` field, frontend reads it in all 3 card styles
Changed
- **`ContentController::extractBlockData()`**: `hero` case extended with `bg_layer`, `cards` case extended with `bg_layer`, `slider` case extended with `layer` (was already present in admin UI but was never saved)
- **`views/blocks/hero.php`**: `$hasOverlay` + hardcoded `overlay-dark` replaced by `$bgLayer` variable (default `'dark'` for backward compatibility)
- **`views/blocks/cards.php`**: Analogous to hero — dynamic layer, all 3 card styles read `$card['animation']` with allowlist validation, fallback `fade-up`
- **`views/admin/content/page_form.php`**: Layer radios in hero form and cards form (parallax row + new layer row, both togglable via `oninput`); `cardRow()` + `syncCards()` extended with `animation` field
Fix
- **Slider Layer**: The layer select in the slider form was displayed but the value was not saved in `extractBlockData()` — fixed
v0.6.7
20. April 2026
Hero: Font Size per Text Field + Changes + Fixes
New
- **Hero: Font Size per Text Field**: In the Hero Editor, an individual font size in px can be set for kicker, title and description (8–200 px). The input field appears directly to the right of the text field as an `input-group` with font symbol. If no value is set, the previous CSS applies without inline style
- **Cards Block Style 3 (Icon Left)**: New card style in Content Manager — icon on the left, title and text to the right of it (horizontal). Own CSS classes `.cx-card3-item`, `.cx-card3-icon`, `.cx-card3-title`, `.cx-card3-text` in `cx-global.css`. Style selected via a 3-button tab group picker (Style 1 / 2 / 3) in the block editor
- **Design Setting `input_focus_color`**: New color setting in Design Options — controls the focus color of form inputs (`--input-focus-color`). Integrated into all 4 themes (`corex`, `universe`, `solaris`, `light_blue`). Migration `2026_04_19_000020_input_focus_color.sql`
- **Setup Wizard: Password Strength Check**: When creating the admin account, minimum requirements are now enforced (uppercase, lowercase, digit, special character). Server-side validation via regex; client-side live display with 4 green/red indicators below the password field
Changed
- **`HeroSettingsService`**: Saves 3 new keys — `hero_subtitle_size`, `hero_title_size`, `hero_description_size` (integer, clamped to 8–200)
- **`views/parts/hero.php`**: Reads font sizes and sets inline `style="font-size:Xpx"` on kicker `<span>`, `<h1>` and description `<p>` in all 3 layout variants (Cinematic / Split / Centered). No style attribute if value is empty
Fix
- **`UserController::save()`**: Password fallback to `'Secret123!'` on empty password field removed — new password is now mandatory when creating a user. Missing `email_verified_at = NOW()` entry added (prevented frontend login for admin-created accounts). `PASSWORD_DEFAULT` → `PASSWORD_BCRYPT`. `catch (\Exception)` → `catch (\Throwable)`
- **`AuthController`**: All 6 `catch (\Exception)` blocks extended to `catch (\Throwable)` — error subclasses (e.g. `TypeError`) were previously not caught
v0.6.6
18. April 2026
NEW: "Contact Form in Header" Mode + Fixes + Changes
New
- **Contact Page: "Form in Header" Mode**: New toggle in admin (`/admin/contact-page` → Header tab). When active, the contact form is embedded directly in the hero area on the left in split layout — only headline and teaser on the right. No separate form section below. Also works without a background image
- **Address Block Below Hero**: In "Form in Header" mode, address, phone, email and response time are output in a 4-column icon box row below the hero — above the map if enabled
- **Migration** `2026_04_18_000025_contact_form_in_header.sql`: New `site_settings` entry `contact_form_in_header`
Changed
- **`PageRenderer::renderFull()` / `render()`**: `$siteSettings` array is now passed as parameter, so all `php_file` templates (contact.php, blog.php, datenschutz.php …) have access to DB settings. Previously all ran on defaults because the scope of the static method did not see `$siteSettings` from `views/index.php`
- **Fetch Interceptor** (`views/admin/parts/header.php`): `X-Requested-With` header is now only set for same-origin requests. External API calls (e.g. Nominatim geocoding) no longer trigger a CORS preflight
- **Leaflet CDN**: `integrity` attributes removed from Leaflet CSS/JS tags — hash no longer matched current unpkg content (`L is not defined` error fixed)
- **Contact Page Hero Card Glassmorphism**: Form card adapts to the background — without image transparent/unstyled, with image light white glass instead of dark panel
- **Admin Height Select** (`contact_header_height`): `(string)$_hv` cast added — numeric array keys were converted by PHP to `int`, causing `===` comparison with string from DB to always be `false` and the selectbox to always show "Fullscreen"
Fix
- **Contact Page**: Settings (`contact_form_in_header`, height, layer, image) were not correctly applied because `$siteSettings` was missing in the `php_file` template scope
v0.6.5
18. April 2026
Top Navbar — Colors & Style + Changes + Fixes
New
- **Top Navbar — Colors & Style** (`/admin/navigation`): Below the layout picker, a new form block. Background type (Transparent / Color / Blur Glass), background color, border color (bottom divider, optional), shadow strength (None / Small / Medium / Large) and link colors (Normal, Hover, Accent/Glow) directly configurable. All values applied as inline `<style>` on `.navbar` — no theme customization needed
- **Contact Page Admin Area** (`/admin/contact-page`): New admin area with 3 tabs — Header (media library picker, type, layer, height), Map (Leaflet map, lat/lng/zoom toggle) and Settings (address, phone, email, response time). Settings saved in `site_settings`
- **Contact Page Frontend Dynamic**: `views/content/contact.php` reads all `contact_*` settings from DB. Header with image/video/layer/height; info column with address, phone, email, response time; optional Leaflet map (CDN, OpenStreetMap) with marker and address popup
- **Timeline/Roadmap Block: Colors & Glow**: In Content Manager, the color of the vertical line and circles can be set individually for each timeline block. Checkbox "Glow Effect" makes the circles shimmer in the chosen circle color (box-shadow)
- **Migration** `2026_04_17_000021_contact_settings.sql`: 17 new `site_settings` entries for contact page
- **Migration** `2026_04_18_000022_desktop_nav_settings.sql`: 7 new `site_settings` entries for desktop navbar
Changed
- **Navigation Admin** (`/admin/navigation`): Sidebar entry remains under Layout; page extended with desktop navbar form (background, colors, border, shadow)
- **Sidebar**: New entry "Contact Page" under Content submenu (`bi-telephone`)
- `views/blocks/timeline.php` and `extractBlockData()` in `ContentController`: New keys `line_color`, `dot_color`, `dot_glow` — existing blocks without these fields retain default CSS behavior
Fix
- **Footer Manager** `FooterManager::sanitizeUrl()`: Regex delimiter conflict fixed (`#` as delimiter collided with `#` anchors in URLs) → delimiter changed to `~`
- **Footer Admin** `views/admin/footer.php`: `setFooterMode()` function was referenced but never defined → new `applyFooterMode()` function replaces broken onclick handler
- **Footer Frontend** `views/parts/footer.php`: Flat mode rendered no correct layout → now as bottom bar (copyright left, links center, social right)
v0.6.4
17. April 2026
Footer Manager + Changes + Fixes
New
- **Footer Manager** (`/admin/footer`): Dedicated admin area with 3 tabs — Navigation (columns & links), Social Icons, Settings. Fully AJAX-based, no page reload when saving
- **Social Icons in Footer**: New table `footer_socials` (migration `2026_04_17_000019_footer_socials.sql`). 20+ pre-populated platforms (Twitter/X, GitHub, LinkedIn, Discord, Instagram, YouTube, TikTok, Twitch, Reddit, Pinterest, Mastodon, Vimeo, Spotify, Behance, Dribbble & more). Each entry has icon class, URL, activation toggle. Customizable display name and icon override
- **Frontend Social Icons Dynamic**: `views/parts/footer.php` reads `footer_socials` directly from DB — no more hardcoded social links; FontAwesome `fab` icons replaced by Bootstrap Icons
- **Icon Picker: Group Tabs**: When opening the icon picker, all categories are automatically generated as filter pills (All / ⭐ Popular / 🏢 Business / 💻 Technology / 📄 Documents / 🎨 Design & Media / 💬 Communication / 👤 People / 🗺️ Navigation / 🔒 Security / ⚙️ System / 🌟 Symbols / 📱 Social Media). Search and groups combinable
- **Icon Library massively extended**: 1,200+ icons in 13 categorized groups instead of previously ~60 icons in a flat list
Changed
- **Content Manager** (`/admin/content`): Footer management area removed — now at `/admin/footer`. Page shows only the page table
- **Sidebar**: New entry "Footer" under Layout submenu (`bi-layout-sidebar-inset-reverse`)
- **Icon Picker**: Duplicate `selectIcon` code removed; `pickIcon` function replaces `selectIcon`; grid height limited to 360px and scrollable
Fix
- Icon Picker: Orphan code (duplicated template literal block after `renderIconPickerModal`) removed — prevented correct icon selection in card blocks
- `/admin/content` forms: AJAX was not active → redirect to `/admin/config` fixed (`data-cx-ajax` added)
v0.6.3
17. April 2026
Setup Wizard + Changes
New
- **Setup Wizard** (`/install/`): Complete 4-step installation assistant. Step 1: Server check (PHP version, MySQLi, PDO, write permissions), Step 2: Database connection + website name + optional APP_BASE path, Step 3: Admin account (username, name, email, password), Step 4: Installation (SQL import, admin user creation, `.env` generation, lock file). Dark Space Glassmorphism design, responsive
- **Install Redirect** in `public/index.php`: If `.installed` is missing, automatically redirects to `/install/` — no manual setup invocation needed
- **Slider Block: Layer Option**: New global setting in slider editor — choice between "Dark Layer", "Light Layer" and "No Layer". Controlled via `$d['layer']` in `slider.php`
Changed
- `MediaController::upload()`: URL response corrected — `/public/assets/img/uploads/` → `/assets/img/uploads/` (web path did not match filesystem path)
- `PageRenderer.php`: Block loop now passes `$_blockSectionClass` (alternating `section-1`/`section-2`) to each block template
- Block templates: `text.php`, `two_col.php`, `timeline.php`, `cards.php` now use `$_blockSectionClass` — section background colors from design settings are applied correctly. `cta.php`, `slider.php`, `hero.php` remain unchanged (own backgrounds)
v0.6.2
17. April 2026
Design Manifest System + Fixes
New
- **Design Manifest System** (`manifest.json` per design in `assets/css/{design}/`): Declares fonts, external CSS/JS dependencies (head + body), CSS file list, dynamic CSS/JS and JS file list. Enables custom designs without hardcoded PHP code
- **Dynamic JS per design** (`{design}-dynamic.js.php` in `assets/js/{design}/`): Outputs DB-stored design variables as `window.CX_DESIGN` object — available to all design JS files. Manifest key: `dynamic_js`
- **cx-global.css**: Central design-agnostic structural styles — `overflow-x:hidden`, `.layer-dark`, `.devider-line-short`, mobile nav hide, roadmap/timeline layout, complete Klaro cookie banner mobile fix
- **Navigation Admin Page** (`/admin/navigation`): Dedicated page for nav layout, extracted from Content Manager — accessible via sidebar under Content → Navigation
- Design assets split into subdirectories: `assets/css/{design}/` and `assets/js/{design}/`
- Font loading from manifest instead of hardcoded if/elseif per design
- jQuery (Universe) declared via manifest entry `head.external_js` — no more hardcoded check
Changed
- **Admin Designs Page** (`/admin/designs`): Now shows info from `manifest.json` — name, version, author, description, tags, mode, fonts count, jQuery dependency, dynamic JS. DesignController automatically scans all installed designs
- **Content Manager**: Nav layout picker removed (→ dedicated nav page)
- `header.php`: Reads fonts, external_css, external_js (head) and CSS file list fully from manifest — no more glob, no old `universe-manifest.json`
- `footer.php`: Reads dynamic_js, JS file list and body.external_js from manifest — no more glob
- Design CSS files: Duplicated styles (roadmap, Klaro, mobile nav hide, divider line) extracted to cx-global.css
Fix
- Designs page: "Activate" button now correctly updates the active badge (page reload after AJAX via `data-cx-reload`)
- Admin users page: `$ is not defined` error fixed — jQuery dependency replaced by Vanilla JS
v0.6.1
15. April 2026
Several Fixes
Fix
- Nav layout card in Content Manager now consistently shows a green "active" badge (like Hero Editor)
- Nav layout save now uses the unified toast instead of old internal notice div
- Header background image is now correctly displayed on `php_file` pages (e.g. Blog)
- User dropdown in sidebar layout (nav-layout-3) now opens upward instead of disappearing from viewport
- Media library picker in Content Manager (header image) was opening old browser popup — now unified modal
v0.6.0
15. April 2026
AdminArea AJAX Migration + Script Optimizations + Sub-page Header BG + Fixes
New: Full AJAX Migration of Admin Area
- All admin forms now use AJAX — no more page reloads when saving
- New toast notification system (`cx-toast`) with BEM classes for success, error, warning, info
- New shared admin JS file `public/assets/admin/js/cx-admin.js` with form interceptor & toast engine
- `AjaxResponse` helper in `src/Core/` for consistent JSON responses (`ok()`, `error()`, `isAjax()`)
- `data-cx-ajax` — opt-in attribute for forms
- `data-cx-confirm="..."` — confirmation dialogs as attribute (replaces `onsubmit="return confirm()"`)
- `data-cx-reload` — reload page after success
New: 4 New MVC Controllers
- `RolesController` — manage roles & permissions (index, savePermissions, createRole, deleteRole)
- `SystemController` — maintenance mode & system message (index, toggleMaintenance, saveMessage)
- `RevisionController` — version management CRUD (index, store, update, delete, setCurrent)
- `DesignController` — activate design (index, activate)
- Inline PHP completely removed from `roles.php`, `system.php`, `revisions.php`, `designs.php`
New: Header Background Image per CMS Page
- New column `header_image` in `cms_pages` — each page can have its own header image
- Admin UI in Content Manager with media library picker directly in the page edit form
Changed
- `FooterManager`, `KlaroManager`, `ConfigSettingsService` — redirect logic removed, AJAX-compatible
- CSRF check added to user delete
- `NewsController::store()` redirects directly to edit page after creation
- All `?saved=1` flash redirects replaced by toast feedback
- Media library picker in Content Manager now consistently opens a modal (no more browser popup)
Fix
- `$flashMsg` undefined variable in `system.php` after MVC refactoring fixed
- Toast CSS BEM classes (`cx-toast--success` etc.) consistent with JS output
v0.5.5
14. April 2026
Several Updates
New: Navbar Layout Selection (3 Variants)
- New admin page in Content Manager: user can choose between 3 navbar variants
- **Layout 1 (Default)**: classic top navbar
- **Layout 2 (Slim)**: compact top navbar (0.18 rem padding, smaller font & logo)
- **Layout 3 (Sidebar)**: fixed left sidebar navigation (252 px), remaining content indented
- Selection saved via AJAX (`admin/nav/save`) and visually confirmed immediately
- CSS classes `nav-layout-1/2/3` on `<body>` and `<nav>` — fully in `nav-layouts.css`
- `nav_layout` saved in `site_settings`
New: Sidebar Navigation Flyout Submenus
- Dropdown menus in Layout 3 open as **flyout to the right** (dark card, shadow, rounded)
- `<main>` wrapper around content area (navi.php → footer.php) creates own stacking context
- Sidebar nav sits below `<main>` (`z-index`), flyout protrudes into the content area
- User menu in Layout 3 pinned to the bottom of sidebar via `margin-top: auto`
New: Hero Slot System (3 Independent Hero Configurations)
- Homepage hero fully refactored: 3 independent slots (no longer design-bound)
- Each slot configures: **Layout** (Cinematic / Split / Centered) + **Background** (image or video)
- `active_hero_slot` controls which slot is displayed on the homepage
- Admin UI (`/admin/hero`): radio buttons select slot — 3 layout cards as preview with green "active" badge
- Background configuration per slot: URL input, media library picker, file upload, preview
- `HeroSettingsService` handles complete save logic (keys: `hero1/2/3_layout`, `_bg_src`, `_bg_type`)
- `views/parts/hero.php` always reads SRC + TYPE from the same slot bucket (no bucket mismatch anymore)
New: SettingsController Refactoring (Service Architecture)
- `SettingsController` split into independent classes:
- `src/Helpers/SettingsSanitizer.php` — input sanitization
- `src/Repositories/DesignSettingsRepository.php` — DB access design settings
- `src/Services/DesignSettingsService.php` — design logic
- `src/Services/HeroSettingsService.php` — hero slot logic
- `src/Services/ConfigSettingsService.php` — general config
- `src/Services/LogoUploadService.php` — logo upload
- `SettingsController` now only delegates, contains no own business logic
New: Designs Universe & Solaris
- **Universe**: second frontend design with own CSS file (`universe-custom.css`)
- **Solaris**: third frontend design (`solaris-custom.css`, cream palette, sun decoration)
- Design isolation: only the associated CSS file is loaded per active design
Fix: Solaris Sub-pages (Changelog, Technical)
- Video section headers on Solaris sub-pages were broken (large video, no overlay, cream BG)
- Cause: `corex-custom.css` not loaded with Solaris → `.hero-video-bg` and `.overlay-dark` had no CSS
- Fix: `.hero-video-bg`, `.overlay-dark`, `section:has(.hero-video-bg)` defined in `solaris-custom.css`
UI Improvements Admin
- Hero admin page restructured: texts first, then hero slots (info alert box explains the system)
- Layout preview cards show name & description as overlay directly on the SVG preview
v0.5.0
12. April 2026
UpdateInstaller
New: Update Installer (`/admin/updates/install`)
- New admin page **Install Updates** — lists all available update packages with status (Installed / Pending / Locked)
- Enforced order — older packages must be applied first
- Confirmation modal before each install with package info and security notice
- Changelog modal per package (read-only preview)
- Maintenance mode is automatically activated/deactivated (`try/finally`)
- Summary cards (Total / Installed / Pending)
New: `src/Core/UpdatePackager.php`
- `getPackages()` — all packages descending by ID
- `getPackageFiles()` — file list of a package
- `applyPackage()` — extract ZIP, run migrations, set `installed_at`
- ZIP path traversal protection: every entry is validated before extraction (no `realpath()` on non-existent files — manual segment resolution)
- Migrations runner: new `.sql` files from `database/migrations-webserver/` are executed alphabetically and recorded in the `migrations` table
New DB Tables (migration `000002`)
- `update_packages` — package metadata (version, label, changelog, archive path, file count, size, `installed_at`)
- `update_package_files` — file manifest per package (path + change type)
- New permissions: `admin.updates.create` + `admin.updates.install` (superadmin only)
Routing & Sidebar
- Route `GET/POST admin/updates/install` added
- Sidebar: "Updates" → two entries: **Update Scanner** + **Install Updates**
- `updates-install` added to `$systemPages`
v0.4.8
12. April 2026
Maintenance + FileScanner + CleanUps
New: Designs System (`/admin/designs`)
- New admin page **Designs** under "Layout" — shows available frontend designs as cards
- Design "corex" active as default; placeholder card for future designs links to Updates
- `active_design` entry in `site_settings` (migration `000029`)
- Permission `admin.designs.view` + assignment to admin role
- Custom CSS / JS now design-prefixed: `corex_custom_css` / `corex_custom_js` — on design switch, custom code per design is preserved
- `SettingsController::save()` reads `active_design` dynamically and saves under `{design}_custom_css` / `{design}_custom_js`
- Route `admin/designs` added
New: Maintenance Mode (`/admin/system`)
- New admin page **System** with toggle for maintenance mode and editable message
- Frontend check in `public/index.php` — logged-in admins are let through, all others see 503 page
- Standalone maintenance page (`views/content/maintenance.php`) — HTTP 503, `Retry-After: 3600`, no layout overhead
- `maintenance_mode` + `maintenance_message` in `site_settings` (migration `000028`)
- PRG pattern: flash in `$_SESSION['_flash_system']`, redirect after POST → no "resubmit form" dialog on F5
- Permission `admin.system.view` + assignment to admin role
New: File Scanner & Updates Preparation (`/admin/updates`)
- `src/Core/FileScanner.php` — scans project files, creates SHA256 snapshots, detects changes
- `src/Controllers/UpdateController.php` — manages snapshots
- Admin page `views/admin/updates.php` — shows changed/new/deleted files since last snapshot
- DB table `file_snapshots` (migration `000026`)
- `database/migrations` in scanner ignore directory, `database/migrations-webserver` is captured
- Concept document for full update installer created (`updates-install.md`)
Asset Rename & Design Structure
- `public/assets/css/custom.css` → `corex-custom.css`
- `public/assets/css/dynamic.php` → `corex-dynamic.php`
- All image assets from `public/assets/img/` moved to `public/assets/img/corex/`
- All references in views, CSS, PHP controllers updated (`glob` paths, `url()`, `<img src=`...)
Admin Sidebar: Restructuring
- New submenu **System**: Maintenance Mode, coreX Versions, Updates
- **Layout** submenu moved after Content, "Designs" as first entry
- **Administration** now after Layout
UI: Admin Button Overrides
- Global `.btn-*` overrides in `main.css` — gradient backgrounds, neon glow, `scale(0.97)` on active
- Outline variants and btn-sm/btn-lg adjustments
Bugfixes
- Maintenance check: `=== '1'` → `== '1'` (robust for DB types), `exit()` → `die()`
- Admin BG thumbnail URLs updated to `assets/img/corex/` path
- `corex-custom.css`: hardcoded `url('../img/hero-bg5.png')` → `../img/corex/hero-bg5.png`
v0.4.1
12. April 2026
CleanUp
jQuery completely removed (Vanilla JS)
- `public/assets/js/corex-init.js` fully rewritten in Vanilla JS:
- `$(function)` → `DOMContentLoaded`
- `$.fadeOut` → CSS opacity transition
- `$(window).scroll` → `addEventListener('scroll', ..., { passive: true })`
- `$.addClass/removeClass` → `classList.toggle`
- `$.css('transform')` → `el.style.transform`
- `$.animate scrollTop` → `window.scrollTo({ behavior: 'smooth' })`
- `views/parts/footer.php`: jQuery script tag removed, contact form handler translated to Vanilla JS
- `public/index.html`: jQuery script tag removed, all jQuery blocks (AOS, Navbar-Scroll, Mouse-Glow, Parallax, Smooth-Scroll, Contact Form) migrated to Vanilla JS
bootstrapv5-colorpicker replaced by Pickr (`/admin/settings`)
- `bootstrapv5-colorpicker@0.0.2` (jQuery plugin) fully removed from `views/admin/parts/footer.php`
- Replaced by **Pickr** (`@simonweis/pickr@1.9.1`) — zero-dependency Vanilla JS Color Picker
- All jQuery initialization blocks, Bootstrap shim and slider-fix workaround removed
- Pickr customized dark theme (matching the admin interface)
- `.c-chip` click opens Pickr; color changes sync live to `input[type=color]` and dispatch `input` events (all `oninput` handlers like `updateEye()`, `chipSync()` remain compatible)
Concept: Update System (`updatesystem.md`)
- Concept document for central coreX update system created
- Update server (`update.aiqia.de`) delivers signed `.zip` packages + `manifest.json`
- Update client in admin: check version, download package, SHA256 verification, rollback snapshot, file patches + SQL migrations applied
- Implementation plan in 3 phases documented for AI assistant
v0.4.0
11. April 2026
Role & Permission System + Revisions/Versioning
- Role-based permission system, Roles & Permissions Admin UI
- Revisions/Versioning
- Sidebar Submenus
- In-Block AOS Animations
- UI Polishing & Bugfixes
v0.3.6
11. April 2026
Initial Release
- Routing, Authentication, Admin Area
- Content Manager & Block Editor
- Media Library, News/Blog
- Design Options, Hero Editor
coreX Technical Specs → Technical Documentation