Imported from aessaputra/apotek-eccomerce (
AGENTS.md). Install upstream withnpx skills add aessaputra/apotek-eccomerce. Copyright stays with the author.
PROJECT KNOWLEDGE BASE
Generated: 2026-05-24 Commit: de745f6 Branch: dev
OVERVIEW
Expo SDK 54 pharmacy e-commerce app built with React Native 0.81.5, React 19.1, TypeScript strict mode, Expo Router v6, Tamagui 1.144, Redux Toolkit, Zustand, TanStack Query, and Supabase. It targets iOS, Android, and Web with dotenvx-managed env wiring, EAS Update/Build/Hosting flows, centralized Jest coverage, and native Android checked in.
STRUCTURE
./
├── app/ # Expo Router route wrappers — see app/AGENTS.md
├── scenes/ # Screen orchestration — see scenes/AGENTS.md
├── components/ # Tamagui reusable UI — see components/AGENTS.md
├── services/ # Supabase/backend boundary — see services/AGENTS.md
├── hooks/ # Stateful orchestration — see hooks/AGENTS.md
├── providers/ # Provider stack — see providers/AGENTS.md
├── constants/ # Domain constants + UI/theme fallbacks — see constants/AGENTS.md
├── utils/ # Infra helpers — see utils/AGENTS.md
├── types/ # Domain, route, generated Supabase types — see types/AGENTS.md
├── __tests__/ # Centralized Jest tests — see __tests__/AGENTS.md
├── .github/workflows/ # CI and EAS Update workflows — see .github/workflows/AGENTS.md
├── .eas/workflows/ # EAS dashboard build/deploy workflows — see .eas/workflows/AGENTS.md
└── android/ # Local native Android project notes — see android/AGENTS.md
CHILD AGENTS
app/AGENTS.md— route group wrappers, protected-route sync, thin-route rules.components/AGENTS.md— Tamagui component shape, UI-only boundaries.components/elements/AGENTS.md— atomic product/order/form UI catalog, skeletons, accessibility.components/layouts/AGENTS.md— tab bar, header, bottom action, and sheet layout primitives.components/AddressForm/AGENTS.md— address form composite, suggestion list, default toggle.components/MapPin/AGENTS.md— native map picker, Expo Location, web-safe dynamic map loading.services/AGENTS.md— Supabase, edge functions, notification service, service return patterns.hooks/AGENTS.md— reusable async state machines and hook export contracts.providers/AGENTS.md— provider order, auth bootstrap, query-client lifetime.utils/AGENTS.md— Supabase/config/theme/storage/retry infrastructure gotchas.types/AGENTS.md— generated Supabase types and notification route contracts.constants/AGENTS.md— tab metadata, courier/address constants, theme fallback sync.scenes/AGENTS.md— screen orchestration and feature map.scenes/auth/AGENTS.md— login/signup/reset/verify-email helper contracts.scenes/home/AGENTS.md— home feed layout, banner CTA, category/product sections.scenes/cart/AGENTS.md— cart, checkout review, payment WebView, persisted checkout session.scenes/profile/AGENTS.md— profile/address and area-picker state machine.scenes/orders/AGENTS.md— order list/detail/status-tab conventions.__tests__/AGENTS.md— centralized Jest layout, mocks, validation expectations..github/workflows/AGENTS.md— test CI, preview branch/env mapping, EAS Update quirks..eas/workflows/AGENTS.md— EAS platform workflow build/deploy jobs for preview/release.android/AGENTS.md— Gradle, dev namespace, Hermes/New Architecture constraints.
Read the closest child file before editing inside that directory. Root covers global rules only.
WHERE TO LOOK
| Task | Location | Notes |
|---|---|---|
| Add a route | app/[group]/ |
Keep route files thin; update PROTECTED_ROUTE_GROUPS if protected |
| Add a screen | scenes/[feature]/ |
Screen implementation stays out of app/ |
| Add UI | components/elements/ or components/layouts/ |
Tamagui primitives and tokens only |
| Add backend/data call | services/[domain].service.ts |
Use @/utils/supabase; no ad hoc clients |
| Add reusable screen logic | hooks/use[Name].ts |
Compose services, app state, navigation, side effects |
| Add auth/session behavior | providers/AuthProvider.tsx + services/auth.service.ts |
Beware GoTrue lock/deadlock notes |
| Add notifications behavior | services/notification.service.ts + hooks/useNotifications.ts |
Service is imported directly where needed |
| Add state/cache | slices/app.slice.ts, utils/store.ts, stores/areaPickerStore.ts |
Redux global; Zustand narrow/local |
| Add route/domain types | types/[domain].ts + types/routes.types.ts |
Do not hand-edit generated types/supabase.ts |
| Add env/config | app.config.ts + utils/config.ts + .env.*.example |
Public env vars must be wired in all three |
| Add theme token | themes.ts + constants/ui.ts + utils/theme.ts |
Keep fallbacks synchronized |
| Add tests | __tests__/[domain]/ |
Centralized tests, inline mocks |
| Check CI/deploy | .github/workflows/ + .eas/workflows/ + eas.json |
GitHub quality gates, OTA updates, EAS build/deploy workflows |
| Check backend contract | /home/coder/dev/pharma/admin-panel/supabase |
Schema migrations + Edge Functions are backend truth |
| Check admin operations | /home/coder/dev/pharma/admin-panel |
Backoffice owns operational workflows and admin read models |
ARCHITECTURE PATTERNS
package.jsonentry isexpo-router/entry;app/_layout.tsxis the true composition root.app/route files are thin wrappers/re-exports intoscenes/.- Allowed route-logic exceptions:
app/_layout.tsx,app/index.tsx,app/google-auth.tsx, andapp/+native-intent.tsx. - Protected groups are hardcoded in
app/_layout.tsx:['(tabs)', 'cart', 'product-details', 'payment-success']; protected stack layouts also usewithAuthGuard. providers/Provider.tsx: Gesture Handler → Safe Area → Redux → Tamagui → React Navigation theme.providers/QueryProvider.tsx: one long-lived QueryClient (staleTime1h,gcTime24h,retry: 2).providers/AuthProvider.tsx: session bootstrap, OAuth hash handling, role/banned checks, push-token sync, mobile token refresh.utils/supabase.tsis the only Supabase client creator. Its crypto polyfill import must remain first.- Services own query shaping, normalization, edge-function calls, retry/abort behavior, and error translation.
- Components and scenes should consume services/hooks, not Supabase clients.
- Public service helpers go through
services/index.tswhen shared broadly;notification.service.tsis a direct-use service for push-token/realtime notification flows. - Backend Supabase repo:
/home/coder/dev/pharma/admin-panel/supabase; read itsAGENTS.mdbefore schema, RLS, RPC, or Edge Function contract changes. - Frontend-relevant functions include
biteship,create-checkout-order,create-snap-token,confirm-midtrans-payment,confirm-order-received, andpush. - Admin operational repo:
/home/coder/dev/pharma/admin-panel; read rootAGENTS.mdandsrc/providers/AGENTS.mdbefore order, catalog, banner, shipping, branding, notification, or ban-state changes. - Never copy admin/server secrets into frontend env; service-role, Midtrans, Biteship, Expo push, DB, and Vault secrets stay backend-only.
- Redux Toolkit (
slices/app.slice.ts) stores auth state and app-wide caches; Zustand currently owns only area-picker workflow state. - React Query provider exists globally, but most current server-state caching is still service/hook/Redux driven.
- Tamagui themes live in
themes.ts;constants/ui.tsmirrors fallbacks;utils/theme.tsbridges non-Tamagui/native style consumers. - Android native config enables New Architecture, Hermes, edge-to-edge, and
softwareKeyboardLayoutMode: 'resize'.
CONVENTIONS
- Path alias:
@/*points to repository root. - Components use PascalCase and usually
Name/Name.tsx+index.ts; hooks/utils/services/constants use camelCase. - Indonesian UI copy; English code/domain names.
- Application logs must be guarded with
if (__DEV__); existing unguarded logs are technical debt, not a pattern to copy. - Tests live under
__tests__/, grouped by domain; Jest permits broader matches, but app convention is centralized tests. - Mock inline with
jest.mock()inside tests; no__mocks__/directories. - Prettier: tab width 2, single quotes, trailing commas, print width 100,
arrowParens: avoid,bracketSameLine: true. - ESLint: flat Expo config + Prettier integration;
dist/*,.agents/**, andsupabase/functions/**ignored. - Pre-commit: Husky runs
lint-staged, then full Jest.
ANTI-PATTERNS (THIS PROJECT)
- NEVER put real screen logic in
app/route files outside the documented root-routing exceptions. - NEVER call Supabase directly from components or scenes.
- NEVER add
@ts-ignore,@ts-expect-error, oras any. - NEVER use bare app logs; guard with
if (__DEV__). - NEVER use
StyleSheet.create()or NativeWind for core UI; use Tamagui. - NEVER add the Tamagui babel plugin back into
babel.config.js; Metro uses@tamagui/metro-plugin. - NEVER create
__mocks__/directories for tests. - NEVER reorder the crypto polyfill import in
utils/supabase.ts. - NEVER add a public env var to only one side of
app.config.ts/utils/config.ts/.env.*.example. - NEVER add Tamagui theme tokens without syncing
THEME_FALLBACKS/DARK_THEME_FALLBACKS. - NEVER access
Constants.expoConfig?.extraoutsideutils/config.tsunless documenting a narrow infrastructure exception. - NEVER use
getThemeColor()for new Tamagui token-capable props; reserve it for non-token/native style escape hatches. - NEVER change checkout/order/shipping/banner/catalog contracts without checking the admin-panel Supabase migrations/functions and admin operational flows.
COMMANDS
npm run dev # Expo dev server with .env.dev
npm run dev:ios|dev:android|dev:web
npm run dev:tailscale[:android|:ios] # LAN dev through Tailscale IP
npm run lint && npm run format:check && npm run test
npm run dev:build:mobile # Push EAS secrets, then development build
npm run dev:build:web && npm run dev:serve:web
npm run dev:deploy:web # EAS Hosting development deploy
TESTING & CI NOTES
- Jest uses
jest-expo,jest.setup.js, fake timers, and common native mocks; CI runsnpm ci, format check, lint, then Jest on Node 20.x. - Preview CI maps branches to env examples and runs EAS Update.
- EAS platform workflows build preview Android APKs from
dev, release Android APKs frommain/release/**, and deploy web targets. - Preview CI installs
lightningcss-linux-x64-gnu --save-optionalafternpm ci; preserve this Tamagui/Linux workaround.
NOTES
- Node 20.x is required; EAS base pins Node 20.19.4;
.npmrcenableslegacy-peer-deps=true; env examples present:.env.dev.example,.env.preview.example,.env.prod.example. - Local Android Gradle uses development namespace
com.apotekecommerce.dev; remote EAS builds use CNG fromapp.config.ts, where env can overrideandroid.package. android/gradle.propertiesstill contains deprecatedexpo.edgeToEdgeEnabled=true; preferedgeToEdgeEnabled/react.edgeToEdgeEnabledgoing forward.