Files

142 lines
7.0 KiB
Markdown

# 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 `img` element MUST expose `srcset` with the available variants
- **AND** MUST expose a `sizes` attribute 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 `img` element MUST carry `loading="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 return `r2`
#### Scenario: Legacy S3 default still supported
- **WHEN** `FILESYSTEM_DISK=s3`
- **THEN** `PublicImageUploadRules::disk()` MUST return `s3`
#### Scenario: Local development uses public disk
- **WHEN** `FILESYSTEM_DISK` is `local`, unset, or any value other than `r2`/`s3`
- **THEN** `PublicImageUploadRules::disk()` MUST return `public`
### 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_path` and `logo_alt` in 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. Editorial layouts MUST use CSS-only tonal treatment and alternating aspect ratios for portfolio media while retaining document order and the image component's `srcset`, `sizes`, dimensions and loading behavior. The system 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
#### Scenario: Editorial portfolio media retains responsive delivery
- **WHEN** a portfolio listing or gallery applies an editorial image proportion
- **THEN** the rendered image MUST still expose the responsive media component markup
- **AND** image order and lazy-loading behavior MUST remain intact