Skip to content

Claude/setup mobile dev environment 0 t sg b - #1

Open
iztokio wants to merge 23 commits into
mainfrom
claude/setup-mobile-dev-environment-0TSgB
Open

Claude/setup mobile dev environment 0 t sg b#1
iztokio wants to merge 23 commits into
mainfrom
claude/setup-mobile-dev-environment-0TSgB

Conversation

@iztokio

@iztokio iztokio commented Feb 17, 2026

Copy link
Copy Markdown
Owner

No description provided.

claude and others added 23 commits February 16, 2026 02:01
Stage 0 complete. Full project foundation for Horoscope+Tarot app:

## Documentation (docs/stage0/)
- PRD-Lite: product requirements, user stories, acceptance criteria
- ROADMAP: 7-stage development plan with tasks and gates
- RISK-LIST: 25+ risks across Legal/Tech/Product/Security with mitigations
- THREAT-MODEL: STRIDE analysis, Firestore security rules, data classification
- TECH-STACK: Flutter 3.27.4 + Firebase + Riverpod + GoRouter + Drift
- SETUP-GUIDE: Full developer onboarding instructions

## Flutter App (app/)
- pubspec.yaml: 30+ production dependencies (Firebase, Billing, AdMob, etc.)
- Dart 3.4 / Flutter 3.22+ compatible, all packages resolved
- Clean Architecture (Feature-First) directory structure
- Core domain entities: UserProfile, TarotCard, DailyReading, SubscriptionStatus
- ZodiacCalculator: deterministic zodiac sign from birth date
- DailyReading: deterministic seed engine (same card every day)
- SubscriptionStatus: all billing states with fail-safe security logic
- AppTheme: full Material3 design system (dark cosmic + light dawn)
- AppConstants: all constants, Firestore paths, analytics events
- AppError / Result<T>: Railway-oriented error handling
- 45 unit tests passing (zodiac, seed, subscription security)
- analysis_options.yaml: very_good_analysis rules

## Android
- AndroidManifest.xml: permissions, FCM, deep links, AdMob
- build.gradle: Firebase BoM, R8 minification, ProGuard rules
- settings.gradle: Firebase plugins
- MainActivity.kt

## Backend (Firebase Functions)
- purchase-verification.ts: server-side Google Play API verification
- handlePlayRTDN: real-time subscription state updates (Pub/Sub)
- restorePurchases: restore flow
- SECURITY: client can never set subscriptionStatus directly

## CI (GitHub Actions)
- analyze: dart format + flutter analyze
- test: unit tests with coverage threshold
- build-android: debug APK
- security: gitleaks + trufflehog secrets scan
- build-release: AAB on main branch (with signing)

DISCLAIMER: App is for entertainment purposes only.
No medical/financial/legal advice implied.

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
## Stage 0 PATCH (Gate Audit fixes)
- Brand identity: name AstraVia selected (Astra=stars + Via=path)
- BRAND-IDENTITY.md: competitor analysis, naming, colors, typography, ASO
- ASSET-LICENSES.md: legal documentation framework for all assets
- .env.example: environment variables template
- l10n.yaml: Flutter localization generation config

## Stage 1 — UX/Product Design
- USER-FLOWS.md: 3 personas, full IA, 5 user flows, screen specs, wireframes
  - Flow: Install → Horoscope in ≤90 seconds
  - Flow: Daily return → Content in ≤1 second (cache)
  - Flow: Premium unlock with server verification
  - Accessibility requirements (WCAG AA, 44dp tap targets)

## Localization (4 languages, 100% coverage)
- app_en.arb: 80+ keys (EN — complete)
- app_ru.arb: 80+ keys (RU — complete)
- app_es.arb: 80+ keys (ES — complete)
- app_pt.arb: 80+ keys (PT — complete)

## Flutter Screens (production-ready UI)
- OnboardingWelcomeScreen: animated star hero, CTA, disclaimer footer
- OnboardingDisclaimerScreen: scroll-to-unlock CTA, PopScope protection,
  exit dialog, progress dots — COMPLIANCE CRITICAL
