Skip to content

feat(admin): consolidate dashboard workbench API and align calendar counts - #45

Merged
ruby0322 merged 4 commits into
mainfrom
feat/dashboard-workbench-api
Aug 7, 2026
Merged

feat(admin): consolidate dashboard workbench API and align calendar counts#45
ruby0322 merged 4 commits into
mainfrom
feat/dashboard-workbench-api

Conversation

@ruby0322

@ruby0322 ruby0322 commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add shared workbench eligibility filters (active + non-rejected) so calendar metrics match patient pool
  • Replace dashboard days/calendar/today-attention calls with single GET /v1/staff/dashboard/workbench
  • Bound week/month aggregation in SQL; add batch image-access endpoint for thumbnails
  • Add regression tests for rejected/inactive mismatch and bundle alignment

Test plan

  • pytest tests/test_staff_workbench_api.py
  • pytest tests/test_attention_triage.py
  • pytest tests/test_staff_dashboard_api.py -k history_overview
  • Manual: dev dashboard 7/15 shows 0/0/0 when pool empty; 7/16–7/18 counts match pool
  • Manual: Network tab shows one workbench + one batch image call on load

…ounts

Unify workbench eligibility (active + non-rejected) across calendar metrics
and patient pool, replace 3–4 dashboard REST calls with one workbench
endpoint, bound week/month aggregation in SQL, and batch thumbnail
image-access to cut request volume.

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 follow-up to #44: shared workbench eligibility filters (active + non-rejected), a consolidated GET /v1/staff/dashboard/workbench, week-bounded SQL aggregation, and batch image-access for thumbnails. The direction is right — fewer round trips, calendar counts aligned with the patient pool, and good backend regression coverage.

What looks good

  • workbench_upload_where_clauses() centralizes the filter used by attention, history overview (scope=workbench), and available dates — fixes the rejected/inactive calendar mismatch.
  • Week metrics now come from a 7-day bounded query instead of loading full calendar months.
  • POST /v1/staff/uploads/image-access/batch + useUploadImageUrls batching addresses the thumbnail N+1 called out on #44 (for components using the hook).
  • test_staff_workbench_api.py covers the important alignment cases (rejected-only day, inactive patient, week metrics vs attention, batch partial errors).
  • get_history_overview_calendar_month month-range filter is a nice perf win for the history tab.

Blocking

Frontend unit tests fail in CI (history-overview/__tests__/page.test.tsx). The jest mock still stubs fetchUploadImageAccess, but useUploadImageUrls now calls fetchUploadImageAccessBatch — 7 tests throw fetchUploadImageAccessBatch is not a function. Update the mock to include fetchUploadImageAccessBatch (returning { items: [{ upload_id, image_url }] }).

Nits (non-blocking)

  1. list_workbench_dates loads every created_at into Python and dedupes in memory. Fine for now, but consider a SQL DISTINCT on Taipei-local date as upload volume grows.
  2. Unified workbench fetch refetches available_dates and week_days when only selectedDate changes within the same week (previously available dates were fetched once on mount). Minor extra load; could cache client-side or split stable fields later.
  3. upload-thumb.tsx still uses per-thumb fetchUploadImageAccess — out of scope here, but the N+1 remains for that component.
  4. _serialize_today_attention: rows param is untyped; could use Sequence[TodayAttentionPatientRow].

CI (at review time)

Check Status
Lint pass
Frontend build pass
K8s render pass
Frontend unit tests fail (mock above)
Backend tests pending

Static review only in this environment; backend tests not run locally.

Verdict: Request changes for the failing test mock; otherwise this is in good shape to merge once CI is green.

Open in Web View Automation 

Sent by Cursor Automation: PD Care PR Reviewer

)
if accessible_patient_ids is not None:
base_query = base_query.where(Patient.id.in_(accessible_patient_ids))
created_ats = session.execute(base_query).scalars().all()

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 pulls every workbench-eligible created_at into Python and dedupes dates in a set. Correct, but it scales with total upload count and runs on every workbench load (including date changes within the same week). Consider pushing distinct Taipei-local dates into SQL (e.g. func.date_trunc / timezone conversion) so the DB returns one row per day.

import { useEffect, useMemo, useState } from "react";

import { fetchUploadImageAccess } from "@/lib/api/staff";
import { fetchUploadImageAccessBatch } from "@/lib/api/staff";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Switching to batch fetch is the right call. Heads-up: history-overview/__tests__/page.test.tsx still mocks only fetchUploadImageAccess, so CI currently fails with fetchUploadImageAccessBatch is not a function. Add a mock for the batch helper (return { items: [{ upload_id, image_url }] }).

