Skip to Content
Internal docs are powered by Nextra Docs Theme.
SystemsPlatformAPI2Rails to API2 migrationPackagesNative public media routes

Native public media routes

API2 natively serves the unauthenticated Rails compatibility routes /rails/active_storage/blobs/redirect/:signed_id/*filename and /conversation_images/:signed_id for both GET and HEAD. Valid Rails Active Storage signed IDs are looked up in active_storage_blobs; only the cloudflare service is served natively.

Contract

Redirect requests return a short-lived, path-style R2 presigned URL with Rails content-disposition and content-type overrides. The URL tail is not used as the filename. Conversation images stream the R2 object without buffering and derive their MIME type from the sanitized filename extension. HEAD performs only a HeadObject request.

Deviations

  • Missing R2 objects return an empty 404 rather than Rails’ storage error.
  • Conversation image responses intentionally omit ETag: generating Rails’ Rack ETag would require hashing the complete body, which would defeat streaming.
  • Filename transliteration is a JavaScript approximation of I18n.transliterate (NFKD, combining-mark removal, and ? replacement).
  • Presigned URLs use the R2 path-style host; this is expected for the S3 compatible endpoint.

Rollback

Flipper’s pause_api2_public_media_routes is a regional kill switch with safe state off. When enabled, API2 forwards to the legacy Rails origin if the fallback is enabled; otherwise it returns 404. Blobs using an unsupported service follow the same fallback path. Flipper lookup failures continue natively and emit a flipper_error telemetry outcome.

Production rollout plan

  1. Deploy with pause_api2_public_media_routes off in both regions.
  2. In each region (US and EU), fetch a known-good redirect URL and a conversation_images URL with both curl -sI and curl -s -o /dev/null -w '%{http_code}'. Expect the redirect to return 302, a Location on the R2 host, and Cache-Control: max-age=300, private. Expect the conversation image to return 200, Content-Disposition: inline, and Content-Length for both GET and HEAD. Also request a tampered signed ID and expect 404.
  3. Watch native_public_media logs per region for outcome distribution (served/redirected versus 404s and 5xx responses), comparing against the baseline of approximately 2,340 redirect and 832 conversation_images events per nine hours. Confirm the legacy_rails_gateway log for these paths drops to zero.
  4. Roll back immediately in an affected region by enabling pause_api2_public_media_routes; requests fall back to Rails while LEGACY_RAILS_FALLBACK_ENABLED is true. A code rollback reverts the PR.

Local checks

cd rulebase-web/rulebase-api2 pnpm vitest run src/routes/public-media src/lib/rails-active-storage-serving src/lib/rails-signed-id src/lib/legacy-rails-gateway pnpm typecheck
Last updated on