TimeSafari.app - Crowd-Funder for Time - PWA
Time Safari allows people to ease into collaboration: start with expressions of gratitude and expand to crowd-fund with time & money, then record and see the impact of contributions.
Roadmap
See ClickUp for current priorities.
Setup & Building
Quick start:
- For setup, we recommend pkgx, which installs what you need (either automatically or with the
devcommand). Core dependencies are typescript & npm; when building for other platforms, you'll need other things such as those in the pkgx.yaml & BUILDING.md files.
npm install
Web
npm run dev
Then go to the test page and click "Become User 0" to take action on the platform.
Android
npm run build:android:test:run
Assumes ADB is installed; see Android Build for SDK, emulator, and PATH setup.
iOS
npm run build:ios:studio
Assumes Xcode and Xcode Command Line Tools are installed.
See BUILDING.md for comprehensive build instructions for all platforms (Web, Electron, iOS, Android, Docker).
Tests
npm run test:web
# ... or do every check:
npm run test:all
🛡️ Build Architecture Guard
This project uses Husky Git hooks to protect the build system
architecture. When you modify build-critical files, the system
automatically blocks commits until you update BUILDING.md.
Quick Setup
npm run guard:setup # Install and activate the guard
How It Works
- Pre-commit: Blocks commits if build files changed without BUILDING.md updates
- Pre-push: Blocks pushes if commits contain undocumented build changes
- Protected paths:
scripts/,vite.config.*,electron/,android/,ios/, etc.
Usage
# Test the guard manually
npm run guard:test
# Emergency bypass (use sparingly)
git commit --no-verify
git push --no-verify
📚 Full documentation: See doc/README-BUILD-GUARD.md
Development Database Clearing
TimeSafari provides a simple script-based approach to clear the local database (not the claim server) for development purposes.
Logging Configuration
TimeSafari supports configurable logging levels via the VITE_LOG_LEVEL environment variable. This allows developers to control console output verbosity without modifying code.
Quick Usage
# Show only errors
VITE_LOG_LEVEL=error npm run dev
# Show warnings and errors
VITE_LOG_LEVEL=warn npm run dev
# Show info, warnings, and errors (default)
VITE_LOG_LEVEL=info npm run dev
# Show all log levels including debug
VITE_LOG_LEVEL=debug npm run dev
Available Levels
error: Critical errors onlywarn: Warnings and errors (default for production web)info: Info, warnings, and errors (default for development/capacitor)debug: All log levels including verbose debugging
See Logging Configuration Guide for complete details.
Notification Debug Panel (dev builds)
In non-production bundles (for example vite dev or a Vite build whose mode is not production), the Notification Debug Panel at /dev/notifications helps you test FCM token registration, AlertSearch authorization upload, FCM wakeup delivery (/debug/send-wakeup), and local schedule inspection on native builds. The app no longer consumes WAKEUP_PING to call /notifications/refresh or schedule api_* notifications.
Access: Account → enable Show All General Advanced Functions → Notification Debug Panel.
Key configuration (independent settings):
- Notification Backend URL — which notification server receives API calls
- Test Mode —
testModesent in JSON request bodies (default on) - Skip JWT Authentication (Local Development Only) — omit JWT headers for local unauthenticated backends (default off)
See doc/notification-debug-panel.md for controls, recommended settings (hosted test server vs local ngrok), and troubleshooting.
Platform-specific end-to-end guides:
Database Clearing (development)
Quick Usage
# Run the database clearing script
./scripts/clear-database.sh
# Then restart your development server
npm run build:electron:dev # For Electron
npm run dev # For Web
What It Does
Electron (Desktop App)
- Automatically finds and clears the SQLite database files
- Works on Linux, macOS, and Windows
- Clears all data and forces fresh migrations on next startup
Web Browser
- Provides instructions for using custom browser data directories
- Shows manual clearing via browser DevTools
- Ensures reliable database clearing without browser complications
Safety Features
- ✅ Interactive Script: Guides you through the process
- ✅ Platform Detection: Automatically detects your OS
- ✅ Clear Instructions: Step-by-step guidance for each platform
- ✅ Safe Paths: Only clears TimeSafari-specific data
Manual Commands (if needed)
Electron Database Location
# Linux
rm -rf ~/.config/TimeSafari/*
# macOS
rm -rf ~/Library/Application\ Support/TimeSafari/*
# Windows
rmdir /s /q %APPDATA%\TimeSafari
Web Browser (Custom Data Directory)
# Create isolated browser profile
mkdir ~/timesafari-dev-data
Domain Configuration
TimeSafari uses a centralized domain configuration system to ensure consistent URL generation across all environments. This prevents localhost URLs from appearing in shared links during development.
Key Features
- ✅ Production URLs for Sharing: All copy link buttons use production domain
- ✅ Environment-Specific Internal URLs: Internal operations use appropriate environment URLs
- ✅ Single Point of Control: Change domain in one place for entire app
- ✅ Type-Safe Configuration: Full TypeScript support
Quick Reference
// For sharing functionality (environment-specific)
import { APP_SERVER } from "@/constants/app";
const shareLink = `${APP_SERVER}/deep-link/claim/123`;
// For internal operations (environment-specific)
import { APP_SERVER } from "@/constants/app";
const apiUrl = `${APP_SERVER}/api/claim/123`;
Documentation
- Constants and Configuration - Core constants
Tests
See TESTING.md for detailed test instructions.
Asset Management
TimeSafari uses a standardized asset configuration system for consistent icon and splash screen generation across all platforms.
Asset Sources
- Single source of truth:
resources/directory (Capacitor default) - Source files:
icon.png,splash.png,splash-dark.png - Format: PNG or SVG files for optimal quality
Asset Generation
- Configuration:
config/assets/capacitor-assets.config.json - Schema validation:
config/assets/schema.json - Build-time generation: Platform assets generated via
capacitor-assets - No VCS commits: Generated assets are never committed to version control
Development Commands
# Generate/update asset configurations
npm run assets:config
# Validate asset configurations
npm run assets:validate
# Clean generated platform assets (local dev only)
npm run assets:clean
# Build with asset generation
npm run build:native
Environment Setup & Dependencies
Before building the application, ensure your development environment is properly configured:
# Install all dependencies (required first time and after updates)
npm install
# Validate your development environment
npm run check:dependencies
# Check prerequisites for testing
npm run test:prerequisites
Common Issues & Solutions:
- "tsx: command not found": Run
npm installto install devDependencies - "capacitor-assets: command not found": Ensure
@capacitor/assetsis installed - Build failures: Run
npm run check:dependenciesto diagnose environment issues
Required Versions:
- Node.js: 18+ (LTS recommended)
- npm: 8+ (comes with Node.js)
- Platform-specific tools: Android Studio, Xcode (for mobile builds)
Platform Support
- Android: Adaptive icons with foreground/background, monochrome support
- iOS: LaunchScreen storyboard preferred, splash assets when needed
- Web: PWA icons generated during build to
dist/(not committed)
Font Awesome Icons
To add a Font Awesome icon, add to fontawesome.ts and reference with
font-awesome element and icon attribute with the hyphenated name.
Other
Reference Material
-
Notifications can be type of
toast(self-dismiss),info,success,warning, anddanger. They are done via notiwind and set up in App.vue. -
If you are deploying in a subdirectory, add it to
publicPathin vue.config.js, eg:publicPath: "/app/time-tracker/",
Code Organization
The project uses a centralized approach to type definitions and interfaces:
src/interfaces/- Contains all TypeScript interfaces and type definitionsdeepLinks.ts- Deep linking type system and Zod validation schemasgive.ts- Give-related interfaces and type definitionsclaims.ts- Claim-related interfaces and verifiable credentialscommon.ts- Shared interfaces and utility types- Other domain-specific interface files
Key principles:
- All interfaces and types are defined in the interfaces folder
- Zod schemas are used for runtime validation and type generation
- Domain-specific interfaces are separated into their own files
- Common interfaces are shared through
common.ts - Type definitions are generated from Zod schemas where possible
Database Architecture
The application uses a platform-agnostic database layer with Vue mixins for service access:
src/services/PlatformService.ts- Database interface definitionsrc/services/PlatformServiceFactory.ts- Platform-specific service factorysrc/services/AbsurdSqlDatabaseService.ts- SQLite implementationsrc/utils/PlatformServiceMixin.ts- Vue mixin for database access with caching
Development Guidelines:
- Always use
PlatformServiceMixinfor database operations in components - Test with PlatformServiceMixin for new features
- Leverage mixin's ultra-concise methods:
$db(),$exec(),$one(),$contacts(),$settings()
Architecture Decision: The project uses Vue mixins over Composition API composables for platform service access. See Architecture Decisions for detailed rationale.
📁 Project Structure
timesafari/
├── 📁 src/ # Source code
├── 📁 scripts/ # Build and automation scripts
├── 📁 electron/ # Electron configuration
├── 📁 android/ # Android configuration
├── 📁 ios/ # iOS configuration
├── 📁 .husky/ # Git hooks (Build Architecture Guard)
├── 📄 BUILDING.md # Build system documentation
├── 📄 pull_request_template.md # PR template
└── 📄 doc/README-BUILD-GUARD.md # Guard system documentation
Building an APK for Android 6 (API 23)
App versions up to 1.4.6 support Android 6.0 (API 23); later versions require Android 7.0 (API 24) or newer. To run the app on an Android 6 device, build your own APK from the 1.4.6 release commit (6183afc2, "bump version to 1.4.6").
Prerequisites: git, Node.js 20 (see .nvmrc), Java 21, and the Android SDK with ANDROID_HOME set (see Android Emulator Without Android Studio for an SDK setup that skips Android Studio). With pkgx, prefix the commands with pkgx, e.g. pkgx npm ci.
-
Get the 1.4.6 source:
git clone https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa.git cd crowd-funder-for-time-pwa git checkout 6183afc2 -
Confirm the minimum SDK is 23:
grep minSdkVersion android/variables.gradle # expect: minSdkVersion = 23 -
Install dependencies and build a production APK:
npm ci npm run build:android:prod -- --apknpm ciinstalls the exact dependency versions locked for 1.4.6.build:android:prod -- --apkbuilds the web app with production server settings, syncs it into the Android project, and runs./gradlew assembleDebug. The result is signed with your local Android debug key, so it installs on any device without a release keystore. -
Find the APK at
android/app/build/outputs/apk/debug/app-debug.apkand install it, either withadb install android/app/build/outputs/apk/debug/app-debug.apk(USB debugging enabled on the phone) or by copying the file to the phone and opening it (allow "Install unknown apps" for the file manager).
Notes:
- Back up your identity first. A self-built APK has a different signature from the Play Store app, so Android refuses to install it over the store version. Uninstalling the store version deletes the app's local data, including your identifier keys. Back up your seed phrase (Profile page → "Backup Identifier Seed") before uninstalling, then import it into the self-built app.
- This build has Firebase disabled, so push notifications through Google's FCM service are off.
- The daily notification plugin calls
java.time, which Android provides only from 8.0 (API 26). On Android 6, scheduling a daily reminder can crash the app; leave daily reminders off. See doc/plugin-feedback-android-6-api23-zoneid-fix.md. - Barcode scanning uses Google Play Services; on devices without them, scanning fails while the rest of the app works.
- A self-built APK does not auto-update.
🤝 Contributing
- Follow the Build Architecture Guard - Update BUILDING.md when modifying build files
- Test your changes - Ensure builds work on affected platforms
- Document updates - Keep BUILDING.md current and accurate
Kudos
Gifts make the world go 'round!
- WebStorm by JetBrains for the free open-source license
- Máximo Fernández for the 3D code and explanatory post
- Many tools & libraries such as Nodejs.org, IntelliJ Idea, Veramo.io, Vuejs.org, threejs.org
- Bush 3D model
- Forest floor image
- Time Safari logo assisted by DALL-E in ChatGPT
- DiceBear and Avataaars for human-looking identicons
- Some gratitude prompts thanks to Develop Good Habits