A React Native (Expo) client for Daykeeper, a social day-planner where you keep your tasks and events on a shareable "day page" and follow what other people are up to. This app talks to the existing DayKeeper-API backend and mirrors the web app.
Built with Expo SDK 56, Expo Router, React Query, and Zustand.
- Day pages — track today's tasks and events, and browse any user's day
- Social feed — posts, comments, likes, follows, close-friends, blocks
- Profiles — public/private accounts, follow requests, editable profile
- Search — find users and day pages
- Notifications — push notifications via
expo-notifications - Auth — email/password, Google sign-in, email confirmation, password reset
- Security — two-factor auth (email OTP + TOTP), trusted-device management, new-device alerts
- Onboarding — guided first-run flow (profile, first day, reminders)
- Light & dark mode — automatic, driven by design tokens shared with the webapp
- Node.js 18+
- The Expo tooling (
npx expo …, no global install required) - iOS Simulator (Xcode) and/or Android Emulator, or the Expo Go app on a physical device
npm installCopy the example env file and fill in the values:
cp .env.example .env| Variable | Purpose |
|---|---|
EXPO_PUBLIC_API_URL |
Backend base URL. Defaults to the hosted API; for local dev point it at your machine. |
EXPO_PUBLIC_GOOGLE_CLIENT_ID_WEB |
Google OAuth web client ID (fallback). |
EXPO_PUBLIC_GOOGLE_CLIENT_ID_IOS |
Google OAuth iOS client ID. |
EXPO_PUBLIC_GOOGLE_CLIENT_ID_ANDROID |
Google OAuth Android client ID. |
Leave the Google client IDs empty to hide the "Continue with Google" button.
Local dev tip:
localhostwon't reach the host machine from a physical device. Use your LAN IP, e.g.EXPO_PUBLIC_API_URL=http://192.168.x.x:3001.
npx expo start # Dev server — scan the QR with Expo Go, or open a simulator
npx expo run:ios # Build and run on the iOS simulator
npx expo run:android # Build and run on the Android emulatorType-check without building:
npx tsc --noEmit --skipLibCheck| Area | Choice |
|---|---|
| Framework | Expo SDK 56, React Native 0.85, React 19 |
| Routing | Expo Router (file-based, typed routes) |
| Server state | TanStack React Query v5 |
| Client state | Zustand |
| HTTP | Axios (shared instance + token-refresh interceptor) |
| Secure storage | expo-secure-store |
| Push | expo-notifications |
| Icons / SVG | @expo/vector-icons, react-native-svg |
daykeeper-app/
├── app/ # Expo Router routes (file-based)
│ ├── _layout.tsx # Root: QueryClient provider + AuthGate
│ ├── index.tsx # Renders null; AuthGate handles the redirect
│ ├── (auth)/ # Unauthenticated screens
│ │ ├── welcome / login / register
│ │ ├── forgot-password / reset-password
│ │ ├── confirm-email / two-factor
│ └── (app)/ # Protected screens
│ ├── (tabs)/ # Bottom tabs: feed, day, search, notifications, profile
│ ├── [username]/ # Any user's profile, day, follows
│ ├── post/ # Post detail, create, edit
│ ├── day/ # Full task & event lists/detail
│ ├── onboarding/ # First-run flow
│ └── settings/ # Privacy, 2FA, devices, blocks, close-friends, …
├── lib/
│ ├── api/ # Typed API layer (one file per domain)
│ └── auth/ # Secure token storage
├── components/ # UI primitives (ui/) + feature components
├── stores/ # Zustand stores (auth, theme)
├── hooks/ # useTheme, usePushNotifications
├── constants/ # Design tokens (theme.ts)
└── utils/ # Helpers (user display names, etc.)
See CLAUDE.md and PLAN.md for the full architecture reference.
- Auth gate —
app/_layout.tsxloads the cached user, verifies it against the API, and redirects between the(auth)and(app)stacks.stores/authStore.tsis the single source of auth truth. - Token refresh — the Axios interceptor in
lib/api/client.tscatches401s, queues concurrent requests, refreshes once, and replays the queue. Tokens live only inexpo-secure-store(never AsyncStorage). - Theme tokens — all colors, spacing, typography, and radii come from
constants/theme.ts, kept in sync with the webapp's CSS variables. Never hardcode colors; use theuseTheme()tokens. - Data fetching — React Query with
staleTime: 60s,gcTime: 10min,retry: 1. Infinite lists useuseInfiniteQuerywith page-based cursors. @/alias maps to the repo root (seetsconfig.json).
Expo SDK 56 changed several APIs — check the SDK 56 docs before touching Expo packages.
Builds are configured with EAS (eas.json).
eas build --platform ios
eas build --platform androidBundle identifier / package: com.daykeeper.app.
See LICENSE.