|
| 1 | +--- |
| 2 | +applyTo: "src/care_demo_facility_setup/services/**/*.{py},src/care_demo_facility_setup/tasks.py,src/care_demo_facility_setup/api/**/*.py" |
| 3 | +description: "Use when: working on CARE demo seed execution, CareFixtureBase integration, internal APIClient usage, Celery seed runs, or seed runner resource creation." |
| 4 | +--- |
| 5 | + |
| 6 | +# CARE demo seed client integration notes |
| 7 | + |
| 8 | +## Use `CareFixtureBase` for CARE resource creation |
| 9 | + |
| 10 | +The demo facility setup plugin should create CARE resources through the existing core fixture helper: |
| 11 | + |
| 12 | +- `CareFixtureBase.create_facility(...)` |
| 13 | +- `CareFixtureBase.create_patient(...)` |
| 14 | +- later resource helpers such as locations, encounters, products, lab tests, etc. |
| 15 | + |
| 16 | +This keeps seed execution aligned with CARE API behavior instead of bypassing serializers, permissions, validation, and side effects through direct model creation. |
| 17 | + |
| 18 | +## Why `SeedAPIClient` exists |
| 19 | + |
| 20 | +`SeedAPIClient` is not a replacement for `CareFixtureBase`. |
| 21 | + |
| 22 | +It is an adapter for the DRF `APIClient` passed into `CareFixtureBase`. |
| 23 | + |
| 24 | +The call flow is: |
| 25 | + |
| 26 | +```text |
| 27 | +DemoSeedRunner |
| 28 | +→ CareSeedClient.create_facility(...) |
| 29 | +→ CareFixtureBase.create_facility(...) |
| 30 | +→ CareFixtureBase.post(...) |
| 31 | +→ SeedAPIClient.post(...) |
| 32 | +→ CARE DRF endpoint |
| 33 | +``` |
| 34 | + |
| 35 | +`CareFixtureBase` expects `self.client.get/post/patch(...)` to return a DRF response with `.data`. |
| 36 | + |
| 37 | +In Celery/plugin runtime, plain `APIClient` can return Django redirect responses before DRF handles the request. That breaks `CareFixtureBase.post(...)`, because redirect responses do not have `.data`. |
| 38 | + |
| 39 | +## Redirect issues handled by `SeedAPIClient` |
| 40 | + |
| 41 | +`SeedAPIClient` handles two runtime issues. |
| 42 | + |
| 43 | +### Trailing slash redirects |
| 44 | + |
| 45 | +Django can redirect paths missing trailing slashes. |
| 46 | + |
| 47 | +So `SeedAPIClient` normalizes request paths with a trailing slash before calling the parent `APIClient`. |
| 48 | + |
| 49 | +### HTTP to HTTPS redirects |
| 50 | + |
| 51 | +CARE may run with security middleware that redirects insecure internal requests: |
| 52 | + |
| 53 | +```text |
| 54 | +http://testserver/api/... |
| 55 | +→ https://testserver/api/... |
| 56 | +``` |
| 57 | + |
| 58 | +So `SeedAPIClient` sets: |
| 59 | + |
| 60 | +```python |
| 61 | +secure=True |
| 62 | +``` |
| 63 | + |
| 64 | +for internal `get`, `post`, and `patch` calls. |
| 65 | + |
| 66 | +This prevents `HttpResponsePermanentRedirect` from reaching `CareFixtureBase`. |
| 67 | + |
| 68 | +## Keep diagnostic response validation |
| 69 | + |
| 70 | +`_ensure_drf_response(...)` should remain in place. |
| 71 | + |
| 72 | +It catches unexpected non-DRF responses early and reports: |
| 73 | + |
| 74 | +- path |
| 75 | +- status code |
| 76 | +- redirect location, if any |
| 77 | + |
| 78 | +This gives a clear error instead of: |
| 79 | + |
| 80 | +```text |
| 81 | +'HttpResponsePermanentRedirect' object has no attribute 'data' |
| 82 | +``` |
| 83 | + |
| 84 | +## Celery enqueueing must happen after DB commit |
| 85 | + |
| 86 | +CARE uses `ATOMIC_REQUESTS=True`. |
| 87 | + |
| 88 | +When a seed run is created from an API request, the `SeedRun` row is not visible to Celery until the request transaction commits. |
| 89 | + |
| 90 | +Always enqueue real seed runs using: |
| 91 | + |
| 92 | +```python |
| 93 | +transaction.on_commit(...) |
| 94 | +``` |
| 95 | + |
| 96 | +Otherwise the worker can receive the task too early and fail with: |
| 97 | + |
| 98 | +```text |
| 99 | +SeedRun.DoesNotExist |
| 100 | +``` |
| 101 | + |
| 102 | +leaving the run stuck as `queued`. |
| 103 | + |
| 104 | +## Phone number behavior |
| 105 | + |
| 106 | +Do not store fixed real-looking phone numbers in seed JSON. |
| 107 | + |
| 108 | +Use deterministic demo phone numbers generated from `SeedRun.id`: |
| 109 | + |
| 110 | +- facility phone: unique per run |
| 111 | +- patient phone: unique per run and patient index |
| 112 | + |
| 113 | +This keeps seed runs reproducible and avoids committing realistic contact data. |
| 114 | + |
| 115 | +## Avoid `care_fixture_context()` in plugin runtime |
| 116 | + |
| 117 | +Do not use `care_fixture_context()` for dashboard-triggered seed execution. |
| 118 | + |
| 119 | +It is development fixture machinery and may: |
| 120 | + |
| 121 | +- create/update the `admin` user |
| 122 | +- force-authenticate fixture clients |
| 123 | +- sync roles/valuesets |
| 124 | +- patch locks |
| 125 | + |
| 126 | +For the plugin, create a controlled `APIClient`, authenticate it with the requesting superuser, and pass it into `CareFixtureBase`. |
0 commit comments