devsnack
Documentation

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.

$18 on CodeCanyon
On this page
01

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

Framework
Flutter 3.41.x / Dart 3.11.x
State management
Riverpod 2.x + flutter_riverpod
Navigation
GoRouter 14.x
Backend
Firebase (Auth, Firestore, Remote Config, FCM)
AI — primary
OpenAI GPT-4o via REST API
AI — secondary
Google Gemini 1.5 Pro via REST API
In-app purchases
RevenueCat (purchases_flutter)
Ads
Google AdMob (google_mobile_ads)
Local storage
SharedPreferences + Hive
HTTP
Dio 5.x
Charts
fl_chart 0.69
02

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
03

Quick start

  1. 01

    Unzip and open the project

    Extract the zip. Open the calm-ai folder in Android Studio or VS Code.
  2. 02

    Install dependencies and generate code

    terminal
    flutter pub get
    dart run build_runner build --delete-conflicting-outputs
  3. 03

    Add Firebase config files

    Follow the Firebase setup section below. Place google-services.json in android/app/ and GoogleService-Info.plist in ios/Runner/.
  4. 04

    Set your API keys in Remote Config

    Add at minimum openai_api_key (or gemini_api_key) in Firebase Remote Config. See the Remote Config keys section.
  5. 05

    Run the mobile app

    terminal
    flutter run

    The app will launch. On first run it shows the onboarding flow → disclaimer → login.

  6. 06

    Run the admin panel (web)

    terminal
    flutter run -d chrome

    Opens the admin panel in Chrome. Uses kIsWeb detection in main.dart to show the admin UI instead of the mobile app.

04

Firebase setup

  1. 01

    Create a Firebase project

    Go to console.firebase.google.com → Create project → give it any name.
  2. 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”)
  3. 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.
  4. 04

    Enable Remote Config

    Build → Remote Config → Get started. Add the keys listed in the Remote Config section.
  5. 05

    Enable Cloud Messaging (FCM)

    Build → Cloud Messaging → automatically enabled when you add the app. For iOS, upload your APNs key (see Notifications).
  6. 06

    Register Android app

    Project Settings → Add app → Android → Package name: com.devsnack.calmai (or your custom ID) → Register → download google-services.json → place in android/app/.
  7. 07

    Register iOS app

    Project Settings → Add app → Apple → Bundle ID: com.devsnack.calmai → Register → download GoogleService-Info.plist → drag into ios/Runner/ in Xcode (not just file system).
Warning

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.

terminal
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android
05

Remote 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.

Key nameTypeDefaultDescription
openai_api_key
String
""
OpenAI API key for GPT-4o chat, journaling, and reports
gemini_api_key
String
""
Google Gemini 1.5 Pro API key (alternative to OpenAI)
default_ai_provider
String
"openai"
Which AI to use: "openai" or "gemini"
free_daily_chat_messages
Int
10
Daily chat message limit for free-tier users
free_weekly_journal_entries
Int
5
Weekly journal entry limit for free-tier users
free_meditations
Int
3
Number of bundled meditations unlocked for free-tier users (rest are paywalled)
admob_banner_id
String
""
AdMob banner ad unit ID. Leave empty to hide banner ads.
admob_interstitial_id
String
""
AdMob interstitial ad unit ID. Leave empty to disable.
revenuecat_api_key
String
""
RevenueCat public SDK key for your app
use_mock_purchase
Boolean
true
Set to false before releasing. When true, premium unlocks without a real purchase (for testing only).
Warning
Before releasing to stores: set use_mock_purchase to false in Remote Config. Releasing with it set to true gives all users free premium access.
Tip
Switch AI provider any time: change default_ai_provider in Remote Config and publish — no app update needed. The app fetches config on every launch.
06

