diff --git a/electron/README-BUILDING.md b/electron/README-BUILDING.md index 552ed742..a470f666 100644 --- a/electron/README-BUILDING.md +++ b/electron/README-BUILDING.md @@ -1,270 +1,272 @@ -# Building TimeSafari Electron App +# TimeSafari Electron Build Guide -This guide explains how to build distributable packages for the TimeSafari Electron desktop application. +**Author**: Matthew Raymer +**Date**: 2025-01-10 +**Status**: **ACTIVE** - Production Ready + +## Overview + +This guide covers building and running the TimeSafari Electron application for desktop platforms (Windows, macOS, Linux). + +## Prerequisites + +- Node.js 18+ and npm +- TypeScript +- Electron Builder +- Platform-specific build tools (see below) ## Quick Start -### From Project Root +### Development Mode ```bash -# Build all Linux packages (AppImage, deb) -npm run electron:build +# Start development server +npm run build:electron:dev -# Build specific package types -npm run electron:build:appimage # AppImage only -npm run electron:build:deb # Debian package only +# Or manually +cd electron +npm run electron:start ``` -### From Electron Directory +### Production Builds ```bash -cd electron +# Build for current platform +npm run build:electron:prod + +# Platform-specific builds +npm run build:electron:windows +npm run build:electron:mac +npm run build:electron:linux + +# Package-specific builds +npm run build:electron:appimage # Linux AppImage +npm run build:electron:dmg # macOS DMG installer +npm run build:electron:deb # Linux DEB package +``` -# Build all packages -./build-packages.sh +## Single Instance Enforcement -# Build specific types -./build-packages.sh appimage -./build-packages.sh deb -./build-packages.sh pack # Unpacked directory (for testing) -``` +The Electron app enforces single instance operation to prevent database conflicts and resource contention: -## Package Types +### Implementation +- Uses Electron's built-in `app.requestSingleInstanceLock()` +- Second instances exit immediately with user-friendly message +- Existing instance focuses and shows informational dialog -### 1. AppImage (Recommended for Linux) -- **File**: `TimeSafari-1.0.0.AppImage` -- **Size**: ~145MB -- **Usage**: Download and run directly, no installation required -- **Distribution**: Upload to GitHub releases or website +### Behavior +- **First instance**: Starts normally and acquires lock +- **Second instance**: Detects existing instance, exits immediately +- **User experience**: Clear messaging about single instance requirement -```bash -# Make executable and run -chmod +x TimeSafari-1.0.0.AppImage -./TimeSafari-1.0.0.AppImage -``` +### Benefits +- Prevents database corruption from concurrent access +- Avoids resource conflicts +- Maintains data integrity +- User-friendly error handling -### 2. Debian Package (.deb) -- **File**: `TimeSafari_1.0.0_amd64.deb` -- **Size**: ~96MB -- **Usage**: Install via package manager -- **Distribution**: Upload to repositories or direct download +## Build Configuration +### Environment Modes ```bash -# Install -sudo dpkg -i TimeSafari_1.0.0_amd64.deb +# Development (default) +npm run build:electron:dev -# Run -timesafari -``` +# Testing +npm run build:electron:test -### 3. RPM Package (.rpm) -- **File**: `TimeSafari-1.0.0.x86_64.rpm` -- **Requirements**: `rpmbuild` must be installed -- **Usage**: Install via package manager +# Production +npm run build:electron:prod +``` +### Platform-Specific Builds ```bash -# Install rpmbuild (Arch Linux) -sudo pacman -S rpm-tools - -# Build RPM -./build-packages.sh rpm +# Windows +npm run build:electron:windows:dev +npm run build:electron:windows:test +npm run build:electron:windows:prod + +# macOS +npm run build:electron:mac:dev +npm run build:electron:mac:test +npm run build:electron:mac:prod + +# Linux +npm run build:electron:linux:dev +npm run build:electron:linux:test +npm run build:electron:linux:prod +``` -# Install (on RPM-based systems) -sudo rpm -i TimeSafari-1.0.0.x86_64.rpm +### Package Types +```bash +# Linux AppImage +npm run build:electron:appimage:dev +npm run build:electron:appimage:test +npm run build:electron:appimage:prod + +# macOS DMG +npm run build:electron:dmg:dev +npm run build:electron:dmg:test +npm run build:electron:dmg:prod + +# Linux DEB +npm run build:electron:deb:dev +npm run build:electron:deb:test +npm run build:electron:deb:prod ``` -## Build Requirements +## Platform-Specific Requirements -### System Dependencies -- Node.js 18+ -- npm or yarn -- Python 3 (for native module compilation) -- Build tools (gcc, make) +### Windows +- Windows 10+ (64-bit) +- Visual Studio Build Tools (for native modules) -### Optional Dependencies -- `rpmbuild` - for RPM packages -- `fpm` - automatically downloaded by electron-builder +### macOS +- macOS 10.15+ (Catalina) +- Xcode Command Line Tools +- Code signing certificate (for distribution) -### Node Dependencies -All required dependencies are in `package.json`: -- `electron-builder` - Main build tool -- `better-sqlite3-multiple-ciphers` - SQLite with encryption -- Native module compilation tools +### Linux +- Ubuntu 18.04+ / Debian 10+ / CentOS 7+ +- Development headers for native modules -## Build Process +## Database Configuration -### 1. Preparation -```bash -# Install dependencies -npm install +### SQLite Integration +- Uses native Node.js SQLite3 for Electron +- Database stored in user's app data directory +- Automatic migration from IndexedDB (if applicable) -# Build TypeScript -npm run build -``` +### Single Instance Protection +- File-based locking prevents concurrent database access +- Automatic cleanup on app exit +- Graceful handling of lock conflicts -### 2. Package Creation -The build process: -1. Compiles TypeScript to JavaScript -2. Rebuilds native modules for Electron -3. Packages the app with electron-builder -4. Creates platform-specific installers +## Security Features -### 3. Output Location -All built packages are saved to `electron/dist/`: -``` -dist/ -├── TimeSafari-1.0.0.AppImage # Portable AppImage -├── TimeSafari_1.0.0_amd64.deb # Debian package -├── TimeSafari-1.0.0.x86_64.rpm # RPM package (if built) -└── linux-unpacked/ # Unpacked directory -``` - -## Features - -### Single Instance Enforcement -TimeSafari Electron enforces single-instance operation to prevent: -- Database corruption from multiple instances -- Resource conflicts and performance issues -- User confusion from multiple windows - -**Behavior:** -- Only one instance can run at a time -- Attempting to launch a second instance shows a user-friendly dialog -- The existing window is focused and restored if minimized -- Second instance exits gracefully - -**Implementation:** -- Uses Electron's `requestSingleInstanceLock()` API -- Handles `second-instance` events to focus existing window -- Shows informative dialog explaining why only one instance is allowed - -## Configuration - -### App Metadata -App information is configured in `electron/package.json`: -```json -{ - "name": "TimeSafari", - "version": "1.0.0", - "description": "Time Safari - Community building through gifts, gratitude, and collaborative projects", - "homepage": "https://timesafari.app", - "author": { - "name": "Matthew Raymer", - "email": "matthew@timesafari.app" - } -} -``` +### Content Security Policy +- Strict CSP in production builds +- Development mode allows localhost connections +- Automatic configuration based on build mode -### Build Configuration -Build settings are in `electron/electron-builder.config.json`: -- Package formats and architectures -- Icons and assets -- Platform-specific settings -- Signing and publishing options +### Auto-Updater +- Disabled in development mode +- Production builds check for updates automatically +- AppImage builds skip update checks ## Troubleshooting ### Common Issues -#### 1. Native Module Compilation Errors +#### Build Failures ```bash -# Clear cache and rebuild -npm run build -``` - -#### 2. Missing Dependencies -```bash -# Install system dependencies (Arch Linux) -sudo pacman -S base-devel python - -# Install Node dependencies -npm install +# Clean and rebuild +npm run clean:electron +npm run build:electron:dev ``` -#### 3. RPM Build Fails +#### Native Module Issues ```bash -# Install rpmbuild -sudo pacman -S rpm-tools - -# Try building again -./build-packages.sh rpm +# Rebuild native modules +cd electron +npm run electron:rebuild ``` -#### 4. Large Package Size -The packages are large (~100-150MB) because they include: -- Complete Electron runtime -- Node.js runtime -- SQLite native modules -- Application assets +#### Single Instance Conflicts +- Ensure no other TimeSafari instances are running +- Check for orphaned processes: `ps aux | grep electron` +- Restart system if necessary -This is normal for Electron applications. +#### Database Issues +- Check app data directory permissions +- Verify SQLite database integrity +- Clear app data if corrupted ### Debug Mode -For detailed build information: ```bash -DEBUG=electron-builder npx electron-builder build +# Enable debug logging +DEBUG=* npm run build:electron:dev +``` + +## File Structure + +``` +electron/ +├── src/ +│ ├── index.ts # Main process entry point +│ ├── preload.ts # Preload script +│ └── setup.ts # App setup and configuration +├── assets/ # App icons and resources +├── package.json # Electron-specific dependencies +├── electron-builder.config.json # Build configuration +└── tsconfig.json # TypeScript configuration ``` -## Distribution +## Development Workflow -### GitHub Releases -1. Create a new release on GitHub -2. Upload the built packages as release assets -3. Users can download and install directly +1. **Start Development** + ```bash + npm run build:electron:dev + ``` -### Package Repositories -- **Debian/Ubuntu**: Upload `.deb` to repository -- **Fedora/CentOS**: Upload `.rpm` to repository -- **Arch Linux**: Create PKGBUILD for AUR +2. **Make Changes** + - Edit source files in `src/` + - Changes auto-reload in development -### Direct Download -Host the packages on your website for direct download. +3. **Test Build** + ```bash + npm run build:electron:test + ``` -## Cross-Platform Building +4. **Production Build** + ```bash + npm run build:electron:prod + ``` -### Current Support -- **Linux**: Full support (AppImage, deb, rpm) -- **Windows**: Configured but requires Windows build environment -- **macOS**: Configured but requires macOS build environment +## Performance Considerations -### Building for Other Platforms -To build for Windows or macOS, you need: -- The target platform's build environment -- Platform-specific signing certificates -- Updated build configuration +### Memory Usage +- Monitor renderer process memory +- Implement proper cleanup in components +- Use efficient data structures -## Security Considerations +### Startup Time +- Lazy load non-critical modules +- Optimize database initialization +- Minimize synchronous operations -### Code Signing -For production releases, consider code signing: -- **Linux**: Not required but recommended -- **Windows**: Required for Windows SmartScreen -- **macOS**: Required for Gatekeeper +### Database Performance +- Use transactions for bulk operations +- Implement proper indexing +- Monitor query performance -### Package Integrity -- Verify package checksums -- Use HTTPS for distribution -- Consider GPG signatures for packages +## Security Checklist -## Performance Tips +- [ ] Content Security Policy configured +- [ ] Auto-updater properly configured +- [ ] Single instance enforcement active +- [ ] Database access properly secured +- [ ] IPC handlers validate input +- [ ] File system access restricted +- [ ] Network requests validated -### Build Optimization -- Use `--dir` flag for faster development builds -- Cache node_modules between builds -- Use CI/CD for automated builds +## Deployment -### Package Size Reduction -- Remove unnecessary dependencies -- Use electron-builder's file filtering -- Consider using electron-updater for delta updates +### Distribution +- Windows: `.exe` installer +- macOS: `.dmg` disk image +- Linux: `.AppImage` or `.deb` package -## Support +### Code Signing +- Windows: Authenticode certificate +- macOS: Developer ID certificate +- Linux: GPG signing (optional) -For build issues: -1. Check the console output for specific errors -2. Verify all dependencies are installed -3. Try cleaning and rebuilding -4. Check electron-builder documentation -5. Open an issue with build logs +### Auto-Updates +- Configured for production builds +- Disabled for development and AppImage +- Handles update failures gracefully --- -**Happy Building! 🚀** \ No newline at end of file +**Last Updated**: 2025-01-10 +**Version**: 1.0.3-beta +**Status**: Production Ready \ No newline at end of file diff --git a/electron/src/index.ts b/electron/src/index.ts index f631c281..58304a49 100644 --- a/electron/src/index.ts +++ b/electron/src/index.ts @@ -10,24 +10,11 @@ import { join } from 'path'; import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup'; -// Single instance enforcement +// Use Electron's built-in single instance lock const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { - console.log('[Electron] Another instance is already running. Exiting...'); - - // Show user-friendly dialog before quitting - dialog.showMessageBox({ - type: 'info', - title: 'TimeSafari Already Running', - message: 'TimeSafari is already running in another window.', - detail: 'Please use the existing TimeSafari window instead of opening a new one.', - buttons: ['OK'] - }).then(() => { - app.quit(); - }); - - // Exit immediately + console.log('[Electron] Another instance is already running. Exiting immediately...'); process.exit(0); } @@ -100,7 +87,7 @@ autoUpdater.on('error', (error) => { // Initialize our app, build windows, and load content. await myCapacitorApp.init(); - // Handle second instance launch (focus existing window) + // Handle second instance launch (focus existing window and show dialog) app.on('second-instance', (event, commandLine, workingDirectory) => { console.log('[Electron] Second instance attempted to launch'); @@ -111,6 +98,17 @@ autoUpdater.on('error', (error) => { mainWindow.restore(); } mainWindow.focus(); + + // Show user-friendly dialog to inform about single instance + dialog.showMessageBox(mainWindow, { + type: 'info', + title: 'TimeSafari Already Running', + message: 'TimeSafari is already running in another window.', + detail: 'Please use this existing TimeSafari window instead of opening a new one.', + buttons: ['OK'] + }).catch((error) => { + console.error('[Electron] Error showing dialog:', error); + }); } });