Skip to content

perf(images): optimize private signed previews through next/image (#014)#1071

Merged
BigSimmo merged 15 commits into
mainfrom
claude/site-audit-quick-wins-21v9gb
Jul 22, 2026
Merged

perf(images): optimize private signed previews through next/image (#014)#1071
BigSimmo merged 15 commits into
mainfrom
claude/site-audit-quick-wins-21v9gb

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Realizes ledger item #14. SignedImage (the shared renderer behind DocumentImage and SourceImage) loaded the full-resolution Supabase scan through a raw <img> just to fill a small 4:3 thumbnail. This routes it through next/image, so the optimizer resizes to preview dimensions and transcodes to AVIF/WebP — cashing in the images config #1024 added, which was inert until now.

  • fill + sizes="(max-width: 768px) 92vw, 320px" matches the fixed-aspect frame and caps the srcset to preview widths (no full-width variant fetched).
  • Deferred IntersectionObserver load, fade-in on decode, and retry-on-error are all preserved. The zoom lightbox keeps its own raw <img> for full-resolution pan/zoom — intentionally not optimized.
  • The signed ?token= query is optimizable because next.config images.remotePatterns pins the exact project host without a search restriction; a non-allow-listed host is rejected with 400.

Measured (demo preview, running app): 79,558 B PNG → 9,966 B AVIF (~87% smaller) / 12,766 B WebP. Full-resolution clinical scans stand to save more in absolute terms, especially in multi-image evidence galleries.

RAG impact: no retrieval behaviour change — this is image-preview rendering only; no retrieval/ranking/selection/eval or answer-generation code touched.

Verification

  • npm run typecheck — clean
  • npm run lint — clean (raw-<img> eslint-disable removed; the rule is now satisfied by next/image)
  • npm run test (focused) — tests/signed-image.test.ts + tests/signed-image.dom.test.tsx 5/5 pass (deferred load, cache-seeded paint, retry→recover, lightbox open/close); updated the two exact-src assertions to the next/image-optimized src (/_next/image?url=…).
  • Functional optimizer proof against the running dev server (npm run ensure): GET /_next/image?url=%2Fdemo-documents%2Fclozapine-table.png&w=640&q=75200 image/avif 9,966 B (WebP 12,766 B); a non-allow-listed host → 400. No next/image warnings in dev-server.log.
  • UI verification not run (npm run verify:ui): the visual frame is unchanged (same 4:3 object-contain frame, fade-in), the swap is proven functionally above, and there is no focused evidence-image UI spec; CI runs the unit suite. The one path not exercisable in-sandbox is the optimizer fetching a real <ref>.supabase.co signed URL server-side (needs live Supabase) — see Risk.

Risk and rollout

  • Risk: Low. Rendering-only; degrades gracefully — if the optimizer cannot fetch/transcode a source (expired token, disallowed host, oversized/SVG source), onError drops to the existing retry/failure state rather than breaking. Demo images (same-origin) optimize locally and are exercised by CI.
  • Untested-in-sandbox path: the optimizer server-side-fetching a live Supabase signed URL. remotePatterns (host + /storage/v1/object/**, unrestricted search) permits it and the token rides in the URL (no header forwarding needed), but worth a post-merge glance in staging/prod that real previews transcode.
  • Rollback: revert the single commit (raw <img> restored).
  • Provider or production effects: None at deploy time. Runtime: the Image Optimization API fetches signed URLs server-side (see preflight).

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use — unchanged (no claim/citation logic touched)
  • No patient-identifiable document workflow was introduced or expanded — unchanged; same signed-URL access path, same /signed-url auth gate
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy) — unchanged
  • Service-role keys and private document access remain server-only — unchanged. Note for review: the Next image optimizer now fetches the private signed URL server-side and caches the optimized bytes app-side (minimumCacheTTL, 4h default) — a new at-rest location for optimized private-preview content. Access is not widened: the signed URL remains the bearer capability, obtained only through the auth-gated /signed-url endpoint. This is the behaviour perf(ui): content-first detail pages + loading & motion quick wins #1024's remotePatterns comment already scoped to "private document/image previews".
  • Demo/synthetic content remains clearly separated — demo previews are same-origin /demo-documents/* and optimize locally; unchanged
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative — unchanged
  • Deployment classification/TGA SaMD impact — no clinical decision-support behaviour changed (image-preview rendering only)

Notes


Generated by Claude Code

Summary by CodeRabbit

  • Improvements
    • Updated signed image previews to render using Next.js image handling for improved responsive sizing, while keeping signed previews unoptimized.
    • Preserved existing preview gating, loading/retry/error behavior, and zoom/lightbox behavior.
  • Configuration
    • Refreshed guidance on private signed image cache TTL expectations to avoid confusion about serving cached bytes after authorization expiry, and clarified that optimization is intentionally scoped.
  • Tests
    • Strengthened signed-image tests to confirm cached/seeded previews keep direct unoptimized image URLs and do not route through the Next.js optimizer path.

SignedImage backed DocumentImage + SourceImage with a raw <img> that
loaded the full-resolution Supabase scan just to fill a small 4:3
thumbnail. Route it through next/image so the optimizer resizes to
preview dimensions and transcodes to AVIF/WebP, realizing the images
config #1024 added (which was inert until now).

- fill + sizes="(max-width: 768px) 92vw, 320px" matches the fixed-aspect
  frame and caps the srcset to preview widths.
- Deferred IntersectionObserver load, fade-in on decode, and
  retry-on-error are all preserved; the lightbox keeps its own raw <img>
  for full-resolution zoom.
- The signed ?token= query is optimizable because next.config
  images.remotePatterns pins the project host without a search
  restriction; a non-allow-listed host is rejected (400).

Measured on a demo preview: 79,558 B PNG -> 9,966 B AVIF (~87% smaller);
full-resolution clinical scans stand to save more.

Governance: the optimizer fetches the signed URL server-side and caches
the optimized bytes app-side (minimumCacheTTL); documented in the PR
clinical-governance preflight. No auth/access-control change — the
signed URL remains the capability and the client still obtains it
through the auth-gated /signed-url endpoint.

Updated the two signed-image tests to assert the next/image-optimized
src (/_next/image?url=…) instead of a raw src.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbhUVWVJRwDibC2YtJ6aRX
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

SignedImage now renders loaded signed previews with unoptimized next/image, using fill-based sizing and a sizes hint. Tests verify direct signed URLs remain unchanged, while configuration comments document signed-preview cache behavior.

Changes

SignedImage rendering

Layer / File(s) Summary
Next image preview integration
src/components/clinical-dashboard/signed-image.tsx, tests/signed-image.dom.test.tsx, tests/signed-image.test.ts
Loaded previews use next/image with fill, sizes, and unoptimized; existing load and error handlers remain connected. Retry and cache-seeding tests assert direct URLs without the /_next/image rewrite.
Signed preview cache documentation
next.config.ts
Comments document why signed previews opt out of optimization, how minimumCacheTTL relates to private signed URLs, and why wildcard storage hostnames are avoided.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: codex

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: switching private signed image previews to next/image.
Description check ✅ Passed The PR description matches the template well, with Summary, Verification, Risk and rollout, Clinical Governance Preflight, and Notes all present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/site-audit-quick-wins-21v9gb

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Jul 22, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review July 22, 2026 06:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bac7df072b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/signed-image.tsx
@BigSimmo

Copy link
Copy Markdown
Owner Author

@codex resolve actionable Codex review findings for this pull request and current head using the repository instructions. This is the pull request's single automatic repair pass: do not perform a fresh review, create new standalone findings, or request another review. Work only the existing unresolved Codex threads on the current head. Always fix P0 and P1 findings. For P2 and lower findings, fix only clear, scoped, low-risk issues; otherwise disposition them with a concise reason. After fixing or dispositioning a thread, reply in that thread with as the first line, followed by a concise summary; that marker authorizes the workflow to close that exact thread. If human input or new authorization is required, do not use the marker and leave the thread open with the blocker. Finish only after every actionable thread is fixed or dispositioned and closed, or explicitly left open for a human decision. Do not update the branch from main, address unrelated reviews, broaden scope, or create more than one scoped fix commit. Do not use external APIs, paid services, credentials, dependency changes, or broad refactors unless explicitly authorized. Add targeted tests where behavior changes and run the narrowest relevant validation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/clinical-dashboard/signed-image.tsx`:
- Around line 131-148: Update the private preview handling in the signed-image
component around the next/image Image element to prevent optimized bytes from
outliving the signed URL: either disable optimization for bearer-backed URLs or
configure the optimizer cache TTL below the signed-URL lifetime. Preserve the
existing preview sizing and loading behavior.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dd8a460-38c7-46b2-89b9-0cdcd8faa691

📥 Commits

Reviewing files that changed from the base of the PR and between ee0c018 and bac7df0.

📒 Files selected for processing (3)
  • src/components/clinical-dashboard/signed-image.tsx
  • tests/signed-image.dom.test.tsx
  • tests/signed-image.test.ts

Comment thread src/components/clinical-dashboard/signed-image.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bac7df072b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/signed-image.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 38aef19bd6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/signed-image.tsx
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 1 unresolved review comment.

Files modified:

  • next.config.ts

Commit: 1cd3cf74f43efda9872af3524ae149be48adf936

The changes have been pushed to the claude/site-audit-quick-wins-21v9gb branch.

Time taken: 4m 26s

@BigSimmo
BigSimmo enabled auto-merge (squash) July 22, 2026 06:39
coderabbitai Bot and others added 2 commits July 22, 2026 06:45
Fixed 1 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@next.config.ts`:
- Around line 55-58: The next.config.ts image optimizer configuration must not
use minimumCacheTTL as a signed-URL expiry boundary. Update the SignedImage
preview flow and its related image configuration so optimized private previews
are auth-aware/non-caching, or ensure their cache lifetime is explicitly bounded
by the signed URL’s remaining lifetime rather than relying on minimumCacheTTL.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 528f7b22-478f-4fed-a9b3-9cfea1e4041f

📥 Commits

Reviewing files that changed from the base of the PR and between bac7df0 and 28f8570.

📒 Files selected for processing (1)
  • next.config.ts

Comment thread next.config.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28f8570ce7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread next.config.ts Outdated
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 1 unresolved review comment.

Files modified:

  • next.config.ts
  • src/components/clinical-dashboard/signed-image.tsx

Commit: 41c9e2b00956102fc9f03d5c4986b838cb45131a

The changes have been pushed to the claude/site-audit-quick-wins-21v9gb branch.

Time taken: 10m 21s

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ebadcc7cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread next.config.ts Outdated
coderabbitai Bot and others added 2 commits July 22, 2026 07:51
Fixed 2 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Unit coverageneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #4469 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@BigSimmo

Copy link
Copy Markdown
Owner Author

@codex please resolve and fix the merge conflict and commit and push jt to this branch and PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Resolved the private-preview optimizer cache issue by returning SignedImage private bearer-backed previews to the raw <img> path, preserving load/error handling, fade-in, fixed frame sizing, and lightbox behavior while avoiding /_next/image cache exposure.
  • Removed the PR’s Supabase signed-preview optimizer allowance and minimumCacheTTL dependency, leaving only safe shared next/image output format preferences in next.config.ts.
  • Updated signed-image SSR/cache-seeding coverage to assert direct private preview URLs and reject /_next/image rewrites.
  • Updated signed-image retry/recovery DOM coverage to assert the recovered preview remains a direct image source.
  • Committed the scoped fix on the current branch: 403ca43 fix(images): keep private previews off optimizer cache.
  • Created PR metadata with make_pr: fix(images): resolve preview optimizer cache conflict.
  • Push note: this checkout has no configured Git remote/upstream, so there was no safe remote target to push to from this environment.

Testing

  • git diff --check
  • source /root/.nvm/nvm.sh && nvm use 24.15.0 >/dev/null && npm ci
  • source /root/.nvm/nvm.sh && nvm use 24.15.0 >/dev/null && npm run test -- tests/signed-image.test.ts tests/signed-image.dom.test.tsx
  • source /root/.nvm/nvm.sh && nvm use 24.15.0 >/dev/null && npm run typecheck
  • source /root/.nvm/nvm.sh && nvm use 24.15.0 >/dev/null && npm run lint

View task →

BigSimmo and others added 2 commits July 22, 2026 16:48
Drop minimumCacheTTL as a false expiry cap and mark SignedImage
unoptimized so bearer URLs never enter the unauthenticated /_next/image
cache. Update tests to assert direct src values.

Co-authored-by: Cursor <cursoragent@cursor.com>
@BigSimmo
BigSimmo disabled auto-merge July 22, 2026 08:54
@BigSimmo
BigSimmo enabled auto-merge (squash) July 22, 2026 09:10
Co-authored-by: Cursor <cursoragent@cursor.com>
@BigSimmo
BigSimmo disabled auto-merge July 22, 2026 09:19
@BigSimmo
BigSimmo enabled auto-merge (squash) July 22, 2026 09:21
@BigSimmo
BigSimmo merged commit 8dad90b into main Jul 22, 2026
19 checks passed
@BigSimmo
BigSimmo deleted the claude/site-audit-quick-wins-21v9gb branch July 22, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants