Files
Abin ToppoandClaude Opus 4.8 95d8e0a925 perf: project-wide optimization pass + UI/theme fixes
Optimization (audited across src/, typecheck green):
- Crash guards: PurchaseAuction data?.result + stray text-node, AuctionItemDetail
  length>0, LiveAuction user?.contractorId, KYC params guard
- Hoisted render-defined components: Login MinimalInput (keyboard-focus bug),
  TenderFullDetail Section/InfoBox (subtree remount)
- Memoized hot paths: Spreadsheet ColumnHeaderRow/DataRow, list makeStyles,
  shared infinite-query select (stops per-render flatMap)
- Removed hot-path/in-list console logs; SkeletonList 10->1 shimmer

UI/theme: themed AppToast, redesigned sidebar drawer, list empty states,
KYC WebView cleanup

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 11:14:23 +05:30

7.9 KiB

ProcureLinc — Architecture Guide (as-built)

This is the as-built companion to ARCHITECTURE_AUDIT.md. The audit is the blueprint (what was wrong, what to build); this document is the map of what now exists and the rules for working within it. Read this before adding a feature or "fixing" something that looks odd — several things that look like smells are deliberate, documented below under Deferred / do not touch blindly.


1. Layering

Presentation   src/Screens/**, src/components/**        (UI only)
      │
Application    src/Services/**, feature hooks           (use-cases, orchestration)
      │
Domain         slices, reducers, pattern configs        (business rules, pure)
      │
Infrastructure src/core/**                              (http, storage, crypto, events)
      │
Platform       react-native, native modules

Dependencies point inward. src/core/** must never import from Screens, Services, or Redux. It reaches outward only through injection/events (see §3).


2. The core/ layer — the single source of infrastructure truth

Module Responsibility Rule
core/config/env.ts All hosts/base URLs, selected by build type No hardcoded URLs anywhere else.
core/http/client.ts THE axios instance; request<T>() Throws AppError; never returns a sentinel. All new network code uses this.
core/http/AppError.ts Normalized typed error Catch with isAppError(); branch on .kind.
core/observability/logger.ts The only sanctioned log sink Never console.* in app code. DEV-only; release-stripped.
core/observability/redact.ts PII/secret masking Every log payload is redacted; extend SENSITIVE_KEY_PATTERN when adding sensitive fields.
core/storage/secureStorage.ts Keychain-backed persist storage for the auth session Token is never in plaintext AsyncStorage.
core/events/appEvents.ts Typed cross-layer event bus How infra signals up without importing the store.
core/query/queryClient.ts Module-singleton React Query client Never construct a QueryClient in a component.
core/errors/ErrorBoundary.tsx App-root render-error guard Wraps the tree in App.tsx.
core/platform/polyfills.ts Buffer / TextEncoder Imported first in index.js; nothing may depend on load order otherwise.

3. Hard rules (enforced by review; some by CI)

  1. Networking: use request() from core/http/client. It injects the JWT, handles 401 (emits auth/unauthorized), times out, and throws AppError. src/Axios/Axios.ts (apiCall) is a legacy compatibility adapter that preserves the old never-throws {success:false} envelope for un-migrated call sites; its contract is pinned by tests. Do not add new apiCall sites.
  2. Auth token: read only via selectAuthJwt(state). The transport reads it through a provider registered in Redux/Store.ts — never import { store } into core.
  3. Logout: call performLogout() from Services/Auth/session.ts. It clears redux + keychain + the query cache in one place. AuthSessionGuard (mounted in App.tsx) resets navigation to Login whenever the session ends.
  4. Post-auth routing: Services/Auth/registrationRouting.ts is the single decision function. Splash and Login both call it. Do not re-implement.
  5. Logging: logger.<level>(scope, message, data?). Never log key material, plaintext bids, OTPs, or full PII (the redactor is a safety net, not a licence).
  6. Theme/colors: use useTheme(). Constant/Color.tsx is deprecated (see §6). There is one brand orange, sourced from theme/colors.
  7. Components: one root — src/components/**. src/Component/ no longer exists.
  8. Navigation: route param shapes live in src/Navigation/types.ts (RootStackParamList). NavigationString is the as const route-name registry.
  9. Forward/Reverse bidding: every behavioural difference lives in Screens/Bidding/biddingPattern.ts. The screen/card contain zero if (pattern === ...).

4. Feature anatomy (pattern to copy)

The tender-bidding and registration features show the intended shape — logic is extracted out of the screen into pure, testable units:

Screens/Tender/tenderBidding/
  TenderBidding.tsx        presentation + state only
  envelopeTypes.ts         types
  envelopeCrypto.ts        AES/RSA (never logs key material)
  envelopePayload.ts       pure payload build + validation   ← unit-tested
  envelopeSubmission.ts    API calls
  components/*              memoized, module-scope sub-components

Screens/Ragistration/
  Ragistration.tsx         orchestration + render
  registrationState.ts     typed useReducer (was ~20 useStates) ← unit-tested
  registrationValidation.ts pure per-stage validation          ← unit-tested

When you build a feature: keep the screen thin; put decisions in pure functions; test the pure functions.


5. Testing & CI

  • npm test (jest). 75 tests across 11 suites, concentrated on the money/crypto/auth/storage paths: envelopePayload, biddingPattern, registrationState/registrationValidation, registrationRouting, Token slice, apiCall envelope contract, AppError, redact, appEvents, and the secureStorage keychain-migration path.
  • CI (.github/workflows/ci.yml) runs install → typecheck → lint → test, all blocking. tsc --noEmit is green; eslint . --quiet (errors) is green. Style warnings still exist and are being burned down; tighten to --max-warnings=0 once clean.
  • New pure logic should ship with tests. UI can follow with RNTL later.

6. Deferred / do not touch blindly

These look like leftovers but were left deliberately. Read before "fixing".

  • Constant/Color.tsx is deprecated but still imported by ~20 files for neutral grays. Its brand tokens are now sourced from the theme, but its neutral values differ from theme/colors in several places. A blind find/replace to useTheme() will change appearance — migrate screen-by-screen with visual review.
  • EnvelopeCExcelPreview.tsx still uses raw axios (responseType: 'arraybuffer') and react-native-fs with 'ascii' write encoding. The RNFS → react-native-blob-util dedupe and the axios → core/http migration are deferred because this sealed-bid document flow can't be runtime-verified here and the encodings aren't 1:1. Needs a device.
  • Sealed-bid crypto is AES-ECB with the symmetric key echoed to the server (randomKeyGenerated). This is a backend-contract weakness (audit §11); fixing it requires a coordinated backend change, not a client edit.
  • ResetPassword sends the new password as a URL query param. Migrated to core/http (so it's redacted in logs) but the query-param placement is a backend contract — see the TODO(backend) at the call site.
  • PurchaseTenderTile "details" tap (in PurchaseTenderAllList) now navigates to the registered LiveTenderDetail route, passing the flat tender item that screen reads from route.params — matching LiveTenderTile's working pattern. It previously targeted an unregistered 'TenderDetail' route (a latent bug that no-op'd with a dev warning).

7. Open work (gated on device or backend/ops)

  • Device/emulator needed: full Auth/App two-stack navigator split (AuthSessionGuard + registrationRouting are the groundwork); release minify/shrink + App Bundle + ABI splits; verifying the Envelope C flow.
  • Backend/ops needed: HTTPS for eproc-backend.lincpay (then remove its cleartext exemption in network_security_config.xml and add pinning); rotate the previously-committed keystore + Sonar token and purge git history.
  • Incremental: finish Constant/Color → useTheme; per-screen typed navigation adoption (useNavigation<NativeStackNavigationProp<RootStackParamList>>); broaden accessibility labels; i18n scaffolding.