RevenueCat (in-app purchases)

  1. 01

    Create a RevenueCat account

    Sign up at app.revenuecat.com. The free plan is sufficient to start.
  2. 02

    Create a new project

    Dashboard → + New Project → give it your app name.
  3. 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.
  4. 04

    Create the entitlement

    Entitlements → + New → Identifier: premium (must match exactly — the app checks for this identifier).
  5. 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.
  6. 06

    Create a default offering

    Offerings → + New offering → Identifier: default → attach your monthly and annual packages.
  7. 07

    Copy SDK key to Remote Config

    Project Settings → API keys → copy the Public (Android/iOS) key → paste into Remote Config as revenuecat_api_key.
  8. 08

    Set use_mock_purchase to false

    Update this Remote Config key before releasing so real purchases are processed.
07

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.

  1. 01

    Create an AdMob account

    Visit admob.google.com and add your app for iOS and Android.
  2. 02

    Create ad units

    For each platform create a Banner ad unit and an Interstitial ad unit.
  3. 03

    Add App ID to native files

    Android: add this to android/app/src/main/AndroidManifest.xml

    AndroidManifest.xml
    <meta-data
        android:name="com.google.android.gms.ads.APPLICATION_ID"
        android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX"/>

    iOS: in ios/Runner/Info.plist add a GADApplicationIdentifier key with your App ID value.

  4. 04

    Add unit IDs to Remote Config

    Copy the Banner unit ID → admob_banner_id. Copy the Interstitial unit ID → admob_interstitial_id.
Tip
Testing: use AdMob’s test ad unit IDs during development to avoid invalid traffic policy violations. Swap in real IDs only in your production Remote Config.
08

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)

  1. 01
    In Apple Developer Portal → Certificates, Identifiers and Profiles → Keys → create an APNs key (or use a certificate).
  2. 02
    Firebase Console → Project Settings → Cloud Messaging → Apple app → upload the APNs key (or p12 certificate) and enter the Key ID + Team ID.
  3. 03
    In 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.

09

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
Warning
Also update Firebase: register a new app in Firebase Console with the new bundle ID and download a fresh 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 CFBundleName value

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: 10
  • free_weekly_journal_entries — default: 5
  • free_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 in lib/core/theme/app_theme.dart to change typography globally
  • All spacing constants are in lib/core/constants/app_sizes.dart
10

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

us
988 Suicide & Crisis Lifeline, Crisis Text Line (741741), SAMHSA Helpline
uk
Samaritans (116 123), Crisis Text Line UK (85258)
au
Lifeline Australia (13 11 14), Beyond Blue
ca
Crisis Services Canada, Kids Help Phone
international
IASP Crisis Centres directory, Befrienders Worldwide

Adding a new region

Add a new entry to the byRegion map in crisis_resources.dart:

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.

11

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.

firestore.rules
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;
    }

  }
}
12

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

ModuleRouteDescription
Dashboard
/dashboard
KPI cards (total users, active today, premium, crisis flags) + charts
Users
/users
Paginated list with search, user detail with data tabs, toggle premium, GDPR delete
Analytics
/analytics
Mood distribution chart, top triggers, date range filtering
Moderation
/moderation
Crisis-flagged conversations list, read-only conversation review, mark as reviewed
Configuration
/config
AI provider, free tier limits. API key editing controlled by _allowApiKeyEditing flag
Crisis config
/config/crisis
Manage crisis detection keywords and resources per region
Reports
/reports
Browse weekly wellness reports across all users, CSV export
Audit log
/audit-log
Immutable trail of all admin actions (premium toggles, GDPR deletes, config changes)

Admin authentication

The admin panel uses Firebase Auth (email/password) and checks the admin_users Firestore collection. To set up:

  1. 01
    Create an email/password account in Firebase Auth
  2. 02
    Add a document in Firestore → admin_users/{uid} with fields: uid, email, displayName, role: "superAdmin", createdAt
  3. 03
    Set _bypassAuth = false in lib/admin/core/router/admin_router.dart
Warning
Development mode: set _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

terminal
# Build the web app
flutter build web

# Deploy to Firebase Hosting
firebase deploy --only hosting --project YOUR_PROJECT_ID

The admin panel will be available at https://YOUR_PROJECT_ID.web.app.

Firestore collections (admin-specific)

admin_users/{uid}
Admin accounts with roles (superAdmin, admin, viewer)
audit_logs/{logId}
Immutable log of admin actions
app_config/{key}
Runtime config (free tier limits, AI provider, crisis keywords)
Note
Firestore indexes required: the Moderation and Reports screens use 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.
13

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_purchase set to false
  • flutter analyze returns zero issues

Commands

terminal
# 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_ID

Signing — Android

Follow these steps to sign your release build for the Play Store.

  1. 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.

    terminal
    keytool -genkey -v \
      -keystore ~/calmai-release.jks \
      -keyalg RSA \
      -keysize 2048 \
      -validity 10000 \
      -alias calmai

    You will be prompted for a keystore password, your name, organisation, city, country, and a key password. Note down both passwords — they cannot be recovered.

  2. 02

    Create android/key.properties

    Create the file android/key.properties (this file must not be committed to version control — add it to .gitignore):

    android/key.properties
    storePassword=YOUR_KEYSTORE_PASSWORD
    keyPassword=YOUR_KEY_PASSWORD
    keyAlias=calmai
    storeFile=/Users/YOUR_USERNAME/calmai-release.jks

    Set storeFile to the absolute path of the .jks file you generated in step 1.

  3. 03

    Configure android/app/build.gradle

    Open android/app/build.gradle and 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'
            }
        }
    }
  4. 04

    Build the signed release

    terminal
    # App Bundle (recommended for Play Store)
    flutter build appbundle --release
    
    # Or APK
    flutter build apk --release

    The signed artifact is output to build/app/outputs/bundle/release/app-release.aab (bundle) or build/app/outputs/flutter-apk/app-release.apk (APK).

Tip

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:

terminal
keytool -list -v -keystore ~/calmai-release.jks -alias calmai

Signing — 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)
14

Feature overview

FeatureWhere to accessTier
AI therapy chat
Chat tab
Free · 10/dayUnlimited
Mood logging (8 moods + intensity + triggers)
Mood tab
Free
AI mood acknowledgment
After logging mood
Free
Free-write journal
Journal tab → FAB
Free · 5/week
AI-prompted journal
Journal tab → FAB
Free · 5/week
CBT thought record (6-step)
Journal tab → FAB
Free · 5/week
Discuss journal with AI
Journal entry detail
Free
Guided breathing (5 techniques, offline)
Home → Breathing
Free
Gratitude journal (daily 3 items + streak)
Home → Gratitude
Free
Mood analytics (charts, patterns, insights)
Analytics tab
Free
Weekly AI wellness report
Analytics → Report
Premium
Morning affirmation (personalized AI)
Home dashboard card
Free
Dark mode
Settings → Appearance
Free
Crisis resources
Chat screen (always visible)
Always on
SOS coping cards (10 grounding techniques, offline)
Persistent FAB on every tab
Always on
Tap-to-dial crisis hotlines (5 regions)
SOS screen → “Talk to a human now”
Always on
Streaks and milestone badges (17 badges)
Profile → Badges shelf / /profile/badges
Free
Google Sign-In
Login screen
Free
Guest mode
Login screen
Free
Data export
Profile → Export Data
Free
Full data deletion (GDPR)
Profile → Delete Account
Free
15

Safety rules

Warning
These safety features are non-negotiable. Removing or weakening them may violate App Store / Play Store policies for mental health apps and could cause real harm to users.

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 disclaimerAccepted flag is false back to this screen. The user must tap “I Understand” to proceed.
  • Client-side crisis detection lib/data/services/crisis_detection_service.dart scans 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.dart on 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.dart explicitly 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.
16

FAQ and troubleshooting

The app crashes immediately on launch.
This almost always means 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.
I see “Remote Config fetch skipped” in the logs.
This is normal — it means the device was offline or the Firebase project isn’t configured yet. The app silently falls back to the default values defined in RemoteConfigService.initialize(). No action needed.
The AI chat isn’t responding.
Check that 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.
In-app purchases aren’t working in production.
Make sure 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.
Push notifications aren’t working on iOS.
Upload your APNs Authentication Key to Firebase Console → Project Settings → Cloud Messaging → Apple app. Also ensure Push Notifications and Background Modes (Remote notifications) capabilities are enabled in Xcode.
I get build_runner errors after flutter pub get.
Run flutter pub run build_runner build --delete-conflicting-outputs. The --delete-conflicting-outputs flag removes any stale generated files that may conflict.
Google Sign-In fails on Android with “ApiException: 10”.
This means the SHA-1 fingerprint of your signing certificate isn’t registered in Firebase. Go to Firebase Console → Project Settings → Your Android app → SHA certificate fingerprints → add the SHA-1 from your debug or release keystore.
How do I switch from OpenAI to Gemini?
Set 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.
Can I add more crisis regions?
Yes. Add a new key and List<CrisisResource> to the byRegion map in lib/core/constants/crisis_resources.dart and rebuild. Users can select their region in Settings.
Where are the AI prompts? Can I edit them?
All prompts are in 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.
17

Changelog

Every version published so far. Updates are free for the life of the item.

v1.5.0 · Jul 2026
Worry Box — CBT worry-postponement with capture, daily reminders, review flow, stats and optional premium AI reflection.
v1.4.0 · May 2026
Sleep tracker, habit tracker, guided meditation library with offline text-to-speech, expanded weekly wellness report.
v1.3.0 · May 2026
SOS coping cards, crisis hotline dialer, 13 unlockable badges with streak tracking and milestones.
v1.2.0 · Apr 2026
Voice input and output, mood trigger analytics, white-label admin branding panel, insight cards.
v1.1.0 · Apr 2026
Web admin panel with dashboard, user management, moderation, analytics, reports and audit log.
v1.0.0 · Mar 2026
Initial release with AI chat, mood and journal logging, breathing exercises, gratitude tracking and analytics.

Version 1.4.0 · May 2026Sleep, habits and meditation

  • Sleep tracker — New /sleep screen 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/history shows 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 at sleepLogs/{uid}/logs/{yyyy-MM-dd} — the wake date is the doc id, so editing the same night updates instead of duplicating.
  • Habit tracker — New /habits screen 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/:id shows a 30-day completion heatmap and archive control. Two collections: habitDefinitions/{uid}/habits/{habitId} and habitCompletions/{uid}/completions/{date}_{habitId} (flat composite key for simple queries).
  • Guided meditation library — New /meditation screen 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/player uses flutter_tts to 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 to meditationSessions/{uid}/sessions/{sessionId}.
  • 4 new milestone badgesfirstSleepLog, sleepStreak7 (7 consecutive nights of sleep logging), firstMeditation, meditations5 (5 completed meditations). BadgeType enum now has 17 values total. Sleep streak is computed in SleepRepository.calculateStreak and passed into BadgeService.onSleepLogged; meditation count is computed in MeditationRepository.completedSessionCount and passed into BadgeService.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 the WeeklyReport model 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 extendeddeleteAllUserData() now wipes 10 user-scoped subcollections (adds sleepLogs, habitDefinitions, habitCompletions, meditationSessions on top of the previous 7 v1.3 collections).
  • New Remote Config keyfree_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 from MainShell). “Add habit” lives as an AppBar action 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 /sos with 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 offline CrisisResources map.
  • 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), and firstWeeklyReport.
  • Badges shelf + grid — Recent-badges shelf on the Profile screen plus a full grid at /profile/badges showing 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 matching on* method.
  • userBadges Firestore subcollection — Path userBadges/{uid}/badges/{badgeType}. Idempotent awards (badge type as document ID). Volume badges use Firestore aggregate count() queries — single billed read regardless of size.
  • GDPR delete updateddeleteAllUserData() now wipes the userBadges subcollection along with the existing six.
  • Journal “New entry” button — Moved from FloatingActionButton to an AppBar action 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_text and 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_users Firestore 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_logs collection 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_purchase Remote 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.
18

Support and licensing

If you have any questions, issues, or need help setting up CalmAI, reach out directly — we’re happy to help.

Note
Response time: we typically respond within 24 hours on business days. Please include your CodeCanyon purchase code when reaching out so we can assist you faster.

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