Skip to content

Fintech Super App refresh — React Native micro-frontends showcase#170

Merged
V3RON merged 46 commits into
mainfrom
super-app-showcase-refresh
Jul 7, 2026
Merged

Fintech Super App refresh — React Native micro-frontends showcase#170
V3RON merged 46 commits into
mainfrom
super-app-showcase-refresh

Conversation

@burczu

@burczu burczu commented May 7, 2026

Copy link
Copy Markdown
Contributor

Summary

A full rebuild of the Super App Showcase into a production-grade Fintech demo app demonstrating React Native micro-frontend architecture with Re.Pack and Module Federation V2.

  • Trading mini app — live crypto asset list (Kraken WebSocket), Skia chart with OHLC history, trade bottom sheet and success screen, Reanimated flash animations
  • Wallet mini app — real-time portfolio balance, per-asset holdings with live value updates
  • Auth mini app — dark Fintech sign-in screen, AuthProvider gating the tab bar
  • SDK — singleton KrakenWebSocketService shared across all mini apps, PriceProvider, hooks, utilities
  • Host shell — dark theme, native bottom tabs, MF remote wiring, React Compiler

Key patterns demonstrated

  • Leaf-component isolation (PriceCell, ValueCell) so only the price node re-renders on ticks
  • useTransition / startTransition marking price updates as non-priority
  • Shared singleton WebSocket — one connection across Trading and Wallet via MF
  • Historical chart seeding from Kraken OHLC REST API
  • TypeScript MF module declarations for all federated remotes

What's in this PR

  • Full app implementation (US-1 through US-9)
  • Bug fixes from Codex review (auth bootstrap state, Jest setup, TS declarations, stale configs)
  • Performance improvements (PriceCell/ValueCell leaf split, startTransition on chart, useFlashAnimation in SDK)
  • Docs: rewritten README with screenshots, GIF, architecture diagram, and docs/MODULE_FEDERATION_DEMO_GUIDE.md

Still to do (post-merge)

  • Fill in _TBD_ bundle size and CI time tables in MODULE_FEDERATION_DEMO_GUIDE.md with real measured numbers

🤖 Generated with Claude Code

burczu and others added 30 commits April 27, 2026 14:06
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add react-native.config.js to trading and wallet so react-native start
  uses Re.Pack/Rspack instead of falling back to Metro (root cause of
  servers never starting)
- Add resolve.modules to trading/wallet rspack configs so rspack finds
  native peer deps (reanimated, skia, victory-native, etc.) in host's
  node_modules at build time
- Add @swc/helpers and react as devDependencies in sdk so SWC-injected
  helper imports resolve when rspack processes sdk TypeScript source
- Declare native libs and super-app-showcase-sdk as MF shared singletons
  so host provides one JS instance per native module bridge and one
  PriceContext/KrakenWebSocketService across all mini apps
- Add GestureHandlerRootView to host App.tsx root (trading exposes
  MainNavigator directly, not App, so the standalone wrapper never ran)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Required for Reanimated 4 worklet transpilation in host, trading, and wallet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add babel-plugin-react-compiler to host, trading, and wallet for
  automatic memoization with React 19
- Add ConnectionStatus type and onStatusChange() to KrakenWebSocketService
  with connecting / connected / reconnecting / disconnected states
- Add useConnectionStatus() hook exported from sdk
- Show "Connecting to market…" / "Reconnecting…" banner in AssetListScreen
  and WalletScreen until first BTC price tick arrives (not just until WS
  connects — ensures banner is visible on every cold open of the tab)
- Rewrite README for Fintech Super App: ASCII architecture diagram, stack
  table, package roles, setup instructions, port reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Trading tab: chart.line.uptrend.xyaxis
