Architecture field notes / 20 September 2026

Pharmacy mono.
Where depth would pay.

Desktop web + small-screen web + React Native4 candidatesdev · 796dc4d
ModuleSeamLeaked coordinationDeep module
01
Strongports & adaptersWeb · both viewports

Deepen purchase draft save and confirmation

Before Current ownership

flowchart TB
  E["Four web draft editors"] --> I["Each owns identity + filtering"]
  I --> S["Pause and save"]
  I --> C["Page confirms stored draft ID"]
  S -. "caller must order" .-> C
  C -. "failure must resume" .-> S
  classDef node fill:#fff,stroke:#78716c,color:#292524;
  class E,I,S,C node;
  linkStyle 3,4 stroke:#b54736,stroke-width:2px;

After Proposed ownership

Scan desktop
Scan small-screen
Manual desktop
Manual small-screen
purchase draft seam
Deep purchase draft moduleRow identity · editable data · ordered save and confirmation · recovery
Transport adapter / test adapter

Problem Four editors repeat draft rules, while the save interface leaves confirmation ordering and recovery with callers.

Solution Give one purchase draft module ownership of editable state, persistence and confirmation; preserve each viewport's editing layout.

Evidence

  • Editors pause autosave, save, then call a page handler that confirms only the stored draft ID.
  • Autosave resumes after a save failure, but the page catches a confirmation failure without resuming it.
  • Duplicate-number correction updates React state just before saving the last-render ref; the confirmation handler ignores the supplied corrected draft.

Files

Tests at the interface

Current editor tests replace autosave. Test edit → save → confirm through the same interface, including failed confirmation, duplicate suffixes and deleted rows. Keep focused viewport interaction tests.

Deletion test

Keep the useful delta-saving implementation. Removing four copies of caller sequencing should concentrate it inside the deep module; a forwarding module would remain shallow.

Real seam

Use the owned persistence adapter and a delayed or failing test adapter. This seam tests the complete sequence, so depth increases without exposing more sequencing controls.

ADRs 0023 and 0034 stay intact. Document jobs and Trusted classification remain server-owned. This candidate's verified scope is web.
02
Strongports & adaptersWeb · both viewports · React Native

Share Unified checkout and recovery policy

Before Current ownership

Web desktop + small-screen
Web checkout modulePayable · retry · bill grouping
React Native
Native checkout modulePayable · retry · bill grouping
Patient identity retained differently on retry
Existing checkout operations

After Proposed ownership

Web desktop · small-screen · RNPresentation adapters
Unified checkout seam
Deep Unified checkout moduleCombined payable · retained attempt · FMCG-only retry · bill grouping
Web / native transport adaptersExisting checkout operations

Problem Web and RN separately implement Combined payable, partial success, bill grouping and retry reconciliation.

Solution Concentrate checkout policy and the retained attempt in a shared deep module, with platform presentation and transport adapters.

Evidence

  • Both implementations retain failed FMCG work and reconcile a conflicting retry through the Customer visit.
  • RN snapshots the patient ID and copies retry items; web retry reads the current patient ID.
  • Both web viewports already share one lifecycle module, so the duplication is between web and RN.

Files

Tests at the interface

Both clients already have substantial recovery tests. Consolidate common outcome cases at one interface, including all visit-link failures and conflict reads; retain adapter integration tests.

Deletion test

Keep useful payment calculations behind the shared module. Removing that module would redistribute checkout knowledge to both clients, which is evidence of depth.

Real seam

Web and RN provide real transport adapters; a controlled test adapter produces partial success and conflicts. Routing, toast and printing stay platform-owned.

ADRs 0014 and 0015 remain binding. Medicine and FMCG commit independently; only uncommitted FMCG is retried; cash remains FMCG-first.
03
Strongports & adaptersWeb · both viewports · React Native

Make cart Hold own pending persistence

Before Current ownership

FMCG edit
500 ms timer
Background save
Hold
Save other fields
Leave cart
Leaving can cancel the pending FMCG timer

RN separately drains writes before leaving.

After Proposed ownership

