Skip to content

feat(admin): refresh nursing review UX and annotation reliability - #46

Merged
ruby0322 merged 10 commits into
mainfrom
feat/review-modal-annotation-ux
Aug 9, 2026
Merged

feat(admin): refresh nursing review UX and annotation reliability#46
ruby0322 merged 10 commits into
mainfrom
feat/review-modal-annotation-ux

Conversation

@ruby0322

@ruby0322 ruby0322 commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • refresh dashboard/history annotation modal with consistent nursing labels, badges, and clearer unannotated states
  • move annotated status badge to patient cards and align modal status displays with shared mapping
  • add backend migration to repair legacy local annotations schema causing annotation save 500 errors

Test plan

  • npm --prefix apps/frontend run lint
  • npm run check:migrations
  • Save annotation in local dev and confirm API no longer returns 500

ruby0322 and others added 2 commits August 9, 2026 15:02
Rework dashboard/history annotation surfaces to use a clinical-first layout, consistent shared label/badge mappings, and clearer unannotated state handling so nursing review decisions are faster and less ambiguous.

Co-authored-by: Cursor <cursoragent@cursor.com>
Repair local SQLite installations where annotations still require staff_user_id so staff annotation saves no longer fail with 500 after moving to reviewer_identity_id.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor 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.

Summary

Solid nursing-workflow refresh: centralized 繁中 label mapping (staff-review-label-mapping.ts), clearer annotation modal sections (symptom chips, badge styling, explicit label selection), and a guarded legacy migration for SQLite snapshots that still carry staff_user_id.

Blocking — CI frontend unit tests (2 failures)

Frontend unit tests fails locally with the same two suites:

  1. history-overview/__tests__/page.test.tsxopens upload detail modal from grouped thumbnails… still expects 開啟病患完整頁, but the annotation modal no longer renders that link after the UX refresh.
  2. review-fast/__tests__/page.test.tsxshows only positive symptoms in modal still asserts 影像判讀 / 症狀綜合, but the modal now uses STAFF_REVIEW_FIELD_LABELS (AI 判讀結果, 症狀綜合判定).

Please update those tests (or restore the removed link if it was unintentional).

Nits (non-blocking)

  • suggestedHistoryUploadLabel in history-upload-review-helpers.ts is now unused after drafts default to existing annotation or "" — consider removing or reusing for first-open suggestions.
  • Migration creates reviewer_identity_id nullable while the SQLAlchemy model is non-nullable; fallback to an arbitrary staff identity for NULL legacy rows is a mild audit-trail concern.
  • Minor copy inconsistency: annotation rejected上傳不採用 vs screening rejected影像不採用; fast-review modal still shows 無症狀 while the shared copy uses 未回報症狀.

CI snapshot

Check Status
Lint and migration policy pass
Backend tests pass
Frontend build pass
K8s manifest render pass
Frontend unit tests fail (above)

Happy to re-review once the unit tests are aligned.

Open in Web View Automation 

Sent by Cursor Automation: PD Care PR Reviewer

sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("patient_id", sa.Integer(), sa.ForeignKey("patients.id", ondelete="CASCADE"), nullable=False),
sa.Column("upload_id", sa.Integer(), sa.ForeignKey("uploads.id", ondelete="CASCADE"), nullable=False),
sa.Column("reviewer_identity_id", sa.Integer(), sa.ForeignKey("liff_identities.id", ondelete="CASCADE"), nullable=True),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This column is nullable=True in the rebuilt table, but Annotation.reviewer_identity_id in models.py is nullable=False. If any legacy rows still have NULL reviewer_identity_id after the COALESCE backfill (e.g. no identities exist yet), inserts succeed but the ORM write path will still require a reviewer on new annotations.

Consider matching the model (nullable=False) once backfill is guaranteed, or documenting that NULL legacy rows are acceptable read-only artifacts.


