Files
pulse-mobile/CLAUDE.md
Daniil Klimov 28fca1de89 feat: major app overhaul — API fixes, glassmorphism UI, health dashboard, notifications
API Integration:
- Fix logHabit: send "date" instead of "completed_at"
- Fix FinanceCategory: "icon" → "emoji" to match API
- Fix task priorities: remove level 4, keep 1-3 matching API
- Fix habit frequencies: map monthly/interval → "custom" for API
- Add token refresh (401 → auto retry with new token)
- Add proper error handling (remove try? in save functions, show errors in UI)
- Add date field to savings transactions
- Add MonthlyPaymentDetail and OverduePayment models
- Fix habit completedToday: compute on client from logs (API doesn't return it)
- Filter habits by day of week on client (daily/weekly/monthly/interval)

Design System (glassmorphism):
- New DesignSystem.swift: Theme colors, GlassCard modifier, GlowIcon, GlowStatCard
- Custom tab bar with per-tab glow colors (VStack layout, not ZStack overlay)
- Deep dark background #06060f across all views
- Glass cards with gradient fill + stroke throughout app
- App icon: glassmorphism style with teal glow

Health Dashboard:
- Compact ReadinessBanner with recommendation text
- 8 metric tiles: sleep, HR, HRV, steps, SpO2, respiratory rate, energy, distance
- Each tile with status indicator (good/ok/bad) and hint text
- Heart rate card (min/avg/max)
- Weekly trends card (averages)
- Recovery score (weighted: 40% sleep, 35% HRV, 25% RHR)
- Tips card with actionable recommendations
- Sleep detail view with hypnogram (step chart of phases)
- Sleep segments timeline from HealthKit (deep/rem/core/awake with exact times)
- Line chart replacing bar chart for weekly data
- Collect respiratory_rate and sleep phases with timestamps from HealthKit
- Background sync every ~30min via BGProcessingTask

Notifications:
- NotificationService for local push notifications
- Morning/evening reminders with native DatePicker (wheel)
- Payment reminders: 5 days, 1 day, and day-of for recurring savings
- Notification settings in Settings tab

UI Fixes:
- Fix color picker overflow: HStack → LazyVGrid 5 columns
- Fix sheet headers: shorter text, proper padding
- Fix task/habit toggle: separate tap zones (checkbox vs edit)
- Fix deprecated onChange syntax for iOS 17+
- Savings overview: real monthly payments and detailed overdues from API
- Settings: timezone as Menu picker, removed Telegram/server notifications sections
- All sheets use .presentationDetents([.large])

Config:
- project.yml: real DEVELOPMENT_TEAM, HealthKit + BackgroundModes capabilities
- Info.plist: BGTaskScheduler + UIBackgroundModes
- Assets.xcassets with AppIcon
- CLAUDE.md project documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:15:36 +03:00

7.7 KiB
Raw Blame History

Pulse Health — iOS App

Overview

iOS-приложение для управления жизнью: привычки, задачи, финансы, накопления, здоровье. Интегрируется с Apple Watch через HealthKit и серверным API.

  • Bundle ID: com.daniil.pulsehealth
  • Platform: iOS 17+, SwiftUI, Swift 5.9
  • Build: XcodeGen (project.yml → .xcodeproj)
  • Team ID: V9AG8JTFLC
  • Язык интерфейса: Русский

Architecture

Project Structure

PulseHealth/
├── App.swift                     # Entry point, AuthManager, BGTask registration
├── Models/
│   ├── AuthModels.swift          # Login/Register/Refresh requests & responses
│   ├── UserModels.swift          # UserProfile, UpdateProfileRequest
│   ├── HealthModels.swift        # Readiness, Latest health, Heatmap, SleepSegment
│   ├── TaskModels.swift          # PulseTask, CreateTask, UpdateTask (priorities 1-3)
│   ├── HabitModels.swift         # Habit, HabitLog, HabitFreeze, HabitStats, HabitFrequency enum
│   ├── FinanceModels.swift       # Transaction, Category (emoji field, not icon), Summary, Analytics
│   └── SavingsModels.swift       # Category, Transaction, Stats, RecurringPlan, MonthlyPaymentDetail, OverduePayment
├── Services/
│   ├── APIService.swift          # Main REST client (api.digital-home.site), auto token refresh on 401
│   ├── HealthAPIService.swift    # Health API (health.digital-home.site), separate JWT auth
│   ├── HealthKitService.swift    # HealthKit data collection & sync, sleep segments timeline
│   └── NotificationService.swift # Local push notifications (morning/evening, task deadlines)
├── Views/
│   ├── DesignSystem.swift        # Theme colors, GlassCard modifier, GlowIcon, GlowStatCard
│   ├── MainTabView.swift         # Custom tab bar with glow effects (VStack layout, not ZStack)
│   ├── LoginView.swift           # Auth + ForgotPassword
│   ├── Dashboard/
│   │   └── DashboardView.swift   # Home: progress, stats, habits, tasks, FAB
│   ├── Health/
│   │   ├── HealthView.swift      # Full health dashboard: readiness, metrics, HR, trends, recovery, tips
│   │   ├── MetricCardView.swift  # SleepCard, StepsCard, SleepPhasesCard, InsightsCard, GradientIcon
│   │   ├── WeeklyChartView.swift # Line chart (not bar), animated
│   │   ├── SleepDetailView.swift # Detailed sleep timeline with phases from HealthKit
│   │   ├── ReadinessCardView.swift # (empty, replaced by ReadinessBanner in HealthView)
│   │   └── ToastView.swift       # Toast notification modifier
│   ├── Tracker/
│   │   └── TrackerView.swift     # Tabs: Habits, Tasks, Statistics. Separate tap zones for edit vs toggle
│   ├── Tasks/
│   │   ├── TasksView.swift
│   │   ├── AddTaskView.swift
│   │   ├── EditTaskView.swift
│   │   └── TaskRowView.swift
│   ├── Habits/
│   │   ├── HabitsView.swift
│   │   ├── AddHabitView.swift
│   │   ├── EditHabitView.swift
│   │   └── HabitRowView.swift
│   ├── Finance/
│   │   ├── FinanceView.swift     # Overview, Transactions, Analytics, Categories tabs
│   │   └── AddTransactionView.swift
│   ├── Savings/
│   │   ├── SavingsView.swift     # Overview (monthly payments, overdues), Categories, Operations
│   │   └── EditSavingsCategoryView.swift
│   ├── Settings/
│   │   └── SettingsView.swift    # Appearance, Profile, Timezone (Menu picker)
│   └── Profile/
│       └── ProfileView.swift     # ChangePasswordView

API Integration

Main API: https://api.digital-home.site

  • Auth: JWT Bearer token with auto-refresh via /auth/refresh
  • AuthManager stores token + refreshToken in UserDefaults
  • APIService.authManager weak ref enables transparent 401 → refresh → retry

Endpoints used:

  • Auth: login, register, me, refresh
  • Profile: GET/PUT /profile
  • Tasks: CRUD + complete/uncomplete, priorities 1-3 (not 4!)
  • Habits: CRUD + log (sends date not completed_at), freezes, stats
  • Habits frequency: iOS uses daily/weekly/monthly/interval internally, sends custom to API for monthly/interval
  • Finance: transactions, categories (field is emoji not icon), summary, analytics
  • Savings: categories, transactions (date required!), stats (includes monthly_payment_details, overdues), recurring plans

Health API: https://health.digital-home.site

  • Separate JWT auth (hardcoded credentials in HealthAPIService)
  • API key for data sync: health-cosmo-2026
  • Server code: /Users/daniilklimov/Personal/health-webhook (Node.js + SQLite)

Data flow:

  1. Apple Watch → HealthKit on iPhone
  2. App collects from HealthKit → POST /api/health?key=API_KEY
  3. health-webhook stores JSON files → parses on GET requests
  4. App displays from GET /api/health/latest, /readiness, /heatmap

HealthKit metrics collected:

  • step_count, heart_rate, resting_heart_rate, heart_rate_variability
  • active_energy (kcal→kJ), blood_oxygen_saturation, walking_running_distance
  • respiratory_rate, sleep_analysis (with phase breakdown: deep/rem/core/awake + timestamps)

Sleep format for webhook:

{"totalSleep": 7.5, "deep": 1.2, "rem": 2.0, "core": 4.3, "awake": 0.5,
 "inBedStart": "...", "sleepEnd": "...", "source": "Apple Watch"}

API response field mapping (CodingKeys):

  • spo2bloodOxygen (BloodOxygenData)
  • respiratoryRate → as-is
  • distance → as-is
  • activeEnergy → as-is

Design System

  • Background: #06060f (deep dark)
  • Accent: #0D9488 (teal)
  • Glass cards: .glassCard() modifier — ultraThinMaterial + gradient fill + gradient stroke
  • Glow icons: GlowIcon — circle with blur glow behind
  • Tab bar: Custom VStack-based (not standard TabView), each tab has its own glow color
  • All sheets: .presentationDetents([.large]), background Color(hex: "06060f")
  • Color pickers: LazyVGrid 5 columns (not HStack — overflow on small screens)
  • App icon: Glassmorphism style, Assets.xcassets/AppIcon.appiconset

Key Design Decisions & Gotchas

  • Buttons in ScrollView/List MUST have .buttonStyle(.plain) — otherwise taps get swallowed
  • Tracker rows: Separate tap zones — .onTapGesture on text area for edit, Button with .buttonStyle(.plain) for checkbox
  • try? is avoided in save functions — errors are shown in UI via @State errorMessage
  • Tab bar uses VStack, not ZStack — prevents content overlap
  • onChange uses iOS 17+ syntax: { } not { _ in }
  • XcodeGen: All capabilities must be in project.yml, manual Xcode changes get reset

Background Sync

  • BGProcessingTask: com.daniil.pulsehealth.healthsync
  • Scheduled every ~30 minutes
  • Collects HealthKit data and POSTs to health-webhook
  • Registered in App.init(), scheduled in .onAppear

External Services & Paths

  • Pulse API source: /Users/daniilklimov/digital-home/pulse-api (Go)
  • Pulse Web source: /Users/daniilklimov/digital-home/pulse-web (React)
  • Health webhook: /Users/daniilklimov/Personal/health-webhook (Node.js)
  • Infrastructure docs: ~/Obsidian/daniil/Инфраструктура

Known Issues / TODO

  • Finance tab is owner-only (user.id === 1) in web, no such restriction in iOS
  • Savings members endpoints (multi-user) not implemented in iOS
  • Auth: password change works via direct URLRequest, not through APIService
  • Health readiness activity.value from API shows different step count than latest (different time periods)