A privacy-focused mood tracking app built with React Native. Record how you feel and review your mood history without a Moodinator account or a server for your mood data. You can send an optional problem report from Settings.
- 11-level mood scale from Elated (0) to Emergency (10), each shown as a weather sign from sun to storm
- One pad check-in: touch or drag to pick mood and energy, add optional details, then Keep with Undo. Available when quick energy is on and detailed labels are off.
- Tile entry: a tap picks the mood and Done saves it with optional detail. With every detail field off, or for a severe tile rating, the tap saves at once with Undo
- Detailed entry with long-press in tile modes for comprehensive records
- Attach emotions, context tags, energy, and notes
- Forecast-style history: each day shows its range from lightest to heaviest
- Month calendar with each day's weather
- Weekly and monthly statistics
- Compare mood averages across periods
- Streak tracking
- Local-first storage. No accounts, developer cloud sync, analytics, or ads
- Mood data stays in the app unless you choose to export, share, copy, or back it up
- Plaintext JSON exports and backups can be saved to user-selected destinations, including cloud-backed providers
- Core mood tracking works offline; crisis-support links, problem reports, and user-selected sharing destinations may require connectivity
- In-app problem reports send only the text you type, an optional reply email, the app version and build, and the system name and version. They go only when you tap Send and never include mood data, entries, emotions, tags, notes, settings, or device identifiers
- Dark and light mode with the calm Soft Sage palette
- Haptic feedback for tactile interactions
- Swipe actions for quick edits and deletes
- Customizable emotion and context tags
- Configurable fields offered after a tap
- React Native with Expo (SDK 55)
- TypeScript for type safety
- SQLite via expo-sqlite for local persistence
- NativeWind (TailwindCSS) for styling
- Expo Router for file-based navigation
- Zustand for state management
- Reanimated for smooth animations
- Node.js 24 LTS, version 24.13.1 or newer within major 24 (
.node-version) - pnpm 11.16.0 (
packageManagerinpackage.json) - Android Studio and an emulator, or Xcode on macOS for iOS
The test suite uses Node's built-in SQLite. Expo Go cannot verify custom native configuration such as SQLCipher; use a native build for that coverage.
git clone https://github.com/MaximilianMauroner/moodinator.git
cd moodinator
pnpm install --frozen-lockfile
pnpm startpnpm run android
pnpm run iosThese commands build the normal app identifier. For disposable test data and automation, use the separate QA app described in Native QA. Do not open a browser for normal app verification.
/src
/app # Expo Router screens and navigation
/components # Reusable UI components
/features # Feature-specific components and logic
/hooks # Custom React hooks
/shared/state # Zustand stores
/constants # Theme colors, mood scale definitions
/lib # Utilities and helpers
/db # SQLite database, repositories, migrations
pnpm run verify # Lint, typecheck, tests, Expo Doctor, Android release config
pnpm run test # Watch tests while editing
pnpm run test:run # Run tests onceThe suite includes real in-memory SQLite queries, migrations and rollback, store/date regressions, and rendered emotion/energy interactions. Native hosts and haptic APIs are mocked in component tests. Physical feedback, native layout, SQLCipher and the Expo bridge require a device build.
Expo Doctor needs network access to check SDK compatibility. It is installed locally so the command does not download a different checker on each run.
QA_WORKSPACE="$(pnpm run qa:prepare | tee /dev/stderr | sed -n 's/^QA workspace: //p')"
cd "$QA_WORKSPACE"
pnpm install --frozen-lockfile
MOODINATOR_VARIANT=qa MOODINATOR_QA_PREPARE_NATIVE=1 pnpm exec expo prebuild --platform android --clean
pnpm run qa:seal-native
MOODINATOR_VARIANT=qa pnpm exec expo run:android --variant release --device
pnpm run qa:smoke emulator-5554 --out /tmp/moodinator-native-smoke-currentqa:prepare requires a clean checkout, then materializes committed HEAD files for the
printed source SHA into a temporary directory. It excludes native
build folders, dependencies, credentials and personal scratch files. It does
not install or launch anything. The clean prebuild and qa:seal-native steps bind
generated Android inputs to that SHA; later source additions or native-source edits
fail closed, while dependency directories and native build outputs remain excluded.
Unset MOODINATOR_QA_PREPARE_NATIVE after sealing; sealed builds reject the prebuild-only flag.
Use one disposable emulator per concurrent run.
The release QA build embeds its bundle and does not need a shared Metro port.
After collecting evidence, remove that temporary workspace and disposable AVD.
The QA app uses com.lab4code.moodinator.qa and separate local storage. The smoke
runner accepts an explicit emulator serial and checks that package before
running a flow which clears QA data. Native evidence commands validate the
executing workspace's sealed prepared manifest and fail closed if it is missing,
unsealed, or no longer matches its files. See Native QA for
coverage, fixture generation, manual checks and performance captures.
The checked-in app metadata starts at marketing version 0.1.5 and Android
version code 40. The coordinated release runner stamps the reserved patch
version and version code into an isolated build workspace. Use its shared
release ledger and Play Internal record for the current candidate; the
checked-in values do not identify the latest uploaded build.
Normal Internal releases use pnpm run release:internal; the shared ledger
reserves the next version and Android code. There is no standalone
version:bump command. Native generation uses pnpm exec expo prebuild in an
isolated workspace.
In older Expo builds, toggling NativeWind shadow-* utilities during state updates can trigger a React Navigation context warning. Workaround: use inline style with iOS shadow props + Android elevation instead of shadow-* classes in dynamic components.
Use GitHub Issues for planned features, implementation slices, dependencies, and issue status. See AGENTS.md for the parent-issue, vertical-slice, review, and merge workflow.
Your working data is stored locally. Moodinator has no developer-operated account and no server for your mood data. Data can leave the app when you deliberately export, share, copy, or back it up to a destination you select. A problem report you choose to send carries only the text you type, an optional email, and the app and system versions. See the Privacy Policy for Android database-encryption, notification, deletion, and platform-backup details.
Contributions are welcome. Use GitHub Issues for planned work and implementation handoff; pull requests should reference the relevant issue when one exists.
For support or feedback: [email protected]
Use npm run release:internal (Zen Mode) or pnpm run release:internal
(Moodinator) for a changed, committed origin/main. The shared release ledger
reserves the next patch version and Android version code, builds locally,
and submits to Google Play Internal testing. Run release:status to see
the latest attempt. See nightly releases for setup and
the daily limit. Do not upload a separately numbered build outside this flow.