Comment thread apps/frontend/app/admin/page.tsx Outdated
const cancelled = isCancelled ?? (() => false);
setLoading(true);
try {
const data = await fetchWorkbenchDashboard({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Consolidating to one endpoint simplifies the page nicely. Small trade-off: loadWorkbench also depends on weekStartDateKey, so changing the selected day within the same week still refetches available_dates and week_days even though only attention changed. Previously available dates were fetched once on mount. Not a blocker — just something to watch if dashboard feels sluggish later.

ruby0322 and others added 2 commits August 7, 2026 12:39
useUploadImageUrls now calls fetchUploadImageAccessBatch; update the
staff API jest mock and add a shared helper so history-overview page
tests render instead of crashing on mount.

Co-authored-by: Cursor <cursoragent@cursor.com>
Type today-attention row serialization and avoid refetching stable
calendar fields when only the selected date changes within the same week.

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

ruby0322 commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@cursoragent review again

@cursor

cursor Bot commented Aug 7, 2026

Copy link
Copy Markdown

PR Review: feat(admin): consolidate dashboard workbench API

Verdict: Approve — ready to merge. CI is green on #45 (lint, backend tests, frontend unit tests, build, K8s render). Follow-up commits since the first review addressed the actionable items.


Previously flagged items — resolved

Comment Status
history-overview tests mock only fetchUploadImageAccess Fixed in ab10e0a — batch mock + shared makeUploadImageAccessBatchResponse helper
Date changes within same week refetch full workbench Fixed in bbad423cachedWeekStartRef + lighter fetchTodayAttention path
list_workbench_dates pulls all created_at into Python Open — non-blocking follow-up (see below)

What works well

1. Eligibility alignment is the core win

workbench_upload_where_clauses() centralizes active + non-rejected filters and is reused by workbench week aggregation, available dates, and today-attention. Regression tests (test_workbench_excludes_rejected_only_day, test_workbench_excludes_inactive_only_day, test_workbench_aligns_week_metrics_with_attention) lock this in — this directly fixes the 7/15 vs 7/16–7/18 mismatch.

2. Sensible API consolidation

GET /v1/staff/dashboard/workbench bundles available_dates, week_days, and attention in one round-trip. The frontend week-cache split is a good trade-off:

  const loadWorkbench = useCallback(
    async (options?: { forceFull?: boolean; isCancelled?: () => boolean }) => {
      // ...
      const weekChanged = forceFull || cachedWeekStartRef.current !== weekStartDateKey;
      // ...
      if (weekChanged) {
        const data = await fetchWorkbenchDashboard({ ... });
        // sets available_dates, week_days, attention
      } else {
        const data = await fetchTodayAttention({ localDate: selectedDate });
        // attention only
      }

onReviewSaved correctly uses forceFull: true so annotations refresh calendar metrics.

3. Batch image access is well-matched

  • Frontend BATCH_SIZE = 50 aligns with backend max_length=50
  • Per-item error handling (not_found / forbidden) with partial success
  • useUploadImageUrls dedupes IDs and chunks requests cleanly

4. Serializer extraction

_serialize_today_attention shared between /today-attention and workbench attention avoids response-shape drift.


Remaining nits (non-blocking)

1. list_workbench_dates scalability

    created_ats = session.execute(base_query).scalars().all()
    dates = {to_taipei_date(created_at) for created_at in created_ats}
    return sorted(dates, reverse=True)

This scales with total upload count and runs on every full workbench load (week change, review save). Fine for current volumes; a follow-up could push distinct Taipei-local dates into SQL. Not a merge blocker.

2. No unit tests for admin/page.tsx

Dashboard load/caching logic (weekChanged, forceFull, error handling) isn't covered. History overview tests are updated; a small test for the workbench load split would help prevent regressions.

3. Manual test plan still open

PR checklist items for dev dashboard date counts and network tab (one workbench + one batch image call) remain unchecked — worth a quick manual pass before prod.

4. History overview vs dashboard scope

History overview still calls fetchHistoryOverviewDays() without scope: "workbench", which is correct — that page should show rejected/inactive days. Dashboard correctly uses workbench scope. Intentional and good.


Summary

The PR delivers what it promises: calendar counts and patient pool share eligibility rules, the dashboard loads in fewer requests, and batch thumbnails reduce N+1 image-access calls. Prior review feedback has been addressed; CI is clean.

Recommendation: Merge after optional manual verification of the open test-plan items. Track list_workbench_dates SQL optimization as a follow-up if upload volume grows.

Open in Web Open in Cursor 

Push workbench available_dates deduplication into the database with
dialect-aware local-date expressions instead of loading every upload
timestamp into Python.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ruby0322
ruby0322 merged commit 96ad00a into main Aug 7, 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