Skip to content
This repository was archived by the owner on Aug 11, 2026. It is now read-only.
This repository was archived by the owner on Aug 11, 2026. It is now read-only.

feat(blog-content): require R2 media references for news images in full-online mode #636

Description

@ahliweb

Depends on: #631, #632, #633, #634, #635

Context

blog_content already supports posts, pages, gallery/media-style content blocks, SEO metadata, public /news routes, widgets, and ads. In full-online R2-only news portal mode, every news image reference must resolve to a verified Cloudflare R2 media object instead of a local path or arbitrary external URL.

Objective

Require R2 media object references for featured images, gallery blocks, SEO images, and related blog/news image surfaces when full-online R2-only mode is enabled.

Scope

Apply R2-only validation to:

featured_image
content_json gallery/image blocks
post/page SEO og:image and twitter:image
homepage section image references
widget image references when used by news portal
ads image references when used by news portal

Allowed reference shape:

{
  "mediaObjectId": "uuid",
  "alt": "Descriptive alt text",
  "caption": "Optional caption"
}

Rejected shapes in full-online R2-only mode:

{ "url": "/uploads/news/image.jpg" }
{ "url": "https://external.example/image.jpg" }

Behavior requirements

  • Referenced media object must exist.
  • Referenced media object must belong to the same tenant.
  • Referenced media object must have storage_driver = 'cloudflare_r2'.
  • Referenced media object must be verified or otherwise safe according to the registry status model.
  • Public renderer must generate image URLs from trusted R2 metadata only.
  • Public renderer must not output local paths such as /uploads, /public, /assets/user-content, or Docker volume paths.
  • Public renderer must not output arbitrary external image URLs for news images.

Out of scope

  • Creating upload sessions.
  • Image transformation/CDN resizing.
  • Importing legacy media.
  • Offline/LAN behavior.

Acceptance criteria

  • Post create/update rejects featured image local paths in full-online R2-only mode.
  • Post create/update rejects arbitrary external image URLs in full-online R2-only mode.
  • Gallery/image content blocks require mediaObjectId in full-online R2-only mode.
  • SEO image rendering uses verified R2 media metadata only.
  • Cross-tenant media object references are rejected.
  • Unverified/failed/deleted media objects cannot be attached as public news images.
  • Public /news routes never render local upload paths for news images.
  • Admin UI shows a clear error when an image is not verified in R2.
  • Tests cover post create/update, gallery block validation, SEO image rendering, cross-tenant rejection, deleted media rejection, and unsafe URL rejection.
  • OpenAPI schemas are updated where image reference payloads change.
  • bun run api:spec:check passes.
  • bun run test passes.
  • bun run build passes.
  • bun run check passes.

Security notes

  • Do not downgrade this to a warning in production.
  • Never allow raw HTML image tags from content to bypass the R2 media object policy.
  • Keep validation server-side; UI validation is supplementary only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions