- State applied rule tags briefly (e.g.
rules: style, tests, feature-flags). - When blocked, ask up to 3 yes/no clarifiers in one message; otherwise proceed.
- Do not apologize or add filler; respond with facts or code.
- Prefer execution (edits, tests, lint) over advisory text.
Multi-tenant white‑label fintech platform. Two personas: Admin (configure, price, brand, monitor) & Agent (transact, wallet, support). Config & feature exposure is heavily file‑driven under constants/.
Layout shell: layout-components/Layout/Layout.tsx orchestrates Nav (components/NavBar), Sidebar (components/SideBar), Bottom bar (components/BottomAppBar). Pages in pages/ delegate UI to page-components/**. Global state via React Contexts in contexts/ (menus, commissions, pub/sub, feature flags). Low‑code transaction & form primitives live in tf-components/.
| Concern | Implementation Anchor |
|---|---|
| Feature Flags | constants/featureFlags.ts + hooks/useFeatureFlag.tsx (returns [enabled, checkFlag]) |
| Pub/Sub | contexts/PubSubContext.js + topics in constants/PubSubTopics.ts |
| Menus / Nav | constants/SidebarMenu.ts, constants/profileCardMenus.js, processed by contexts/MenuContext.tsx |
| Theming / Branding | styles/themes.tsx, constants/colorThemes.js, org theme loaded in _app.tsx |
| Android Bridge | utils/AndroidUtils.ts & usage in layout for WebView comms |
| Auth Tokens | SessionStorage keys: access_token, refresh_token, etc.; route guard in components/RouteProtecter/ |
Setup: npm i && npm run prepare && chmod +x .husky/pre-commit
Run (HTTP): npm run dev (3002) | HTTPS: npm run dev.https (3004) | Perf scan: npm run scan (3006)
Quality Gate (pre-commit): npm run lint && npm test (or quicker focus: npm run test:quick path/to/test/file)
Bundle analysis: npm run analyze.
Functional React + TypeScript; prefer interfaces, as const objects over enums, explicit return types. Tabs for indentation, ternaries instead of && chains, optional chaining ?., defaults via ??. Favor custom components/* wrappers over raw Chakra primitives; import absolutely (import X from 'components/X'). Keep one responsibility per file; config, not conditionals, drives variation.
Use dynamic import for non-critical or rarely-hit admin subpages: const Widget = dynamic(() => import('page-components/Admin/HeavyWidget'), { ssr: false }). Guard re-renders: memo derived lists (menus, pricing slabs). Clean up effects (events, intervals, observers).
Tests mirror source tree under __tests__/. Render helpers in __tests__/test-utils/ provide pageRender, adminRender, loggedOutPageRender. For a pure component use render; for context-dependent UI choose the matching wrapper. Always add at least: renders smoke + one behavioral expectation (e.g. feature flag branch) when touching logic.
New Sidebar / Bottom bar item: update constants/SidebarMenu.ts (respect shape), ensure any new pub/sub topic is added to constants/PubSubTopics.ts. New pricing page: add slug + meta in ProductBusinessConfigurations.ts, generate UI under page-components/Admin/PricingCommission/SlugName, optionally select template="fileupload" for upload-driven flows. New feature flag: append to featureFlags.ts and gate UI with const [enabled] = useFeatureFlag('FLAG_KEY').
Short-lived auth + org/user metadata live in SessionStorage (user_detail, org_detail, tokens). Avoid duplicating this state in React unless deriving computed values. Daily caching pattern: see useDailyCacheState.
When adding functionality that must work inside the Android WebView wrapper, centralize bridge calls in AndroidUtils.ts; do not inline window.Android... references inside feature components.
- Update or add tests in mirrored
__tests__path. - Run lint + tests; fix before committing.
- For new config-driven feature, document key/value in related
constants/*file JSDoc. - If adding heavy dependency, justify via comment near first import.
- Keep instructions file updated only with proven patterns (avoid aspirational text).
No enums, no class components, no untyped any, no direct DOM access unless via ref & cleanup, no duplicate config keys, no silent catch blocks (log or rethrow).
const [isNewFlow] = useFeatureFlag('NEW_FLOW');
return isNewFlow ? <NewComponent /> : <LegacyComponent />;it('shows new flow when flag active', () => {
const { getByText } = pageRender(<Target />);
expect(getByText('New Flow')).toBeInTheDocument();
});Feedback welcome: identify unclear sections or missing high-leverage patterns to iterate.