Major Features:
- Normalize dbExec() changes count across all platforms using SQLite changes()
- Create WebAuthn verification server (Fastify) for secure passkey operations
- Add platform diagnostics interface and UI view
- Implement diagnostic export service with memory logs and git hash
- Add git hash extraction to build config
Database Improvements:
- Create dbResultNormalizer.ts shared helper for reliable change counts
- Update CapacitorPlatformService to use normalizer with SQLite queries
- Remove read-before/read-after workaround from databaseUtil.ts
- All platforms now return reliable { changes: number; lastId?: number }
WebAuthn Security:
- Split WebAuthn into client/offline modules for proper isolation
- Create passkeyDidPeer.client.ts (server endpoint integration)
- Create passkeyDidPeer.offlineVerify.ts (offline mode, dynamic import only)
- Refactor passkeyDidPeer.ts as facade routing to client/offline
- Server-side verification required by default (offline mode behind flag)
WebAuthn Server:
- Fastify-based server in server/ directory
- 4 endpoints: registration/options, registration/verify, authentication/options, authentication/verify
- In-memory storage for development (production-ready structure)
- Comprehensive API documentation and setup guide
Platform Diagnostics:
- Create PlatformDiagnostics interface
- Implement getDiagnostics() in all platform services
- Create PlatformDiagnosticsView.vue debug UI
- Add /debug/diagnostics route
- Display platform info, capabilities, DB status, worker/queue stats
Diagnostic Export:
- Update DiagnosticExportService to include memory logs
- Add redaction for sensitive data
- Include git hash and build info in exports
- Export via platform file sharing
Build Configuration:
- Extract git hash at build time in vite.config.common.mts
- Set VITE_GIT_HASH via define for all builds
- Available in diagnostics and export bundles
Documentation:
- Add WebAuthn server section to README.md and BUILDING.md
- Explain security rationale for server-side verification
- Document setup, deployment, and configuration
- Add environment variable examples
Files Created:
- src/services/dbResultNormalizer.ts
- src/libs/crypto/vc/passkeyDidPeer.client.ts
- src/views/debug/PlatformDiagnosticsView.vue
- server/package.json, server/tsconfig.json, server/src/index.ts
- server/README.md, server/.env.example
Files Modified:
- src/services/platforms/CapacitorPlatformService.ts
- src/db/databaseUtil.ts
- src/libs/crypto/vc/passkeyDidPeer.ts
- src/services/DiagnosticExportService.ts
- src/services/platforms/WebPlatformService.ts
- src/services/platforms/ElectronPlatformService.ts
- src/services/PlatformService.ts
- src/interfaces/diagnostics.ts
- src/router/index.ts
- src/constants/app.ts
- vite.config.common.mts
- README.md, BUILDING.md
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
npm run build:web:serve -- --test
To be able to take action on the platform: go to the test page and click "Become User 0".
See BUILDING.md for comprehensive build instructions for all platforms (Web, Electron, iOS, Android, Docker).
🛡️ 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 build:web:dev
# Show warnings and errors
VITE_LOG_LEVEL=warn npm run build:web:dev
# Show info, warnings, and errors (default)
VITE_LOG_LEVEL=info npm run build:web:dev
# Show all log levels including debug
VITE_LOG_LEVEL=debug npm run build:web: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.
WebAuthn Verification Server
TimeSafari includes a server-side WebAuthn verification service for secure passkey registration and authentication.
Why a Separate Server?
WebAuthn verification must be performed server-side for security. Client-side verification can be tampered with and should never be trusted. The server:
- Verifies attestation signatures during registration
- Validates authentication signatures during login
- Prevents replay attacks by tracking counters
- Stores credentials securely with proper user binding
- Enforces origin and RP ID validation
Note: The client includes an optional "offline mode" for development (VITE_OFFLINE_WEBAUTHN_VERIFY=true), but this is not recommended for production as it compromises security.
Quick Start
# Navigate to server directory
cd server
# Install dependencies
npm install
# Copy environment template
cp .env.example .env
# Edit .env with your configuration
# RP_ID=your-domain.com
# RP_NAME=Time Safari
# RP_ORIGIN=https://your-app-url.com
# Start development server
npm run dev
The server runs on http://localhost:3002 by default (configurable via PORT in .env).
Documentation
See server/README.md for:
- Complete API documentation
- Endpoint specifications
- Production deployment guide
- Security considerations
Client Configuration
The client automatically uses the server when VITE_OFFLINE_WEBAUTHN_VERIFY is not set to true. Configure the server URL via:
- Environment variable:
VITE_WEBAUTHN_SERVER_URL - Defaults to
http://localhost:3002in development - Defaults to same origin in production
Development Database Clearing
TimeSafari provides a simple script-based approach to clear the local database (not the claim server) for development purposes.
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 build:web: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
🤝 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