# Custom Files

A project-scoped **file manager** for adding static or dynamic files and folders
that are copied into the generated application at build time and served as part
of the site — the PPphp equivalent of PHPRunner's *Custom Files*.

## Where files live
`projects/<user>/<slug>/custom/` — a real directory tree, edited through the SPA.

## Build integration
`BuildWriter::copyCustomFiles()` (called from `BuildEngine`, step 13b) copies the
whole `custom/` tree into the generated app **root**, preserving structure, e.g.
`custom/site/index.html` → `<app>/site/index.html`, served at `/site/index.html`.

Reserved system paths are **skipped** so a stray upload can never overwrite the
generated runtime: `_runtime.php, index.php, app-shell.php, cron.php, routes.json,
manifest.json, database.sql, core/, app/, api/, config/, generated/, plugins/`.
Everything else (including `assets/`, new top-level folders, root files) is copied
and overrides generated output where paths collide.

## Security
Every filesystem operation in `CustomFilesController` is confined to the project's
`custom/` directory via `safe()`, which rejects `..` traversal and any path that
resolves outside the base. Uploads preserve `webkitRelativePath` for folder drops.

## Routes
`GET /project/{slug}/custom-files` (SPA) plus JSON API: `tree`, `read`, `save`,
`mkdir`, `create`, `rename`, `delete`, `upload`.