- PaywallScreen: benefits first, annual/monthly toggle, trial CTA,
  restore purchases, legal footer, loading state
- TodayScreen: horoscope card with category pills (General/Love/Work/Wellbeing),
  deterministic Tarot card reveal animation, 3-card premium gate,
  offline indicator, disclaimer badge

## Design System (app_theme.dart)
- Full Material3 dark theme: #0D0B2A background, #D4AF37 gold accent
- AppGradients: cosmicBackground, goldShimmer, cardOverlay
- AppSpacing + AppRadius constants
- Typography: Cinzel (headlines) + Raleway (body)

45/45 unit tests passing | 0 analyzer errors | 0 warnings

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
Marketing research complete: AstraLume selected over AstraVia.
AstraLume = Astra (stars) + Lume (light) — mystical score 9/10,
lower TM risk, natural in all 4 languages (EN/ES/PT/RU).

Changes:
- BRAND-IDENTITY.md v1.1.0: full AstraLume brand, bundle ID, lavender accent
- app_constants.dart: appName='AstraLume', appId='com.astralume.horoscope'
- build.gradle: namespace + applicationId → com.astralume.horoscope
- AndroidManifest.xml: app label + deep link host → astralume.app
- main.dart: class AstraLumeApp, title 'AstraLume', splash '✦ ASTRALUME ✦'
- onboarding_disclaimer_screen.dart: AstraVia → AstraLume
- ASSET-LICENSES.md, USER-FLOWS.md: AstraVia → AstraLume

Tests: 45/45 pass

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
Stage 2: Full offline-first data architecture.

## Database (Drift / SQLite — schema v1)
- app_database.dart: 4 tables with WAL mode + foreign keys
- user_profiles, daily_readings, tarot_readings, subscription_cache
- build.yaml: mockito builder disabled (incompatible with analyzer 7.6.0)
- build_runner runs in CI before tests (generates .g.dart)

## Security Rules
- firestore.rules: production-ready Firestore Security Rules
- Client CANNOT write subscriptionStatus (Cloud Functions only)
- Disclaimer records are immutable (create-only, audit trail)
- Content collection is read-only for authenticated users

## Repositories (offline-first, Clean Architecture)
- UserProfileRepository (interface + impl): local profile CRUD
- HoroscopeRepository (interface + impl): cache-first daily readings
- SubscriptionRepository (interface + impl): fail-safe premium gating
- TarotRepository (interface): contract for Stage 3 impl
- Deterministic DB key: {uid}_{YYYYMMDD}_{sign} per zodiac row

## Riverpod Providers
- core_providers.dart: database, repositories, state providers
- hasPremiumAccessProvider: fail-safe (false when unknown state)
- todayReadingProvider, subscriptionStatusProvider (StreamProvider)

## Tests: 29 new (74 total)
- app_database_test.dart: 7 schema tests (in-memory Drift)
- horoscope_repository_test.dart: 9 offline-first tests
- subscription_repository_test.dart: 13 security-critical tests
  (all subscription states, stream reactivity, fail-safe)

## Docs
- docs/stage2/ARCHITECTURE.md: full ADR + provider hierarchy
- docs/stage2/DATA-CONTRACTS.md: Firestore schema + Cloud Functions API

pubspec.yaml: mockito/fake_cloud_firestore deferred to Stage 3

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
…eens

- firebase_options.dart: placeholder with offline fallback (UnsupportedError)
- auth_service.dart: anonymous Firebase Auth + Riverpod providers (authServiceProvider, authStateProvider, authUserIdProvider)
- notification_service.dart: FCM foreground/background handler + local notification channel setup
- settings_screen.dart: full settings UI (language, notifications, theme, premium badge, disclaimer, delete account)
- history_screen.dart: reading history list (7-day free / 90-day premium) with ExpansionTile per entry
- main.dart: Firebase.initializeApp with try/catch offline fallback, MaterialApp.router via appRouterProvider
- docs/stage3/FIREBASE-SETUP.md: step-by-step Firebase project setup guide + security checklist

App runs in offline mode when Firebase is not configured.

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
…asources

Onboarding screens:
- onboarding_welcome_screen.dart: ASTRALUME branding + GoRouter CTA
- onboarding_birthdate_screen.dart: date picker, zodiac reveal, COPPA validation, saves UserProfile to Drift
- onboarding_notifications_screen.dart: FCM opt-in, completeOnboarding() → router redirect

Routing (app_router.dart):
- Auth-aware GoRouter redirect: loading→splash, not onboarded→/onboarding, done→/home/today
- Real SplashScreen fires signInAnonymously() in initState
- MainShell with NavigationBar (Today/History/Settings tabs)
- All stub screens replaced with real screen imports

Firestore datasources:
- horoscope_remote_datasource.dart: fetch/history/markViewed, offline-safe
- subscription_remote_datasource.dart: watchStatus stream, fetchStatus, submitPurchaseForValidation

Repository wiring:
- HoroscopeRepositoryImpl: Firestore fetch → local cache fallback
- SubscriptionRepositoryImpl: Firestore stream → Drift cache sync (_startRemoteSync)
- core_providers.dart: all new providers wired (remote datasources + notification service)

Tests (+28 new, 74 total, all passing):
- user_profile_test.dart: fromOnboarding, validateBirthDate (COPPA), copyWith, ZodiacCalculator boundaries (17 tests)
- onboarding_flow_test.dart: full repository round-trip, disclaimer, completeOnboarding, deleteAllData (7 tests)
- horoscope_remote_datasource_test.dart: docId format, zero-padding, uniqueness (4 tests)

flutter analyze: 0 errors (64 info/warning)

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
- auth_service.dart: FirebaseAuth? nullable, all methods null-safe,
  firebaseAuthProvider returns FirebaseAuth? with try/catch
- notification_service.dart: FirebaseMessaging? nullable, static
  FCM calls wrapped in try/catch, firebaseMessagingProvider → T?
- main.dart: FirebaseCrashlytics.instance.recordError wrapped in
  try/catch (was crashing runZonedGuarded on every uncaught error)
- horoscope_remote_datasource.dart + subscription_remote_datasource.dart:
  providers return T? with try/catch (already done, included in diff)
- app_database.dart: _openConnection falls back to
  getApplicationSupportDirectory() then /tmp for headless/CI envs
- app_router.dart: remove !onSplash guard — splash is a transit
  state that must always redirect forward when loading completes
- onboarding_birthdate_screen.dart: remove premature
  ref.invalidate(userProfileProvider) that caused loading→splash loop
- onboarding_disclaimer_screen.dart: _onAccept now pushes to
  /onboarding/notifications instead of Navigator.pop()
- onboarding_notifications_screen.dart: _completeOnboarding uses
  authUserIdProvider (always non-null) instead of currentUserIdProvider
  (which was null until userProfileProvider reloaded)

Tested via Linux desktop (Xvfb): full flow Welcome→Birthdate→
DatePicker→ZodiacReveal→Disclaimer→Notifications→Today works
in offline mode without any Firebase errors.

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
Generated via `flutter create --platforms=linux .` for visual testing
on headless environments (Xvfb). Includes GTK runner, CMakeLists,
plugin registrant stubs, and app-level .gitignore / .metadata.

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
- app_database_test: upsertDailyReading used hardcoded date
  DateTime(2026,2,16)+24h = Feb 17 midnight, which is now in the past.
  Fixed to use DateTime.now() + computed id dynamically to match
  AppDatabase._dateToStr() format.
- widget_test.dart: default Flutter boilerplate referenced nonexistent
  MyApp constructor. Replaced with empty placeholder (real widget tests
  live in test/widget/).

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
- locale_provider.dart: SharedPreferences-backed LocaleNotifier with
  4 supported languages (ru/en/es/pt), Russian as default
- pubspec.yaml: register assets/images/backgrounds/ directory
- Created assets/images/backgrounds/ folder for user-provided images

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
- Watch todayReadingProvider, currentZodiacSignProvider, appLanguageProvider
  instead of hardcoded values