Wallet tab: creditcard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add react-native-bottom-tabs and @bottom-tabs/react-navigation as MF
shared singletons so trading mini app reads the same
BottomTabBarHeightContext provided by host's tab navigator. Use
useBottomTabBarHeight() in AssetDetailsScreen to compute the exact
native tab bar height (including home indicator) instead of guessing
with safe area insets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plain React refs are not readable inside Reanimated worklets (UI thread),
causing the flash to always use the initial value (green). Replacing with
useSharedValue makes the direction correctly accessible on the UI thread.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hoist @types/* packages to root node_modules via public-hoist-pattern in .npmrc so TypeScript can find them across all workspace packages
- Add getSharedDependencies as a TypeScript implementation in sdk/src so it is accessible via the react-native exports condition (customConditions in @react-native/typescript-config)
- Add missing peer deps as devDependencies in trading (reanimated, gesture-handler, bottom-sheet, victory-native) and wallet (reanimated) so pnpm symlinks them for IDE resolution
- Add resolveJsonModule to sdk tsconfig and index.d.ts for the CJS entry point

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
public-hoist-pattern[]=@types/* in .npmrc was hoisting @types/react to root
node_modules, which pnpm picked up as an optional peer when resolving
react-native. Packages with and without typescript in scope then produced two
distinct peer-resolution hashes, creating separate physical instances of
react-native, react-native-reanimated, and react-native-worklets. Rspack
resolved each from a different path, causing both initialisation routines to
run in the same binary and triggering "RCTText registered twice".

Fixes:
- Remove public-hoist-pattern for @types/* from .npmrc
- Add @types/react and typescript devDeps to sdk so its react-native peer hash
  matches host/trading/wallet (single instance across all packages)
- Replace native devDeps in trading/wallet with tsconfig paths pointing to
  ../host/node_modules so the IDE can resolve types without pnpm creating
  duplicate instances
- Regenerate pnpm-lock.yaml; now a single instance of react-native,
  react-native-reanimated, and react-native-worklets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add TypeScript-source exports consumed by mini apps via the react-native
package-exports condition (customConditions: ["react-native"]):

- sharedDeps.ts: TS implementation of getSharedDependencies, fixing TS2305 in
  rspack.config.ts files that import it from the SDK
- theme.ts: shared colors constant (was duplicated in trading and wallet)
- utils/formatPrice.ts: shared formatPrice/formatValue helpers
- components/ConnectionBanner.tsx: single source-of-truth for the live WS
  connection status banner (was duplicated in trading and wallet)
- constants.ts: add ASSET_MAP for O(1) symbol lookup
- index.ts: re-export all new symbols plus ConnectionStatus type

Delete index.d.ts which was shadowing the react-native source entry and
breaking host typecheck under moduleResolution: node.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
trading:
- Delete ConnectionBanner (now from SDK)
- AssetRow: extract flash-animation logic into useFlashAnimation hook,
  replace inline price formatter with formatPrice from SDK
- AssetDetailsScreen: merge split reanimated imports, use formatPrice from SDK
- AssetListScreen: import ConnectionBanner from SDK

wallet:
- Delete ConnectionBanner (now from SDK)
- HoldingRow: remove ASSETS.find lookup (caller now passes asset prop),
  extract flash-animation into useFlashAnimation hook, use formatPrice/
  formatValue from SDK
- WalletScreen: fix TotalBalance calculation (was returning hardcoded 0 for
  assets not in a static map), use ASSET_MAP for O(1) lookup, pass asset prop
  to HoldingRow

Flash animation is kept as a local hook in each mini app rather than exported
from SDK to avoid pulling react-native-reanimated into the SDK peer graph.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AuthProvider:
- Replace loose {type, token} action shape with a discriminated union so
  each action carries only the fields it needs and the reducer is exhaustive
- signIn/signUp: dispatch only after SecureStore.setItem resolves, not after
  the catch block, so a storage failure never puts the app in a signed-in state
- signOut: dispatch unconditionally (storage failure is best-effort; the user
  is still considered signed out in JS)

AuthService:
- Mark TOKEN_KEY as private readonly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tubs

React Navigation v7 removed the independent prop from NavigationContainer.
The mini-app standalone App.tsx files (used only for local dev without a host)
were passing independent={true}, causing a TS2322 type error. The prop is not
needed here since there is no outer navigation context when running standalone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add useHistoricalPrices(krakenPair) hook to SDK that fetches the last 60
one-minute candles from Kraken's public OHLC REST endpoint on mount and
returns the close prices as number[].

AssetDetailsScreen seeds its 60-tick buffer from this data so the chart
renders immediately on open. A seededRef ensures the seed runs exactly once
— it fires on the first non-empty response regardless of any live WebSocket
ticks that may have already landed in the buffer. Subsequent ticks continue
appending as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use victory-native's yAxis prop to render 4 price tick labels on the right
side of the chart. Labels are formatted as compact values ($95.2k for prices
≥ 1000, $150 for ≥ 1, $0.452 for sub-dollar assets). Font is resolved via
Skia's matchFont using the system font, with a null fallback so the chart
renders gracefully if font loading fails.

Add @shopify/react-native-skia to trading's tsconfig paths so TypeScript
resolves the import from host/node_modules without a devDep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ction

- Delete duplicate theme.ts from trading and wallet; all files now import
  colors directly from super-app-showcase-sdk
- Add getAssetIconUri(symbol) util to SDK; remove inline ICON_BASE_URL
  constant that was duplicated in AssetRow and HoldingRow
- Fix ConnectionBanner: was hiding when btcPrice > 0 (fragile BTC proxy);
  now hides when status === 'connected' using useConnectionStatus directly
- Restyle AccountScreen to match the app's dark Fintech theme; remove
  react-native-paper dependency and MD3Colors from this screen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Account tab to TabsNavigator with person.crop.circle SF Symbol
- Wrap AccountScreenRemote in a NativeStackNavigator so the "Account"
  title renders in a native header matching the Wallet/Trading pattern
- Restyle AccountScreen: ScrollView content area with 16px padding,
  Sign Out button pinned to the bottom above the tab bar using
  useBottomTabBarHeight, styled to match the Trade button (primary color)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore the original problem → solution → app → architecture sections
updated for the Fintech Super App refresh. Covers the full stack, package
structure, key design decisions (shared singletons, peer deps in host,
useTransition for price updates), and setup/running instructions.

Two TODO markers left for owner to fill in: app screenshot/GIF and
updated architecture diagram image.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 250–350ms random delay to each mini app lazy import so the
  Suspense fallback is visible during demos
- Restyle Placeholder and SplashScreen to use the dark theme background
  with a primary-blue ActivityIndicator, replacing white SafeAreaView
  with MD3Colors that were inconsistent with the rest of the app

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d bottom-tabs mocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
burczu and others added 12 commits May 6, 2026 13:21
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ice ticks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e-renders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@V3RON V3RON marked this pull request as ready for review June 29, 2026 13:14
@dannyhw

dannyhw commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator
  • on android I get some some flickering when navigating
  • bottom sheet not reacting to keyboard presenting
  • android bottom tabs not showing icons
  • light mode on android shows a white bottom tabs with a dark background which is a bit jarring
image android-screenshot
androidnavigationcompressed.mp4

borisyankov and others added 3 commits July 1, 2026 16:31
## What

Removes the `@react-native/community-cli-plugin` patch, which is no
longer needed.

## Why

The patch replaced `node-fetch` with the global `fetch` and dropped the
`node-fetch` dependency. It was written for an older React Native
version. The currently installed **0.84.1 already uses native `fetch`
upstream** (`var _util = require("util")`, no `node-fetch`), so the
patch had become a no-op leftover.

The `react-native-paper` icon patch is intentionally **kept** — it's
still required to point paper at the installed
`react-native-vector-icons/MaterialCommunityIcons` (it was just
refreshed in b4a49de).

## Changes

- `package.json` — removed the `@react-native/community-cli-plugin`
entry from `pnpm.patchedDependencies`
- `patches/@react-native__community-cli-plugin.patch` — deleted (210
lines)
- `pnpm-lock.yaml` — regenerated; the package now resolves without
`patch_hash`

## Verification

- `pnpm install` succeeds with the patch removed
- The unpatched 0.84.1 dist still uses native `fetch`
(`OpenDebuggerKeyboardHandler.js`, `isDevServerRunning.js`) — no
`node-fetch` import remains
- Lockfile diff confirms the dependency resolves without the patch hash

---------

Co-authored-by: Daniel Williams <me@dannyhw.com>
@V3RON

V3RON commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@dannyhw Keyboard should now behave correctly for the trading bottom sheet. I don't see other issues you mentioned, they were most-likely fixed in the #172

@dannyhw

dannyhw commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

@V3RON i first saw the issues on #172 actually maybe I can retry on this branch after a rebuild 🤔
it was on a pixel 7 physical device just in case that matters

@dannyhw

dannyhw commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Ok looks like its all resolved now after I pull latest changes and rebuild

theres one thing maybe worth looking at with the bottomsheet behind the tabs

image

@dannyhw

dannyhw commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

see if this looks ok #173

### Summary

Fixes spacing for the trading flow around the native bottom tab bar.

The trade bottom sheet now receives the tab bar inset from the asset
details screen and uses it as bottom content padding, so the sheet
content stays clear of the tabs while the sheet can still present from
the bottom. The trade button footer also keeps compact Android padding
while preserving iOS tab bar clearance.

The iOS tab bar height can briefly report as zero on initial render, so
the details screen uses a standard tab bar height plus safe-area inset
as a fallback.

### Test plan

- Open an asset details screen on iOS and tap Trade. Confirm the bottom
sheet actions are not covered by the tab bar.
- Focus the amount input on iOS. Confirm the sheet works with the
keyboard open and with keyboard closed
- Open an asset details screen on Android. Confirm the sheet works with
the keyboard open and with keyboard closed

<img width="443" height="897" alt="image"
src="https://github.com/user-attachments/assets/3c32a77b-7b43-48db-8156-f09c38c7d102"
/>

<img width="443" height="897" alt="image"
src="https://github.com/user-attachments/assets/04ac0191-ff90-44f5-9d57-f4437a6cb018"
/>

---------

Co-authored-by: Szymon Chmal <szymon@chmal.it>
@V3RON V3RON merged commit 97e39e4 into main Jul 7, 2026
3 checks passed
@V3RON V3RON deleted the super-app-showcase-refresh branch July 7, 2026 06:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants