Technical Documentation - NateEaton/mind-pwa GitHub Wiki
Understanding the MIND Diet Tracker Architecture
This document provides technical details about the MIND Diet Tracker PWA for developers who want to understand, modify, or extend the application.
Architecture Overview
The application follows a modular architecture with these key components:
MIND Diet Tracker
├── Client (client/)
│ ├── Core Modules (core/)
│ │ ├── appManager.js - Application lifecycle and coordination
│ │ ├── dataService.js - Data handling (localStorage and IndexedDB)
│ │ ├── stateManager.js - Centralized state management
│ │ ├── eventHandlers.js - Event handling and user interactions
│ │ ├── settingsManager.js - Settings and configuration management
│ │ ├── themeManager.js - Light/dard theme management
│ │ ├── setupWizard.js - First-time user setup wizard
│ │ ├── historyModalManager.js - Historical data editing functionality
│ │ ├── importExportManager.js - Data import/export operations
│ │ ├── trackingEngine.js - Date tracking and reset logic
│ │ ├── devTools.js - Developer utilities and debugging
│ │ └── logger.js - Configurable logging system
│ ├── User Interface (ui/)
│ │ ├── renderer.js - UI rendering based on application state
│ │ ├── components.js - Reusable UI components
│ │ └── templates.js - HTML templates for dynamic content
│ ├── Utilities (utils/)
│ │ ├── config.js - Expose environment variables to app
│ │ ├── appUtils.js - General application utilities
│ │ └── dateUtils.js - Date manipulation and formatting
│ ├── Cloud Synchronization (cloudSync/)
│ │ ├── cloudSync.js - Main cloud sync manager
│ │ ├── changeDetectionService.js - Detects data changes for sync
│ │ ├── fileMetadataManager.js - Manages file metadata for sync
│ │ ├── mergeCoordinator.js - Coordinates data merging operations
│ │ ├── mergeStrategies.js - Implements merge conflict resolution
│ │ ├── syncOperationHandler.js - Handles individual sync operations
│ │ └── syncUtils.js - Cloud sync utility functions
│ ├── Cloud Provider Implementations (cloudProviders/)
│ │ ├── googleDriveProvider.js - Google Drive implementation
│ │ └── dropboxProvider.js - Dropbox implementation
│ ├── Web Components
│ │ ├── app.js - Main application entry point
│ │ ├── index.html - Main application HTML
│ │ ├── icons/ - Application icons
│ │ └── style.css - Application styling
│ └── PWA Components
│ ├── serviceWorker.js - Offline functionality
│ ├── manifest.json - PWA installation configuration
│ └── version.json - Application version information
├── Server (server/)
│ ├── server.js - Express.js OAuth server
│ ├── logger.js - Server-side logging
│ └── package.json - Server dependencies
├── Infrastructure
│ ├── .env - Build-time environment variable definitions
│ ├── src/vite.config.js - VITE configuration
│ ├── scripts/pre-commit.example - Example for controlling update-version.cjs during commit
│ ├── scripts/update-version.cjs - Update version.json during commit
│ ├── docker-compose.yml - Docker deployment configuration
│ ├── docker-compose.client-only.yml - Docker deployment configuration for client-only deployment
│ ├── nginx/nginx.conf - Nginx reverse proxy configuration
│ ├── nginx/nginx.client-only.conf - Nginx reverse proxy configuration for client-only deployment
│ ├── deploy-server.sh - Deployment script for server-enabled
│ ├── deploy-client.sh - Deployment script for client-only
│ ├── start-server.sh - Container management script for server-enabled deployment
│ └── start-client-only.sh - Container management script for client-only deployment
└── Documentation
├── README.md - Project overview
├── LICENSE - GPL v3 license
├── screenshots/ - Application screenshots
├── docs/index.html - Github Pages web page for application
└── wiki/ - Complete documentation
Feature Gating System
The application uses build-time feature gating to create two distinct deployment modes with different capabilities and bundle sizes.
Build-Time Constants
Vite configuration (client/vite.config.js) converts environment variables to embedded constants:
define: {
__SERVER_FEATURES_ENABLED__: JSON.stringify(env.VITE_SERVER_FEATURES_ENABLED === "true"),
__DEV_MODE__: JSON.stringify(env.VITE_DEV_MODE === "true"),
__DEMO_MODE__: JSON.stringify(env.VITE_DEMO_MODE === "true"),
}
Conditional Code Loading
Cloud sync features are conditionally imported based on build-time constants:
// In client code
if (__SERVER_FEATURES_ENABLED__) {
const { CloudSyncManager } = await import('./cloudSync/cloudSync.js');
// Initialize cloud sync
}
Deployment Modes
Client-Only Mode (VITE_SERVER_FEATURES_ENABLED=false):
- Local data storage and import/export
- Theme management
- PWA installation and offline use
- Smaller bundle size (cloud sync code excluded)
Server-Enabled Mode (VITE_SERVER_FEATURES_ENABLED=true):
- All client-only features
- Google Drive and Dropbox synchronization
- OAuth authentication flows
- Cross-device data consistency
Server Architecture
The server component handles OAuth authentication flows using Express.js. It exists solely to keep OAuth client secrets secure and manage token refresh operations.
Server Responsibilities
- OAuth Token Exchange: Converting authorization codes to access/refresh tokens
- Token Refresh: Handling expired access token renewal
- Security: Keeping client secrets server-side and away from browser code
- Provider Abstraction: Unified OAuth handling for Google Drive and Dropbox
OAuth Flow
- Client redirects user to
/api/{provider}/auth - Server redirects to cloud provider OAuth URL
- Provider redirects back to
/api/{provider}/callback - Server exchanges authorization code for tokens
- Server redirects client with tokens in URL fragment
- Client extracts tokens and stores for API calls
API Endpoints
/api/gdrive/auth - Initiate Google Drive OAuth
/api/gdrive/callback - Handle Google OAuth callback
/api/gdrive/refresh - Refresh Google access tokens
/api/dropbox/auth - Initiate Dropbox OAuth
/api/dropbox/callback - Handle Dropbox OAuth callback
/api/dropbox/refresh - Refresh Dropbox access tokens
Client Architecture
The client is a single-page application emphasizing local-first functionality with optional cloud enhancement.
Core Design Principles
- Local-First: All functionality works without internet connection
- Progressive Enhancement: Cloud features are additive, not required
- Event-Driven: Components communicate through state changes and events
- Modular: Clear separation between data, UI, cloud, and utility layers
Module Interaction
- State-Driven: All components interact through centralized state management
- Publisher-Subscriber: Components subscribe to state changes for reactive updates
- Service Layer: Core services (data, settings, theme) provide APIs to other modules
- Feature Isolation: Cloud functionality conditionally loaded and isolated
State Management
The application uses a Redux-style state management system with actions, reducers, and subscribers.
State Structure
{
// Current tracking context
currentDayDate: "2024-01-15",
currentWeekStartDate: "2024-01-14",
selectedTrackerDate: "2024-01-15",
// Tracking data
dailyCounts: {
"2024-01-15": { leafyGreens: 2, nuts: 1 }
},
weeklyCounts: { leafyGreens: 8, nuts: 5 },
// Historical data
history: [
{
weekStartDate: "2024-01-07",
totals: { leafyGreens: 6, nuts: 3 },
targets: { leafyGreens: 6, nuts: 5 }
}
],
// Application metadata
metadata: {
lastModified: 1642234567890,
dailyTotalsDirty: false,
weeklyTotalsDirty: false,
weekStartDay: "Sunday"
}
}
Action Types
Key actions supported by the state manager:
INITIALIZE_STATE: Set initial state on app loadUPDATE_DAILY_COUNT: Modify daily food countsSET_CURRENT_DAY: Update current date trackingRESET_DAILY_COUNTS: Clear daily counts (new day)RESET_WEEKLY_COUNTS: Clear weekly counts (new week)RECALCULATE_WEEKLY_TOTALS: Recompute weekly totals from daily dataSET_HISTORY: Update historical weekly dataUPDATE_METADATA: Modify application metadata
Publisher-Subscriber Pattern
Components subscribe to state changes for reactive updates:
stateManager.subscribe((newState, action) => {
// React to state changes
uiRenderer.updateUI(newState);
});
Data Storage
The application uses a hybrid storage approach combining localStorage and IndexedDB for different data types and access patterns.
Storage Strategy
localStorage (Synchronous):
- Current week tracking data
- Application settings and preferences
- Wizard completion status
- Quick-access metadata
IndexedDB (Asynchronous):
- Historical weekly data
- Large dataset operations
- Import/export processing
Data Service API
The dataService module provides unified access:
// Synchronous operations
dataService.loadState()
dataService.saveState(state)
dataService.getPreference(key, defaultValue)
// Asynchronous operations
await dataService.saveWeekHistory(weekData)
await dataService.getAllWeekHistory()
await dataService.getWeekHistory(weekStartDate)
Data Schemas
All data follows defined schemas with version tracking for migration support. The current schema version is stored in metadata and checked on application initialization.
Setup Wizard
The setup wizard provides guided first-time configuration through a modal-based flow. The wizard implementation uses a simple step-based state machine.
Wizard Steps
The wizard progresses through these steps based on feature availability:
- Welcome → First Day of Week → Appearance → [Cloud Sync] → [Provider Selection] → Complete
Cloud sync steps are only shown when __SERVER_FEATURES_ENABLED__ is true.
State Persistence
The wizard saves progress to localStorage during OAuth flows, allowing resumption after provider redirects. The wizard integrates with the OAuth flow by storing state before redirecting to server endpoints.
Date Handling and Tracking Engine
The trackingEngine manages date transitions and ensures data integrity across day and week boundaries.
Date Transition Detection
The checkDateAndReset() function handles date changes:
- Compare current state date with system date
- If dates differ, determine reset type (day, week, or multi-day gap)
- Archive completed periods if needed
- Reset tracking data for new period
- Update metadata with reset information
Week Transitions
When a new week begins:
- Archive current week data to history
- Clear daily and weekly counts
- Update current week start date based on user preference
Multi-Day Gaps
The system handles absences gracefully:
- Detect gaps between last used date and current date
- Archive only completed weeks, not partial data
- Reset directly to current date without creating empty periods
Cloud Synchronization
The cloud sync system handles data synchronization across devices with conflict resolution and network awareness.
Sync Architecture
CloudSyncManager: Coordinates all sync operations and schedules automatic syncing Change Detection: Monitors state metadata dirty flags to determine what needs syncing Merge Strategies: Resolves conflicts using timestamp-based rules with fallback to higher values Provider Interface: Unified API for Google Drive and Dropbox implementations
Conflict Resolution
The system uses a two-tier resolution strategy:
- Primary: Most recent timestamp wins
- Secondary: Higher value wins (only when timestamps identical)
Special handling for week transitions where reset operations take precedence over individual food entries.
Sync Process
- Check authentication status
- Analyze local dirty flags and remote file metadata
- Download remote data if changed
- Merge local and remote data using conflict resolution
- Upload merged data to cloud
- Update local metadata and clear dirty flags
Progressive Web App Features
The application implements PWA technologies for native app-like behavior across platforms.
Service Worker
The service worker (serviceWorker.js) provides:
- Offline functionality through resource caching
- Background sync for queued operations
- App update management
Web App Manifest
The manifest (manifest.json) defines:
- App identity and branding
- Installation behavior
- Display preferences
- Platform-specific icons
Platform Integration
- iOS Safari: Specific optimizations for Safari PWA limitations
- Android Chrome: Full PWA feature support
- Desktop: Installation support across Windows, macOS, and Linux
Developer Utilities
The application includes debugging and development assistance tools.
Logging System
Configurable logging with module-based organization:
- Debug, info, warn, and error levels
- Per-module logger instances
- Development vs production log filtering
Development Mode Features
When __DEV_MODE__ is enabled:
- Test date override for simulating date transitions
- Extended debugging information
- Development-only UI elements
Debug Tools
Available through the About dialog when developer mode is active:
- Manual date override for testing transitions
- Cloud file management for debugging sync issues
- State inspection and manipulation tools
Performance Considerations
Bundle Optimization
- Feature Gating: Cloud sync code excluded from client-only builds
- Tree Shaking: Unused code automatically removed
- Code Splitting: Lazy loading of optional features
- Asset Optimization: Image and CSS optimization during build
Storage Efficiency
- Selective Persistence: Only changed data written to storage
- Efficient Serialization: Optimized data formats
- Memory Management: Careful handling of large historical datasets
Network Optimization
- Incremental Sync: Only changed data synchronized
- Compression: Data compressed before transmission
- Network Awareness: Wi-Fi only mode for data conservation
- Retry Logic: Exponential backoff for failed operations
Extending the Application
Adding Food Groups
Food groups are defined in the foodGroups array in app.js. Each group requires:
{
id: "unique_id",
name: "Display Name",
frequency: "day" | "week",
target: number,
unit: "servings",
type: "positive" | "limit",
description: "Serving size information"
}
Adding Cloud Providers
- Implement provider class in
cloudProviders/following the common interface - Add OAuth endpoints to server for the new provider
- Update setup wizard and settings UI for provider selection
- Test authentication and sync flows
Modifying Tracking Logic
The tracking engine can be extended to support:
- Different reset schedules
- Custom tracking periods
- Additional data types beyond food counts
- Alternative conflict resolution strategies
Code Organization
Module Structure
- Single Responsibility: Each module focused on one domain
- Explicit Dependencies: Clear import/export relationships
- Interface Contracts: Well-defined APIs between modules
- Error Isolation: Contained error handling within module boundaries
Coding Standards
- ES6+ Features: Modern JavaScript with backward compatibility
- JSDoc Documentation: Function and class documentation
- Consistent Naming: Descriptive variable and function names
- Type Safety: Runtime validation where appropriate