§1Overview

Rosie AI is a Flutter app for keeping personal memories — journaling, photo albums, an AI chat ("Rosie"), and people connections. Package com.bandraroad.heyrosie on Android, com.bandraroad.rosieai on iOS.

Stack

  • Flutter 3.x (Dart ^3.5.3)
  • State: provider + ChangeNotifier
  • Theme: MobX
  • DI: GetIt
  • Routing: Navigator 1.0 named routes
  • Local cache: sqflite + SharedPreferences

Backend

  • Firebase project rosie-main
  • Firestore + Firebase Auth + Storage + Remote Config + Analytics
  • REST APIs (env-switchable: staging / production)
  • OneSignal push
  • Socket.io for real-time
Where to start If you're new: skim the proposed screenshot → APK workflow first to see the intended operating model. Note: that workflow is proposed and prototype-validated, not yet day-to-day. The rest of this doc is reference for the codebase as it exists today.

Architecture at a glance

flowchart TB subgraph UI["UI Layer · lib/features/*"] Screens["Screens
JournalPage, Dashboard,
NewMemoryBuilder, ChatScreen, …"] SharedWidgets["Shared Widgets
lib/widgets/, lib/core/widgets/"] end subgraph State["State Layer"] Providers["20 Global ChangeNotifierProviders
+ feature-local providers"] Theme["MobX ThemeStore"] end subgraph ServiceLayer["Service Layer · lib/core/services/"] Services["28 services
analytics, firebase, notification,
journal_api, vault, …"] DI["GetIt locator"] end subgraph Persistence["Persistence"] Firestore[("Firestore
rosie-main")] Storage[("Firebase
Storage")] SQLite[("SQLite
sqflite")] Prefs[("Shared
Preferences")] end subgraph External["External"] REST["REST APIs
(env-switchable)"] OneSignal["OneSignal
Push"] Socket["Socket.io
Real-time"] OAuth["Google · Apple ·
Facebook · Spotify · …"] end Screens --> Providers Screens --> SharedWidgets Screens --> Theme Providers --> Services Services -.uses.-> DI Services --> Firestore Services --> Storage Services --> SQLite Services --> Prefs Services --> REST Services --> OneSignal Services --> Socket Services --> OAuth classDef ui fill:#ff6b5e,stroke:#ff6b5e,color:#fff classDef state fill:#7cb7ff,stroke:#7cb7ff,color:#0f1115 classDef svc fill:#ffb86c,stroke:#ffb86c,color:#0f1115 classDef ext fill:#bd93f9,stroke:#bd93f9,color:#0f1115 class Screens,SharedWidgets ui class Providers,Theme state class Services,DI svc class REST,OneSignal,Socket,OAuth ext
Layered architecture · UI talks to Providers, Providers talk to Services, Services own all I/O.

§2Screenshot → APK workflow

The intended headline workflow. Drop a screenshot + describe the bug, get back a working APK.

Status · proposed, not yet in regular use This is a designed and prototype-validated workflow — the infrastructure is in place (drop folder, build automation, agent rules in AppCode/CLAUDE.md), and the loop has been run end-to-end once on a clean APK build. It is not yet the day-to-day flow for this project. Treat this section as the target operating model; expect rollout to be incremental.

The contract

You giveYou get
A screenshot (paste in chat or drop in Frontend-Plan/inbox/) A debug APK at Frontend-Plan/builds/app-debug-<timestamp>.apk
One sentence describing what's wrong A 3–5 line report: bug, file:line, APK path, install command

The 7 steps

  1. Read the screenshot — identify the screen, match it to a Dart file under AppCode/lib/features/
  2. Locate the code — open the widget + its provider + relevant constants
  3. State the bug in one sentence — if you can't, you don't understand it yet
  4. Fix — minimal change, matching existing patterns. No drive-by refactors.
  5. Verify it compiles: flutter analyze must pass
  6. Build the APK: flutter build apk --debug, copy to timestamped slot
  7. Report back in 3–5 lines
flowchart LR Screenshot[/"📸 Screenshot
+ 1-sentence bug"/] --> Read["1 · Read image
(identify screen)"] Read --> Locate["2 · Locate code
lib/features/<screen>.dart"] Locate --> Diagnose["3 · State bug
in one sentence"] Diagnose --> Fix["4 · Fix
(minimal Edit)"] Fix --> Analyze{"5 · flutter analyze"} Analyze -->|fail| Fix Analyze -->|pass| Build["6 · flutter build apk --debug"] Build --> Copy["cp to
builds/app-debug-<ts>.apk"] Copy --> Report[/"7 · 3–5 line report
📦 APK ready"/] classDef input fill:#bd93f9,stroke:#bd93f9,color:#0f1115 classDef step fill:#7cb7ff,stroke:#7cb7ff,color:#0f1115 classDef gate fill:#ffb86c,stroke:#ffb86c,color:#0f1115 classDef output fill:#50fa7b,stroke:#50fa7b,color:#0f1115 class Screenshot input class Read,Locate,Diagnose,Fix,Build,Copy step class Analyze gate class Report output
No confirmations · The only branch is the analyze gate; everything else flows straight through.

Trigger phrases

Any of these enters the workflow: "fix this", "ship a build", "fix and build", "do this", or any image with a problem description.

Install on the emulator

# JDK 17 required — Gradle 8.9 rejects JDK 26
export JAVA_HOME=$(/usr/libexec/java_home -v 17)

adb -s emulator-5554 install -r \
  Frontend-Plan/builds/app-debug-<timestamp>.apk

# Launch:
adb -s emulator-5554 shell am start -n com.bandraroad.heyrosie/.MainActivity
Existing install with different signature If adb install fails with INSTALL_FAILED_UPDATE_INCOMPATIBLE, uninstall first: adb -s emulator-5554 uninstall com.bandraroad.heyrosie

§3Build & run

# All commands run from AppCode/
cd /Users/gauravtewari/PycharmProjects/AutomatedTestingApp/AppCode

# JDK 17 — REQUIRED. System default JDK 26 will fail.
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH=$JAVA_HOME/bin:$PATH

flutter pub get
flutter analyze
flutter test                              # unit + widget
flutter test integration_test/            # on a device/emulator

# Run on the project's emulator (rosie_proper / emulator-5554):
flutter run -d emulator-5554

# Build debug APK:
flutter build apk --debug
# Output: build/app/outputs/flutter-apk/app-debug.apk

# MobX codegen (after editing observables):
dart run build_runner build --delete-conflicting-outputs
Emulator AVD name rosie_proper · 1080×2340 · serial emulator-5554.
Start: ~/Library/Android/sdk/emulator/emulator -avd rosie_proper -no-window -no-audio &

§4Entry & app shell

Startup sequence (lib/main.dart)

  1. WidgetsFlutterBinding.ensureInitialized()
  2. IntentHandler.handleIntent() — incoming Android intents / deep links
  3. setupLocator() — GetIt DI container (lib/core/di/locator.dart)
  4. Firebase.initializeApp() with platform options (rosie-main project)
  5. Firestore offline persistence + unlimited cache (Samsung-device quirk noted in code)
  6. initializeApp() — NotificationService, RemoteConfigService, PhotoCacheService, AnalyticsService
  7. OneSignal init (lines 138–303 in main.dart) with deep-link router

Root widget

MyApp (line 325 in main.dart) wraps everything with:

Theme

Driven by MobX themeStore (lib/features/settings/theme_store.dart), observed in MyApp.build. Light/dark/system modes.

Startup sequence

sequenceDiagram participant OS as Android/iOS OS participant Main as main() participant DI as GetIt locator participant FB as Firebase participant Svc as Core Services participant OS1 as OneSignal participant App as MyApp / MaterialApp OS->>Main: launch Main->>Main: WidgetsFlutterBinding.ensureInitialized() Main->>Main: IntentHandler.handleIntent() Main->>DI: setupLocator() Note over DI: FirebaseService
NotificationService
UserProfileService
BiometricAuthService Main->>FB: initializeApp(rosie-main) Main->>FB: Firestore.settings (offline, ∞ cache) Main->>Svc: initializeApp() Note over Svc: NotificationService
RemoteConfigService
PhotoCacheService
AnalyticsService Main->>OS1: OneSignal.initialize(appId) OS1-->>Main: deep-link router ready Main->>App: runApp(MyApp) App->>App: MultiProvider (20 providers) App->>App: MaterialApp(home: SplashScreen) App-->>OS: first frame rendered
main.dart startup · ~7 steps, OneSignal init is the longest (lines 138–303).

§5State management

provider + ChangeNotifier for app state, MobX for theme only, GetIt for service singletons. No Riverpod, no Bloc.

Global providers

ProviderFileResponsibility
AuthenticationProviderlib/providers/authentication_provider.dartFirebase Auth (email, Google, Apple, Facebook)
HomepageProviderlib/features/home/provider/...Dashboard data
HomepageStateProviderlib/features/home/provider/...Home UI state (tabs, filters)
CollectionMemoryProviderlib/features/home/provider/...Memory collections
TimelineProvider / TimelineStateProviderlib/features/home/provider/...Timeline data & UI state
MemoryViewerProviderlib/providers/memory_viewer_provider.dartMemory detail & galleries
GlobalNotificationProviderlib/providers/global_notification_provider.dartIn-app toasts
ThirdPartyServicesProviderlib/providers/third_party_services_provider.dartGoogle Photos, Calendar, Spotify, …
JournalProvider largelib/features/journal/provider/...Journal CRUD + AI summaries — 500+ lines, tech-debt candidate
JournalCartProviderlib/features/journal/provider/...Unsaved journal drafts
MemoryBuilderProvider mixedlib/providers/memory_builder_provider.dartMemory creation + Firestore user data + OneSignal token
VoiceRecorderServicelib/providers/voice_recorder.dartVoice input (doubles as ChangeNotifier)
ChatProviderlib/features/chat_screens/chat_provider.dartChat with Rosie AI
ProfileDataProviderlib/features/drawer/provider/...User profile state
ConnectionProvider / FamProviderlib/features/Connections/provider/...People & family
NotesProvider / NoteCartProviderlib/features/Connections/provider/...Connection notes
NewMemoryProviderlib/features/memory_builder/...New memory builder logic
PhotoUploadProviderlib/providers/photo_upload_provider.dartUpload progress

Consumption patterns

// Read once (no rebuild):
context.read<JournalProvider>().fetchEntries();

// Listen & rebuild on change:
final entries = context.watch<JournalProvider>().entries;

// Outside a widget (e.g. from a service callback):
Provider.of<JournalProvider>(
  navigatorKey.currentContext!, listen: false,
);

DI (GetIt)

// lib/core/di/locator.dart
locator.registerSingleton<FirebaseService>(FirebaseService());
locator.registerSingleton<NotificationService>(NotificationService());
locator.registerLazySingleton(() => UserProfileService());
locator.registerLazySingleton(() => BiometricAuthService());

State flow: a typical user action

Example: user taps "save" on a journal entry.

sequenceDiagram participant User participant Widget as JournalPage
(Widget) participant Provider as JournalProvider
(ChangeNotifier) participant API as JournalApi
(Service) participant FB as Firestore participant Cache as SQLite cache User->>Widget: tap "Save" Widget->>Provider: context.read<JournalProvider>()
.saveEntry(entry) Provider->>Provider: _isLoading = true Provider->>Provider: notifyListeners() Widget-->>User: spinner shown Provider->>API: POST /journal/entries API->>FB: write doc FB-->>API: ack API-->>Provider: JournalEntry Provider->>Cache: upsert entry Provider->>Provider: _entries.add(entry)
_isLoading = false Provider->>Provider: notifyListeners() Widget->>Widget: context.watch rebuilds Widget-->>User: entry appears in list
The Provider is the single coordinator. Service handles I/O; cache happens write-through; UI re-renders via notifyListeners().

§6Routing & navigation

Navigator 1.0 with named routes via onGenerateRoute. Router lives at lib/core/navigation/app_router.dart. Not GoRouter.

RouteScreenNotes
/SplashScreenAuth-state gate; initial routing
/homeDashboard5-tab hub: Home, Journal, Timeline, Connections, Chat
/memories/{id}NewMemoryViewer(batchId)Dynamic param; deep-linked
/loginAuthScreenEmail + OAuth
/onboardingOnboardingScreenFirst-run flow
/settingsSettingsScreenPreferences
/profile-homeProfileHomeScreenUser profile
/tutorialsTutorialScreenFeature tutorials
/faqFAQScreenBackend-driven FAQs
/helpHelpScreenSupport resources
/get-in-touchGetInTouchScreenContact form
/third-partyThirdPartyScreenIntegrations list
/connect-servicesConnectServicesScreenOAuth callback
/memory-ideasMemoryIdeasScreenAI suggestions

Deep linking

OneSignal payload keys memoryId, deepLink, route are translated to navigator pushes in main.dart:216–290.

Programmatic navigation

final navigatorKey = GlobalKey<NavigatorState>();
navigatorKey.currentState?.pushNamed('/home');

Navigation map

flowchart LR Start(["App launch"]) --> Splash["/
SplashScreen"] Splash -->|signed in| Dashboard Splash -->|new user| Onboarding["/onboarding"] Splash -->|signed out| Login["/login
AuthScreen"] Login -->|success| Dashboard Onboarding --> Dashboard Dashboard["/home · Dashboard"] --> TabHome["Tab: Home"] Dashboard --> TabJournal["Tab: Journal"] Dashboard --> TabTimeline["Tab: Timeline"] Dashboard --> TabConnections["Tab: Connections"] Dashboard --> TabChat["Tab: Chat"] TabHome --> Memory["/memories/{id}
NewMemoryViewer"] TabHome --> Ideas["/memory-ideas"] TabJournal --> MemoryBuilder["NewMemoryBuilder"] TabConnections --> ProfileHome["/profile-home"] Dashboard -.drawer.-> Settings["/settings"] Dashboard -.drawer.-> FAQ["/faq"] Dashboard -.drawer.-> Help["/help"] Dashboard -.drawer.-> Tutorials["/tutorials"] Dashboard -.drawer.-> ThirdParty["/third-party"] ThirdParty --> ConnectSvc["/connect-services
(OAuth callback)"] PushDL{{"Push notification
OneSignal deep link"}} PushDL -.memoryId.-> Memory PushDL -.route.-> Dashboard classDef entry fill:#ff6b5e,stroke:#ff6b5e,color:#fff classDef tab fill:#7cb7ff,stroke:#7cb7ff,color:#0f1115 classDef drawer fill:#ffb86c,stroke:#ffb86c,color:#0f1115 classDef push fill:#bd93f9,stroke:#bd93f9,color:#0f1115 class Splash,Login,Onboarding entry class TabHome,TabJournal,TabTimeline,TabConnections,TabChat tab class Settings,FAQ,Help,Tutorials,ThirdParty,ConnectSvc drawer class PushDL push
Named routes registered in lib/core/navigation/app_router.dart. Dashboard owns 5 tabs; push notifications can deep-link anywhere.

§7Feature modules

Each feature in lib/features/ follows the same shape: screens/, provider/, models/, services/, widgets/.

FeaturePurposeEntry class
splashAuth-state gateSplashScreen
authEmail + OAuth loginAuthScreen
auth_dialogsVerification & reset dialogs
onboardingFirst-run welcomeOnboardingScreen
homeDashboard with 5 tabsDashboard
journalDaily journaling, moods, AI summariesJournalPage
memoryPhoto picker (incl. Google Photos)SelectPhotosScreen
memory_builderCollage editor, narration, sharingNewMemoryBuilder / NewMemoryViewer
memory_ideasAI memory promptsMemoryIdeasScreen
ConnectionsPeople & family managementConnections
chat_screensChat with Rosie AIChatScreen
drawerSide menu, FAQ/Help/Tutorials
biographer stubLife-story capture (placeholder)BiographerComingSoonScreen
settingsTheme, biometric, accountSettingsScreen
profilespageProfile view/editProfileHomeScreen
share_rosieShareable collages & wrapsCreateTypeScreen → … → ExportScreen
third_partyGoogle Calendar, Spotify, etc.ThirdPartyScreen
introductionPost-login welcome flowsIntroductionScreen
appsApp-specific integrationsfeatures/apps/whatsapp/

Example: journal feature layout

features/journal/
├── journal_page.dart              // main screen
├── models/
│   ├── journal_model.dart
│   ├── journal_content_model.dart
│   └── focus_item_model.dart
├── provider/
│   ├── journal_provider.dart      // CRUD, AI summaries
│   └── journal_cart_provider.dart // drafts
├── services/
│   ├── journal_api.dart
│   ├── journal_data_service.dart
│   └── journal_firebase_service.dart
└── widgets/                       // notes, prompts, voice input

Feature module shape

Every feature in lib/features/<name>/ follows this internal structure.

flowchart TB Feature["lib/features/<name>/"] Feature --> Screens["screens/
main_page.dart"] Feature --> Provider["provider/
main_provider.dart
cart_provider.dart"] Feature --> Models["models/
data classes
(serialisable)"] Feature --> Services["services/
api.dart
firebase_service.dart"] Feature --> Widgets["widgets/
feature-local UI"] Screens -->|read/watch| Provider Screens -->|use| Widgets Provider -->|calls| Services Provider -->|holds| Models Services -->|returns| Models Services -->|persists| External[("Firestore
REST
SQLite")] classDef root fill:#ff6b5e,stroke:#ff6b5e,color:#fff classDef child fill:#7cb7ff,stroke:#7cb7ff,color:#0f1115 class Feature root class Screens,Provider,Models,Services,Widgets child
Same pattern across all 18 features · UI in screens/ + widgets/, state in provider/, I/O in services/.

§8Core services

lib/core/services/ holds the cross-cutting singletons and API wrappers used app-wide.

Services index

ServicePurpose
firebase_serviceFirebase init wrapper; guards duplicate apps
notification_serviceLocal notifications; creates channels
analytics_serviceFirebase Analytics; consent-gated; route observer
remote_config_serviceFirebase Remote Config — feature flags & env
photo_cache_serviceImage caching & cleanup on foreground
deep_link_serviceApp-link handling post-first-frame
user_profile_serviceCached user profile; SharedPreferences backed
biometric_auth_serviceFingerprint / Face unlock
notification_trigger_serviceScheduled local notifications
memory_note_count_serviceNote counts per memory
connection_serviceREST for connections
profile_api_serviceProfile CRUD against backend
journal_apiJournal REST endpoints
journal_firebase_serviceJournal entries in Firestore
notes_apiNotes CRUD
fam_api_serviceFamily relationships
user_connections_serviceFirestore connection docs
collaborator_serviceMulti-user memory access
face_image_serviceFace detection & cropping
link_metadata_serviceOpenGraph extraction
location_serviceGPS + geocoding
exif_servicePhoto EXIF parsing
screen_time_serviceTime-on-screen analytics
vault_upload_servicePhoto uploads to Firebase Storage
photo_vault_sync_serviceBi-directional vault sync
intent_handlerAndroid intent processing
update_serviceApp version check
premission_service typoPermission wrapper — note misspelling, do not rename in isolation

Local database

cache_manager_sqflite.dart in lib/core/database/ — SQLite via sqflite v2.4.1. Backs journal entries, notes, offline sync.

Environment switching

// lib/core/config/api_urls.dart
enum ApiEnvironment { production, staging }

class ApiUrls {
  static ApiEnvironment _currentEnvironment = ApiEnvironment.staging;

  static setEnvironment(ApiEnvironment env) =>
      _currentEnvironment = env;
}

No rebuild needed to flip — call ApiUrls.setEnvironment(...) at runtime.

§9Shared widgets

Cross-cutting UI lives in lib/widgets/ and lib/core/widgets/.

WidgetUse
CustomAppBarStandard header with back, title, actions
CustomShareDialogShare memory dialog
FullScreenImageViewerFullscreen photo gallery with swipe
PermissionDialogSystem-permission request
LoadingSpinnerAnimated loading indicator
MemorySkeletonLoaderShimmer placeholder for memory cards
SyncCompleteDialogConfirmation when sync finishes
LinkPreviewCardOpenGraph card (image, title, description)
DashedBorderPainterCustom dashed border
DeleteNoteDialogNote deletion confirm
ExitDialogApp-exit confirm
SnackbarUtilsToast helper
WebViewDocumentScreenEmbedded document viewer
WeeklyWrapScreen / MonthlyWrapScreen / YearlyWrapScreenPeriod summaries
WelcomeGuideScreenFeature tutorial guide
NotificationDrawerNotification center overlay
RippleEffectTouch feedback
ScreenSizeResponsive layout helper

§10Backend integration

Firebase (rosie-main)

REST APIs

Endpoints centralised in lib/core/config/api_urls.dart. Categories: chat, journal, memory, connection, profile. Auth via Firebase ID tokens in headers. http package v1.3.0. SQLite fallback for offline.

OneSignal push

Real-time

socket_io_client v3.0.0 — used for real-time notifications & chat.

Third-party integrations

Google Photos · Google Calendar (+ Calendly) · Spotify · WhatsApp · Facebook · Apple Sign-In.


§11Build & tooling

Android

iOS

Linting

flutter_lints enabled in analysis_options.yaml. prefer_const_constructors is intentionally disabled — flipping it on requires a project-wide cleanup; do not do in a single PR.

Codegen

build_runner ^2.4.13 + mobx_codegen ^2.6.2 (theme observables).

Assets

assets/{fonts,svgs,images,data,chatscreen}/ — fonts include Inter, Geist, serif variants.

CI/CD

No GitHub Actions present. Builds are manual. Adding lint + tests + build per PR is on the backlog.

§12Testing

Coverage is intentionally light — the AI testing harness in /test_runner does the heavy E2E lifting.

test/
├── unit/
│   ├── authentication_provider_test.dart  // pure error-mapping logic
│   ├── api_urls_test.dart                 // env switching
│   └── journal_api_test.dart
├── widget/
│   ├── dashboard_navigation_test.dart
│   ├── splash_screen_test.dart
│   └── screenshot_test.dart
├── collaborator_service_test.dart
└── widget_test.dart

integration_test/
├── app_flow_test.dart                     // captures screenshots
└── real_app_test.dart                     // full flow with Firebase
Adding tests for a new feature
  • Unit test for any new provider's pure logic
  • Widget test for any new screen's initial render + error state
  • Don't add integration tests without checking — they need the emulator and the AI harness

§13Conventions

§14Known gotchas

1 · JDK version for APK builds Gradle 8.9 (pinned in android/gradle/wrapper/gradle-wrapper.properties) rejects JDK 26. Always export JAVA_HOME=$(/usr/libexec/java_home -v 17) before flutter build apk. Failure signature: "Error resolving plugin [id: 'dev.flutter.flutter-plugin-loader'…] > 26".
2 · OneSignal App ID is hardcoded main.dart:139. Swapping environments today means editing source. Should be Remote Config or build-time env (see backlog).
3 · premission_service.dart filename typo Don't rename in isolation — touches many imports across the app.
4 · JournalProvider and MemoryBuilderProvider are large & mix concerns Don't grow them. If your change adds >50 lines, split first.
5 · Firestore offline persistence is unlimited Be careful with writes in tight loops — you'll fill local storage.
6 · OAuth callbacks land on /connect-services Keep that route handler intact.
7 · Samsung Firestore quirk Code is commented around the Firestore settings block in main.dart. Test on Samsung if touching startup.
8 · Deep-link payload schema OneSignal additional-data keys: memoryId, deepLink, route. See main.dart:216–290.
9 · Existing-install signature mismatch on emulator If adb install errors with INSTALL_FAILED_UPDATE_INCOMPATIBLE, uninstall first: adb -s emulator-5554 uninstall com.bandraroad.heyrosie

§15Tech debt & backlog

Surfaced from the architecture audit. Source of truth lives in Frontend-Plan/backlog.md — this section mirrors it for reference.

ItemSizeArea
Split JournalProvider (500+ lines) — separate UI state from data layerMjournal
Untangle MemoryBuilderProvider — currently mixes memory build, Firestore user data, OneSignal tokenMmemory_builder
Introduce a structured logger; replace scattered print() / debugPrint()Score
Move OneSignal App ID off main.dart:139 hardcode — Remote Config or build-time envScore
Reconcile version drift: pubspec 1.0.16+439 vs gradle 1.0.23/446Sbuild
Dedup user-profile state between AuthenticationProvider and ProfileDataProviderMauth
Adopt a consistent API result envelope (ApiResult<T>); standardise error messagingLcore
Rename premission_service.dartpermission_service.dartScore
One-off cleanup pass to enable prefer_const_constructorsLbuild
Add unit tests for the largest providersMtesting
Wire up the Biographer feature (currently a "coming soon" stub)Lbiographer
Set up CI (lint + tests + build per PR)Mbuild
Pin Android NDK to 28.2.13676358 in android/app/build.gradle (integration_test plugin requires it; only a warning today)Sbuild

§16Investor / mentor Q&A

Likely questions from investors and engineering mentors, with honest answers framed for credibility. Source of truth: Frontend-Plan/talking-points.md — edit there.

The 60-second pitch Rosie is a Flutter app — one codebase ships to both iOS and Android. It's a memory-keeping product: people journal, build photo memories, chat with an AI, and connect with family. ~50,000 lines of Dart across 18 feature modules. Backend is Firebase (auth, Firestore, storage, analytics) plus our own REST APIs and OneSignal for push. We deliberately picked boring, mainstream tools — the result is shipped on both platforms by a small team without a separate iOS / Android specialist.

Architecture & technical choices

Q · Why Flutter and not native iOS + Android?

Q · Walk me through how the app is structured.

  1. UIlib/features/ has one folder per feature (journal, memory builder, chat, …). Self-contained.
  2. State management — Provider pattern. Each feature has one or two "Providers" holding its data; UI rebuilds when data changes.
  3. Serviceslib/core/services/ is the only layer that talks to Firebase, our REST APIs, or the local cache. UI never touches the network directly.

Visual: architecture diagram, §1.

Q · Why Provider for state, not Riverpod or Bloc?

Q · What database do you use?

Q · How does authentication work?

Firebase Auth — email/password, Google, Apple, or Facebook. Sessions persisted. Firebase ID tokens (signed by Google) used when talking to our own backend. No passwords ever touch our servers.

Velocity & team productivity

Q · How fast can you ship a UI change?

Be precise on the workflow's status The screenshot → APK loop is proposed and prototype-validated, not yet our day-to-day flow. The infrastructure exists and the loop has been run end-to-end once on a clean build; cadence at scale is unproven. Say "designed, validated end-to-end once, rolling out" — not "our standard practice."

Q · How do you know a build is safe to ship?

  1. flutter analyze — static analysis on every build
  2. Unit and widget tests for the riskiest pure logic (auth, API config, journaling)
  3. AI testing harness — separate system that runs the real APK on a real Android emulator and uses GPT-4o vision to navigate the UI like a user would

Honest gap: frontend unit-test coverage is intentionally light — we offloaded broad coverage to the E2E harness because it's more representative. Trade-off is a slower feedback loop. CI pipeline that runs both layers per PR is on the roadmap.

Q · How big is the engineering team?

Frontend is currently a single developer + AI-assisted coding (Claude Code). Architecture and tooling are explicitly set up so a second developer can onboard in a day — top-level handoff doc plus per-folder CLAUDE.md conventions.

Scalability & cost

Q · Will this scale to a million users?

Q · What's the riskiest dependency?

Q · What if Google raises Firebase prices?

Firestore reads / writes are individually cheap; meaningful cost is storage at scale. Migration to self-hosted Postgres + S3 is a 6–8 week project if ever forced — not painless, not existential. Today, costs are well under $200/month all-in.

Quality & maintainability

Q · What's the worst part of the codebase right now?

Three honest items, all tracked in §15 backlog:

  1. Two providers (JournalProvider, MemoryBuilderProvider) are too large and mix concerns. Refactor is scoped.
  2. No CI pipeline yet — builds are manual. Test scripts exist; need to wire them into GitHub Actions.
  3. Version-number drift between pubspec.yaml and the Android Gradle config. Cosmetic but should pick a source of truth before the first App Store release.

None are user-facing or block shipping.

Q · What happens when this developer gets hit by a bus?

Q · How are user-reported bugs handled?

Today: standard developer triage — Slack/email → repro → fix → next release. Nothing unusual.

Proposed (in design, not yet daily-use): the screenshot → APK workflow (§2) lets a non-engineer drop a screenshot + one sentence and produces a debug APK in 15–30 minutes. Validated once end-to-end; not yet the default for incoming bugs.

Production releases follow normal cadence (TestFlight / Play Store internal → external).

Security & privacy

Q · How is user data protected?

Roadmap (frontend angle)

Q · What's the next major frontend investment?

  1. Biographer feature — currently a "coming soon" stub. Voice + text life-story capture.
  2. CI pipeline — automated lint + test + build per PR.
  3. Provider refactor — split the two large ones; cleaner foundation for new contributors.
  4. iOS-side polish — Flutter handles both platforms but iOS-specific UX touches (haptics, dynamic type) deserve a pass before App Store launch.

Q · What can the frontend NOT do today that you wish it could?

"Show, don't tell" — when asked for proof, point at:
  • This HTML doc — six diagrams + reference for every layer
  • workflow.md + the debug APK in builds/ — the proposed loop, validated end-to-end once
  • backlog.md — every known issue logged. Transparency is a feature.
  • The running app on the emulator — already installed, can demo end-to-end
What NOT to claim
  • "Production-ready test coverage" — intentionally light on frontend; be honest about the trade-off.
  • "Scales to millions today" — designed to, hasn't been load-tested. Say "designed to scale."
  • "No tech debt" — every codebase has it; ours is logged and triaged.
  • Don't oversell the AI testing harness as fully autonomous — powerful but benefits from human review.
  • Don't call the screenshot → APK workflow "our standard practice." It's proposed and prototype-validated. Say "designed, validated end-to-end once, rolling out."
Credibility comes from honest framing, not perfect answers.

§17Quick reference

Where things live

ConcernClassFile
App entryMyApplib/main.dart:325
AuthAuthenticationProviderlib/providers/authentication_provider.dart
ThemeThemeStorelib/features/settings/theme_store.dart
RoutingAppRouterlib/core/navigation/app_router.dart
HomeDashboardlib/features/home/dashboard.dart
JournalJournalProvider / JournalPagelib/features/journal/...
Memory buildNewMemoryBuilder / MemoryBuilderProviderlib/features/memory_builder/...
AnalyticsAnalyticsServicelib/core/services/analytics_service.dart
FirebaseFirebaseServicelib/core/services/firebase_service.dart
NotificationsNotificationServicelib/core/services/notification_service.dart
DIlocatorlib/core/di/locator.dart
SplashSplashScreenlib/features/splash/splash_screen.dart
ConnectionsConnectionProviderlib/features/Connections/provider/connection_provider.dart
API configApiUrlslib/core/config/api_urls.dart

Companion documents