Repository navigation
feat(pharmacy-orders, facilities): clean recovery of Phase 5 partial fulfillment + facility distance sorting - #257
Oluwaferanmi18 wants to merge 14 commits into
Conversation
…istance-sorted facility selection Closes DocForum#73: FulfillmentItem rows under a FulfillmentRecord carry dispensed quantity/status per routed order item; order status derives from items (partially_fulfilled/fulfilled) via forward-only conditional updates through the prescriptions/lab-orders services; patients can route remaining items to a second facility; a unique index on (orderType, dispensedKey) makes two-facility double-dispense a constraint-level 409 under concurrency. Payment-release rule documented in ARCHITECTURE.md §5.3: no release until the whole order fulfills. Closes DocForum#74: FacilityProfile gains address/latitude/longitude + composite index; GET /facilities/eligible?near=lat,lng sorts by bounding box + haversine (PostGIS justification in ARCHITECTURE.md §5.4); the patient's point is never stored; unlocated facilities stay listed, sorted last; fictional seeded coordinates; perf measured at ~5ms p50 over ~3000 facilities. Also fills in PrescriptionItem.prescriptionId and FulfillmentRecord.facilityId (both already documented in ARCHITECTURE §4, schema was behind) and updates ROADMAP/ARCHITECTURE_ESSENTIALS/docs/api. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
…ng-and-facility-location
The merge in 536504e resolved app.ts, ROADMAP.md and docs/api/README.md toward main's side, silently dropping content from b888485: - /facilities and /pharmacy-orders router imports + mounts (this is what failed CI — every fulfillment route 404'd in the integration tests) - the 2026-10-17 Phase 5 changelog entry in ROADMAP.md - the Facilities and Pharmacy orders endpoint tables in docs/api/README.md 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
…ng-and-facility-location Brings in upstream DocForum#151 (Prisma 7.10.1 + driver adapter), DocForum#155 (patient data export), DocForum#150 (field-level encryption), DocForum#147 (access-control tests). Conflicts resolved in backend/src/app.ts (kept /facilities and /pharmacy-orders mounts alongside /patients) and docs/api/README.md (kept the new Facilities/Pharmacy-orders tables; facilities and pharmacy-orders come out of the "no routes yet" list since this branch gives them routes). 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
…ver adapters
Prisma 7's driver adapter sends bound params with an unspecified type
OID, so Postgres does the inference itself. The bounding-box predicate
`fp."latitude" BETWEEN ${lat} - ${boxLat} AND ...` was therefore
`unknown - unknown`, which Postgres rejects as ambiguous (SQLSTATE
42725) — every ?near+radiusKm query 500'd after the Prisma 7 upgrade.
The box bounds are now precomputed in JS (they never depended on row
data), and every numeric param that reaches the SQL carries an explicit
`::float8`. Result shape, ordering and index usage are unchanged;
facility-distance integration tests (incl. the perf measurement, p50
4.4ms over 3005 facilities) pass again.
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
Prisma 7 stopped reading `prisma.seed` from package.json (the seed command now lives in prisma.config.ts's migrations section) and `new PrismaClient()` without a driver adapter throws — the issue DocForum#74 dev seed hit both. Seed command moved to prisma.config.ts, seed.ts now builds the same PrismaPg adapter as src/db/prisma-client.ts. Verified end-to-end against a throwaway embedded Postgres: `npx prisma db seed` runs and is idempotent (8 fictional facilities, 11 capabilities, 6 with coordinates after two consecutive runs). 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
…ranch The five earlier merges with main resolved conflicts toward main's side and silently dropped this branch's work: the `FulfillmentItem` model (e613309), the `/pharmacy-orders/fulfillments*` routes (57ce53c) and the distance query in facilities/repositories (bf30314) were all gone by PR head — which is why CI failed at `npm run typecheck` (duplicate `pharmacyOrdersRouter`/ `facilitiesRouter` identifiers in app.ts, plus tests referencing `prisma.fulfillmentItem` and `near`). This redoes the merge as one clean three-way merge from ac86f2a (the last commit that still contained every piece) and resolves each conflict as the union of both sides, re-seated onto what main changed underneath: - schema.prisma: main's typed-order `FulfillmentRecord` (ADR 0012) keeps the feature's `items FulfillmentItem[]` relation; `FacilityProfile` gains the issue DocForum#74 location columns *and* main's relations + `@@index([latitude, longitude])`. - pharmacy-orders: feature's item-level fulfillment service/controllers/ routes alongside main's Order creation + fulfillment-proof endpoints; the record's order reference is now derived from `prescriptionId`/`labOrderId` instead of the removed polymorphic pair, and `createFulfillmentRecord` writes the typed FKs. - facilities: main's price-aware `GET /facilities/eligible` contract is kept (public, `{facilities: [...]}`) and extended with issue DocForum#74's `capabilityType`/`detail`/`near`/`radiusKm`/`limit` params and `address`/`distanceKm` fields; one merged repository query does qualification + bounding box + haversine. - lab-orders: main's order services plus the feature's forward-only `applyFulfillmentStatus`. - app.ts: duplicate router imports/mounts from both sides removed. - docs: ARCHITECTURE §4.5/§4.6/§4.7/§6.1, ARCHITECTURE_ESSENTIALS data map, ROADMAP status/changelog and docs/api endpoint tables merged by hand. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
… merge Two collisions the merge with main left behind; both broke the suite (`prisma migrate deploy` failed in all 33 integration files, and the split scenario 409'd where issue DocForum#73 requires a 201). 1. Duplicate DDL. Both this branch's Phase 5 migration and main's later migrations added `PrescriptionItem.prescriptionId` (and its index/FK) and `FulfillmentRecord.facilityId` (and its index/FK), so the second definition failed with 42701 "column already exists". The Phase 5 migration now creates only what it actually owns — the two `partially_fulfilled` enum values, the facility location columns + index, and the `FulfillmentItem` table — with a comment naming the migrations that own the rest. 2. One record per order vs. split routing. ADR 0012 put a UNIQUE on each order FK; issue DocForum#73 requires routing an order's remaining items to a *second* facility as a new record, which that UNIQUE forbids. Uniqueness moves down one level to (order FK, facilityId) — the guarantee ADR 0012 was buying (no duplicated fulfillment of one order at one facility) — and the order relation becomes one-to-many (`fulfillments[]`) as Prisma requires once the FK is no longer unique. Amendment recorded in docs/adr/0012, ARCHITECTURE.md §4.7 and ARCHITECTURE_ESSENTIALS.md; new migration 20261026000000 drops the two per-column indexes and creates the composite ones. Also: facility-distance.test.mts now asserts main's documented `GET /facilities/eligible` contract — the public `{ facilities: [...] }` envelope carrying issue DocForum#74's `address`/`distanceKm` fields — since that endpoint doubles as the price-comparison query and must stay unauthenticated for main's tests; a bare `near` without `type`/`capabilityType` is rejected 400 (fail closed, never an unqualified directory), and the never-store-the- point rule is unchanged. ROADMAP's changelog entry moved into `changelog.d/73-74-partial-fulfillment-facility-distance.md` per AGENTS.md, and a line the conflict resolution had joined back onto DocForum#14's entry is split. Checks (backend/): audit:prod, i18n:check, typecheck, unit 270/270, integration 435/435 (33 files), build — all green. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
afeezorobsco-cyber
left a comment
There was a problem hiding this comment.
Sweep: malware scan clean, CI green.
|
@Oluwaferanmi18 This PR now has merge conflicts with git fetch upstream # upstream = https://github.com/DocForum/docforum-core.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-leaseThe usual culprits are shared docs like Automated message. It won't repeat unless the PR conflicts again after your next push. |
|
@Oluwaferanmi18 After updating this branch with
|
|
@Oluwaferanmi18 Still the same The relation field on line 1001 survived the merge, but the |
|
@Oluwaferanmi18 This PR now has merge conflicts with git fetch upstream # upstream = https://github.com/DocForum/docforum-core.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-leaseThe usual culprits are shared docs like Automated message. It won't repeat unless the PR conflicts again after your next push. |
Closes #73
Closes #74
What this is
A clean recovery of the Phase 5 implementation for #73 (item-level partial fulfillment) and #74 (facility location + distance-sorted selection), rebuilt on top of current
main(8712c70).Disclosure: #154 is the original PR for these two issues and remains open and untouched — this work is submitted as a separate PR rather than force-pushing that contributor's branch. #154 is referenced here purely for context: its description, review notes and history are the source material this branch recovers. Nothing here closes, edits or replaces #154.
Why a new branch was needed
By its head
57ce53c, #154's five successive merges withmainhad resolved conflicts towardmain's side and silently deleted the branch's own work, while the tests, migration SQL and validation schemas referencing that work survived:model FulfillmentItem+FulfillmentRecord.itemse613309/pharmacy-orders/fulfillments*routes + controllers57ce53c(the PR head)facilities/repositories(near/radiusKm)bf30314CI's latest run on #154 (run 544) therefore failed at
npm run typecheck— TS2300 duplicatepharmacyOrdersRouter/facilitiesRouterinsrc/app.ts,prisma.fulfillmentItemmissing,nearnot accepted — with unit tests, integration tests and build all skipped.This branch redoes the merge once, cleanly, from
ac86f2a(the last commit that still contained every piece, including the Prisma 7 fixes) againstmain, resolving each conflict as the union of both sides rather than either side wholesale.Two collisions that only running the suite exposed
PrescriptionItem.prescriptionIdandFulfillmentRecord.facilityIdwith their indexes/FKs, soprisma migrate deployfailed with 42701 in all 33 integration files. The Phase 5 migration now creates only what it owns: the twopartially_fulfilledenum values, the facility location columns + index, and theFulfillmentItemtable.UNIQUEvs. split routing. [Phase 5] Partial fulfillment: item-level dispensing for multi-item prescriptions #73 requires routing an order's remaining items to a second facility as a new record, which thatUNIQUEforbids (the split scenario returned 409 where the issue requires a 201). Uniqueness moved down one level to (order FK, facilityId) — the guarantee the ADR was actually buying — and the order relation becomes one-to-many (fulfillments[]). Recorded as a dated amendment indocs/adr/0012,ARCHITECTURE.md§4.7 andARCHITECTURE_ESSENTIALS.md, plus migration20261026000000_fulfillment_record_per_order_facility.Consequence reviewers should check:
record.facilityIdis now the facility the patient routed to, which for a split order is not the order's ownfacility_profile_id.GET /facilities/eligiblecontract decisionThe endpoint doubles as main's public price-comparison query, so it keeps main's contract: unauthenticated,
{ facilities: [...] }envelope. #74'scapabilityType/detail/near/radiusKm/limitparams andaddress/distanceKmfields are added inside it. A query with neithertypenorcapabilityTypeis a 400 (fail closed — no unqualified directory),radiusKmwithoutnearis 400, and the patient's point is never stored, logged or echoed back. #74's test was updated to assert this shared contract.Test results (backend/, exact CI steps)
npm run audit:prod— PASSnpm run i18n:check— PASSnpm run typecheck— PASS (the step that fails on feat(pharmacy-orders, facilities): item-level partial fulfillment + distance-sorted facility selection #154)npm run test— PASS, 270/270 (31 files)npm run test:integration— PASS, 435/435 (33 files, each on a fresh embedded Postgres, somigrate deployis genuinely exercised)npm run build— PASSgit diff --check origin/main...ci-fix— cleanNew coverage (11 tests): split routing across two facilities with status derivation at each step, concurrent double-dispense race (exactly one 200, one 409), one-shot item claims, hard-rule-5 cross-facility 403s, expired-order non-resurrection, lab-order single-item flow, distance ordering against a haversine reference, unlocated-facility placement, query-contract validation, and the perf measurement below.
Issue #74 DoD (perf): 3005 facilities,
near+radiusKm=60, 25 runs → p50 6.8 ms, p95 7.9 ms, max 8.5 ms (test ceiling 500 ms).Docs (per AGENTS.md)
ARCHITECTURE.md§4.5/§4.6/§4.7/§5.3/§5.4/§6.1,ARCHITECTURE_ESSENTIALS.mddata map,ROADMAP.mdPhase 5 status + two checked items,docs/adr/0012amendment,docs/api/README.mdendpoint tables, andchangelog.d/73-74-partial-fulfillment-facility-distance.md(a new file, not an append toROADMAP.md, perchangelog.d/README.md).