Web Hold · RN Hold / Next
cart persistence seam
Deep cart editing moduleOwn pending edits → finish older writes → save latest state → acknowledge
acknowledged save
Navigation adapterLeave only after persistence succeeds

Problem Correct Hold behavior depends on callers coordinating pending inputs, autosave timers, in-flight writes and navigation.

Solution Deepen the cart editing module so it owns the last edit through acknowledged persistence before departure.

Evidence

  • Web delays FMCG persistence by 500 ms and cancels the timer on unmount.
  • Web Hold saves other cart fields and navigates without flushing FMCG edits; an immediate Hold can discard that scheduled save.
  • RN explicitly drains older writes and saves current lines before Hold and Next, repeating that ordering in the route.

Files

Tests at the interface

Web FMCG cart tests explicitly skip waiting for autosave; RN tests cover draining. Test edit → immediate Hold → reopen, older-write ordering and failed-save departure through the cart interface.

Deletion test

Concentrate per-screen save ordering inside the cart module. Exporting more flush helpers would leave the shallow coordination with callers.

Real seam

Use a cart persistence adapter plus a controllable test adapter. The clock and navigation remain internal seams or platform adapters; depth comes from owning the sequence.

ADR 0014 requires parked FMCG lines to survive another-device resume. This is a bounded alternative to the checkout-policy candidate.
04
Worth exploringports & adaptersWeb · both viewports · React Native

Unify stock browsing behavior across platforms

Before Current ownership

Web stock moduleCategories · groups · facets · pagination
Web Marketplace moduleSeparate category normalization
RN stock moduleSearch · status · sort · separate pagination
Browsing vocabulary changes require separate ports

After Proposed ownership

Web URL adapter · RN focus adapter
stock browsing seam
Deep stock browsing moduleFilter policy · request identity · rows and facets · refresh and retry
Web and native stock viewsPlatform-specific list and navigation adapters

Problem Filter meaning and list recovery are spread across platform modules, and the native stock contract has fallen behind the web contract.

Solution Deepen stock browsing around shared filter and result state, with web URL and native focus/list adapters; port native category controls as explicit feature work.

Evidence

  • Web supports product groups, Browsing categories and retained selected facets; native stock types and requests omit these fields.
  • Web stock splits category keys directly; Marketplace also trims and deduplicates them.
  • Web and RN already encapsulate useful pagination behavior. Shared ownership must reduce caller knowledge to justify the move.

Files

Tests at the interface

Web stock tests exercise real query bindings on both viewports; RN tests cover refresh and pagination separately. Share filter and stale-result scenarios, retaining platform navigation and list tests.

Deletion test

Do not replace working hooks with shallow forwarding modules. Proceed only if filter policy, result identity and recovery move together and reduce knowledge in both clients.

Real seam

Web URL/scroll and RN focus/FlashList are real adapter differences. Keep Marketplace cursor pagination distinct from stock offset pagination.

ADRs 0021, 0033 and 0034 remain intact. Product group and Browsing category never choose stock ownership. Native parity adds behavior, so scope it explicitly.

Keep the existing depth

The shared Document job engine already owns polling, recovery and terminal outcomes. Web and RN supply real adapters. Preserve that module and its server-authoritative behavior under ADR 0023.

packages/shared/src/utils/documentJobEngine.ts

How to read this review

Evidence comes from current code, existing tests, recent changes and domain ADRs. Timing hazards are source-derived, not running-app reproductions. Proposed diagrams show ownership only; interface design follows your choice.

W means apps/pharmacy-web/src, N means apps/pharmacy-mobile/src. File links point to the reviewed commit; display labels shorten folders. Native parity in candidate 4 includes feature work.

Baseline verification: 47 tests passed across four targeted web suites covering draft editing, checkout recovery, FMCG cart editing and stock filters. Native tests were inspected, not executed. No full-suite or live-app verification was performed.

Top recommendation

Start with purchase draft save and confirmation.

Recent category and support-hold changes keep touching these four editors, and their shared save/confirm sequence leaves important failure behavior between test seams.

Explore candidate 01 ↑

Read-only review. No repository files changed. No ADR conflict identified in these proposals. Source glossary: docs/domain/CONTEXT.md and be/CONTEXT.md.