# Copilot instructions — zedge (DataLife Engine)

## Request flow (the parts that matter)
- Public entrypoint: `index.php` defines `DATALIFEENGINE`, `ROOT_DIR`, `ENGINE_DIR`, loads `engine/classes/plugins.class.php`, then runs `engine/init.php` via `DLEPlugins::Check(...)`.
- Early controller dispatch happens inside `engine/classes/plugins.class.php`: `?controller=ajax` → `engine/ajax/controller.php` (then includes `engine/ajax/<mod>.php`), `?controller=antibot` → `engine/modules/antibot.php`.
- Main bootstrap: `engine/init.php` (after `include_once .../modules/functions.php`) calls `DLEUrl::Route()` when `$config['allow_alt_url']` is enabled, then `dle_session()` + `check_xss()`, then dispatches to modules like `engine/download.php`, `engine/go.php`, RSS, etc.
- Admin entrypoint: `admin.php` → `engine/inc/include/init.php`.

## Routing & URL rules
- Alt-URL routing is FastRoute-based (`engine/classes/urls.class.php`) and writes a cached rules file to `engine/cache/system/route.rules.php`.
- If you add/adjust routes, check both the human rule and the querystring mapping in `DLEUrl::$default_rules`.

## Plugins/overrides (don’t break this)
- Always wrap engine includes with `DLEPlugins::Check(...)` so plugin overrides work, e.g. `include_once(DLEPlugins::Check(ENGINE_DIR . '/modules/functions.php'));`.
- Overrides are served from `engine/cache/system/plugins/…` when a mapping exists; core “protected files” are listed in `DLEPlugins::$protected_files`.

## Conventions that are everywhere
- Guard public modules/classes: `if (!defined('DATALIFEENGINE')) { header(...); die('Hacking attempt!'); }`.
- Input handling is defensive/legacy: `intval()` for IDs, `strip_tags()/totranslit()` for strings, and `$db->safesql()` before SQL (see `engine/init.php`, `engine/ajax/controller.php`, `engine/ajax/upload.php`).
- Minimum PHP: `engine/classes/plugins.class.php` sets `DLE_PHP_MIN_VERSION` to 8.0.0.

## Templates/skins & front-end bits
- Skins live under `templates/<skin>/`; template parsing is in `engine/classes/templates.class.php` (global tags like `{page-title}` and conditional blocks like `[smartphone]...[/smartphone]`).
- Media handler customization is documented in `MEDIA_HANDLER_GUIDE.md` (targets `templates/vkino/*` and adds `public/js/media-handler.js` + `public/css/media-handler.css`).
- PWA is implemented via `sw.js` + `manifest.json` with offline fallback at `assets/pwa/offline.html`; the service worker intentionally bypasses `/engine/`, `/admin.php`, `/admin/`, and `/api/`.

## Local workflow
- Built-in server: `php -S localhost:8000 router.php` (routes non-files to `index.php`).
- If `engine/data/config.php` is missing, `engine/classes/plugins.class.php` will stop/redirect to `install.php`.
- Enable PHP errors (dev only): `$config['display_php_errors'] = 1` in `engine/data/config.php`.
- No test runner in repo; validate by exercising pages and `?controller=ajax` endpoints.

## Don’ts
- Don’t edit vendored code under `engine/classes/composer/vendor/`.
- Don’t commit real secrets from `engine/data/*.php` (especially `dbconfig.php`).
