feat: ship public site with SEO and visuals (#3)
* feat: ship public site with SEO and visuals Publish CMS content on public routes with responsive media, accessibility checks, and deterministic visual baselines. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: make browser visual CI deterministic for media Mount host public storage into FrankenPHP so seeded fixtures are served, and replace PNG-as-JPG fixtures with real JPEGs so Chromium can render them. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: serve public media on same-origin storage paths Pest Browser hosts on 127.0.0.1:port while Storage::url used http://localhost, so screenshots captured broken images. Use relative /storage URLs for media and absolutize only OG tags via url(). Co-authored-by: Cursor <cursoragent@cursor.com> * test: refresh visual baselines from CI Ubuntu screenshots Media now loads on same-origin /storage paths, so baselines must capture the rendered fixtures. Use full-page snapshots from the CI runner to keep Pest's exact snapshot match stable across environments. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### 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
|
||||
Reference in New Issue
Block a user