feat: architecture refactor — core layer, spreadsheet engine, envelope bidding, tests
CI / quality (push) Waiting to run
CI / quality (push) Waiting to run
- Add src/core/ (config, errors, events, http, observability, storage, query) - Add src/Spreadsheet/ engine with native POI backend and Excel bridge - Add Envelope C spreadsheet flow and tender bidding envelope modules - Consolidate components into src/components/, remove legacy Component/ and Hooks/ - Add registration state/validation, auth session guard, profile edit modules - Add unit tests across axios, redux, bidding, registration, encryption, core - Add CI workflow, docs (architecture, audit, DSC API spec), keystore example - Remove tracked keystore binary; ignore scripts.zip Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9acec328a7
commit
1d7646d938
@@ -0,0 +1,153 @@
|
||||
# ProcureLinc — Architecture Guide (as-built)
|
||||
|
||||
This is the **as-built** companion to [`ARCHITECTURE_AUDIT.md`](./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** navigates to `'TenderDetail'`, an
|
||||
unregistered route (a pre-existing latent bug). The intended destination is
|
||||
ambiguous (the tile already renders an in-tile modal), so it awaits a product
|
||||
decision rather than a guessed target.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
@@ -0,0 +1,363 @@
|
||||
# ProcureLinc — Principal-Level Architectural Audit & Redesign
|
||||
|
||||
**Subject:** ProcureLinc React Native mobile app (e-procurement: auctions + tenders + eKYC + sealed-bid bidding)
|
||||
**Stack:** React Native 0.79.0, React 19, Redux Toolkit + redux-persist, React Query, STOMP/SockJS, Axios, Formik/Yup, Hermes + New Architecture (Fabric/TurboModules) enabled.
|
||||
**Scope:** Full-project architectural review — no code was modified. Every claim below is anchored to `file:line` evidence.
|
||||
**Verdict:** The app *works*, but it is at **prototype maturity carrying production-grade risk**. It is not currently safe to ship to a real user base handling money and Aadhaar/PAN PII, and it is not structured to scale to a large team or user count without significant rework. This document is the redesign blueprint.
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
ProcureLinc is a functional e-procurement client with genuinely good *ideas* in places (a clean `AppText` typography primitive, a correct paginated-list template in `LiveTender.tsx`, a working dark-mode theme system, STOMP-based live bidding). But the codebase is in a state common to fast-moving startups: **multiple half-finished architectural attempts layered on top of each other, none fully adopted, with security and correctness debt that compounds as it grows.**
|
||||
|
||||
The five findings that matter most, in priority order:
|
||||
|
||||
| # | Finding | Severity | Where |
|
||||
|---|---------|----------|-------|
|
||||
| 1 | **A binary signing keystore (`appKeyStore`) is committed to git**, and **release builds are signed with the public debug keystore** (`storePassword 'android'`). Anyone with repo access can forge signed ProcureLinc APKs. | 🔴 Critical | `android/app/appKeyStore` (git-tracked), `android/app/build.gradle:103` |
|
||||
| 2 | **A global Axios interceptor logs every request/response — full URLs, JWT headers, login passwords, Aadhaar/PAN/OTP, and sealed-bid amounts — to logcat, ungated by `__DEV__`, in release builds.** | 🔴 Critical | `src/Axios/Axios.ts:47-99` |
|
||||
| 3 | **The data layer is four competing API stacks across three different backend hosts**, and the dominant one (`apiCall`) *swallows every error and returns `{success:false}` cast to the success type* — defeating TypeScript, React Query error/retry/cache, and forcing brittle status-code checks everywhere. | 🔴 Critical (architecture) | `Axios.ts:124-141`, `api/client.ts`, `apis.ts`, `Constant/Variable.tsx` |
|
||||
| 4 | **App-wide cleartext HTTP is permitted in release, with no SSL pinning**; auth JWT + full login response (incl. PII) is persisted **unencrypted** in AsyncStorage; device binding is client-spoofable and DSC "binding" is UI-only. | 🔴 Critical (security) | `network_security_config.xml`, `Redux/Store.js:20-24`, `DeviceBinding.tsx`, `DscBinding.tsx` |
|
||||
| 5 | **God-components with mixed concerns and massive duplication** — `TenderBidding.tsx` is 1205 lines (crypto + REST + upload + validation + UI); `StartBidding`/`StartReverseBidding` and their card components are ~90% copy-paste forks. | 🟠 High (maintainability) | `TenderBidding.tsx`, `Bidding/*` |
|
||||
|
||||
**Bottom line:** before any new feature work, the project needs (a) a security remediation sprint (secrets, transport, logging, storage), and (b) a data-layer consolidation onto a single typed client + properly-configured React Query. Everything else — modularization, design-system unification, testing, CI/CD — follows from those two.
|
||||
|
||||
**On the "AI-powered operating system" vision:** I am challenging the premise directly (see §16). The current codebase contains **zero AI, agent, RAG, voice, or knowledge-graph subsystems**. That is not a criticism — an e-procurement app doesn't need them today. But the audit cannot review AI architecture that doesn't exist; instead §16 lays out what an AI-native evolution would *actually* require and why the current foundation must be fixed first.
|
||||
|
||||
---
|
||||
|
||||
## 2. Current Architecture Overview
|
||||
|
||||
**Shape:** A single-module React Native app. No feature-module boundaries; organized by loose type-folders (`Screens/`, `Component/` **and** `components/`, `Hooks/`, `Services/`, `Redux/`, `socket/`, `theme/` **and** `Constant/Color`, `Styles/`).
|
||||
|
||||
**Runtime composition** (`App.tsx:19-41`): `NavigationContainer → QueryClientProvider → GestureHandlerRootView → AlertNotificationRoot → Redux Provider → PersistGate → Routes`. `LogBox.ignoreAllLogs(true)` is set at module load (`App.tsx:15`).
|
||||
|
||||
**Navigation** (`Navigation/MainStack.jsx`): one flat native-stack with 23 sibling screens; `Home` hosts a custom animated `BottomTab` (4 tabs). No logged-in/out navigator split — auth gating is a one-shot imperative redirect inside `Splash.tsx`.
|
||||
|
||||
**State:** Redux Toolkit, 6 slices (`token`, `auction`, `selectPurchaseAuction`, `selectPurchaseTender`, `tender`, `theme`), only `token` + `theme` persisted. `serializableCheck:false` globally (`Store.js:30`).
|
||||
|
||||
**Data:** Four coexisting mechanisms — `apiCall` wrapper (dominant), a second `apiClient` axios instance, raw `axios` calls in `apis.ts`, and raw `axios` in screens — hitting **three** hardcoded hosts: `eproc.godemo.in` (REST), `procurelinc.in` (sockets), `procurelinc.com` (dead `client.ts`).
|
||||
|
||||
**Real-time:** STOMP-over-SockJS (`socket/Socket.tsx`) for receiving bid updates; bids are *placed* over REST, not STOMP.
|
||||
|
||||
**Crypto:** JS-side AES (ECB mode, SHA-256 key truncated to 128 bits) + RSA (jsencrypt) for sealed-bid envelopes (`Services/Encryption/encrypt.tsx`).
|
||||
|
||||
**Native:** No custom Java/Kotlin — stock RN host. Hermes on, New Architecture on. No env abstraction, no tests, no CI/CD.
|
||||
|
||||
Total: ~26k LOC of TS/JS across 138 source files.
|
||||
|
||||
---
|
||||
|
||||
## 3. Architectural Strengths (worth preserving)
|
||||
|
||||
An honest audit names what's good so it isn't lost in a refactor:
|
||||
|
||||
- **`components/AppText.tsx`** — a proper typographic primitive: variant + theme color + Android-safe font-family merging. This is the seed of a real design system. Keep and expand.
|
||||
- **`useTheme` + `ThemeSlice`** — a working light/dark/system theme with a user switcher (`CustomDrawer.tsx`). Solid foundation; the problem is only that half the app bypasses it.
|
||||
- **`LiveTender.tsx`** — the *correct* FlatList pattern: memoized `renderItem`/`renderFooter`, `keyExtractor`, infinite-scroll pagination via React Query `fetchNextPage`/`hasNextPage`, and tuned perf props (`initialNumToRender`, `windowSize`, `removeClippedSubviews`). **This should be the template every list screen follows.**
|
||||
- **`socket/Socket.tsx`** — a reasonable `useReducer`-based STOMP abstraction with a pending-subscription queue and reconnect/heartbeat config. The core is sound; the consumers misuse it.
|
||||
- **Modern baseline** — RN 0.79, Hermes, New Architecture, React Query, Redux Toolkit, Formik/Yup are all present. The *ingredients* of a good architecture exist; they are simply half-wired.
|
||||
- **`android:allowBackup="false"`** is correctly set — limits `adb backup` extraction of the (unfortunately plaintext) token.
|
||||
|
||||
---
|
||||
|
||||
## 4. Architectural Weaknesses
|
||||
|
||||
Grouped by subsystem. Severity: 🔴 Critical, 🟠 High, 🟡 Medium.
|
||||
|
||||
### 4.1 Data / API layer
|
||||
- 🔴 **Four parallel API stacks, three hosts, two auth-header names.** `apiCall` sends `Authentication: Bearer` (note: not `Authorization`) reading `token.token` (`Axios.ts:118`); `apiClient` sends `Authorization` reading `token.token.token` (`client.ts:17`); screens send raw axios with `Authentication: Bearer ${Token.token}` (`BiddingCard.tsx:82`). There is no single place to add retry, refresh, tracing, or error handling.
|
||||
- 🔴 **`apiCall` swallows errors and casts `{success:false}` to `R`** (`Axios.ts:124-141`). This is the single most damaging decision in the codebase — it defeats the type system, makes React Query believe every call succeeded (`isError` never fires, retries never happen, bad responses get cached as valid), and forces defensive `res?.statusCode===200` checks in every consumer. `try/catch` blocks around `apiCall` (e.g. `apis.ts:76-82`) are dead code because it never throws.
|
||||
- 🟠 **React Query is present but mis-configured.** `new QueryClient()` with no defaults (`App.tsx:20`) ⇒ `staleTime:0`, refetch-on-mount/focus ⇒ refetch storms. It's also instantiated *inside the component body*, so it's recreated on every re-render. Broken query keys: `useAucitonItemDetail` uses `queryKey:[]` (all instances collide), `useGetAuciton` uses static `['getAuction']` ignoring the id. Missing `enabled` guards fire `?tenderId=undefined` calls. No `invalidateQueries` anywhere — lists go stale after writes.
|
||||
- 🟡 **Dead/broken config.** `Constant/AllUrls.tsx` builds ~30 URLs from `${Variable.Main_Base}` — but `Main_Base` doesn't exist, so every URL is `undefined/...`. This whole file is leftover from a different (e-commerce) app. The generic hooks (`useFetch/useUpdate/useDelete`) are imported nowhere.
|
||||
|
||||
### 4.2 State management
|
||||
- 🟠 **The token slice lies about its type.** Declared `{token:''}` (`Token.tsx:3`) but at runtime holds a full object (`Login.tsx:212`). No `RootState`/`AppDispatch` types exist; every `useSelector` is `(state:any)`. Zero compile-time safety on auth state.
|
||||
- 🟡 **Two inconsistent logout paths** — `removeToken()` (sets `''`) vs `setToken({})` (leaves a truthy empty object) vs direct `AsyncStorage.removeItem('persist:root')`. These can desync in-memory state from disk and confuse the splash auth check.
|
||||
- 🟡 **`serializableCheck:false` globally** hides genuine non-serializable leaks, and the slices store whole API response objects.
|
||||
|
||||
### 4.3 UI / screens
|
||||
- 🟠 **God-components:** `TenderBidding.tsx` (1205), `ProfileTab.tsx` (1031), `Login.tsx` (792), `Ragistration.tsx` (725, ~25 `useState`), `Emd.tsx` (608). Networking + crypto + validation + sub-components + rendering all in one file.
|
||||
- 🟠 **Copy-paste forks:** `StartBidding`≈`StartReverseBidding` (~90%), `BiddingCard`≈`ReverseBiddingCard` (identical StyleSheets) — diverging subtly (one card is `memo`'d, the other isn't; wrong color import in reverse). Every fix must be made twice, and they *will* drift.
|
||||
- 🟠 **Split-brain design system:** `src/Component/` (old) vs `src/components/` (new); two `MyInput`, two `PrimaryButton`, three side-drawers (one dead), two color palettes with **two different brand oranges** (`Constant/Color:#F97316` vs `theme/colors:#e39546ff`).
|
||||
|
||||
### 4.4 Navigation
|
||||
- 🟠 **No route type safety** (`createNavigationContainerRef<any>()`, `useNavigation<any>()`, `useRoute<any>()` everywhere), **no route guards** (every screen reachable), **no deep linking** (`NavigationContainer` has no `linking`).
|
||||
|
||||
### 4.5 Real-time
|
||||
- 🟠 **`subscribe()` called in the render body** (`StartBidding.tsx:137`, `StartReverseBidding.tsx:171`), re-registering the STOMP callback every render; **no `disconnect()`/`unsubscribe()` on unmount** ⇒ leaked connections that keep reconnecting (5s) and draining battery/data. Bids split across REST *and* STOMP for the same feature.
|
||||
|
||||
---
|
||||
|
||||
## 5. Design Smells
|
||||
|
||||
- **Misspelled, leaked-through names as public API:** folder `Ragistration/`, components `Serach/SeacrhInput`, props `isVarify`/`maxlength`, constant `FORARD_AUCTION_ITEM`, string `'Failed load cities'`. Names are the cheapest documentation; these signal no review gate.
|
||||
- **Duplicate constants pointing at the same endpoint** (`SELECTED_AUCTION_ITEM` == `EMD_CHECK`).
|
||||
- **`useState` used as a value holder**: `const tenderId = useState(route.params?.tenderId)` captures the `[state,setState]` tuple and never uses it (`TenderBidding.tsx:71`).
|
||||
- **Sub-components declared inside a parent's render body** (`InfoRow`, `EnvelopeButton`, `renderEnvelopeItem` in `TenderBidding.tsx:113-309`) — recreated every render, defeating memoization and remounting subtrees.
|
||||
- **A test/debug screen wired into production** (`TestScreen/DecryptionScreen.tsx`) with a hardcoded real AES key copyable to clipboard.
|
||||
- **`LogBox.ignoreAllLogs(true)`** — silencing all warnings is hiding the smoke detector.
|
||||
|
||||
## 6. Anti-Patterns
|
||||
|
||||
- **Error-swallowing service layer** (`apiCall` returning `{success:false} as R`) — the "exceptions considered harmful, return sentinels typed as success" anti-pattern.
|
||||
- **Effect logic in render** (`subscribe()` outside `useEffect`).
|
||||
- **Fat controller / god object** (the 1205-line screen).
|
||||
- **Shotgun surgery by construction** (forward/reverse duplication guarantees every change touches ≥2 files).
|
||||
- **Config-by-comment** (base URLs selected by commenting/uncommenting lines in `ApiUrls.tsx`).
|
||||
- **Boolean-flip refetch** (`setAllBoolean(reload:!prev.reload)` to trigger a parent `useEffect` instead of query invalidation).
|
||||
- **Primitive obsession in state** (~25 discrete boolean `useState`s in `Ragistration.tsx` instead of a reducer/state machine).
|
||||
|
||||
## 7. Bottlenecks
|
||||
|
||||
- **Refetch storms** from `staleTime:0` + refetch-on-focus on dashboards/lists.
|
||||
- **Whole-list re-renders** on every live bid tick (inline `renderItem`, unmemoized reverse card) — worsens as bidder lists grow.
|
||||
- **Per-second `setState` timers** (`CountdownTimer` *and* the parallel `AuctionTimer`) re-rendering timer subtrees every second; two implementations doing it.
|
||||
- **Nested non-virtualized `FlatList scrollEnabled={false}` inside `ScrollView`** (`TenderBidding.tsx:1056,1099`) renders all rows eagerly.
|
||||
- **Synchronous blocking API call on the Splash screen** (registration-state fetch gates app entry for tender users, `Splash.tsx:45-107`).
|
||||
- **Startup polyfills** (`Buffer`, `TextEncoder`) set synchronously; `QueryClient` recreated per render.
|
||||
|
||||
## 8. Tight Coupling
|
||||
|
||||
- **Transport layer knows about UI and navigation:** `apiCall` dispatches `setToken({})` on 401 (`Axios.ts:129`); `Socket.placeBid` calls `showSuccessAlert`/`showErrorAlert` from inside the service (`Socket.tsx:200-207`). Data/transport should emit events, not drive UI.
|
||||
- **Screens coupled directly to the crypto implementation** (`TenderBidding` calls `encrypt`/`encryptWithRSA` inline with hardcoded ECB assumptions).
|
||||
- **Redux token shape coupled across ≥3 readers** with different nesting (`token.token` vs `token.token.token`) — change one, break the others silently.
|
||||
- **Components coupled to two different color modules**, so a rebrand touches both.
|
||||
|
||||
## 9. Hidden Dependencies
|
||||
|
||||
- **`jsencrypt` is in `devDependencies`** (`package.json:91`) but imported by runtime code (`encrypt.tsx`). A production install with `--production` (or a clean CI install) **breaks the sealed-bid crypto path**. This is a latent production outage.
|
||||
- **`global.Buffer` / `global.TextEncoder`** monkey-patched at startup (`index.js:9-10`, `App.tsx:22`) — any code depending on them has an invisible ordering dependency on app bootstrap.
|
||||
- **Socket token captured at hook-init** (`StartBidding.tsx:55`) — if the token refreshes mid-session, the socket keeps the stale one with no re-read.
|
||||
- **`text-encoding`, `react-native-get-random-values`** are crypto polyfills whose absence would silently weaken/break encryption.
|
||||
|
||||
## 10. Single Points of Failure
|
||||
|
||||
- **The one signing key** — committed to git, so its secrecy is already lost; simultaneously the *only* thing standing between the app and forged updates.
|
||||
- **`apiCall` / the default axios instance** — every feature funnels through it; its error-swallowing behavior means one backend contract change produces silent `undefined`s app-wide rather than a visible failure.
|
||||
- **The single flat navigator + imperative Splash gate** — if Splash's registration-state call fails, the recovery path *wipes persisted state and forces re-login* (`Splash.tsx:103`); a backend hiccup logs everyone out.
|
||||
- **`Constant/Variable.tsx` socket host** — hardcoded to a single origin; no failover.
|
||||
|
||||
---
|
||||
|
||||
## 11. Security Risks
|
||||
|
||||
> Full evidence in the security appendix; the highest-priority items:
|
||||
|
||||
| Severity | Risk | Evidence |
|
||||
|----------|------|----------|
|
||||
| 🔴 Critical | **Signing keystore committed to git** (`.gitignore` `*.keystore` missed it — no extension) + **release signed with debug key** (`storePassword 'android'`). Forgeable/ tamperable APKs. | `android/app/appKeyStore` (git-tracked, verified), `build.gradle:88-104` |
|
||||
| 🔴 Critical | **Global request/response logger dumps JWTs, passwords, Aadhaar/PAN/OTP, and sealed-bid values to logcat in release** (no `__DEV__` gate). 378 `console.*` calls across 34 files, none stripped (no `transform-remove-console`). | `Axios/Axios.ts:47-99`, `Login.tsx:213-216`, `encrypt.tsx:30-155`, `TenderBidding.tsx:474,561` |
|
||||
| 🔴 Critical | **Committed SonarQube auth token.** | `sonar-project.properties:13` (verified git-tracked) |
|
||||
| 🟠 High | **App-wide cleartext HTTP permitted in release + no SSL pinning.** A hardcoded `http://` base with attached Bearer token also lives in `client.ts`. | `network_security_config.xml`, `AndroidManifest.xml:19`, `api/client.ts:6` |
|
||||
| 🟠 High | **JWT + full login response persisted unencrypted in AsyncStorage.** Readable on rooted/backed-up devices. No Keychain/Keystore/EncryptedStorage. | `Redux/Store.js:20-24`, `Login.tsx:212` |
|
||||
| 🟠 High | **Device binding is client-spoofable** (`getUniqueId()`/`getIpAddress()`, no Play Integrity attestation) and **silently falls back to fabricated GPS coords** on permission denial. This is the *fraud control* for bidding. | `DeviceBinding.tsx:47-86` |
|
||||
| 🟠 High | **Weak sealed-bid crypto:** AES-**ECB** mode, SHA-256 key **truncated to 128 bits**, and the symmetric key is **echoed back to the server in plaintext alongside the ciphertext** (`randomKeyGenerated`) — adding no real confidentiality. | `encrypt.tsx:9-71`, `TenderBidding.tsx:546` |
|
||||
| 🟡 Medium | **WebView KYC success detected by page-title string match** (spoofable); loads **raw server-supplied HTML** with JS enabled; logs Aadhaar callback URLs. | `KycWebViewScreen.tsx:85-143` |
|
||||
| 🟡 Medium | **No root/tamper/Frida detection, no `FLAG_SECURE`** (sealed bids & Aadhaar OTP are screenshot-/screen-recordable and appear in the app-switcher thumbnail), **no ProGuard/R8** minification. | grep-confirmed absent; `build.gradle:60,104` |
|
||||
| 🟡 Medium | **`loginWithoutDecryption` endpoints** + **`ResetPassword` sends new password as a URL query param** (`?newPassword=...`) — lands in server/proxy logs. | `apis.ts:29-46`, `ResetPassword.tsx:220` |
|
||||
| 🟡 Medium | **Repo-committed bulk-user script with default password `P@ssword123`** targeting the live backend. | `scripts/create-users.js:10` |
|
||||
|
||||
## 12. Privacy Risks
|
||||
|
||||
- **Regulated PII logged in the clear.** Full Aadhaar number, PAN, GST, DOB are `console.log`-ed (`Ragistration.tsx:363`) and the **Aadhaar OTP is displayed in an `Alert` dialog** (`Ragistration.tsx:422`). Under UIDAI/Aadhaar Act and India's DPDP Act, logging full Aadhaar is a compliance exposure, not just a bug.
|
||||
- **PII travels over a transport that permits cleartext** (§11) and through the global logger (§11) on every request.
|
||||
- **No data-minimization or masking layer** anywhere — the app has no concept of "sensitive field."
|
||||
- **Unjustified permissions:** `READ_MEDIA_AUDIO` (no audio feature) and always-on FINE+COARSE location whose only use is a device-binding geo-tag that fabricates coordinates anyway.
|
||||
- **Cached profile PII** (from `getcontractorfulldetails`) may persist unencrypted via React Query + any persisted slice.
|
||||
|
||||
## 13. Scalability Risks
|
||||
|
||||
- **Team scalability** is the nearer-term problem than user scalability: no module boundaries, god-components, and duplicated screens mean two developers *cannot* work on bidding without colliding, and every change risks the forward/reverse drift.
|
||||
- **No env/config abstraction** ⇒ dev/staging/prod require source edits and recompiles; you cannot run a QA build against staging without a code change. This blocks a release pipeline.
|
||||
- **The error-swallowing data layer** means production incidents are invisible (no error surfaced, bad data cached as good) — you scale the user base but lose the ability to see failures.
|
||||
- **No observability** (no crash reporting, no analytics, no structured logging) — at 10k+ users you'd be flying blind.
|
||||
- **Backend coupling by string concatenation** (`${BASE_URL}path?query=`) with no client SDK/contract means backend changes break the app silently.
|
||||
|
||||
## 14. Performance & Battery Risks
|
||||
|
||||
- Refetch storms (§7), per-second timer re-renders (§7), whole-list re-renders on bid ticks (§7).
|
||||
- **Leaked STOMP connections** (no unmount disconnect) keep reconnecting every 5s with 1s heartbeats — a measurable battery/data drain when a user leaves a bidding screen without killing the app.
|
||||
- **No `getItemLayout`** on any list — every list pays layout measurement cost.
|
||||
- **No release minification/shrinkResources** — larger APK, and no ABI splits/App Bundle so users download all architectures.
|
||||
- **Duplicate heavy libs shipped:** `exceljs` **and** `xlsx`; `react-native-fs` **and** `react-native-blob-util`; two icon systems — dead weight in the bundle.
|
||||
|
||||
## 15. Maintainability Risks
|
||||
|
||||
- **~26k LOC, zero tests, no CI, lint/format enforced only by developer discipline** (no husky/lint-staged). There is no automated safety net for any refactor.
|
||||
- **`.jsx`/`.js` files bypass TypeScript** entirely (`Store.js`, `MainStack.jsx`, `Routes.jsx`, `ImagePath.jsx`).
|
||||
- **Duplication tax:** every bidding change is a 2-file (often 4-file) edit; the two color palettes and two component roots triple the surface for any visual change.
|
||||
- **`any` everywhere** (navigation, selectors, socket callbacks, `apiCall` generics) — the compiler cannot help.
|
||||
- **Dead code** (`AllUrls.tsx`, `DrawerStack`, `CustomDrawer`, generic hooks, `useLogin`, `userLogin`) increases cognitive load and hides which path is live.
|
||||
|
||||
---
|
||||
|
||||
## 16. AI System Evaluation
|
||||
|
||||
**Finding: there is no AI subsystem in this codebase.** No LLM/model integration, no agent/orchestration layer, no intent recognition, no task planning, no RAG/retrieval, no knowledge graph, no vector/embedding index, no voice pipeline, no local or cloud inference. Grep confirms none of the associated libraries or patterns are present.
|
||||
|
||||
I'm flagging this plainly because the brief framed the review around an "AI-powered operating system," and a Principal Engineer's job is to challenge the premise rather than invent findings. **An e-procurement bidding app does not need any of that to succeed, and bolting an "AI OS" onto the current foundation would be a strategic mistake** — you'd be building a second story on a cracked foundation (committed keys, cleartext transport, error-swallowing data layer).
|
||||
|
||||
If AI capabilities *are* a genuine roadmap goal, here is the honest prerequisite ordering and what each would require:
|
||||
|
||||
1. **Fix the foundation first** (§17–19). An AI feature that calls a cloud LLM over the current cleartext-permitted transport, logging prompts (which would contain tender/bid PII) through the global logger, is a data-leak generator.
|
||||
2. **Realistic, high-value AI features for *this* domain** (in priority order):
|
||||
- **Tender discovery & ranking** — semantic search over live tenders (embeddings + a vector index server-side; the app just calls a ranked-search endpoint). Low risk, high user value.
|
||||
- **Document intelligence** — extract/summarize tender documents and envelope requirements (server-side LLM + RAG over the tender corpus; app renders results).
|
||||
- **Bid-assist / anomaly detection** — flag unusual bid patterns or missing mandatory documents before submission (server-side).
|
||||
- **Conversational support agent** — scoped, tool-using assistant answering "what tenders match my class?" via typed tool calls to existing endpoints.
|
||||
3. **Architectural requirement:** all of the above should be **server-mediated** (model keys never on-device; PII never sent to a third-party model without consent + DPA). The mobile app's role is a thin, typed client to an AI *gateway* service — which is exactly the clean data-layer boundary §17 prescribes. **Build the clean API/domain layer, and AI features become just more endpoints behind it.**
|
||||
|
||||
**Verdict:** AI is a *future* concern gated on foundation work. Do not start it now.
|
||||
|
||||
---
|
||||
|
||||
## 17. Android System Evaluation
|
||||
|
||||
- **Build config is not release-ready.** No release keystore (debug-signed release), no minify/shrink/ProGuard, no ABI splits or App Bundle, hardcoded `versionCode 1`/`versionName 1.0` with no bump automation.
|
||||
- **New Architecture + Hermes are on** (good, modern), and confirmed in native host code (`MainApplication.kt`). No custom native modules — everything is JS + autolinked libs, which keeps the native surface small but means device-binding/DSC/crypto get *no* native security guarantees (no Keystore-backed keys, no attestation).
|
||||
- **Manifest:** app-wide cleartext, no orientation lock, single exported `MainActivity` with only MAIN/LAUNCHER (no deep links). `allowBackup=false` is correct.
|
||||
- **Cross-platform:** iOS project exists and is set up (`ios/` with Podfile, AppDelegate.swift, PrivacyInfo.xcprivacy) — this is *not* Android-only, so all remediation must be applied per-platform (e.g. ATS on iOS mirrors the network-security-config fix).
|
||||
- **Tooling gaps:** no tests, no CI/CD (`.github` contains only a Java-upgrade tooling artifact), stock ESLint/Prettier with no enforcement, committed Sonar token pointing at `localhost:9000` scanning `node_modules`.
|
||||
|
||||
## 18. Data Architecture Review
|
||||
|
||||
**Current:** string-concatenated endpoints off a hardcoded base, four transport styles, error-swallowing wrapper, mis-configured React Query, plaintext persisted auth, three backend hosts.
|
||||
|
||||
**Target (see §20):** one typed API client → a **domain/repository layer** (feature-scoped: `auth`, `tenders`, `auctions`, `bidding`, `kyc`, `profile`) → React Query hooks with correct keys/`staleTime`/invalidation → screens. Errors *thrown* and normalized once. Secrets in secure storage. Env-driven base URLs. This is the highest-leverage change in the whole document.
|
||||
|
||||
## 19. UX Architecture Review
|
||||
|
||||
- **Strong primitives, inconsistent application.** `AppText` + `useTheme` are good, but per-element inline styles + `color=` overrides dilute the tokens, and half the app uses the *other* palette/components.
|
||||
- **No accessibility** (zero `accessibilityLabel`/`Role`/`Hint` — icon-only touchables and steppers are unusable with TalkBack), **no i18n** (hardcoded English + inline `₹`), **no responsive scaling** (fixed pixels), **no error boundary** (an unhandled render error crashes the app; warnings are globally silenced).
|
||||
- **Inconsistent loading/empty/error states** — no shared wrapper; main lists lack `ListEmptyComponent`; most `catch` blocks only `console.log`, so React Query `isError` never reaches the user.
|
||||
- **Forms are backwards:** the *simplest* screens (Login, SignUp) use Formik+Yup; the *hardest* (multi-step registration, envelope bidding) use hand-rolled `useState` state machines.
|
||||
|
||||
---
|
||||
|
||||
## 20. Recommended Target Architecture
|
||||
|
||||
**Principle:** feature-modular, layered, with dependencies pointing inward (Clean/Hexagonal). The mobile app is a *thin typed client* over well-defined domain boundaries.
|
||||
|
||||
```
|
||||
app/
|
||||
├─ core/ # cross-cutting, no feature knowledge
|
||||
│ ├─ config/ env.ts # ← react-native-config; NO hardcoded hosts
|
||||
│ ├─ http/ client.ts # ONE axios instance; throws on error
|
||||
│ │ interceptors # auth (single token read), tracing, refresh
|
||||
│ ├─ storage/ secure.ts # react-native-keychain for token; MMKV/AsyncStorage for prefs
|
||||
│ ├─ crypto/ envelope.ts # AES-GCM (not ECB), key never echoed to server
|
||||
│ ├─ realtime/ stomp.ts # subscribe in useEffect; disconnect on unmount
|
||||
│ ├─ errors/ AppError.ts # normalized error type + ErrorBoundary
|
||||
│ ├─ observability/ # crash reporting + structured, PII-scrubbed logging (DEV-gated)
|
||||
│ └─ ui/ # ONE design system: AppText, Button, Input, Modal, List, tokens
|
||||
├─ features/
|
||||
│ ├─ auth/ { api, hooks, screens, state }
|
||||
│ ├─ tenders/ { api, hooks, screens }
|
||||
│ ├─ auctions/ { api, hooks, screens }
|
||||
│ ├─ bidding/ { api, hooks, screens } # forward+reverse UNIFIED via config/props
|
||||
│ ├─ kyc/ { api, hooks, screens }
|
||||
│ └─ profile/ { api, hooks, screens }
|
||||
├─ navigation/ RootNavigator # typed ParamList; Auth vs App stack split; deep linking
|
||||
└─ App.tsx # QueryClient (module-const, tuned defaults) + ErrorBoundary + providers
|
||||
```
|
||||
|
||||
**Key decisions & justifications:**
|
||||
|
||||
| Decision | Replaces | Principle |
|
||||
|----------|----------|-----------|
|
||||
| **One `apiClient` that throws typed `AppError`** | 4 stacks + error-swallowing | Single Responsibility; lets React Query do retry/error/cache; restores TypeScript safety |
|
||||
| **`react-native-config` env files** (dev/staging/prod) | Hardcoded/commented hosts | 12-factor config; enables CI + QA builds without code edits |
|
||||
| **`react-native-keychain` for token**, MMKV for prefs | Plaintext AsyncStorage | Defense in depth for auth/PII |
|
||||
| **Typed navigation** (`RootStackParamList`) + **Auth/App stack split** | `any` + imperative Splash gate | Compile-time route safety; declarative auth gating; enables deep links |
|
||||
| **Feature modules** (`api/hooks/screens` per domain) | Type-folders + god-components | High cohesion, low coupling; two devs work without collision |
|
||||
| **Unify forward/reverse bidding** behind one config-driven screen | 90% duplicated forks | DRY; one place to fix bugs |
|
||||
| **One design system** (`core/ui`), delete `src/Component` + one palette | Split-brain components/colors | Single source of visual truth |
|
||||
| **AES-GCM, key wrapped by server RSA public key, never echoed back** | AES-ECB + echoed key | Actual confidentiality for sealed bids |
|
||||
| **`transform-remove-console` + PII-scrubbing logger, DEV-gated** | 378 raw console calls | Privacy/compliance |
|
||||
| **Server-mediated integrity** (Play Integrity / SafetyNet) for device binding | Client-spoofable IDs | Real anti-fraud |
|
||||
| **ErrorBoundary + shared Loading/Empty/Error wrappers** | Per-screen ad-hoc + crashes | Consistent, resilient UX |
|
||||
|
||||
---
|
||||
|
||||
## 21. Migration Roadmap
|
||||
|
||||
Sequenced so each phase is shippable and de-risks the next. **Phase 0 is non-negotiable and blocks release.**
|
||||
|
||||
### Phase 0 — Security stop-the-bleed (days, do first)
|
||||
1. **Rotate and remove signing keys from git.** Purge `appKeyStore` + `debug.keystore` from history (`git filter-repo`), rotate on Play Console if `appKeyStore` was the release key, move signing to `keystore.properties` (gitignored) / CI secrets. Create a real release signing config.
|
||||
2. **Rotate the leaked Sonar token**, remove it from `sonar-project.properties`, fix `sonar.sources` to exclude `node_modules`.
|
||||
3. **Gate/remove the global logger** behind `__DEV__` + add `babel-plugin-transform-remove-console` for release; scrub PII. Remove `TestScreen/DecryptionScreen` and the hardcoded key.
|
||||
4. **Disable cleartext** (`usesCleartextTraffic=false`, restrictive network-security-config for release; iOS ATS) once backends are HTTPS. Fix/remove the `http://` `client.ts`.
|
||||
5. **Move the token to Keychain**; stop persisting the full login response.
|
||||
6. **Move `jsencrypt` to `dependencies`** (latent prod outage).
|
||||
|
||||
### Phase 1 — Data-layer consolidation (1–2 sprints)
|
||||
7. Introduce `core/config` env + a **single throwing `apiClient`**; migrate feature by feature off `apiCall`/raw axios/`client.ts`. Delete `AllUrls.tsx` and the dead generic hooks.
|
||||
8. Tune `QueryClient` defaults (`staleTime`, `retry`), fix query keys, add `enabled` guards and `invalidateQueries` on mutations. Move `QueryClient` to a module const.
|
||||
9. Add typed `RootState`/`AppDispatch`; fix the token slice type; unify logout on `persistor.purge()` + Keychain clear + socket disconnect + query cache clear.
|
||||
|
||||
### Phase 2 — Structure & correctness (2–3 sprints)
|
||||
10. Typed navigation + **Auth/App stack split**; move Splash gating into declarative navigator logic.
|
||||
11. **Unify forward/reverse bidding** and the two card components into one config-driven module; move `subscribe` into `useEffect` with cleanup; disconnect on unmount.
|
||||
12. Break up `TenderBidding`/`ProfileTab`/`Ragistration`: extract crypto, API, and validation into `core`/feature modules; convert registration to a reducer/state machine (or Formik).
|
||||
13. Fix crypto (AES-GCM, no echoed key); add `FLAG_SECURE` to bidding/KYC; add Play Integrity to device binding.
|
||||
|
||||
### Phase 3 — Consistency & platform (2 sprints)
|
||||
14. Collapse to **one design system + one palette**; delete `src/Component` and `Constant/Color` after migration. Add ErrorBoundary + shared state wrappers.
|
||||
15. Add responsive scaling + accessibility labels; introduce i18n scaffolding (even if only `en` at first).
|
||||
16. Remove duplicate deps (`xlsx` or `exceljs`; `fs` or `blob-util`; one icon lib); enable release minify/shrink + App Bundle + ABI splits; automate version bumps.
|
||||
|
||||
### Phase 4 — Quality gates (ongoing, start in Phase 1)
|
||||
17. CI (GitHub Actions): install → typecheck → lint → test → build. Add husky + lint-staged.
|
||||
18. Testing: unit tests for `core/http`, crypto, and domain hooks; component tests for the design system; a Detox smoke test for login→bid. Add crash reporting + analytics.
|
||||
|
||||
## 22. Prioritized Refactoring Plan (single ranked backlog)
|
||||
|
||||
| Rank | Item | Effort | Risk if skipped |
|
||||
|------|------|--------|-----------------|
|
||||
| 1 | Purge & rotate committed keys; real release signing | S | Critical — forgeable app |
|
||||
| 2 | DEV-gate/strip logging; scrub PII | S | Critical — credential/PII leak |
|
||||
| 3 | Rotate Sonar token | XS | Critical — exposed secret |
|
||||
| 4 | HTTPS-only + kill cleartext + fix `client.ts` | S | High — MITM |
|
||||
| 5 | Token → Keychain; stop persisting login response | S | High — PII at rest |
|
||||
| 6 | `jsencrypt` → dependencies | XS | High — prod crypto outage |
|
||||
| 7 | Single throwing `apiClient` + env config | M | Critical — invisible failures, no envs |
|
||||
| 8 | React Query defaults + keys + invalidation | M | High — stale data, refetch storms |
|
||||
| 9 | Typed navigation + Auth/App split | M | High — no auth enforcement |
|
||||
| 10 | Unify bidding forward/reverse + socket cleanup | M | High — drift + leaks |
|
||||
| 11 | Break up god-components | L | High — unmaintainable |
|
||||
| 12 | Crypto (AES-GCM) + FLAG_SECURE + Play Integrity | M | High — weak sealed bids/fraud |
|
||||
| 13 | One design system + one palette | L | Medium — visual drift |
|
||||
| 14 | ErrorBoundary + shared states + a11y + i18n | M | Medium — UX/compliance |
|
||||
| 15 | Dedup deps + release optimization + CI/CD + tests | M | Medium — quality/velocity |
|
||||
|
||||
## 23. Risk Assessment (residual, if nothing is done)
|
||||
|
||||
- **Compliance/legal:** logging full Aadhaar + storing PII in plaintext over cleartext-capable transport is a DPDP/UIDAI exposure — **the highest business risk**, not merely technical.
|
||||
- **Financial fraud:** spoofable device binding + UI-only DSC + weak sealed-bid crypto undermine the integrity guarantees a tendering platform legally depends on.
|
||||
- **Supply-chain/integrity:** committed + debug signing key means a malicious actor with repo access (or the public debug key) can distribute a trojaned "ProcureLinc."
|
||||
- **Operational:** error-swallowing + no observability means production incidents are silent; you learn about outages from users, not dashboards.
|
||||
- **Velocity:** duplication + god-components + no tests means feature velocity *decreases* as the app grows, and every bidding change risks a regression in the un-fixed twin.
|
||||
|
||||
## 24. Future Vision
|
||||
|
||||
Once the foundation is fixed, ProcureLinc is well-positioned:
|
||||
|
||||
- **Short term (foundation solid):** a secure, observable, typed, feature-modular app where two teams can build tenders and auctions in parallel; QA runs against staging without code edits; releases are automated and signed correctly.
|
||||
- **Medium term:** offline-first for tender/auction browsing (React Query persistence + optimistic bid queueing over a resilient socket), full accessibility + i18n for a national user base, and a real design system that supports white-labeling for multiple procurement authorities.
|
||||
- **Long term (only after the above):** the AI features in §16 — semantic tender discovery, document intelligence, bid-assist — added as *endpoints behind the clean data layer*, with all model access server-mediated and PII-governed. The "AI-powered OS" framing is better realized as **an intelligent procurement platform with a thin, secure mobile client**, not an AI runtime on the device.
|
||||
|
||||
**The single most important sentence in this report:** *Fix the security foundation and consolidate the data layer first; every other improvement — modularity, design system, testing, and eventually AI — compounds cleanly on top of those two, and none of them is safe or durable without them.*
|
||||
|
||||
---
|
||||
|
||||
### Appendix A — Evidence index (key files)
|
||||
- Data/transport: `src/Axios/Axios.ts`, `src/api/client.ts`, `src/Services/ApiCall/{apis.ts,ApiUrls.tsx,Hooks.ts}`, `src/Hooks/use{Fetch,Create,Update,Delete}.ts`, `src/Constant/{Variable.tsx,AllUrls.tsx}`
|
||||
- State: `src/Redux/Store.js`, `src/Redux/Slices/*`
|
||||
- Realtime/crypto: `src/socket/Socket.tsx`, `src/Services/Encryption/encrypt.tsx`
|
||||
- UI: `src/Screens/Tender/tenderBidding/TenderBidding.tsx`, `src/Screens/Bidding/{StartBidding,StartReverseBidding,Emd}.tsx` + `Component/{BiddingCard,ReverseBiddingCard}.tsx`, `src/Screens/Ragistration/Ragistration.tsx`, `src/Screens/Tender/LiveTender.tsx` (good template), `src/components/AppText.tsx`
|
||||
- Navigation: `src/Navigation/{MainStack.jsx,Bottom.tsx,NavigationService.ts}`, `src/Screens/Splash/Splash.tsx`
|
||||
- Android/build: `android/app/build.gradle`, `android/gradle.properties`, `android/app/src/main/{AndroidManifest.xml,res/xml/network_security_config.xml}`, `android/app/appKeyStore` (remove), `sonar-project.properties` (remove token)
|
||||
- Security-sensitive: `src/Screens/Home/KycWebViewScreen.tsx`, `src/Screens/Tender/{DeviceBinding,DscBinding}.tsx`, `src/Screens/TestScreen/DecryptionScreen.tsx` (remove), `scripts/create-users.js`
|
||||
@@ -0,0 +1,15 @@
|
||||
# Mobile bid encryption contract
|
||||
|
||||
The mobile client uses the server-issued envelope key `K` for all bid
|
||||
submissions. For text values, encrypt with AES-128/ECB/PKCS5 using the first
|
||||
16 bytes of SHA-256(`K`) and send Base64 ciphertext. For the Envelope-C BOQ,
|
||||
encrypt the raw workbook bytes with AES-128/ECB/PKCS5 using the first 16 bytes
|
||||
of SHA-1(`K`) and upload the raw ciphertext bytes as the multipart `file`.
|
||||
|
||||
The same `K` must be sent as `randomKeyGenerated` and RSA-wrapped with every
|
||||
officer/contractor public key in `saveEnvelopesOfficersDetailsResDTO`.
|
||||
|
||||
Envelope-C `requestDto` includes `deviceType: "Mobile"`, `fieldValue`,
|
||||
`fieldValueInWord`, `hashValue` (SHA-256 of the unencrypted workbook bytes),
|
||||
`fileName`, and the wrapped officer keys. The workbook editor preserves the
|
||||
source workbook structure and only applies permitted cell edits.
|
||||
Reference in New Issue
Block a user