Status: Draft
Updated: 2026-05-24
Owner: Core
Purpose: Draft for uploaded files, media library workflows, storage integration, and media usage inside structured content.
- Defines how the CMS stores, indexes, previews, selects, and protects uploaded media and files.
- Covers media fields, file metadata, storage adapters, thumbnails/previews, usage tracking, ACL, and cleanup behavior.
- Depends on content model, security/ACL, system UI, schema fields, and backup/restore storage decisions.
- Makes the CMS practical for real websites where images, downloads, and embedded media are everyday content.
A CMS without media management is not fully usable for project websites. The first media library should provide safe upload, browse, preview, select, replace, and delete workflows. It should integrate with schema media-reference fields and public rendering without hard-coding storage details into content values.
Media should be treated as managed content-adjacent assets. Files need durable identifiers, metadata, storage paths, visibility rules, usage information, and cleanup behavior. Public URLs should be generated through controlled services so storage can change later.
Uploaded media and managed files should not live directly below public/. They should be stored behind a media/file abstraction and delivered through controlled services, for example a controller, resolver, or signed URL strategy. This keeps ACL decisions enforceable for private files and avoids mixing public build assets with protected project files.
The first implementation should stay conservative: local/Flysystem-backed storage, validation, safe filenames, metadata, previews for common image types, and usage checks before deletion. Advanced image transformations, CDN integration, DAM workflows, and external media providers can come later through adapters.
Media records should not be limited to uploaded local files. A later file resolver should also support external source URLs while exposing only the CMS-managed media route to editors, templates, and visitors. This lets installations use CDN-backed objects, remote file servers, WebDAV-like sources, or other controlled upstreams without leaking the physical source URL in public markup.
- Use Flysystem-backed storage boundaries for uploaded media.
- Store managed files outside the public web root, for example below an application-controlled
/filesstorage abstraction rather than physicalpublic/paths. - Store durable media identifiers separate from physical storage paths.
- Store metadata such as original filename, MIME type, size, extension, dimensions where available, alt text, caption, credit, created/modified audit metadata, visibility, and ACL restrictions.
- Allow per-file ACL restrictions so individual files can be limited to specific ACL groups where needed.
- Support optional per-project or global storage quotas with warning and hard-limit behavior once project/account scopes exist.
- Validate upload size, MIME type, extension, and image dimensions where applicable.
- Keep a pluggable virus/malware scan hook available; when unconfigured, scans are safely skipped and uploads still pass normal validation.
- Normalize filenames and never trust user-provided filenames for storage paths.
- Provide media library admin UI for upload, list/grid view, search/filter, preview, metadata edit, select, replace, archive/delete, and usage inspection.
- Integrate with schema media-reference fields.
- Track usage from content fields, schema Twig, themes, and module contributions where practical.
- Prevent destructive deletion when media is still used unless explicitly confirmed with impact information.
- Generate public URLs through a media URL resolver.
- Keep public and private media delivery behind a media/file delivery service rather than exposing raw storage paths.
- Keep private/ACL-restricted media protected by controller, resolver, or signed URL strategy when needed.
- Allow managed media records to reference external source URLs in addition to locally uploaded storage objects.
- Resolve external media sources through the same controlled media/file delivery service so public consumers see a stable CMS URL, not the upstream URL.
- Support optional upstream HTTP authentication metadata for edge cases such as protected WebDAV or private HTTP sources; credentials must be stored as sensitive configuration/metadata and never exposed through logs, rendered markup, exports, or unprivileged APIs.
- Treat external media delivery as a proxy/streaming resolver, not as a blind open relay. It must validate schemes, hosts, redirects, response size, MIME type, and timeout limits to avoid SSRF, credential leakage, cache poisoning, or uncontrolled bandwidth usage.
- Allow resolver implementations to redirect to trusted signed/CDN URLs where safe, or stream/proxy the upstream response when source hiding, ACL checks, or HTTP authentication requires it.
- Include media files in backup/restore scope.
- Keep image processing optional and adapter-based.
- Test upload validation for allowed and rejected files.
- Test metadata persistence and safe filename/path generation.
- Test media-reference field selection and rendering.
- Test ACL/private media access.
- Test managed files are not directly served from
public/storage paths. - Test per-file ACL restrictions before delivery.
- Test external media source validation rejects unsafe schemes, private/internal hosts where disallowed, redirect abuse, and oversized or mismatched responses.
- Test external media delivery does not expose source URLs or upstream HTTP authentication data in public output, logs, exports, or error messages.
- Test usage tracking before delete/archive.
- Test backup/restore includes media files and metadata.
- Test media admin UI render and validation behavior once routes exist.
- Decision recorded: Media needs its own managed library and durable identifiers; schema fields should reference media records, not raw paths.
- Decision recorded: Start with local/Flysystem-backed storage and keep URL generation behind a resolver.
- Decision recorded: Managed media/files are delivered through an abstraction and should not physically live under
public/; per-file ACL restrictions should be possible. - Decision recorded: Managed media may later use external source URLs as resolver-backed placeholders. The CMS-facing URL remains stable and controlled, while the resolver can either stream/proxy the upstream file or redirect to a trusted signed/CDN URL depending on ACL, authentication, and source-hiding requirements.
- Decision recorded: External media source authentication is allowed only as sensitive metadata/configuration for resolver use. Upstream credentials must never be exposed to public output, normal logs, exports, or unprivileged APIs.
- Decision recorded: Deletion should be usage-aware and recoverable where practical.
- Open: Decide first allowed MIME types, max upload size, thumbnail strategy, exact private-media delivery strategy, and external-source allowlist policy before implementation. Start with generic conservative defaults and adjust later.
- Open: Decide whether quotas and scanner hooks ship in the first media slice or remain operator-focused follow-ups.