01Concentrate Direct Sell preview rules
Strongin-processDesktop + small-screen + RN
Observed disagreement₹1,000 subtotal · 10% invoice discount · 18% GST. Web tests expect ₹1,080; RN create tests expect ₹1,062. Both suites pass.
Before / copied rules
Same line and invoice discount
↓
Web createBoth viewports₹1,080
RN createDiscount changes GST₹1,062
Web edit + RN edit repeat unreduced GST logic
Separate tests preserve separate answers.
After / shared depth
Desktop adapterSmall-screen adapterRN adapter
shared preview seam
Direct Sell preview moduleOne commercial rule set
Discount precedence · rounding · limits
Create and edit interpretation
↓
One set of server-aligned expectations
ProblemShallow calculation modules leave edit callers rebuilding rules, so their interface does not keep previews consistent.
SolutionConcentrate preview and edit normalization in one deep module, then settle the arithmetic against authoritative server fixtures.
- Depth across create and edit
- Locality for discount rules
- Leverage across three presentations
- One interface, shared outcome tests
Deletion test. Retiring copied calculations concentrates rules; extracting another arithmetic helper leaves callers coordinating them.
Seam and adapters. Pure calculation needs no I/O adapter. Desktop, small-screen and RN presentation adapters consume the same behavior.
Tests. Cover identical create/edit inputs, mixed GST rates, free quantity, overlarge discounts, rounding and clearing. Keep presentation checks for wiring.
Scope. This proves client preview disagreement. It does not establish which total the live server stores.
Files and evidenceW/modules/sales/hooks/useDistSaleCalculations.ts:89W/modules/sales/hooks/__tests__/useDistSaleCalculations.test.ts:121W/modules/sales/components/DistSaleEditDialog.tsx:84N/src/utils/saleCalculations.ts:111 · N/src/utils/saleCalculations.test.ts:125N/app/(app)/sale/[id]/edit.tsx:110
Preserve ADR 0027 and ADR 0028. The server owns atomic Checkout and Distributor Draft revisions.
02Give Direct Sell one cart-editing owner
Strongports & adaptersDesktop + small-screen + RN
Observed coordination gapDesktop defers saves by 400 ms but Checkout does not await them. Small-screen omits cleared discounts and notes; RN explicitly sends clearing values.
Before / callers own ordering
flowchart TB
D[Desktop edits] --> T[400 ms save timer]
D --> C[Checkout]
S[Small-screen review] --> P[Persisted cart]
R[RN review] --> P
T --> P
P --> C
F[FMCG add and edit callers] --> P
T -. pending save .-> C
classDef risk fill:#faefeb,stroke:#aa493a,color:#182d29;
class T,C risk;
After / concentrate ordering
flowchart TB
D[Desktop adapter] --> M[Direct Sell editing module]
S[Small-screen adapter] --> M
R[RN adapter] --> M
M --> W[Existing write adapters]
W --> C[Atomic server Checkout]
classDef deep fill:#182d29,stroke:#32664e,stroke-width:4px,color:#ffffff;
class M deep;
ProblemThe cart interface exposes save timing, clearing and validation to each presentation, while changing viewport replaces its state owner.
SolutionConcentrate cart identity, pending edits and save ordering in a deep Direct Sell module shared by the presentation adapters.
- Depth hides save timing
- Locality for pending edits
- Leverage across cart callers
- Test Checkout through one interface
Deletion test. Removing the shallow FMCG write module only moves a mutation and toast; a deep owner would make callers stop building replacement arrays and coordinating writes.
Seam and adapters. Keep existing Medicine and FMCG writes behind the editing seam. Delayed request adapters can exercise ordering without a full screen.
Tests. Edit then immediately Checkout or Hold; clear a saved discount; switch carts or viewport during a save; overlap two FMCG edits.
Evidence limit. These are source-level ordering gaps. Timing consequences were not reproduced in the running app.
Files and evidenceW/modules/sales/pages/DistSalePage/index.tsx:5W/modules/sales/pages/DistSalePage/desktop/index.tsx:65 · :150 · :167W/modules/sales/pages/DistSalePage/small-screen/index.tsx:169W/modules/sales/hooks/useDistFMCGCartWrite.ts:17W/modules/sales/components/FMCGCartItemsPanel.tsx:27N/src/features/salesFlow/model.ts:469
Preserve ADR 0027. Seller Checkout stays atomic; buyer Distributor Draft confirmation remains a later action.
03Deepen Document job recovery
Strongports & adaptersDesktop + small-screen + RN
Existing fixes reveal the seamRecent commits repair terminal recovery, retry cleanup and supplier discard. Web owns durable Document job states; RN still consumes the legacy scan-status contract.
Before / distributed recovery knowledge
Web page + global resume decide when to restart
Session hook polls and retires terminal recovery
Scan store + upload queue coordinate completion
Page also orders cancellation and cleanup
Duplicated client decisions
RN flow + session + tasks repeat recovery policy
After / one recovery implementation
Web viewsGlobal resumeRN views
Document job recovery seam
Document job client moduleIdentity and recovery stay together
Authorized server snapshot · continuation
Retry · retirement · separate Media status
Browser adapterIndexedDB + visibility
Native adapterFiles + AsyncStorage + AppState
ProblemRecovery knowledge crosses several modules, widening the interface each caller must understand and allowing web and RN behavior to diverge.
SolutionConcentrate client recovery around the existing Document job contract, retaining native and browser storage and file-handling adapters.
- Depth hides recovery ordering
- Locality for actor identity
- Leverage across entry points
- Lifecycle tests cross one interface
Deletion test. Deleting the queue would scatter real persistence behavior. Absorb caller orchestration into a deep owner instead of replacing useful storage modules.
Tests. Preserve the passing web recovery cases. Exercise restart, actor changes, uncertain completion, cleanup failure and Supplier continuation against both adapters.
Existing coverage. Web already tests page-level IndexedDB recovery for both viewports. RN tests cover decision helpers and its task store; no tests were found for the full flow or upload module.
Migration constraint. RN compatibility handling needs deliberate migration. Its legacy client shape alone does not prove every scan fails.
Files and evidenceW/modules/scan/pages/ScanPage/shared/useScanPageState.ts:493 · :697W/modules/scan/hooks/useScanSession.ts:249W/shared/hooks/useGlobalScanResume.ts:29W/modules/scan/utils/documentJobs.ts:51 · :740N/src/features/scan/useScanFlow.ts:89 · N/src/hooks/useScanSession.ts:301N/src/utils/scanUpload.ts:178 · :509S/types/documentJobs.ts
Follow ADR 0023. The server remains the Document job authority. Navigation does not cancel accepted work, and Result ready stays distinct from Media status.
04Concentrate RN history refresh policy
Worth exploringports & adaptersReact Native first
Concrete callerRecording a Pharmacy payment requests a ledger refresh. The ledger hook skips that refresh if another page request is already running.
Before / refresh can disappear
sequenceDiagram
participant V as Pharmacy dues view
participant L as Ledger module
participant R as Request adapter
V->>L: Load more
L->>R: Request older entries
V->>L: Payment recorded, refresh
Note over L: Busy, refresh skipped
R-->>L: Older entries
L-->>V: Append only
After / refresh has one owner
sequenceDiagram
participant V as Pharmacy dues view
participant H as Deep history module
participant R as Request adapter
V->>H: Load more
H->>R: Request older entries
V->>H: Payment recorded, refresh
Note over H: Supersede older request
H->>R: Request current head
R-->>H: Current entries
H-->>V: Replace visible history
ProblemThree RN modules repeat request generations, refresh and retry, but give the same caller intent different guarantees.
SolutionDeepen the existing history-loading implementation so one seam owns stale responses and refresh precedence for actual offset and cursor adapters.
- Depth absorbs request ordering
- Locality for refresh policy
- Leverage across RN histories
- One interface tests delayed responses
Deletion test. Deleting merge helpers leaves ordering scattered. Retiring duplicate request loops concentrates the difficult behavior.
Existing depth. The offset pager already lets refresh supersede an append and tracks the failed page for retry. Build on those behaviors.
Tests. Use deferred request adapters for payment during append, a late response from another Pharmacy, append failure and exact-page retry.
Scope. Start with RN Pharmacy dues and Invoice history. Web pagination has not established a need for this seam. No ADR conflict found.
Files and evidenceN/src/hooks/useOffsetPagination.ts:57 · :140N/src/hooks/usePaginatedInvoiceList.ts:53 · :146N/src/features/dues/usePharmacyLedger.ts:42 · :149N/app/(app)/dues/[pharmacyId].tsx:124 · :156N/src/features/dues/ledgerModel.test.ts