React Native and Expo conventions for SuperHabits. Use when writing UI, screens, navigation, styling, or platform-specific code.
Apply this when writing any UI, navigation, or platform-specific code.
@shopify/[email protected]): estimatedItemSize is not required in TypeScript props (differs from v1 docs). TodosScreen uses data, renderItem, and keyExtractor only.The following are initialized here in order:
ensureAnonymousSession() (lib/supabase.ts) when Supabase env is configuredWhen isRemoteEnabled() is true (lib/supabase.ts — remoteMode defaults to "enabled"), a separate effect registers syncEngine.flush() on a 30s interval, on web visibility (hidden), and on NetInfo reconnect — not when setRemoteMode("disabled") is used.
Do NOT add DB calls before AppProviders initializes. Any component that calls a *.data.ts function must be a descendant of AppProviders.
app_meta identity for the app; remote backup uses Supabase anonymous auth + SupabaseSyncAdapter (separate from guest JSON)require-corp (aligned with app.json for crossOriginIsolated on web)/index.html (see knowledge base)nextPomodoroState() in pomodoro.domain.ts — used in Vitest; PomodoroScreen does not import it yet (labels inline)EXPO_PUBLIC_*; remoteMode defaults to "enabled"; ensureAnonymousSession on bootstrap; setRemoteMode / isRemoteEnabled gate flush (not wired from product UI by default)Three MCP servers are commonly configured for this project in the user’s MCP config (e.g. ~/.cursor/mcp.json):
| Server | Package | Key tools | Used for |
|---|---|---|---|
| playwright | @playwright/mcp@latest | browser_navigate, browser_evaluate, browser_take_screenshot, browser_console_messages | Web inspection, pre-PR checks |
| lighthouse | @danielsogl/lighthouse-mcp@latest | Lighthouse audit tools | Performance, PWA, accessibility |
| fetch | mcp-server-fetch (uvx) | fetch | HTTP header verification |
Use /inspect-web and /pre-pr for browser-based checks. Use /audit-performance for Lighthouse scores.
E2E tests live in e2e/ at the project root.
Setup files:
playwright.config.ts — config (headless: true, Chromium only, workers: 1 for OPFS/SQLite lock on web, HTML report paths)e2e/global.setup.ts — confirms crossOriginIsolated before the suite runse2e/helpers/navigation.ts — goToTab(), waitForDb(), hardReload()e2e/helpers/db.ts — clearDatabase() via OPFS removeEntry()clearDatabase() pattern: Called in test.beforeEach (not afterEach) so failures leave state intact for debugging. Deletes superhabits.db, .db-wal, .db-shm from OPFS then reloads the page.
Selector conventions for React Native Web: RN Web renders components differently from standard HTML. Prefer in this order:
getByText('exact label') for visible copygetByPlaceholderText(/hint/i) or getByPlaceholder(...) for inputsgetByRole('button', { name: /label/i }) when accessible names matchinput) or helpers in e2e/helpers/forms.ts for controlled TextInput (often needs click + type() with delay, not fill() alone)locator('[data-testid="..."]') — only if already present in a componentDo NOT add data-testid to components to make tests pass.
Running after UI changes:
npx playwright test e2e/{feature}.spec.ts
If a UI change breaks a selector, fix the selector in the spec. Use /e2e-fix to auto-detect and repair selector mismatches.
Output locations:
.cursor/playwright-output/e2e-report/.cursor/playwright-output/e2e-failures/.cursor/playwright-output/ (gitignored as appropriate in .gitignore)