CalmAI documentation
Run it, point it at your own accounts, ship it under your own brand. Written against version 1.5.0 of the download you get on CodeCanyon.
- Version v1.5.0
- Updated Jul 2026
- Platform Flutter
- Stack Flutter · AI
- Demo APK · v1.5.0 · Android 8.0+
On this page
Introduction
CalmAI is a complete Flutter application (Android + iOS + Web Admin Panel) that serves as an AI-powered mental wellness companion. It combines AI chat therapy, mood tracking, guided journaling, CBT thought records, breathing exercises, a gratitude journal, a sleep tracker, a habit tracker, a guided meditation library with offline TTS playback, mood analytics, weekly AI wellness reports, an always-on SOS grounding screen, and a 17-badge streaks and milestones system.
The app is built with a Living Sanctuary design system (forest green + Newsreader/Manrope typography), fully supports dark mode, and follows strict mental health safety guidelines including offline crisis detection, mandatory disclaimer screens, and always-visible professional help links.
It also includes a web-based admin panel that runs on Chrome — dashboard with KPIs, user management with GDPR delete, crisis conversation moderation, analytics charts, configuration editor, weekly reports browser with CSV export, and a full audit log.
What’s included
- Full Flutter source code (Android + iOS + Web Admin Panel)
- 33 mobile screens + 11 admin screens, 5-tab bottom navigation, persistent SOS button
- Firebase Auth, Firestore, Remote Config, FCM integration
- OpenAI GPT-4o + Google Gemini dual AI backend
- RevenueCat in-app purchases (monthly + annual premium)
- AdMob banner + interstitial ads
- Sleep tracker — bedtime/wake-time pickers, weekly bar chart, 30-night history, consecutive-night streak
- Habit tracker — 6 seeded defaults + custom habits, daily cards, weekly completion rate, 30-day heatmap
- Guided meditation library — 8 bundled scripts (3 free / 5 premium), offline TTS player with real
[pause Xs]silence - Offline crisis detection, crisis resource database, and 10-card SOS grounding pool
- Streaks and milestone badges system (17 badges, snackbar unlocks, profile grid)
- Web admin panel with dashboard, user management, moderation, analytics, config, reports, and audit log
- Firebase Hosting deployment for the admin panel
- 183 unit tests (crisis detection, badge enum, coping cards, mood patterns, validators, sleep quality, meditation category, script parser, all enums)
- This documentation
Tech stack
Requirements
Development machine
- Flutter 3.41.x — stable channel (
flutter upgrade) - Dart 3.11.x (bundled with Flutter)
- Android Studio Hedgehog (2023.1.1) or newer, or VS Code with Flutter extension
- Xcode 15+ (macOS only, required for iOS builds)
- CocoaPods (
sudo gem install cocoapods)
External accounts (required)
- Firebase — free Spark plan is enough for development; Blaze plan needed for production at scale
- OpenAI — API key for GPT-4o (pay-as-you-go), or Google Gemini API key
- RevenueCat — free account; needed only to enable premium purchases
External accounts (optional)
- AdMob — leave Remote Config banner/interstitial IDs empty to disable ads entirely with no code changes
Quick start
- 01
Unzip and open the project
Extract the zip. Open thecalm-aifolder in Android Studio or VS Code. - 02
Install dependencies and generate code
terminalflutter pub get dart run build_runner build --delete-conflicting-outputs - 03
Add Firebase config files
Follow the Firebase setup section below. Placegoogle-services.jsoninandroid/app/andGoogleService-Info.plistinios/Runner/. - 04
Set your API keys in Remote Config
Add at minimumopenai_api_key(orgemini_api_key) in Firebase Remote Config. See the Remote Config keys section. - 05
Run the mobile app
terminalflutter runThe app will launch. On first run it shows the onboarding flow → disclaimer → login.
- 06
Run the admin panel (web)
terminalflutter run -d chromeOpens the admin panel in Chrome. Uses
kIsWebdetection inmain.dartto show the admin UI instead of the mobile app.
Firebase setup
- 01
Create a Firebase project
Go to console.firebase.google.com → Create project → give it any name. - 02
Enable Authentication
In the Firebase console → Build → Authentication → Sign-in method → Enable:
- Email/Password
- Google (requires SHA-1 fingerprint for Android)
- Anonymous (for “Continue as Guest”)
- 03
Enable Firestore
Build → Firestore Database → Create database → Start in production mode. Then go to Rules tab and paste the security rules from this document. - 04
Enable Remote Config
Build → Remote Config → Get started. Add the keys listed in the Remote Config section. - 05
Enable Cloud Messaging (FCM)
Build → Cloud Messaging → automatically enabled when you add the app. For iOS, upload your APNs key (see Notifications). - 06
Register Android app
Project Settings → Add app → Android → Package name:com.devsnack.calmai(or your custom ID) → Register → downloadgoogle-services.json→ place inandroid/app/. - 07
Register iOS app
Project Settings → Add app → Apple → Bundle ID:com.devsnack.calmai→ Register → downloadGoogleService-Info.plist→ drag intoios/Runner/in Xcode (not just file system).
SHA-1 for Google Sign-In (Android): get it with the command below and add the SHA-1 fingerprint in Project Settings → Your Android app → SHA certificate fingerprints.
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass androidRemote Config keys
All API keys and feature flags are managed via Firebase Remote Config — nothing is hardcoded in the source. Create these keys in Firebase Console → Remote Config → Add parameter.
"openai" or "gemini"false before releasing. When true, premium unlocks without a real purchase (for testing only).use_mock_purchase to false in Remote Config. Releasing with it set to true gives all users free premium access.default_ai_provider in Remote Config and publish — no app update needed. The app fetches config on every launch.RevenueCat (in-app purchases)
- 01
Create a RevenueCat account
Sign up at app.revenuecat.com. The free plan is sufficient to start. - 02
Create a new project
Dashboard → + New Project → give it your app name. - 03
Add iOS and Android apps
In your project → Apps → Add app for each platform. For iOS enter your Bundle ID; for Android enter your package name. - 04
Create the entitlement
Entitlements → + New → Identifier:premium(must match exactly — the app checks for this identifier). - 05
Create products in App Store Connect and Google Play Console
Create your subscription products (e.g. monthly, annual) there first, then add them to RevenueCat under Products. - 06
Create a default offering
Offerings → + New offering → Identifier:default→ attach your monthly and annual packages. - 07
Copy SDK key to Remote Config
Project Settings → API keys → copy the Public (Android/iOS) key → paste into Remote Config asrevenuecat_api_key. - 08
Set
Update this Remote Config key before releasing so real purchases are processed.use_mock_purchasetofalse
AdMob (optional)
Ads are completely optional. If you leave the Remote Config IDs empty, no ads will be shown and no code changes are required.
- 01
Create an AdMob account
Visit admob.google.com and add your app for iOS and Android. - 02
Create ad units
For each platform create a Banner ad unit and an Interstitial ad unit. - 03
Add App ID to native files
Android: add this to
android/app/src/main/AndroidManifest.xmlAndroidManifest.xml<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX"/>iOS: in
ios/Runner/Info.plistadd aGADApplicationIdentifierkey with your App ID value. - 04
Add unit IDs to Remote Config
Copy the Banner unit ID →admob_banner_id. Copy the Interstitial unit ID →admob_interstitial_id.
Notifications (FCM)
The app uses Firebase Cloud Messaging (FCM) for push notifications and flutter_local_notifications for scheduled local reminders (daily check-in, streak alerts, weekly report ready). Local notifications work with no additional configuration.
iOS — APNs setup (required for push on iOS)
- 01In Apple Developer Portal → Certificates, Identifiers and Profiles → Keys → create an APNs key (or use a certificate).
- 02Firebase Console → Project Settings → Cloud Messaging → Apple app → upload the APNs key (or p12 certificate) and enter the Key ID + Team ID.
- 03In Xcode → Runner target → Signing and Capabilities → add Push Notifications and Background Modes → Remote notifications.
Android
No extra setup needed. FCM works automatically once google-services.json is in place.
Customization
Change the bundle ID / package name
Replace com.devsnack.calmai with your own ID in two places:
- Android:
android/app/build.gradle→applicationId "com.devsnack.calmai" - iOS: Open Xcode → select Runner target → General tab → Bundle Identifier
google-services.json / GoogleService-Info.plist.Change the app name
- Android:
android/app/src/main/AndroidManifest.xml→android:label="CalmAI" - iOS:
ios/Runner/Info.plist→CFBundleNamevalue
Change the app icon
- Android: Replace files in
android/app/src/main/res/mipmap-*/ - iOS: Replace assets in
ios/Runner/Assets.xcassets/AppIcon.appiconset/
Adjust free tier limits
Change via Remote Config — no code changes needed:
free_daily_chat_messages— default: 10free_weekly_journal_entries— default: 5free_meditations— default: 3 (rest of the 8 bundled meditations are paywalled)
Disclaimer text
Edit the disclaimer body in lib/presentation/screens/disclaimer_screen.dart. You must keep the “I Understand” button and the disclaimerAccepted flag — removing these violates mental health app safety requirements.
Change the AI provider
Set default_ai_provider in Remote Config to "openai" or "gemini". You can have both API keys set simultaneously — the app uses whichever is configured as default. No rebuild required.
Colors and typography
- All colors are in
lib/core/constants/app_colors.dart— change the const values there to retheme the entire app - All fonts use
GoogleFonts— swap font names inlib/core/theme/app_theme.dartto change typography globally - All spacing constants are in
lib/core/constants/app_sizes.dart
Crisis resources by region
Crisis resources are stored as a const map in the source code — they work completely offline without any API call. Customize this file for your target audience before publishing.
File: lib/core/constants/crisis_resources.dart
The map key is the region code. The default region for new users is 'us' (set in UserProfile.crisisRegion). The user can change their region in Settings.
Built-in regions
Adding a new region
Add a new entry to the byRegion map in crisis_resources.dart:
'de': [
CrisisResource(
name: 'Telefonseelsorge',
phone: '0800 111 0 111',
description: 'Kostenlos, vertraulich, 24/7',
url: 'https://www.telefonseelsorge.de',
),
],Then change the default region in lib/data/models/user_profile.dart — the crisisRegion field default value.
Firestore security rules
All data is strictly user-scoped — users can only read and write their own documents. Paste these rules into Firebase Console → Firestore → Rules tab.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
match /moodLogs/{userId}/logs/{logId} {
allow read, write: if request.auth.uid == userId;
}
match /journalEntries/{userId}/entries/{entryId} {
allow read, write: if request.auth.uid == userId;
}
match /chatConversations/{userId}/conversations/{convId} {
allow read, write: if request.auth.uid == userId;
}
match /breathingSessions/{userId}/sessions/{sessionId} {
allow read, write: if request.auth.uid == userId;
}
match /gratitudeEntries/{userId}/entries/{date} {
allow read, write: if request.auth.uid == userId;
}
match /weeklyReports/{userId}/reports/{weekId} {
allow read, write: if request.auth.uid == userId;
}
match /userBadges/{userId}/badges/{badgeType} {
allow read, write: if request.auth.uid == userId;
}
match /sleepLogs/{userId}/logs/{logId} {
allow read, write: if request.auth.uid == userId;
}
match /habitDefinitions/{userId}/habits/{habitId} {
allow read, write: if request.auth.uid == userId;
}
match /habitCompletions/{userId}/completions/{completionId} {
allow read, write: if request.auth.uid == userId;
}
match /meditationSessions/{userId}/sessions/{sessionId} {
allow read, write: if request.auth.uid == userId;
}
}
}Admin panel
CalmAI includes a web-based admin panel built with the same Flutter codebase. It runs on Chrome using flutter run -d chrome and is detected via kIsWeb in main.dart.
Features
_allowApiKeyEditing flagAdmin authentication
The admin panel uses Firebase Auth (email/password) and checks the admin_users Firestore collection. To set up:
- 01Create an email/password account in Firebase Auth
- 02Add a document in Firestore →
admin_users/{uid}with fields:uid,email,displayName,role: "superAdmin",createdAt - 03Set
_bypassAuth = falseinlib/admin/core/router/admin_router.dart
_bypassAuth = true in admin_router.dart to skip login during development. Always set it back to false before deploying.API key visibility
The _allowApiKeyEditing flag in lib/admin/presentation/screens/config/config_screen.dart controls whether API key fields are shown:
false(default) — API keys hidden. Use this for demo/preview builds.true— API key fields visible and editable. Use this for real buyer builds.
Deploy to Firebase Hosting
# Build the web app
flutter build web
# Deploy to Firebase Hosting
firebase deploy --only hosting --project YOUR_PROJECT_IDThe admin panel will be available at https://YOUR_PROJECT_ID.web.app.
Firestore collections (admin-specific)
collectionGroup queries that require composite indexes. When you first access these screens, the error message includes a direct URL to create the required index — just click it.Build and release
Pre-build checklist
- Firebase config files in place (
google-services.json,GoogleService-Info.plist) - Bundle ID / package name updated
- Remote Config keys set (at minimum one AI key)
use_mock_purchaseset tofalseflutter analyzereturns zero issues
Commands
# Clean and install
flutter clean
flutter pub get
dart run build_runner build --delete-conflicting-outputs
# Verify — must show 0 issues before releasing
flutter analyze
# Format code (optional)
dart format lib/
# Android — Play Store (recommended)
flutter build appbundle --release
# Android — Direct APK
flutter build apk --release
# iOS — then archive in Xcode → Product → Archive → Distribute
flutter build ios --release
# Web Admin Panel — deploy to Firebase Hosting
flutter build web
firebase deploy --only hosting --project YOUR_PROJECT_IDSigning — Android
Follow these steps to sign your release build for the Play Store.
- 01
Generate a keystore
Run the following command in your terminal. Replace the placeholder values with your own information. Keep this file safe — you will need it for every future update.
terminalkeytool -genkey -v \ -keystore ~/calmai-release.jks \ -keyalg RSA \ -keysize 2048 \ -validity 10000 \ -alias calmaiYou will be prompted for a keystore password, your name, organisation, city, country, and a key password. Note down both passwords — they cannot be recovered.
- 02
Create
android/key.propertiesCreate the file
android/key.properties(this file must not be committed to version control — add it to.gitignore):android/key.propertiesstorePassword=YOUR_KEYSTORE_PASSWORD keyPassword=YOUR_KEY_PASSWORD keyAlias=calmai storeFile=/Users/YOUR_USERNAME/calmai-release.jksSet
storeFileto the absolute path of the.jksfile you generated in step 1. - 03
Configure
android/app/build.gradleOpen
android/app/build.gradleand add the following blocks:android/app/build.gradle// At the top of the file, before the `android` block: def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } android { ... signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } - 04
Build the signed release
terminal# App Bundle (recommended for Play Store) flutter build appbundle --release # Or APK flutter build apk --releaseThe signed artifact is output to
build/app/outputs/bundle/release/app-release.aab(bundle) orbuild/app/outputs/flutter-apk/app-release.apk(APK).
Google Sign-In SHA-1: after generating your release keystore, register its SHA-1 fingerprint in Firebase Console → Project Settings → Your Android app → SHA certificate fingerprints. This prints it:
keytool -list -v -keystore ~/calmai-release.jks -alias calmaiSigning — iOS
Set up your Apple Developer certificate and provisioning profile in Xcode → Runner target → Signing and Capabilities. Use automatic signing for simplicity.
Store ratings
- App Store: 17+ (medical/mental health content)
- Google Play: Mature (mental health topics)
Feature overview
/profile/badgesSafety rules
Implemented safety features
- Mandatory disclaimer screen — shown on every first launch before the user can access any content. The router redirects any authenticated user whose
disclaimerAcceptedflag isfalseback to this screen. The user must tap “I Understand” to proceed. - Client-side crisis detection —
lib/data/services/crisis_detection_service.dartscans every chat message for crisis keywords before any API call is made. Works offline, runs in under 1ms. If triggered: crisis resource card is shown immediately. - “Talk to a Professional” link — permanently visible above the chat input bar. Cannot be hidden by any setting. Links to the user’s configured crisis resources.
- Persistent SOS floating button — rendered inside
lib/presentation/widgets/common/main_shell.darton every authenticated screen (hidden only on the chat screen, which already has the professional-help link, and on the SOS screen itself). Tapping opens/sos— three offline grounding techniques drawn from a 10-card pool plus a “Talk to a human now” button that opens region-specific tap-to-dial crisis hotlines. - Offline crisis resources — the full crisis resource database and the SOS coping-card pool are Dart const maps compiled into the app binary. No internet connection required.
- Journal privacy — journal entries are never automatically included in AI context. They are only sent to the AI when the user explicitly taps “Discuss with CalmAI” inside a journal entry.
- Age gate — users are asked to confirm they are 18+ before completing onboarding. Under-18 users see a message directing them to age-appropriate resources.
- AI never diagnoses — the system prompt in
lib/core/constants/therapy_prompts.dartexplicitly prohibits diagnostic language. The AI is instructed to recommend professional help for serious concerns. - Full data deletion — the delete account flow removes all Firestore subcollections (moodLogs, journalEntries, chatConversations, breathingSessions, gratitudeEntries, weeklyReports, userBadges) plus the user document and Firebase Auth account.
FAQ and troubleshooting
google-services.json is missing from android/app/, or GoogleService-Info.plist is missing from ios/Runner/. It can also happen if the package name in the file doesn’t match the one registered in Firebase.RemoteConfigService.initialize(). No action needed.openai_api_key (or gemini_api_key) is set in Remote Config and that default_ai_provider matches the key you set. Also verify the key is valid and has credit/quota.use_mock_purchase is set to false in Remote Config, revenuecat_api_key is set, and your RevenueCat entitlement identifier is exactly premium. Also confirm your App Store / Play Store products are approved and linked to RevenueCat offerings.flutter pub get.flutter pub run build_runner build --delete-conflicting-outputs. The --delete-conflicting-outputs flag removes any stale generated files that may conflict.gemini_api_key in Remote Config with your Gemini API key, then change default_ai_provider to "gemini". No code change or app update needed — the change takes effect on the next app launch.List<CrisisResource> to the byRegion map in lib/core/constants/crisis_resources.dart and rebuild. Users can select their region in Settings.lib/core/constants/therapy_prompts.dart. You can customize tone, persona, and focus areas. Keep the safety rules in the system prompt (no diagnoses, crisis escalation, professional help recommendations) intact.Changelog
Every version published so far. Updates are free for the life of the item.
Version 1.4.0 · May 2026Sleep, habits and meditation
- Sleep tracker — New
/sleepscreen with bedtime / wake-time pickers, 5-emoji quality picker (terrible → excellent), optional note, and a live duration ring that updates as you adjust the pickers./sleep/historyshows a 7-day bar chart of duration (fl_chart) plus a 30-night list with emoji + duration. Consecutive-night streak chip on the log screen. Stored atsleepLogs/{uid}/logs/{yyyy-MM-dd}— the wake date is the doc id, so editing the same night updates instead of duplicating. - Habit tracker — New
/habitsscreen with 6 buyer-seeded default habits (hydration, exercise, going outside, no screens before bed, meditate, gratitude). Tap-to-complete daily cards, weekly completion-rate card, and a 14-emoji picker bottom sheet for custom habits./habits/:idshows a 30-day completion heatmap and archive control. Two collections:habitDefinitions/{uid}/habits/{habitId}andhabitCompletions/{uid}/completions/{date}_{habitId}(flat composite key for simple queries). - Guided meditation library — New
/meditationscreen with 8 bundled scripts (one per category: anxiety, sleep, focus, self-compassion, morning, stress, grief, confidence). 3 free (anxiety / morning / stress) and 5 premium-gated. Category filter chips at the top./meditation/:id/playerusesflutter_ttsto narrate the script at a calm 0.42 speech rate, inserting real silence between chunks parsed from[pause Xs]markers. Play / pause / stop controls. Sessions logged tomeditationSessions/{uid}/sessions/{sessionId}. - 4 new milestone badges —
firstSleepLog,sleepStreak7(7 consecutive nights of sleep logging),firstMeditation,meditations5(5 completed meditations).BadgeTypeenum now has 17 values total. Sleep streak is computed inSleepRepository.calculateStreakand passed intoBadgeService.onSleepLogged; meditation count is computed inMeditationRepository.completedSessionCountand passed intoBadgeService.onMeditationCompleted. - Weekly AI wellness report v2 — Both OpenAI and Gemini implementations now call
TherapyPrompts.weeklyReportPromptV2, which adds 4 new fields to the prompt: meditation session count, average sleep hours, average sleep quality, and weekly habit completion rate. The response JSON returns two new sections (sleepSummary,habitTip) which are rendered conditionally on the report screen, included in the PDF export, and added to the Share text. Both new fields are nullable on theWeeklyReportmodel so v1.3 reports still deserialize. - Home dashboard — Tool grid grew from 6 → 9 tiles: AI Chat, Journal, Breathe, Gratitude, Sleep, Habits, Meditate, Insights, Premium.
- GDPR delete extended —
deleteAllUserData()now wipes 10 user-scoped subcollections (addssleepLogs,habitDefinitions,habitCompletions,meditationSessionson top of the previous 7 v1.3 collections). - New Remote Config key —
free_meditations(Int, default 3) controls the free-tier meditation cap. - 183 unit tests — Added
sleep_quality_test(4),meditation_category_test(4),meditation_script_parser_test(6 covering pause-marker split, case insensitivity, adjacent pause merging, no-marker scripts, and duration estimation). Badge enum test bumped to assert 17 values. Total: 169 → 183 tests, all passing. - UX fix — Habits screen avoids a screen-level
FloatingActionButton(would overlap the persistent SOS FAB fromMainShell). “Add habit” lives as anAppBaraction plus an inline outlined button under the daily list.
Version 1.3.0 · May 2026SOS and engagement
- SOS coping cards screen — Persistent floating SOS button (
lib/presentation/widgets/sos/sos_fab.dart) on every authenticated screen except chat (which already has the professional-help link) and the SOS screen itself. Tapping opens/soswith 3 randomly-shuffled grounding techniques from a const pool of 10 (5-4-3-2-1, Box Breathing, Cold Water Reset, Safe Place Visualization, Name Your Emotion, Opposite Action, Body Check-In, Reach Out, STOP, One Breath/One Step). 100% offline. - Tap-to-dial crisis resources sheet — Bottom sheet on the SOS screen that lists region-specific hotlines and dials them via
tel:URI. Pulls from the same offlineCrisisResourcesmap. - Streaks and milestone badges — 13 unlockable badges. The day-streak counter now bumps on any tracked activity (mood log, journal, CBT thought record, breathing session, gratitude entry) instead of mood-only. Awards:
streak3/streak7/streak14/streak30, four first-time badges, four volume badges (10-count), andfirstWeeklyReport. - Badges shelf + grid — Recent-badges shelf on the Profile screen plus a full grid at
/profile/badgesshowing earned badges in color with earned-date and locked badges desaturated with a lock icon. - Badge unlock snackbar — Surfaces from any tab via a global Riverpod listener in
main_shell.dart. Single unlock shows badge title; multiple simultaneous unlocks show “N badges unlocked”. - Centralized streak logic — All streak math moved into
BadgeService._bumpStreakAndAward. Each save-path provider (mood, journal, breathing, gratitude, weekly report) calls one matchingon*method. - userBadges Firestore subcollection — Path
userBadges/{uid}/badges/{badgeType}. Idempotent awards (badge type as document ID). Volume badges use Firestore aggregatecount()queries — single billed read regardless of size. - GDPR delete updated —
deleteAllUserData()now wipes the userBadges subcollection along with the existing six. - Journal “New entry” button — Moved from
FloatingActionButtonto anAppBaraction so the persistent SOS FAB has a clear slot on the journal tab. - 169 unit tests — Added BadgeType enum tests (round-trip, completeness, getter coverage) and SOS coping-cards tests (pool size, shuffle distinctness).
Version 1.2.0 · Apr 2026Voice, insights and white-label
- Voice input — Tap the mic button in chat to speak your message; speech is transcribed via
speech_to_textand auto-populated in the text field. - Text-to-speech — Toggle voice mode in chat to have CalmAI’s responses read aloud via
flutter_tts. - Day streak counter — Shown on the Analytics screen, pulling from the user profile’s live streak data.
- Top mood triggers — Horizontal bar chart on Analytics showing the user’s top 5 recurring triggers with frequency counts.
- Color-coded insight cards — Each insight type (positive, downward trend, trigger, pattern) has a distinct icon and accent color.
- White-label branding panel — Set app name, support email, privacy policy URL, and terms URL at runtime from the Admin Config screen — no redeployment needed.
Version 1.1.0 · Apr 2026Admin panel
- Web admin panel — Full admin dashboard running on Chrome. Dashboard with KPI cards and charts, paginated user management with search, crisis conversation moderation with read-only review, mood analytics with date range filtering, runtime configuration editor, weekly reports browser with CSV export, and immutable audit log of all admin actions.
- Admin authentication — Email/password login verified against
admin_usersFirestore collection. Role-based access (superAdmin, admin, viewer). Bypass flag for development. - Audit trail — All admin actions (toggle premium, GDPR delete, config changes, crisis keyword updates, conversation reviews) logged to
audit_logscollection with admin identity, timestamp, and details. - CSV export — Export weekly reports, audit logs, and per-user mood logs/journal entries as CSV files.
- Crisis config via web — Manage crisis detection keywords and regional resources directly from the admin panel.
- Firebase Hosting — One-command deployment via
firebase deploy --only hosting. - Design alignment — Admin panel uses the same Living Sanctuary theme (forest green, Newsreader + Manrope) as the mobile app.
- 160+ unit tests — Crisis detection, mood pattern detector, validators, date helpers, all enums, breathing exercises.
Version 1.0.0 · Mar 2026Initial release
- AI therapy chat — GPT-4o and Google Gemini 1.5 Pro chatbot with CBT-based responses, conversation history, and conversation starters. Switchable via Firebase Remote Config (no app update needed).
- Mood logging — 8 mood types (Great, Good, Neutral, Low, Sad, Anxious, Frustrated, Exhausted), 1–5 intensity slider, trigger tags, AI mood acknowledgment after each log.
- Guided journal — Free-write, AI-prompted journal (1 AI-generated prompt per entry), and 6-step CBT Thought Record with AI compassionate review at the end.
- 5 guided breathing exercises — Box Breathing, 4-7-8, Deep Calm, Energize, Sleep Wind-Down. Fully animated breathing circle, 100% offline — no API call required.
- Gratitude journal — Daily 3-item entry, streak tracking, and scrollable gratitude jar view.
- Mood analytics — Trend charts, weekly pattern insights, and wellness score powered by fl_chart.
- Weekly AI wellness report — Personalized summary with wins, insights, recommended technique, and next-week intention. PDF export included. Premium feature.
- Morning affirmation — Personalized AI-generated affirmation shown on the home dashboard each morning.
- Onboarding flow — 4 animated slides + Wellness Setup screen (name, primary concern, therapy experience level).
- Firebase Auth — Email/password, Google Sign-In, and anonymous guest mode.
- RevenueCat IAP — Monthly and annual premium subscriptions with paywall screen.
use_mock_purchaseRemote Config flag for review/testing without live IAP credentials. - AdMob ads — Banner and interstitial ads. Fully optional — leave Remote Config IDs empty to disable all ads.
- Push notifications — Daily check-in reminders, streak alerts, and weekly report notifications via Firebase Cloud Messaging and flutter_local_notifications.
- Dark mode — Full dark theme (soft indigo palette) with persisted user preference across restarts.
- Crisis safety system — Client-side keyword detection (offline, <100 ms), 5-region crisis resource database (US, UK, AU, CA, International), always-visible “Talk to a Professional” link in the chat screen.
- Mandatory disclaimer screen — Shown on every first launch. User must acknowledge before accessing the app. Stored in Firestore; router redirects if not accepted.
- Age gate — 18+ confirmation step during onboarding. Users under 18 are shown a message directing them to appropriate resources.
- GDPR-ready — Full data export and one-tap account + data deletion (removes all Firestore subcollections).
- Firebase Remote Config — All API keys and feature flags (AI provider, free tier limits, ad IDs, mock purchase flag) managed remotely without app updates.
- Offline HTML documentation — This documentation file and a Quick Start Guide included in the
documentation/folder.
Support and licensing
If you have any questions, issues, or need help setting up CalmAI, reach out directly — we’re happy to help.
What support covers
- Six months of support from purchase, extendable at checkout
- Support covers bugs in the template and questions about how it is put together
- It does not cover custom feature work, third-party API changes or store review outcomes
- The Regular licence covers one free end product. Charging users for the app itself needs the Extended licence