- cja_media table; POST /api/media/upload (admin-gated, multipart).
- Images optimised with GD (downscale to 1600px, re-encode; WebP for
transparency, JPG for photos). Video via ffmpeg (scale, compress, drop audio).
- Stored in app/public/media/ (source tree) so uploads survive rebuilds and are
copied into public/ on build.
- requireAdmin() moved to PublicController base (fixes a static/non-static
clash with AdminAuth). Type detection uses getimagesize (fileinfo ext absent).
Note: php-fpm must be in the caweb group to write app/public/media (restart
after adding www to caweb).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DoFYZY9gkGPNDqZ7NuEa9a