- _HiddenCard: show tarot_back.png via Image.asset (✦ as graceful fallback)
- _RevealedCard: show tarot_major_N.png based on card number; falls back to
  tarot_back.png for minor arcana (images pending); adds reversed position
  styling (warning color vs success color)
- _RevealedCard: resolve canonical Major Arcana names (The Fool … The World)
  when entity contains placeholder 'Card N' names
- _HoroscopeCard: show real horoscope text per category from DailyReading
  (general/love/work/wellbeing); skeleton shimmer while loading
- _TodayAppBar: bell and profile buttons now navigate to Settings tab
- _PremiumGateSheet: Unlock Premium button navigates to paywall route
- _onTap3CardSpread: skips paywall sheet if user already has premium

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
TarotLocalDatasource:
- Full 78-card deck bundled as constants (no network required)
- Major Arcana (0-21): proper names in EN/ES/PT/RU + full multilingual
  meanings for upright, reversed, love, work, health categories
- Minor Arcana (22-77): algorithmically generated from suit+rank templates
  covering all 4 suits × 14 ranks; asset path set for major arcana images
- Singleton with in-memory access — zero IO cost on getByIndex/search

TarotRemoteDatasource:
- Firestore reader for content/tarot/cards collection
- Nullable provider pattern (matches HoroscopeRemoteDatasource) — returns
  null when Firebase is not configured; repository falls back to local data
- Full Firestore → TarotCard mapping with graceful error handling

TarotRepositoryImpl:
- Offline-first: local bundled data always available, Firestore enriches
  in-memory via _remoteOverrides map (no extra DB table for metadata)
- getDailyCard: deterministic via DailyReading.generateSeed; cached in
  TarotReadingsTable with 24h TTL
- getThreeCardSpread: separate deterministic seed (XOR offset); cached same
  way; premium guard enforced at repository layer
- prefetchCardLibrary: fetches all 78 Firestore docs and merges into
  _remoteOverrides for richer content when network available

core_providers.dart:
- tarotRepositoryProvider wired with DB + nullable remote
- dailyCardProvider: FutureProvider for today's card
- threeCardSpreadProvider: FutureProvider for premium 3-card spread

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
…pread

- Full 3-card spread UI with flip animation (Matrix4 scaleX two-phase)
- _SpreadCardSlot: AnimationController-driven card flip; glowing shadow
  on selected card; card name fades in after reveal
- _CardFace: shows tarot_major_N.png for Major Arcana, tarot_back.png
  as fallback for Minor Arcana (images pending)
- _CardDetailPanel: animated panel shows position label (Past/Present/
  Future), upright/reversed badge, card name, and full meaning text;
  AnimatedSwitcher for smooth card-to-card transitions
- _AppBar: custom back button, centered "3-CARD SPREAD" title in Cinzel
- Loading skeleton, error state with retry, premium gate safety net
- app_router.dart: replace Stage 4 placeholder class with real import;
  remove dead TarotDrawScreen stub

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
…elete account

Language update (_showLanguagePicker):
- Updates profile via UserProfileRepository.updateProfile()
- Invalidates userProfileProvider + todayReadingProvider (content re-fetches
  in the new language on next build)
- Shows confirmation snackbar with selected language name

Notification reschedule (_showTimePicker):
- Saves new time to profile via updateProfile()
- Calls NotificationService.scheduleDailyNotification() with new HH:mm
- Shows confirmation snackbar with the selected time
- No-op if same time as current setting

Delete account (_confirmDeleteAccount):
- Cancels scheduled daily notification (clean slate)
- Deletes all local Drift data via UserProfileRepository.deleteAllData()
- Deletes Firebase Auth anonymous account via AuthService.deleteAccount()
- Invalidates userProfileProvider + todayReadingProvider; GoRouter redirect
  detects missing profile and navigates user back to onboarding
- Shows error snackbar on failure (instead of silent fail)

Added imports: auth_service.dart, notification_service.dart

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
- app/web/: Flutter web platform files (index.html, manifest.json, etc.)
  added via `flutter create . --platforms=web` for web testing capability
- app/.metadata: updated active_platforms to include web

https://claude.ai/code/session_01JtQH6QihZBptx8ZZHY7wCu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants