You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Show each provider's source value(s) on the list card in the Medical Providers pop-out.
Rebind the "Provider Details" form field in the edit modal from the provider_details column to the details column. Requires wiring details into the backend PATCH endpoint.
Change 1: Source Display on Provider Card
What
Add a source line to MedicalProviderCard.tsx in the card header, below the roles line.
Implementation
Call the existing getMedicalProviderSources(provider) utility, which returns string[] of source labels.
Render below the roles line: Source — label1, label2 using text-xs text-muted-foreground.
Skip rendering entirely when the sources array is empty.
Change 2: Rebind "Provider Details" to details Column
Background
The contact_medical_provider table has two JSONB columns:
provider_details: legacy blob, returned by the API as a JSON-stringified string.
details: newer JSONB column, returned as a raw dict (or null). Currently used as a legacy fallback for role storage (details.roles) by providers predating the junction table migration.
The PATCH endpoint (/v2/matter-medical-providers/{matterId}) currently accepts provider_details in its request model but has no details field.
BaseResponse.details: widen from Optional[dict] = None to Optional[Any] = None so both existing dicts and newly-written strings deserialize without Pydantic validation errors.
getEditMedicalProviderDefaults: read from provider.details. If it's a string, use as-is. If it's a dict (legacy), JSON.stringify it. If null, use null.
buildUpdateMedicalProviderPayload: send details: data.details ?? undefined and remove provider_details.
MatterMedicalProviderV2Contract.details: widen type to { roles?: string[]; [key: string]: unknown } | string | null.
MatterMedicalProviderUpdateResponseContract.details: same widening.
Behavioral Notes
getMedicalProviderRoles reads provider.details?.roles. When details is a string, string?.roles is undefined, so the legacy fallback gracefully returns []. This is correct — providers with string details will have proper junction table roles.
The parseMedicalProviderDetails utility reads provider_details, not details. It is unchanged.
The add flow (AddMedicalProviderDialog / MedicalProviderLinkDetails) does not have a provider_details field and is not touched.
Tests
Per CLAUDE.md testing rules:
Card source display and field rebinding are presentational changes — no new tests required.
The backend _CONTACT_MEDICAL_PROVIDER_FIELD_MAP change is a mechanical addition with no logic — no new test required.
If existing unit tests in edit-medical-provider-dialog-utils.test.ts assert on provider_details form values, update them to details.
Out of Scope
No changes to provider_details column handling anywhere else.
CLU-530: Medical Provider Source Display + Details Column Rebind
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
Goal: Show provider source on the Medical Providers list card; rebind the "Provider Details" edit field from provider_details to the details DB column, including the necessary backend PATCH support.
Architecture: Two independent changes sharing one PR. Backend wires details into the PATCH request model and repository field map. Frontend renames the form field throughout the edit flow and adds a source line to the card component.
Tech Stack: FastAPI (Pydantic v2, SQLAlchemy async), Next.js 14, react-hook-form + zod, Jest (unit tests via pnpm test:unit)
Step 2: Widen BaseResponse.details to Optional[Any]
In BaseResponse, change:
details: Optional[dict] =None
to:
details: Optional[Any] =None
This allows the response to return either a legacy dict (pre-existing JSONB data) or a plain string (written by this new field) without Pydantic validation errors.
Step 3: Add details to the repository field map and create path
Open api_hub/database/repositories/matter_medical_provider.py.
In _CONTACT_MEDICAL_PROVIDER_FIELD_MAP, add details:
cd case_management_pipeline/projects/next-js/ui-2.0
pnpm typecheck 2>&1| head -30
Expected: zero errors related to details or medical-providers.ts.
Step 4: Commit
git add case_management_pipeline/projects/next-js/ui-2.0/lib/api-hub/contracts/medical-providers.ts
git commit -m "feat(ui): widen medical provider details type to support string values"
Task 3: Frontend — rebind edit form from provider_details to details
Open test/unit/app/edit-medical-provider-dialog-utils.test.ts.
In the "maps provider data into stable form defaults" test, the fixture currently passes provider_details and the expectation asserts provider_details. Change both to details:
cd case_management_pipeline/projects/next-js/ui-2.0
pnpm test:unit -- --testPathPattern="edit-medical-provider-dialog-utils" --no-coverage
Expected: 2 test failures — "maps provider data into stable form defaults" and "builds the update payload from form values and provider ids".
Step 3: Update the Zod schema in edit-medical-provider-dialog-utils.ts
Open edit-medical-provider-dialog-utils.ts. In editMedicalProviderSchema, rename the provider_details field to details:
exportconsteditMedicalProviderSchema=z.object({medical_provider_npi_id: z.string().optional().nullable(),npi_taxonomy_code: z.string().optional().nullable(),is_primary_care_physician: z.boolean(),is_on_ehealth_exchange: z.boolean(),requires_wet_ink_signature: z.boolean(),requires_drivers_license: z.boolean(),record_collection_method: z.string().optional().nullable(),details: z.string().optional().nullable(),// was: provider_detailsstart_date: z.string().optional().nullable(),end_date: z.string().optional().nullable(),is_current: z.boolean(),role_ids: z.array(z.string()).min(1,"At least one role is required"),source_ids: z.array(z.string()).min(1,"At least one source is required"),})// ... superRefine unchanged
Step 4: Update getEditMedicalProviderDefaults
Replace the provider_details mapping with details. The provider.details field from the API is either a dict (legacy) or a string (new writes), or null:
No new test required — this is a presentational change with no new logic (the getMedicalProviderSources utility it calls is already tested separately).
Step 1: Import getMedicalProviderSources
Open MedicalProviderCard.tsx. The import block currently reads:
cd case_management_pipeline/projects/next-js/ui-2.0
pnpm typecheck 2>&1| head -30
npx tsx scripts/check-conventions.ts 2>&1| tail -20
Expected: no errors.
Step 5: Commit
git add case_management_pipeline/projects/next-js/ui-2.0/app/\(dashboard\)/\(matters\)/\[id\]/components/MedicalProviderCard.tsx
git commit -m "feat(ui): show source on medical provider card"
Task 5: Final verification
Step 1: Run full unit test suite
cd case_management_pipeline/projects/next-js/ui-2.0
pnpm test:unit --no-coverage 2>&1| tail -20
Expected: all tests pass, no regressions.
Step 2: Run API Hub flake8 on all touched files
cd case_management_pipeline/projects/api-hub
python -m flake8 \
api_hub/api/models/matter_medical_provider.py \
api_hub/database/repositories/matter_medical_provider.py
Expected: no errors.
Step 3: Check git log looks clean
git log --oneline -5
Expected output (order may vary):
feat(ui): show source on medical provider card
feat(ui): rebind Provider Details field to details column
feat(ui): widen medical provider details type to support string values
feat(api-hub): add details field to medical provider PATCH endpoint
docs: add CLU-530 design spec for ...