return (
<div className="fixed inset-0 z-[60] flex items-end justify-center bg-zinc-900/60 p-0 sm:items-center sm:p-4">
<div className="h-[90vh] w-full overflow-auto rounded-t-2xl bg-white shadow-xl sm:h-auto sm:max-w-3xl sm:rounded-2xl">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removing the 開啟病患完整頁 link from this modal breaks history-overview/__tests__/page.test.tsx (opens upload detail modal from grouped thumbnails…). If the link removal is intentional UX, please update that test; otherwise consider keeping a patient-detail link in the modal header.

<div className="flex flex-col gap-2 text-xs text-zinc-500">
<div className="flex items-center justify-between gap-2">
<span>影像判讀</span>
<span>{STAFF_REVIEW_FIELD_LABELS.aiResult}</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

review-fast/__tests__/page.test.tsx still asserts the old labels 影像判讀 / 症狀綜合. With STAFF_REVIEW_FIELD_LABELS, the modal now shows AI 判讀結果 / 症狀綜合判定 — update the test expectations to match the new copy.

normal: "正常",
suspected: "疑似感染",
confirmed_infection: "確認感染",
rejected: "上傳不採用",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: annotation rejected is 上傳不採用 here, but screeningResultText('rejected') returns 影像不採用. Nurses may see different wording for the same verdict depending on context — worth aligning if intentional.

return screeningResultText(upload.screening_result);
}

export function suggestedHistoryUploadLabel(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestedHistoryUploadLabel looks unused now that drafts initialize from annotation_label ?? "" instead of an AI suggestion. Safe cleanup candidate unless you plan to restore auto-suggest on first open.

ruby0322 and others added 7 commits August 9, 2026 15:09
Expose the latest annotation label in today-attention API responses and render the actual nursing verdict badge beside patient names so staff see actionable status at a glance. Update impacted unit tests to match the revised review modal copy and structure.

Co-authored-by: Cursor <cursoragent@cursor.com>
Establish a contract-first workflow for browser feature demos and add a deterministic Playwright setup for local persona-based scenarios. Separate unit and e2e lanes so CI unit runs stay stable while keeping recorded demo artifacts local-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
Document and ship a systemd-driven recovery path that brings minikube, ingress bridge, and dependent workloads back in order after host reboot incidents. This reduces manual recovery steps and gives operators a repeatable health-gated startup sequence.

Co-authored-by: Cursor <cursoragent@cursor.com>
Require migrated annotations to retain a valid reviewer identity instead of assigning an arbitrary account. This keeps the schema aligned with the non-null model contract and prevents audit attribution from being fabricated.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use one nursing-facing vocabulary for rejected images and absent symptom reports, while removing an obsolete suggested-verdict helper that no longer matches review draft behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
Show every patient card's manual annotation status prominently and separate clinical risk badges from AI confidence. Keep symptom detail out of elevated-risk list cards so the dashboard remains scannable while preserving it in the selected patient preview and review flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the obsolete isTodaySelected prop from TodayPatientPool now that the detail panel no longer accepts it. This unblocks production builds by keeping the pool and panel interfaces aligned.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ruby0322

ruby0322 commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@cursoragent review again

@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

Re-review summary

I re-checked PR #46 against the earlier review comments. The follow-up commits on feat/review-modal-annotation-ux already address every flagged item. CI is green (lint, backend tests, frontend unit tests, build, K8s render).

Prior findings — resolved

Issue Status
Migration reviewer_identity_id nullable mismatch Fixed in 4723b26 — rebuilt column is nullable=False, with a pre-migration guard that fails if rows cannot be backfilled from staff_user_id
history-overview test broken by removed patient link Fixed — test renamed/updated to opens upload detail modal from grouped thumbnails without patient header navigation
review-fast tests using old labels Fixed — expects AI 判讀結果 / 症狀綜合判定
rejected wording split (上傳不採用 vs 影像不採用) Fixed in 1916023 — unified to 影像不採用 via STAFF_ANNOTATION_LABEL_TEXT and screeningResultText
Unused suggestedHistoryUploadLabel Removed in 1916023

Verification run locally

  • npm run lint — pass
  • Frontend unit tests (review-fast, history-overview, today-patient-row) — 19/19 pass

Remaining nit (non-blocking)

TodayPatientDetailPanel still shows workflow copy 已註解 / 未處理 for risk-tier patients in the subtitle, while patient cards use the shared 未標註 badge. That looks intentional: cards show annotation state; the detail panel subtitle still signals review workflow for high-risk patients. Worth aligning later if nurses find it confusing, but it is not a regression from this PR.

Verdict

Approve from a code-review standpoint. The nursing label mapping is centralized in staff-review-label-mapping.ts, the legacy annotation migration is safe and model-aligned, tests match the new UX, and CI is fully green.

No additional code changes were needed on this pass.

Open in Web Open in Cursor 

Use the shared 已標註 and 未標註 labels for every patient tier in the detail subtitle. This prevents high-risk patients from showing a conflicting review-workflow status beside the annotation badge.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ruby0322
ruby0322 merged commit 2499548 into main Aug 9, 2026
5 checks passed
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.

1 participant