6.8 KiB
Setup
Backend Base URL
Build-time (recommended):
flutter run --dart-define=BACKEND_BASE_URL=https://api.example.com
Runtime override (for future settings screens):
AppConfig.overrideBackendBaseUrl('https://staging.example.com');
Bugsink Error Tracking
Release builds initialize sentry_flutter with the project Bugsink DSN by
default. Bugsink is Sentry API compatible, so the app uses the normal Sentry
Flutter SDK.
The default DSN is:
https://97fb0a56bc35440fba0ba139dc3b1ccc@bugs.zuzo.ch/2
Override metadata at build time when needed:
flutter build apk --release \
--dart-define=SENTRY_ENVIRONMENT=production \
--dart-define=SENTRY_RELEASE=relationship_saver@1.0.0+1
To point a build at a different Sentry-compatible project:
flutter build apk --release \
--dart-define=SENTRY_DSN=https://public-key@example.com/1
Run With Fake Gateway
Use fake gateway for local/offline development:
flutter run --dart-define=USE_FAKE_BACKEND=true
Background Sync
Background sync (startup + resume + periodic ticks while authenticated) is disabled by default. The current product direction is backendless/local-first, so backend sync should be enabled only for REST transport development.
In REST mode, auto-triggers are reachability-gated to avoid unnecessary sync attempts while offline.
When connectivity returns (offline -> online), sync now triggers immediately in addition to startup/resume/periodic ticks.
Control flags:
flutter run \
--dart-define=ENABLE_BACKGROUND_SYNC=true \
--dart-define=BACKGROUND_SYNC_INTERVAL_SECONDS=180
Disable it explicitly:
flutter run --dart-define=ENABLE_BACKGROUND_SYNC=false
Reminder Delivery Scaffold
Reminder scheduling is now wired through ReminderScheduler and reconciled
from LocalRepository on startup/state changes.
Default implementation now uses local notifications runtime where supported.
Control flag:
flutter run --dart-define=ENABLE_LOCAL_NOTIFICATIONS=true
Disable notifications explicitly:
flutter run --dart-define=ENABLE_LOCAL_NOTIFICATIONS=false
Behavior notes:
- web: no-op fallback
- linux: schedule fallback (no-op) due platform scheduling limitations in plugin
- android/iOS/macOS/windows: scheduled local notifications
- settings screen includes
Request Notification Accessaction for runtime permission prompts - tapping a reminder notification opens reminder management UI in-app
Phone-Only Private AI Digest
The app can run without a production backend by keeping USE_FAKE_BACKEND=true
and using the LLM integration for local profile extraction and private digest
generation.
Selected product flow:
- share messages/text from WhatsApp, iMessage, Notes, Safari, or similar apps into the app
- auto-match only when identity evidence is strong
- keep ambiguous or low-information shares in
Share Inbox - let the user gradually resolve inbox items over days, weeks, and months
- run local/profile-building extraction opportunistically and on scheduled nightly windows when the OS allows it
- run grounded weekly recommendations on request or on the configured digest schedule
Backend sync is not part of this path. The fake backend is intentionally inert for sync pulls and must not seed people or other relationship records.
Digest behavior:
- relationship data remains local-first in the Hive/shared-preferences store
- scheduled digest payloads use pseudonymous tokens such as
person_001 - names, aliases, sender names, source URLs, raw shared text, and sensitive notes are not sent in the scheduled digest prompt
- repeated LLM work should be avoided by fingerprinting unresolved/new share batches and skipping extraction when the same batch has already completed
- weekly recommendation prompts should include previously suggested/dismissed items so the model avoids repeats
- LLM results are saved as pending AI review drafts first
- accepting a draft creates a local idea, task, or reminder
- dismissing a draft leaves existing local data unchanged
Scheduling:
- default cadence is weekly
- default run window is Sunday 21:00
- default policy is Wi-Fi + charging
- iOS background execution is best-effort because the OS controls exact timing
- Settings includes
Run Private Digest Nowfor physical-phone debug builds
iOS setup now includes:
UIBackgroundModes:fetch,processingBGTaskSchedulerPermittedIdentifiers:com.relationshipsaver.llm.digest- Workmanager registration in
AppDelegate.swift
Local notifications are used for the digest-ready alert. No APNs/FCM remote push payload is required.
WhatsApp Share Intake (MVP)
Inbound WhatsApp share-intake is now wired behind a listener in the authenticated app shell.
Control flag:
flutter run --dart-define=ENABLE_WHATSAPP_SHARE_INTAKE=true
Disable explicitly:
flutter run --dart-define=ENABLE_WHATSAPP_SHARE_INTAKE=false
Behavior notes:
- iOS/Android: integrates with share-intent plugin (
receive_sharing_intent) - iOS also ships a
Save to Relationship SaverAction extension for the lower share-sheet action row; use it when that row is easier to reach than the app share row - shared text is parsed and ingested into:
- person profile (auto-create when identity is confident)
- source->profile link map for follow-up matching
- moment history (
type=whatsapp)
- ambiguous or missing-identity shares are queued in
Share Inboxfor manual resolution - near-name conflicts now also route to
Share Inboxto avoid accidental profile mismatches - follow-up routing prefers stable source fingerprint matching (when source user/thread IDs are available)
- Share Inbox now provides a
Review & Matchconflict flow with candidate confidence scoring and side-by-side preview before confirming profile link - app launch from initial share intent auto-opens the relevant destination:
- resolved import ->
Peoplewith imported profile selected - unresolved import ->
Share Inbox
- resolved import ->
- Settings includes:
Simulate WhatsApp Sharefor local/dev testingOpen Share Inboxto resolve queued items
People view includes Merge duplicates action for resolving duplicate profile
records after import.
Local Persistence Backend
Default local store:
Hive(USE_HIVE_LOCAL_DB=trueby default)- first-run migration imports legacy
shared_preferencespayload when present - applies to both:
- local product state (
LocalRepository) - sync queue state (
SyncQueueRepository)
- local product state (
Optional migration path:
flutter run --dart-define=USE_HIVE_LOCAL_DB=true
Use legacy mode explicitly if needed:
flutter run --dart-define=USE_HIVE_LOCAL_DB=false
Run Tests
flutter test
Generate Code
dart run build_runner build --delete-conflicting-outputs