6.6 KiB
content-media Specification
Purpose
Define validation, storage, responsive variants, disk selection, and accessibility requirements for public content images.
Requirements
Requirement: Public content images are validated and stored securely
The system SHALL validate public content uploads (service covers, portfolio covers/gallery, testimonial photos, site OG image) per SPEC §6.4 and §12.4. Validation MUST enforce MIME allowlist (jpeg, png, webp), matching extensions, maximum size of 10 MB, and mandatory alt text when an image is uploaded.
Scenario: Invalid MIME is rejected
- WHEN an admin uploads a file with disallowed MIME type
- THEN validation MUST fail with a pt-BR error message
Scenario: Oversized file is rejected
- WHEN an admin uploads an image exceeding 10 MB
- THEN validation MUST fail
Scenario: Storage path is not derived from original filename
- WHEN an image is stored
- THEN the physical path MUST be generated (UUID/hash based)
- AND MUST NOT use the original upload filename as the storage key
Scenario: Alt text required with image
- WHEN an admin uploads a cover or gallery image without alt text
- THEN validation MUST fail
Scenario: Images are not stored in PostgreSQL
- WHEN content with images is persisted
- THEN only the filesystem path MUST be stored in the database
- AND binary image data MUST NOT be written to PostgreSQL columns
Requirement: Public images are served in responsive variants
The system SHALL generate or serve responsive variants for public content images (service covers, portfolio covers and gallery, testimonial photos) and reference them with srcset and sizes so browsers download an appropriately sized file (SPEC §6.4). Variant generation MUST happen on upload, not on each request.
Scenario: Variants are produced on upload
- WHEN an admin uploads a public content image
- THEN responsive variants MUST be generated and stored alongside the original
- AND the database MUST keep only paths, never binary data
Scenario: Public markup offers multiple sources
- WHEN a public page renders a content image
- THEN the
imgelement MUST exposesrcsetwith the available variants - AND MUST expose a
sizesattribute matching the layout
Scenario: Missing variant falls back to the original
- GIVEN an image stored before variant generation existed
- WHEN it is rendered on a public page
- THEN the original file MUST be used without breaking the page
Requirement: Public images avoid layout shift and defer offscreen loading
Public content images SHALL reserve their space through explicit width and height (or equivalent aspect-ratio styling) and MUST use loading="lazy" when rendered below the fold. Above-the-fold hero imagery MUST NOT be lazy loaded (SPEC §6.4, §6.6).
Scenario: Offscreen image is lazy loaded
- WHEN a page renders an image below the first viewport
- THEN the
imgelement MUST carryloading="lazy"
Scenario: Hero image loads eagerly
- WHEN the home hero image is rendered
- THEN it MUST NOT carry
loading="lazy"
Scenario: Dimensions are reserved
- WHEN any public content image is rendered
- THEN width and height (or aspect ratio) MUST be declared so layout does not shift after load
Requirement: Production images are not served from ephemeral container disk
Public image variants SHALL be stored on the configured filesystem disk (S3-compatible in production) and referenced by URL, so a container restart or redeploy does not lose media (SPEC §6.4).
Scenario: Media survives container replacement
- GIVEN production uses the S3-compatible disk
- WHEN the application container is replaced
- THEN previously uploaded images and variants MUST remain reachable
Requirement: CMS public image uploads select production object storage disk
Public content image uploads (Filament FileUpload via PublicImageUploadRules) MUST store files on the disk matching the configured default filesystem (SPEC §6.4). When FILESYSTEM_DISK is r2, uploads MUST use the r2 disk. When FILESYSTEM_DISK is s3, uploads MUST use the s3 disk. Otherwise uploads MUST use the local public disk.
Scenario: Production R2 disk is used for CMS uploads
- WHEN
FILESYSTEM_DISK=r2 - THEN
PublicImageUploadRules::disk()MUST returnr2
Scenario: Legacy S3 default still supported
- WHEN
FILESYSTEM_DISK=s3 - THEN
PublicImageUploadRules::disk()MUST returns3
Scenario: Local development uses public disk
- WHEN
FILESYSTEM_DISKislocal, unset, or any value other thanr2/s3 - THEN
PublicImageUploadRules::disk()MUST returnpublic
Requirement: Brand logo assets are available to the public layout
The system SHALL provide optimized Amare brand logo assets derived from the official faceted-heart lockup for use in the public header, footer and institutional pages. Assets MUST preserve the original geometry, include an accessible text alternative, and provide variants suitable for light and dark tonal fields. When site_settings.logo_path is present, the uploaded logo MUST be used; otherwise the versioned static brand asset MUST be used.
Scenario: Header renders brand mark with alt text
- WHEN any public page is rendered
- THEN the brand mark image or equivalent MUST expose accessible alternative text identifying Amare Assessoria
Scenario: Dark portfolio field uses a legible logo variant
- WHEN the brand mark is rendered on an olive-deep or otherwise dark public surface
- THEN the chosen logo variant MUST remain legible against that background
Scenario: Uploaded logo overrides static fallback
- GIVEN an admin has saved
logo_pathandlogo_altin site settings - WHEN the public layout renders the brand mark
- THEN the uploaded logo MUST be used instead of the static fallback
Requirement: Editorial image treatment remains self-hosted and deterministic
Public photography SHALL continue to use validated self-hosted uploads and responsive variants. Decorative saturation/contrast treatment for editorial mood MUST be applied via CSS on self-hosted images and MUST NOT introduce external image CDN dependencies that compromise browser-test reliability.
Scenario: Public pages do not depend on external stock hosts
- WHEN the visual or browser suite loads covered public routes
- THEN content images MUST resolve from the application media disk or static fixtures
- AND MUST NOT require network access to third-party stock hosts