Compare commits
12 Commits
get-get-ha
...
build-with
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a2966a13e | |||
| bfa75484f3 | |||
| f71bd9fb42 | |||
| 2bd191e255 | |||
| 5905ae871a | |||
| 65877627c7 | |||
| cbe8c2e427 | |||
| 538c2a4369 | |||
| 36469a7fd2 | |||
| 43c5a28153 | |||
| b6c932b22c | |||
| 322c785119 |
@@ -1,310 +0,0 @@
|
||||
# Cursor Markdown Ruleset for TimeSafari Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This ruleset enforces consistent markdown formatting standards across all project
|
||||
documentation, ensuring readability, maintainability, and compliance with
|
||||
markdownlint best practices.
|
||||
|
||||
## General Formatting Standards
|
||||
|
||||
### Line Length
|
||||
|
||||
- **Maximum line length**: 80 characters
|
||||
- **Exception**: Code blocks (JSON, shell, TypeScript, etc.) - no line length
|
||||
enforcement
|
||||
- **Rationale**: Ensures readability across different screen sizes and terminal
|
||||
widths
|
||||
|
||||
### Blank Lines
|
||||
|
||||
- **Headings**: Must be surrounded by blank lines above and below
|
||||
- **Lists**: Must be surrounded by blank lines above and below
|
||||
- **Code blocks**: Must be surrounded by blank lines above and below
|
||||
- **Maximum consecutive blank lines**: 1 (no multiple blank lines)
|
||||
- **File start**: No blank lines at the beginning of the file
|
||||
- **File end**: Single newline character at the end
|
||||
|
||||
### Whitespace
|
||||
|
||||
- **No trailing spaces**: Remove all trailing whitespace from lines
|
||||
- **No tabs**: Use spaces for indentation
|
||||
- **Consistent indentation**: 2 spaces for list items and nested content
|
||||
|
||||
## Heading Standards
|
||||
|
||||
### Format
|
||||
|
||||
- **Style**: ATX-style headings (`#`, `##`, `###`, etc.)
|
||||
- **Case**: Title case for general headings
|
||||
- **Code references**: Use backticks for file names and technical terms
|
||||
- ✅ `### Current package.json Scripts`
|
||||
- ❌ `### Current Package.json Scripts`
|
||||
|
||||
### Hierarchy
|
||||
|
||||
- **H1 (#)**: Document title only
|
||||
- **H2 (##)**: Major sections
|
||||
- **H3 (###)**: Subsections
|
||||
- **H4 (####)**: Sub-subsections
|
||||
- **H5+**: Avoid deeper nesting
|
||||
|
||||
## List Standards
|
||||
|
||||
### Unordered Lists
|
||||
|
||||
- **Marker**: Use `-` (hyphen) consistently
|
||||
- **Indentation**: 2 spaces for nested items
|
||||
- **Blank lines**: Surround lists with blank lines
|
||||
|
||||
### Ordered Lists
|
||||
|
||||
- **Format**: `1.`, `2.`, `3.` (sequential numbering)
|
||||
- **Indentation**: 2 spaces for nested items
|
||||
- **Blank lines**: Surround lists with blank lines
|
||||
|
||||
### Task Lists
|
||||
|
||||
- **Format**: `- [ ]` for incomplete, `- [x]` for complete
|
||||
- **Use case**: Project planning, checklists, implementation tracking
|
||||
|
||||
## Code Block Standards
|
||||
|
||||
### Fenced Code Blocks
|
||||
|
||||
- **Syntax**: Triple backticks with language specification
|
||||
- **Languages**: `json`, `bash`, `typescript`, `javascript`, `yaml`, `markdown`
|
||||
- **Blank lines**: Must be surrounded by blank lines above and below
|
||||
- **Line length**: No enforcement within code blocks
|
||||
|
||||
### Inline Code
|
||||
|
||||
- **Format**: Single backticks for inline code references
|
||||
- **Use case**: File names, commands, variables, properties
|
||||
|
||||
## Special Content Standards
|
||||
|
||||
### JSON Examples
|
||||
|
||||
```json
|
||||
{
|
||||
"property": "value",
|
||||
"nested": {
|
||||
"property": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shell Commands
|
||||
|
||||
```bash
|
||||
# Command with comment
|
||||
npm run build:web
|
||||
|
||||
# Multi-line command
|
||||
VITE_GIT_HASH=`git log -1 --pretty=format:%h` \
|
||||
vite build --config vite.config.web.mts
|
||||
```
|
||||
|
||||
### TypeScript Examples
|
||||
|
||||
```typescript
|
||||
// Function with JSDoc
|
||||
/**
|
||||
* Get environment configuration
|
||||
* @param env - Environment name
|
||||
* @returns Environment config object
|
||||
*/
|
||||
const getEnvironmentConfig = (env: string) => {
|
||||
switch (env) {
|
||||
case 'prod':
|
||||
return { /* production settings */ };
|
||||
default:
|
||||
return { /* development settings */ };
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## File Structure Standards
|
||||
|
||||
### Document Header
|
||||
|
||||
```markdown
|
||||
# Document Title
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: 🎯 **STATUS** - Brief description
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of the document's purpose and scope.
|
||||
```
|
||||
|
||||
### Section Organization
|
||||
|
||||
1. **Overview/Introduction**
|
||||
2. **Current State Analysis**
|
||||
3. **Implementation Plan**
|
||||
4. **Technical Details**
|
||||
5. **Testing & Validation**
|
||||
6. **Next Steps**
|
||||
|
||||
## Markdownlint Configuration
|
||||
|
||||
### Required Rules
|
||||
|
||||
```json
|
||||
{
|
||||
"MD013": { "code_blocks": false },
|
||||
"MD012": true,
|
||||
"MD022": true,
|
||||
"MD031": true,
|
||||
"MD032": true,
|
||||
"MD047": true,
|
||||
"MD009": true
|
||||
}
|
||||
```
|
||||
|
||||
### Rule Explanations
|
||||
|
||||
- **MD013**: Line length (disabled for code blocks)
|
||||
- **MD012**: No multiple consecutive blank lines
|
||||
- **MD022**: Headings should be surrounded by blank lines
|
||||
- **MD031**: Fenced code blocks should be surrounded by blank lines
|
||||
- **MD032**: Lists should be surrounded by blank lines
|
||||
- **MD047**: Files should end with a single newline
|
||||
- **MD009**: No trailing spaces
|
||||
|
||||
## Validation Commands
|
||||
|
||||
### Check Single File
|
||||
|
||||
```bash
|
||||
npx markdownlint docs/filename.md
|
||||
```
|
||||
|
||||
### Check All Documentation
|
||||
|
||||
```bash
|
||||
npx markdownlint docs/
|
||||
```
|
||||
|
||||
### Auto-fix Common Issues
|
||||
|
||||
```bash
|
||||
# Remove trailing spaces
|
||||
sed -i 's/[[:space:]]*$//' docs/filename.md
|
||||
|
||||
# Remove multiple blank lines
|
||||
sed -i '/^$/N;/^\n$/D' docs/filename.md
|
||||
|
||||
# Add newline at end if missing
|
||||
echo "" >> docs/filename.md
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Implementation Plans
|
||||
|
||||
```markdown
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation (Day 1)
|
||||
|
||||
#### 1.1 Component Setup
|
||||
|
||||
- [ ] Create new component file
|
||||
- [ ] Add basic structure
|
||||
- [ ] Implement core functionality
|
||||
|
||||
#### 1.2 Configuration
|
||||
|
||||
- [ ] Update configuration files
|
||||
- [ ] Add environment variables
|
||||
- [ ] Test configuration loading
|
||||
```
|
||||
|
||||
### Status Tracking
|
||||
|
||||
```markdown
|
||||
**Status**: ✅ **COMPLETE** - All phases finished
|
||||
**Progress**: 75% (15/20 components)
|
||||
**Next**: Ready for testing phase
|
||||
```
|
||||
|
||||
### Performance Metrics
|
||||
|
||||
```markdown
|
||||
#### 📊 Performance Metrics
|
||||
- **Build Time**: 2.3 seconds (50% faster than baseline)
|
||||
- **Bundle Size**: 1.2MB (30% reduction)
|
||||
- **Success Rate**: 100% (no failures in 50 builds)
|
||||
```
|
||||
|
||||
## Enforcement
|
||||
|
||||
### Pre-commit Hooks
|
||||
|
||||
- Run markdownlint on all changed markdown files
|
||||
- Block commits with linting violations
|
||||
- Auto-fix common issues when possible
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
- Include markdownlint in build pipeline
|
||||
- Generate reports for documentation quality
|
||||
- Fail builds with critical violations
|
||||
|
||||
### Team Guidelines
|
||||
|
||||
- All documentation PRs must pass markdownlint
|
||||
- Use provided templates for new documents
|
||||
- Follow established patterns for consistency
|
||||
|
||||
## Templates
|
||||
|
||||
### New Document Template
|
||||
|
||||
```markdown
|
||||
# Document Title
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: 🎯 **PLANNING** - Ready for Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of the document's purpose and scope.
|
||||
|
||||
## Current State
|
||||
|
||||
Description of current situation or problem.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation
|
||||
|
||||
- [ ] Task 1
|
||||
- [ ] Task 2
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review and approve plan**
|
||||
2. **Begin implementation**
|
||||
3. **Test and validate**
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for implementation
|
||||
**Priority**: Medium
|
||||
**Estimated Effort**: X days
|
||||
**Dependencies**: None
|
||||
**Stakeholders**: Development team
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-07-09
|
||||
**Version**: 1.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
@@ -7,13 +7,13 @@ alwaysApply: true
|
||||
|
||||
## 1. Platform Support Matrix
|
||||
|
||||
| Feature | Web (PWA) | Capacitor (Mobile) | Electron (Desktop) |
|
||||
|---------|-----------|-------------------|-------------------|
|
||||
| QR Code Scanning | WebInlineQRScanner | @capacitor-mlkit/barcode-scanning | Not Implemented |
|
||||
| Deep Linking | URL Parameters | App URL Open Events | Not Implemented |
|
||||
| File System | Limited (Browser API) | Capacitor Filesystem | Electron fs |
|
||||
| Camera Access | MediaDevices API | Capacitor Camera | Not Implemented |
|
||||
| Platform Detection | Web APIs | Capacitor.isNativePlatform() | process.env checks |
|
||||
| Feature | Web (PWA) | Capacitor (Mobile) | Electron (Desktop) | PyWebView (Desktop) |
|
||||
|---------|-----------|-------------------|-------------------|-------------------|
|
||||
| QR Code Scanning | WebInlineQRScanner | @capacitor-mlkit/barcode-scanning | Not Implemented | Not Implemented |
|
||||
| Deep Linking | URL Parameters | App URL Open Events | Not Implemented | Not Implemented |
|
||||
| File System | Limited (Browser API) | Capacitor Filesystem | Electron fs | PyWebView Python Bridge |
|
||||
| Camera Access | MediaDevices API | Capacitor Camera | Not Implemented | Not Implemented |
|
||||
| Platform Detection | Web APIs | Capacitor.isNativePlatform() | process.env checks | process.env checks |
|
||||
|
||||
## 2. Project Structure
|
||||
|
||||
@@ -42,6 +42,7 @@ src/
|
||||
├── main.common.ts # Shared initialization
|
||||
├── main.capacitor.ts # Mobile entry
|
||||
├── main.electron.ts # Electron entry
|
||||
├── main.pywebview.ts # PyWebView entry
|
||||
└── main.web.ts # Web/PWA entry
|
||||
```
|
||||
|
||||
@@ -51,7 +52,9 @@ root/
|
||||
├── vite.config.common.mts # Shared config
|
||||
├── vite.config.capacitor.mts # Mobile build
|
||||
├── vite.config.electron.mts # Electron build
|
||||
└── vite.config.web.mts # Web/PWA build
|
||||
├── vite.config.pywebview.mts # PyWebView build
|
||||
├── vite.config.web.mts # Web/PWA build
|
||||
└── vite.config.utils.mts # Build utilities
|
||||
```
|
||||
|
||||
## 3. Service Architecture
|
||||
@@ -65,7 +68,8 @@ services/
|
||||
├── platforms/ # Platform-specific services
|
||||
│ ├── WebPlatformService.ts
|
||||
│ ├── CapacitorPlatformService.ts
|
||||
│ └── ElectronPlatformService.ts
|
||||
│ ├── ElectronPlatformService.ts
|
||||
│ └── PyWebViewPlatformService.ts
|
||||
└── factory/ # Service factories
|
||||
└── PlatformServiceFactory.ts
|
||||
```
|
||||
@@ -149,7 +153,7 @@ export function createBuildConfig(mode: string) {
|
||||
return {
|
||||
define: {
|
||||
'process.env.VITE_PLATFORM': JSON.stringify(mode),
|
||||
// PWA is automatically enabled for web platforms via build configuration
|
||||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative),
|
||||
__IS_MOBILE__: JSON.stringify(isCapacitor),
|
||||
__USE_QR_READER__: JSON.stringify(!isCapacitor)
|
||||
}
|
||||
@@ -163,7 +167,8 @@ export function createBuildConfig(mode: string) {
|
||||
# Build commands from package.json
|
||||
"build:web": "vite build --config vite.config.web.mts",
|
||||
"build:capacitor": "vite build --config vite.config.capacitor.mts",
|
||||
"build:electron": "vite build --config vite.config.electron.mts"
|
||||
"build:electron": "vite build --config vite.config.electron.mts",
|
||||
"build:pywebview": "vite build --config vite.config.pywebview.mts"
|
||||
```
|
||||
|
||||
## 6. Testing Strategy
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
description: rules used while developing
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
✅ use system date command to timestamp all interactions with accurate date and time
|
||||
✅ python script files must always have a blank line at their end
|
||||
✅ remove whitespace at the end of lines
|
||||
✅ use npm run lint-fix to check for warnings
|
||||
✅ do not use npm run dev let me handle running and supplying feedback
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
# Directive for Documentation Generation
|
||||
|
||||
1. Produce a **small, focused set of documents** rather than an overwhelming volume.
|
||||
2. Ensure the content is **maintainable and worth preserving**, so that humans
|
||||
are motivated to keep it up to date.
|
||||
3. Prioritize **educational value**: the documents must clearly explain the
|
||||
workings of the system.
|
||||
4. Avoid **shallow, generic, or filler explanations** often found in
|
||||
AI-generated documentation.
|
||||
5. Aim for **clarity, depth, and usefulness**, so readers gain genuine understanding.
|
||||
6. Always check the local system date to determine current date.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
All references in the codebase to Dexie apply only to migration from IndexedDb to Sqlite and will be deprecated in future versions.
|
||||
@@ -1,332 +0,0 @@
|
||||
---
|
||||
globs: *.md
|
||||
alwaysApply: false
|
||||
---
|
||||
# Cursor Markdown Ruleset for TimeSafari Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This ruleset enforces consistent markdown formatting standards across all project
|
||||
documentation, ensuring readability, maintainability, and compliance with
|
||||
markdownlint best practices.
|
||||
|
||||
## General Formatting Standards
|
||||
|
||||
### Line Length
|
||||
|
||||
- **Maximum line length**: 80 characters
|
||||
- **Exception**: Code blocks (JSON, shell, TypeScript, etc.) - no line length
|
||||
enforcement
|
||||
- **Rationale**: Ensures readability across different screen sizes and terminal
|
||||
widths
|
||||
|
||||
### Blank Lines
|
||||
|
||||
- **Headings**: Must be surrounded by blank lines above and below
|
||||
- **Lists**: Must be surrounded by blank lines above and below
|
||||
- **Code blocks**: Must be surrounded by blank lines above and below
|
||||
- **Maximum consecutive blank lines**: 1 (no multiple blank lines)
|
||||
- **File start**: No blank lines at the beginning of the file
|
||||
- **File end**: Single newline character at the end
|
||||
|
||||
### Whitespace
|
||||
|
||||
- **No trailing spaces**: Remove all trailing whitespace from lines
|
||||
- **No tabs**: Use spaces for indentation
|
||||
- **Consistent indentation**: 2 spaces for list items and nested content
|
||||
|
||||
## Heading Standards
|
||||
|
||||
### Format
|
||||
|
||||
- **Style**: ATX-style headings (`#`, `##`, `###`, etc.)
|
||||
- **Case**: Title case for general headings
|
||||
- **Code references**: Use backticks for file names and technical terms
|
||||
- ✅ `### Current package.json Scripts`
|
||||
- ❌ `### Current Package.json Scripts`
|
||||
|
||||
### Hierarchy
|
||||
|
||||
- **H1 (#)**: Document title only
|
||||
- **H2 (##)**: Major sections
|
||||
- **H3 (###)**: Subsections
|
||||
- **H4 (####)**: Sub-subsections
|
||||
- **H5+**: Avoid deeper nesting
|
||||
|
||||
## List Standards
|
||||
|
||||
### Unordered Lists
|
||||
|
||||
- **Marker**: Use `-` (hyphen) consistently
|
||||
- **Indentation**: 2 spaces for nested items
|
||||
- **Blank lines**: Surround lists with blank lines
|
||||
|
||||
### Ordered Lists
|
||||
|
||||
- **Format**: `1.`, `2.`, `3.` (sequential numbering)
|
||||
- **Indentation**: 2 spaces for nested items
|
||||
- **Blank lines**: Surround lists with blank lines
|
||||
|
||||
### Task Lists
|
||||
|
||||
- **Format**: `- [ ]` for incomplete, `- [x]` for complete
|
||||
- **Use case**: Project planning, checklists, implementation tracking
|
||||
|
||||
## Code Block Standards
|
||||
|
||||
### Fenced Code Blocks
|
||||
|
||||
- **Syntax**: Triple backticks with language specification
|
||||
- **Languages**: `json`, `bash`, `typescript`, `javascript`, `yaml`, `markdown`
|
||||
- **Blank lines**: Must be surrounded by blank lines above and below
|
||||
- **Line length**: No enforcement within code blocks
|
||||
|
||||
### Inline Code
|
||||
|
||||
- **Format**: Single backticks for inline code references
|
||||
- **Use case**: File names, commands, variables, properties
|
||||
|
||||
## Special Content Standards
|
||||
|
||||
### JSON Examples
|
||||
|
||||
```json
|
||||
{
|
||||
"property": "value",
|
||||
"nested": {
|
||||
"property": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shell Commands
|
||||
|
||||
```bash
|
||||
# Command with comment
|
||||
npm run build:web
|
||||
|
||||
# Multi-line command
|
||||
VITE_GIT_HASH=`git log -1 --pretty=format:%h` \
|
||||
vite build --config vite.config.web.mts
|
||||
```
|
||||
|
||||
### TypeScript Examples
|
||||
|
||||
```typescript
|
||||
// Function with JSDoc
|
||||
/**
|
||||
* Get environment configuration
|
||||
* @param env - Environment name
|
||||
* @returns Environment config object
|
||||
*/
|
||||
const getEnvironmentConfig = (env: string) => {
|
||||
switch (env) {
|
||||
case 'prod':
|
||||
return { /* production settings */ };
|
||||
default:
|
||||
return { /* development settings */ };
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## File Structure Standards
|
||||
|
||||
### Document Header
|
||||
|
||||
```markdown
|
||||
# Document Title
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: 🎯 **STATUS** - Brief description
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of the document's purpose and scope.
|
||||
```
|
||||
|
||||
### Section Organization
|
||||
|
||||
1. **Overview/Introduction**
|
||||
2. **Current State Analysis**
|
||||
3. **Implementation Plan**
|
||||
4. **Technical Details**
|
||||
5. **Testing & Validation**
|
||||
6. **Next Steps**
|
||||
|
||||
## Markdownlint Configuration
|
||||
|
||||
### Required Rules
|
||||
|
||||
```json
|
||||
{
|
||||
"MD013": { "code_blocks": false },
|
||||
"MD012": true,
|
||||
"MD022": true,
|
||||
"MD031": true,
|
||||
"MD032": true,
|
||||
"MD047": true,
|
||||
"MD009": true
|
||||
}
|
||||
```
|
||||
|
||||
### Rule Explanations
|
||||
|
||||
- **MD013**: Line length (disabled for code blocks)
|
||||
- **MD012**: No multiple consecutive blank lines
|
||||
- **MD022**: Headings should be surrounded by blank lines
|
||||
- **MD031**: Fenced code blocks should be surrounded by blank lines
|
||||
- **MD032**: Lists should be surrounded by blank lines
|
||||
- **MD047**: Files should end with a single newline
|
||||
- **MD009**: No trailing spaces
|
||||
|
||||
## Validation Commands
|
||||
|
||||
### Check Single File
|
||||
|
||||
```bash
|
||||
npx markdownlint docs/filename.md
|
||||
```
|
||||
|
||||
### Check All Documentation
|
||||
|
||||
```bash
|
||||
npx markdownlint docs/
|
||||
```
|
||||
|
||||
### Auto-fix Common Issues
|
||||
|
||||
```bash
|
||||
# Remove trailing spaces
|
||||
sed -i 's/[[:space:]]*$//' docs/filename.md
|
||||
|
||||
# Remove multiple blank lines
|
||||
sed -i '/^$/N;/^\n$/D' docs/filename.md
|
||||
|
||||
# Add newline at end if missing
|
||||
echo "" >> docs/filename.md
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Implementation Plans
|
||||
|
||||
```markdown
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation (Day 1)
|
||||
|
||||
#### 1.1 Component Setup
|
||||
|
||||
- [ ] Create new component file
|
||||
- [ ] Add basic structure
|
||||
- [ ] Implement core functionality
|
||||
|
||||
#### 1.2 Configuration
|
||||
|
||||
- [ ] Update configuration files
|
||||
- [ ] Add environment variables
|
||||
- [ ] Test configuration loading
|
||||
```
|
||||
|
||||
### Status Tracking
|
||||
|
||||
```markdown
|
||||
**Status**: ✅ **COMPLETE** - All phases finished
|
||||
**Progress**: 75% (15/20 components)
|
||||
**Next**: Ready for testing phase
|
||||
```
|
||||
|
||||
### Performance Metrics
|
||||
|
||||
```markdown
|
||||
#### 📊 Performance Metrics
|
||||
- **Build Time**: 2.3 seconds (50% faster than baseline)
|
||||
- **Bundle Size**: 1.2MB (30% reduction)
|
||||
- **Success Rate**: 100% (no failures in 50 builds)
|
||||
```
|
||||
|
||||
## Enforcement
|
||||
|
||||
### Pre-commit Hooks
|
||||
|
||||
- Run markdownlint on all changed markdown files
|
||||
- Block commits with linting violations
|
||||
- Auto-fix common issues when possible
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
- Include markdownlint in build pipeline
|
||||
- Generate reports for documentation quality
|
||||
- Fail builds with critical violations
|
||||
|
||||
### Team Guidelines
|
||||
|
||||
- All documentation PRs must pass markdownlint
|
||||
- Use provided templates for new documents
|
||||
- Follow established patterns for consistency
|
||||
|
||||
## Templates
|
||||
|
||||
### New Document Template
|
||||
|
||||
```markdown
|
||||
# Document Title
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: 🎯 **PLANNING** - Ready for Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of the document's purpose and scope.
|
||||
|
||||
## Current State
|
||||
|
||||
Description of current situation or problem.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation
|
||||
|
||||
- [ ] Task 1
|
||||
- [ ] Task 2
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review and approve plan**
|
||||
2. **Begin implementation**
|
||||
3. **Test and validate**
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for implementation
|
||||
**Priority**: Medium
|
||||
**Estimated Effort**: X days
|
||||
**Dependencies**: None
|
||||
**Stakeholders**: Development team
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-07-09
|
||||
**Version**: 1.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
|
||||
|
||||
### Heading Uniqueness
|
||||
|
||||
- **Rule**: No duplicate heading content at the same level
|
||||
- **Scope**: Within a single document
|
||||
- **Rationale**: Maintains clear document structure and navigation
|
||||
- **Example**:
|
||||
|
||||
```markdown
|
||||
## Features ✅
|
||||
### Authentication
|
||||
### Authorization
|
||||
|
||||
## Features ❌ (Duplicate heading)
|
||||
### Security
|
||||
### Performance
|
||||
```
|
||||
@@ -1,96 +1,70 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
# Time Safari Context
|
||||
|
||||
## Project Overview
|
||||
|
||||
Time Safari is an application designed to foster community building through gifts,
|
||||
gratitude, and collaborative projects. The app should make it extremely easy and
|
||||
intuitive for users of any age and capability to recognize contributions, build
|
||||
trust networks, and organize collective action. It is built on services that
|
||||
preserve privacy and data sovereignty.
|
||||
Time Safari is an application designed to foster community building through gifts, gratitude, and collaborative projects. The app should make it extremely easy and intuitive for users of any age and capability to recognize contributions, build trust networks, and organize collective action. It is built on services that preserve privacy and data sovereignty.
|
||||
|
||||
The ultimate goals of Time Safari are two-fold:
|
||||
|
||||
1. **Connect** Make it easy, rewarding, and non-threatening for people to
|
||||
connect with others who have similar interests, and to initiate activities
|
||||
together. This helps people accomplish and learn from other individuals in
|
||||
less-structured environments; moreover, it helps them discover who they want
|
||||
to continue to support and with whom they want to maintain relationships.
|
||||
1. **Connect** Make it easy, rewarding, and non-threatening for people to connect with others who have similar interests, and to initiate activities together. This helps people accomplish and learn from other individuals in less-structured environments; moreover, it helps them discover who they want to continue to support and with whom they want to maintain relationships.
|
||||
|
||||
2. **Reveal** Widely advertise the great support and rewards that are being
|
||||
given and accepted freely, especially non-monetary ones. Using visuals and text,
|
||||
display the kind of impact that gifts are making in the lives of others. Also
|
||||
show useful and engaging reports of project statistics and personal accomplishments.
|
||||
2. **Reveal** Widely advertise the great support and rewards that are being given and accepted freely, especially non-monetary ones. Using visuals and text, display the kind of impact that gifts are making in the lives of others. Also show useful and engaging reports of project statistics and personal accomplishments.
|
||||
|
||||
|
||||
## Core Approaches
|
||||
|
||||
Time Safari should help everyday users build meaningful connections and organize
|
||||
collective efforts by:
|
||||
Time Safari should help everyday users build meaningful connections and organize collective efforts by:
|
||||
|
||||
1. **Recognizing Contributions**: Creating permanent, verifiable records of gifts
|
||||
and contributions people give to each other and their communities.
|
||||
1. **Recognizing Contributions**: Creating permanent, verifiable records of gifts and contributions people give to each other and their communities.
|
||||
|
||||
2. **Facilitating Collaboration**: Making it ridiculously easy for people to ask
|
||||
for or propose help on projects and interests that matter to them.
|
||||
2. **Facilitating Collaboration**: Making it ridiculously easy for people to ask for or propose help on projects and interests that matter to them.
|
||||
|
||||
3. **Building Trust Networks**: Enabling users to maintain their network and activity
|
||||
visibility. Developing reputation through verified contributions and references,
|
||||
which can be selectively shown to others outside the network.
|
||||
3. **Building Trust Networks**: Enabling users to maintain their network and activity visibility. Developing reputation through verified contributions and references, which can be selectively shown to others outside the network.
|
||||
|
||||
4. **Preserving Privacy**: Ensuring personal identifiers are only shared with
|
||||
explicitly authorized contacts, allowing private individuals including children
|
||||
to participate safely.
|
||||
4. **Preserving Privacy**: Ensuring personal identifiers are only shared with explicitly authorized contacts, allowing private individuals including children to participate safely.
|
||||
|
||||
5. **Engaging Content**: Displaying people's records in compelling stories, and
|
||||
highlighting those projects that are lifting people's lives long-term, both in
|
||||
physical support and in emotional-spiritual-creative thriving.
|
||||
5. **Engaging Content**: Displaying people's records in compelling stories, and highlighting those projects that are lifting people's lives long-term, both in physical support and in emotional-spiritual-creative thriving.
|
||||
|
||||
|
||||
## Technical Foundation
|
||||
|
||||
This application is built on a privacy-preserving claims architecture (via
|
||||
endorser.ch) with these key characteristics:
|
||||
This application is built on a privacy-preserving claims architecture (via endorser.ch) with these key characteristics:
|
||||
|
||||
- **Decentralized Identifiers (DIDs)**: User identities are based on public/private
|
||||
key pairs stored on their devices
|
||||
- **Cryptographic Verification**: All claims and confirmations are
|
||||
cryptographically signed
|
||||
- **User-Controlled Visibility**: Users explicitly control who can see their
|
||||
identifiers and data
|
||||
- **Merkle-Chained Claims**: Claims are cryptographically chained for verification
|
||||
and integrity
|
||||
- **Native and Web App**: Works on Capacitor (iOS, Android), Desktop (Electron
|
||||
and CEFPython), and web browsers
|
||||
- **Decentralized Identifiers (DIDs)**: User identities are based on public/private key pairs stored on their devices
|
||||
- **Cryptographic Verification**: All claims and confirmations are cryptographically signed
|
||||
- **User-Controlled Visibility**: Users explicitly control who can see their identifiers and data
|
||||
- **Merkle-Chained Claims**: Claims are cryptographically chained for verification and integrity
|
||||
- **Native and Web App**: Works on Capacitor (iOS, Android), Desktop (Electron and CEFPython), and web browsers
|
||||
|
||||
## User Journey
|
||||
|
||||
The typical progression of usage follows these stages:
|
||||
|
||||
1. **Gratitude & Recognition**: Users begin by expressing and recording gratitude
|
||||
for gifts received, building a foundation of acknowledgment.
|
||||
1. **Gratitude & Recognition**: Users begin by expressing and recording gratitude for gifts received, building a foundation of acknowledgment.
|
||||
|
||||
2. **Project Proposals**: Users propose projects and ideas, reaching out to connect
|
||||
with others who share similar interests.
|
||||
2. **Project Proposals**: Users propose projects and ideas, reaching out to connect with others who share similar interests.
|
||||
|
||||
3. **Action Triggers**: Offers of help serve as triggers and motivations to execute
|
||||
proposed projects, moving from ideas to action.
|
||||
3. **Action Triggers**: Offers of help serve as triggers and motivations to execute proposed projects, moving from ideas to action.
|
||||
|
||||
## Context for LLM Development
|
||||
|
||||
When developing new functionality for Time Safari, consider these design principles:
|
||||
|
||||
1. **Accessibility First**: Features should be usable by non-technical users with
|
||||
minimal learning curve.
|
||||
1. **Accessibility First**: Features should be usable by non-technical users with minimal learning curve.
|
||||
|
||||
2. **Privacy by Design**: All features must respect user privacy and data sovereignty.
|
||||
|
||||
3. **Progressive Enhancement**: Core functionality should work across all devices,
|
||||
with richer experiences where supported.
|
||||
3. **Progressive Enhancement**: Core functionality should work across all devices, with richer experiences where supported.
|
||||
|
||||
4. **Voluntary Collaboration**: The system should enable but never coerce participation.
|
||||
|
||||
@@ -98,40 +72,31 @@ with richer experiences where supported.
|
||||
|
||||
6. **Network Effects**: Consider how features scale as more users join the platform.
|
||||
|
||||
7. **Low Resource Requirements**: The system should be lightweight enough to run
|
||||
on inexpensive devices users already own.
|
||||
7. **Low Resource Requirements**: The system should be lightweight enough to run on inexpensive devices users already own.
|
||||
|
||||
## Use Cases to Support
|
||||
|
||||
LLM development should focus on enhancing these key use cases:
|
||||
|
||||
1. **Community Building**: Tools that help people find others with shared
|
||||
interests and values.
|
||||
1. **Community Building**: Tools that help people find others with shared interests and values.
|
||||
|
||||
2. **Project Coordination**: Features that make it easy to propose collaborative
|
||||
projects and to submit suggestions and offers to existing ones.
|
||||
2. **Project Coordination**: Features that make it easy to propose collaborative projects and to submit suggestions and offers to existing ones.
|
||||
|
||||
3. **Reputation Building**: Methods for users to showcase their contributions
|
||||
and reliability, in contexts where they explicitly reveal that information.
|
||||
3. **Reputation Building**: Methods for users to showcase their contributions and reliability, in contexts where they explicitly reveal that information.
|
||||
|
||||
4. **Governance Experimentation**: Features that facilitate decision-making and
|
||||
collective governance.
|
||||
4. **Governance Experimentation**: Features that facilitate decision-making and collective governance.
|
||||
|
||||
## Constraints
|
||||
|
||||
When developing new features, be mindful of these constraints:
|
||||
|
||||
1. **Privacy Preservation**: User identifiers must remain private except when
|
||||
explicitly shared.
|
||||
1. **Privacy Preservation**: User identifiers must remain private except when explicitly shared.
|
||||
|
||||
2. **Platform Limitations**: Features must work within the constraints of the target
|
||||
app platforms, while aiming to leverage the best platform technology available.
|
||||
2. **Platform Limitations**: Features must work within the constraints of the target app platforms, while aiming to leverage the best platform technology available.
|
||||
|
||||
3. **Endorser API Limitations**: Backend features are constrained by the endorser.ch
|
||||
API capabilities.
|
||||
3. **Endorser API Limitations**: Backend features are constrained by the endorser.ch API capabilities.
|
||||
|
||||
4. **Performance on Low-End Devices**: The application should remain performant
|
||||
on older/simpler devices.
|
||||
4. **Performance on Low-End Devices**: The application should remain performant on older/simpler devices.
|
||||
|
||||
5. **Offline-First When Possible**: Key functionality should work offline when feasible.
|
||||
|
||||
@@ -151,14 +116,12 @@ on older/simpler devices.
|
||||
|
||||
## Project Architecture
|
||||
|
||||
- The application must work on web browser, PWA (Progressive Web Application),
|
||||
desktop via Electron, and mobile via Capacitor
|
||||
- The application must work on web browser, PWA (Progressive Web Application), desktop via Electron, and mobile via Capacitor
|
||||
- Building for each platform is managed via Vite
|
||||
|
||||
## Core Development Principles
|
||||
|
||||
### DRY development
|
||||
|
||||
- **Code Reuse**
|
||||
- Extract common functionality into utility functions
|
||||
- Create reusable components for UI patterns
|
||||
@@ -214,24 +177,14 @@ on older/simpler devices.
|
||||
- Use shared test configurations
|
||||
- Create reusable test helpers
|
||||
- Implement consistent test patterns
|
||||
- F.I.R.S.T. (for Unit Tests)
|
||||
F – Fast
|
||||
I – Independent
|
||||
R – Repeatable
|
||||
S – Self-validating
|
||||
T – Timely
|
||||
|
||||
|
||||
### SOLID Principles
|
||||
|
||||
- **Single Responsibility**: Each class/component should have only one reason to
|
||||
change
|
||||
- **Single Responsibility**: Each class/component should have only one reason to change
|
||||
- Components should focus on one specific feature (e.g., QR scanning, DID management)
|
||||
- Services should handle one type of functionality (e.g., platform services,
|
||||
crypto services)
|
||||
- Services should handle one type of functionality (e.g., platform services, crypto services)
|
||||
- Utilities should provide focused helper functions
|
||||
|
||||
- **Open/Closed**: Software entities should be open for extension but closed for
|
||||
modification
|
||||
- **Open/Closed**: Software entities should be open for extension but closed for modification
|
||||
- Use interfaces for service definitions
|
||||
- Implement plugin architecture for platform-specific features
|
||||
- Allow component behavior extension through props and events
|
||||
@@ -252,7 +205,6 @@ on older/simpler devices.
|
||||
- Implement factory patterns for component creation
|
||||
|
||||
### Law of Demeter
|
||||
|
||||
- Components should only communicate with immediate dependencies
|
||||
- Avoid chaining method calls (e.g., `this.service.getUser().getProfile().getName()`)
|
||||
- Use mediator patterns for complex component interactions
|
||||
@@ -260,7 +212,6 @@ on older/simpler devices.
|
||||
- Keep component communication through defined events and props
|
||||
|
||||
### Composition over Inheritance
|
||||
|
||||
- Prefer building components through composition
|
||||
- Use mixins for shared functionality
|
||||
- Implement feature toggles through props
|
||||
@@ -268,7 +219,6 @@ on older/simpler devices.
|
||||
- Use service composition for complex features
|
||||
|
||||
### Interface Segregation
|
||||
|
||||
- Define clear interfaces for services
|
||||
- Keep component APIs minimal and focused
|
||||
- Split large interfaces into smaller, specific ones
|
||||
@@ -276,7 +226,6 @@ on older/simpler devices.
|
||||
- Implement role-based interfaces for different use cases
|
||||
|
||||
### Fail Fast
|
||||
|
||||
- Validate inputs early in the process
|
||||
- Use TypeScript strict mode
|
||||
- Implement comprehensive error handling
|
||||
@@ -284,7 +233,6 @@ on older/simpler devices.
|
||||
- Use assertions for development-time validation
|
||||
|
||||
### Principle of Least Astonishment
|
||||
|
||||
- Follow Vue.js conventions consistently
|
||||
- Use familiar naming patterns
|
||||
- Implement predictable component behaviors
|
||||
@@ -292,7 +240,6 @@ on older/simpler devices.
|
||||
- Keep UI interactions intuitive
|
||||
|
||||
### Information Hiding
|
||||
|
||||
- Encapsulate implementation details
|
||||
- Use private class members
|
||||
- Implement proper access modifiers
|
||||
@@ -300,7 +247,6 @@ on older/simpler devices.
|
||||
- Use TypeScript's access modifiers effectively
|
||||
|
||||
### Single Source of Truth
|
||||
|
||||
- Use Pinia for state management
|
||||
- Maintain one source for user data
|
||||
- Centralize configuration management
|
||||
@@ -308,9 +254,23 @@ on older/simpler devices.
|
||||
- Implement proper state synchronization
|
||||
|
||||
### Principle of Least Privilege
|
||||
|
||||
- Implement proper access control
|
||||
- Use minimal required permissions
|
||||
- Follow privacy-by-design principles
|
||||
- Restrict component access to necessary data
|
||||
- Implement proper authentication/authorization
|
||||
|
||||
### Continuous Integration/Continuous Deployment (CI/CD)
|
||||
- Automated testing on every commit
|
||||
- Consistent build process across platforms
|
||||
- Automated deployment pipelines
|
||||
- Quality gates for code merging
|
||||
- Environment-specific configurations
|
||||
|
||||
This expanded documentation provides:
|
||||
1. Clear principles for development
|
||||
2. Practical implementation guidelines
|
||||
3. Real-world examples
|
||||
4. TypeScript integration
|
||||
5. Best practices for Time Safari
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
# Rules for peaceful co-existence with developers
|
||||
|
||||
do not add or commit for the user; let him control that process
|
||||
|
||||
the content of commit messages should be from the files awaiting staging
|
||||
and those which have been staged. use the differences in those files
|
||||
to inform the content of the commit message
|
||||
|
||||
always preview changes and commit message to use and allow me to copy and paste
|
||||
✅ Preferred Commit Message Format
|
||||
|
||||
Short summary in the first line (concise and high-level).
|
||||
Avoid long commit bodies unless truly necessary.
|
||||
|
||||
✅ Valued Content in Commit Messages
|
||||
|
||||
Specific fixes or features.
|
||||
Symptoms or problems that were fixed.
|
||||
Notes about tests passing or TS/linting errors being resolved (briefly).
|
||||
|
||||
❌ Avoid in Commit Messages
|
||||
|
||||
Vague terms: “improved”, “enhanced”, “better” — especially from AI.
|
||||
Minor changes: small doc tweaks, one-liners, cleanup, or lint fixes.
|
||||
Redundant blurbs: repeated across files or too generic.
|
||||
Multiple overlapping purposes in a single commit — prefer narrow, focused commits.
|
||||
Long explanations of what can be deduced from good in-line code comments.
|
||||
|
||||
Guiding Principle
|
||||
|
||||
Let code and inline documentation speak for themselves. Use commits to highlight what isn't obvious from reading the code.
|
||||
267
.cursor/rules/wa-sqlite.mdc
Normal file
@@ -0,0 +1,267 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
# wa-sqlite Usage Guide
|
||||
|
||||
## Table of Contents
|
||||
- [1. Overview](#1-overview)
|
||||
- [2. Installation](#2-installation)
|
||||
- [3. Basic Setup](#3-basic-setup)
|
||||
- [3.1 Import and Initialize](#31-import-and-initialize)
|
||||
- [3.2 Basic Database Operations](#32-basic-database-operations)
|
||||
- [4. Virtual File Systems (VFS)](#4-virtual-file-systems-vfs)
|
||||
- [4.1 Available VFS Options](#41-available-vfs-options)
|
||||
- [4.2 Using a VFS](#42-using-a-vfs)
|
||||
- [5. Best Practices](#5-best-practices)
|
||||
- [5.1 Error Handling](#51-error-handling)
|
||||
- [5.2 Transaction Management](#52-transaction-management)
|
||||
- [5.3 Prepared Statements](#53-prepared-statements)
|
||||
- [6. Performance Considerations](#6-performance-considerations)
|
||||
- [7. Common Issues and Solutions](#7-common-issues-and-solutions)
|
||||
- [8. TypeScript Support](#8-typescript-support)
|
||||
|
||||
## 1. Overview
|
||||
wa-sqlite is a WebAssembly build of SQLite that enables SQLite database operations in web browsers and JavaScript environments. It provides both synchronous and asynchronous builds, with support for custom virtual file systems (VFS) for persistent storage.
|
||||
|
||||
## 2. Installation
|
||||
```bash
|
||||
npm install wa-sqlite
|
||||
# or
|
||||
yarn add wa-sqlite
|
||||
```
|
||||
|
||||
## 3. Basic Setup
|
||||
|
||||
### 3.1 Import and Initialize
|
||||
```javascript
|
||||
// Choose one of these imports based on your needs:
|
||||
// - wa-sqlite.mjs: Synchronous build
|
||||
// - wa-sqlite-async.mjs: Asynchronous build (required for async VFS)
|
||||
// - wa-sqlite-jspi.mjs: JSPI-based async build (experimental, Chromium only)
|
||||
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs';
|
||||
import * as SQLite from 'wa-sqlite';
|
||||
|
||||
async function initDatabase() {
|
||||
// Initialize SQLite module
|
||||
const module = await SQLiteESMFactory();
|
||||
const sqlite3 = SQLite.Factory(module);
|
||||
|
||||
// Open database (returns a Promise)
|
||||
const db = await sqlite3.open_v2('myDatabase');
|
||||
return { sqlite3, db };
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Basic Database Operations
|
||||
```javascript
|
||||
async function basicOperations() {
|
||||
const { sqlite3, db } = await initDatabase();
|
||||
|
||||
try {
|
||||
// Create a table
|
||||
await sqlite3.exec(db, `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT UNIQUE
|
||||
)
|
||||
`);
|
||||
|
||||
// Insert data
|
||||
await sqlite3.exec(db, `
|
||||
INSERT INTO users (name, email)
|
||||
VALUES ('John Doe', 'john@example.com')
|
||||
`);
|
||||
|
||||
// Query data
|
||||
const results = [];
|
||||
await sqlite3.exec(db, 'SELECT * FROM users', (row, columns) => {
|
||||
results.push({ row, columns });
|
||||
});
|
||||
|
||||
return results;
|
||||
} finally {
|
||||
// Always close the database when done
|
||||
await sqlite3.close(db);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Virtual File Systems (VFS)
|
||||
|
||||
### 4.1 Available VFS Options
|
||||
wa-sqlite provides several VFS implementations for persistent storage:
|
||||
|
||||
1. **IDBBatchAtomicVFS** (Recommended for general use)
|
||||
- Uses IndexedDB with batch atomic writes
|
||||
- Works in all contexts (Window, Worker, Service Worker)
|
||||
- Supports WAL mode
|
||||
- Best performance with `PRAGMA synchronous=normal`
|
||||
|
||||
2. **IDBMirrorVFS**
|
||||
- Keeps files in memory, persists to IndexedDB
|
||||
- Works in all contexts
|
||||
- Good for smaller databases
|
||||
|
||||
3. **OPFS-based VFS** (Origin Private File System)
|
||||
- Various implementations available:
|
||||
- AccessHandlePoolVFS
|
||||
- OPFSAdaptiveVFS
|
||||
- OPFSCoopSyncVFS
|
||||
- OPFSPermutedVFS
|
||||
- Better performance but limited to Worker contexts
|
||||
|
||||
### 4.2 Using a VFS
|
||||
```javascript
|
||||
import { IDBBatchAtomicVFS } from 'wa-sqlite/src/examples/IDBBatchAtomicVFS.js';
|
||||
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs';
|
||||
import * as SQLite from 'wa-sqlite';
|
||||
|
||||
async function initDatabaseWithVFS() {
|
||||
const module = await SQLiteESMFactory();
|
||||
const sqlite3 = SQLite.Factory(module);
|
||||
|
||||
// Register VFS
|
||||
const vfs = await IDBBatchAtomicVFS.create('myApp', module);
|
||||
sqlite3.vfs_register(vfs, true);
|
||||
|
||||
// Open database with VFS
|
||||
const db = await sqlite3.open_v2('myDatabase');
|
||||
|
||||
// Configure for better performance
|
||||
await sqlite3.exec(db, 'PRAGMA synchronous = normal');
|
||||
await sqlite3.exec(db, 'PRAGMA journal_mode = WAL');
|
||||
|
||||
return { sqlite3, db };
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Best Practices
|
||||
|
||||
### 5.1 Error Handling
|
||||
```javascript
|
||||
async function safeDatabaseOperation() {
|
||||
const { sqlite3, db } = await initDatabase();
|
||||
|
||||
try {
|
||||
await sqlite3.exec(db, 'SELECT * FROM non_existent_table');
|
||||
} catch (error) {
|
||||
if (error.code === SQLite.SQLITE_ERROR) {
|
||||
console.error('SQL error:', error.message);
|
||||
} else {
|
||||
console.error('Database error:', error);
|
||||
}
|
||||
} finally {
|
||||
await sqlite3.close(db);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Transaction Management
|
||||
```javascript
|
||||
async function transactionExample() {
|
||||
const { sqlite3, db } = await initDatabase();
|
||||
|
||||
try {
|
||||
await sqlite3.exec(db, 'BEGIN TRANSACTION');
|
||||
|
||||
// Perform multiple operations
|
||||
await sqlite3.exec(db, 'INSERT INTO users (name) VALUES (?)', ['Alice']);
|
||||
await sqlite3.exec(db, 'INSERT INTO users (name) VALUES (?)', ['Bob']);
|
||||
|
||||
await sqlite3.exec(db, 'COMMIT');
|
||||
} catch (error) {
|
||||
await sqlite3.exec(db, 'ROLLBACK');
|
||||
throw error;
|
||||
} finally {
|
||||
await sqlite3.close(db);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Prepared Statements
|
||||
```javascript
|
||||
async function preparedStatementExample() {
|
||||
const { sqlite3, db } = await initDatabase();
|
||||
|
||||
try {
|
||||
// Prepare statement
|
||||
const stmt = await sqlite3.prepare(db, 'SELECT * FROM users WHERE id = ?');
|
||||
|
||||
// Execute with different parameters
|
||||
await sqlite3.bind(stmt, 1, 1);
|
||||
while (await sqlite3.step(stmt) === SQLite.SQLITE_ROW) {
|
||||
const row = sqlite3.row(stmt);
|
||||
console.log(row);
|
||||
}
|
||||
|
||||
// Reset and reuse
|
||||
await sqlite3.reset(stmt);
|
||||
await sqlite3.bind(stmt, 1, 2);
|
||||
// ... execute again
|
||||
|
||||
await sqlite3.finalize(stmt);
|
||||
} finally {
|
||||
await sqlite3.close(db);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Performance Considerations
|
||||
|
||||
1. **VFS Selection**
|
||||
- Use IDBBatchAtomicVFS for general-purpose applications
|
||||
- Consider OPFS-based VFS for better performance in Worker contexts
|
||||
- Use MemoryVFS for temporary databases
|
||||
|
||||
2. **Configuration**
|
||||
- Set appropriate page size (default is usually fine)
|
||||
- Use WAL mode for better concurrency
|
||||
- Consider `PRAGMA synchronous=normal` for better performance
|
||||
- Adjust cache size based on your needs
|
||||
|
||||
3. **Concurrency**
|
||||
- Use transactions for multiple operations
|
||||
- Be aware of VFS-specific concurrency limitations
|
||||
- Consider using Web Workers for heavy database operations
|
||||
|
||||
## 7. Common Issues and Solutions
|
||||
|
||||
1. **Database Locking**
|
||||
- Use appropriate transaction isolation levels
|
||||
- Implement retry logic for busy errors
|
||||
- Consider using WAL mode
|
||||
|
||||
2. **Storage Limitations**
|
||||
- Be aware of browser storage quotas
|
||||
- Implement cleanup strategies
|
||||
- Monitor database size
|
||||
|
||||
3. **Cross-Context Access**
|
||||
- Use appropriate VFS for your context
|
||||
- Consider message passing for cross-context communication
|
||||
- Be aware of storage access limitations
|
||||
|
||||
## 8. TypeScript Support
|
||||
wa-sqlite includes TypeScript definitions. The main types are:
|
||||
|
||||
```typescript
|
||||
type SQLiteCompatibleType = number | string | Uint8Array | Array<number> | bigint | null;
|
||||
|
||||
interface SQLiteAPI {
|
||||
open_v2(filename: string, flags?: number, zVfs?: string): Promise<number>;
|
||||
exec(db: number, sql: string, callback?: (row: any[], columns: string[]) => void): Promise<number>;
|
||||
close(db: number): Promise<number>;
|
||||
// ... other methods
|
||||
}
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Official GitHub Repository](https://github.com/rhashimoto/wa-sqlite)
|
||||
- [Online Demo](https://rhashimoto.github.io/wa-sqlite/demo/)
|
||||
- [API Reference](https://rhashimoto.github.io/wa-sqlite/docs/)
|
||||
- [FAQ](https://github.com/rhashimoto/wa-sqlite/issues?q=is%3Aissue+label%3Afaq+)
|
||||
- [Discussion Forums](https://github.com/rhashimoto/wa-sqlite/discussions)
|
||||
171
.dockerignore
@@ -1,171 +0,0 @@
|
||||
# TimeSafari Docker Ignore File
|
||||
# Author: Matthew Raymer
|
||||
# Description: Excludes unnecessary files from Docker build context
|
||||
#
|
||||
# Benefits:
|
||||
# - Faster build times
|
||||
# - Smaller build context
|
||||
# - Reduced image size
|
||||
# - Better security (excludes sensitive files)
|
||||
|
||||
# Dependencies
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build outputs
|
||||
# dist - Allow dist directory for Docker builds (contains pre-built assets)
|
||||
dist-*
|
||||
build
|
||||
*.tsbuildinfo
|
||||
|
||||
# Development files
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
CONTRIBUTING.md
|
||||
BUILDING.md
|
||||
LICENSE
|
||||
|
||||
# IDE and editor files
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# Test files
|
||||
test-playwright
|
||||
test-playwright-results
|
||||
test-results
|
||||
test-scripts
|
||||
|
||||
# Documentation
|
||||
doc
|
||||
|
||||
# Scripts (keep only what's needed for build)
|
||||
scripts/test-*.sh
|
||||
scripts/*.js
|
||||
scripts/README.md
|
||||
|
||||
# Platform-specific files
|
||||
android
|
||||
ios
|
||||
electron
|
||||
|
||||
# Docker files (avoid recursive copying)
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
.dockerignore
|
||||
|
||||
# CI/CD files
|
||||
.github
|
||||
.gitlab-ci.yml
|
||||
.travis.yml
|
||||
.circleci
|
||||
|
||||
# Temporary files
|
||||
tmp
|
||||
temp
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.backup
|
||||
|
||||
# Archive files
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.zip
|
||||
*.rar
|
||||
|
||||
# Certificate files
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
*.p12
|
||||
|
||||
# Configuration files that might contain secrets
|
||||
*.secrets
|
||||
secrets.json
|
||||
config.local.json
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# iOS doesn't like spaces in the app title.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# iOS doesn't like spaces in the app title.
|
||||
TIME_SAFARI_APP_TITLE="TimeSafari_Test"
|
||||
VITE_APP_SERVER=https://test.timesafari.app
|
||||
# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
|
||||
# This is the claim ID for actions in the BVC project.
|
||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch
|
||||
|
||||
80
.gitignore
vendored
@@ -8,6 +8,7 @@ signature.bin
|
||||
# generated during `npm run build`
|
||||
sw_scripts-combined.js
|
||||
*.pem
|
||||
tsconfig.node.tsbuildinfo
|
||||
verified.txt
|
||||
myenv
|
||||
|
||||
@@ -40,92 +41,15 @@ pnpm-debug.log*
|
||||
playwright-tests
|
||||
dist-electron-packages
|
||||
.ruby-version
|
||||
+.env
|
||||
|
||||
# Test files generated by scripts test-ios.js & test-android.js
|
||||
.generated/
|
||||
|
||||
.env.default
|
||||
vendor/
|
||||
|
||||
# Build logs
|
||||
build_logs/
|
||||
|
||||
# PWA icon files generated by capacitor-assets
|
||||
icons
|
||||
|
||||
*.log
|
||||
|
||||
# Generated Android assets and resources (should be generated during build)
|
||||
android/app/src/main/assets/public/
|
||||
|
||||
# Generated Android resources (icons, splash screens, etc.)
|
||||
android/app/src/main/res/drawable*/
|
||||
android/app/src/main/res/mipmap*/
|
||||
android/app/src/main/res/values/ic_launcher_background.xml
|
||||
|
||||
# Keep these Android configuration files in version control:
|
||||
# - android/app/src/main/assets/capacitor.plugins.json
|
||||
# - android/app/src/main/res/values/strings.xml
|
||||
# - android/app/src/main/res/values/styles.xml
|
||||
# - android/app/src/main/res/layout/activity_main.xml
|
||||
# - android/app/src/main/res/xml/config.xml
|
||||
# - android/app/src/main/res/xml/file_paths.xml
|
||||
|
||||
sql-wasm.wasm
|
||||
|
||||
# Temporary and generated files
|
||||
temp.*
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
*.cache
|
||||
git.diff.*
|
||||
*.har
|
||||
|
||||
# Development artifacts
|
||||
dev-dist/
|
||||
*.map
|
||||
|
||||
# OS generated files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Capacitor build outputs and generated files
|
||||
android/app/build/
|
||||
android/capacitor-cordova-android-plugins/build/
|
||||
ios/App/App/public/assets/
|
||||
ios/App/App/build/
|
||||
ios/App/build/
|
||||
|
||||
# Capacitor build artifacts (covered by android/app/build/ above)
|
||||
|
||||
# Keep these Capacitor files in version control:
|
||||
# - capacitor.config.json (root, electron, ios)
|
||||
# - src/main.capacitor.ts
|
||||
# - vite.config.capacitor.mts
|
||||
# - android/capacitor.settings.gradle
|
||||
# - android/app/capacitor.build.gradle
|
||||
# - android/app/src/main/assets/capacitor.plugins.json
|
||||
|
||||
# Electron build outputs and generated files
|
||||
electron/build/
|
||||
electron/app/
|
||||
electron/dist/
|
||||
electron/out/
|
||||
|
||||
# Keep these Electron files in version control:
|
||||
# - electron/src/preload.ts (source)
|
||||
# - electron/src/index.ts (source)
|
||||
# - electron/src/setup.ts (source)
|
||||
# - electron/package.json
|
||||
# - electron/electron-builder.config.json
|
||||
# - electron/build-packages.sh
|
||||
# - electron/live-runner.js
|
||||
# - electron/resources/electron-publisher-custom.js
|
||||
|
||||
# Gradle cache files
|
||||
android/.gradle/file-system.probe
|
||||
android/.gradle/caches/
|
||||
coverage
|
||||
android/app/src/main/res/
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"MD013": {"code_blocks": false}}
|
||||
2403
BUILDING.md
11
CHANGELOG.md
@@ -5,16 +5,13 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.3] - 2025.07.12
|
||||
### Changed
|
||||
- Photo is pinned to profile mode
|
||||
### Fixed
|
||||
- Deep link URLs (and other prod settings)
|
||||
- Error in BVC begin view
|
||||
|
||||
## [Unreleased]
|
||||
### Fixed
|
||||
- Set the environment variables correctly (so simulator deep link domain is right).
|
||||
### Changed
|
||||
- Photo is pinned to profile mode
|
||||
- Photo is pinned to profile mode.
|
||||
- NODE_ENV is now mandatory.
|
||||
|
||||
|
||||
## [1.0.2] - 2025.06.20 - 276e0a741bc327de3380c4e508cccb7fee58c06d
|
||||
|
||||
166
Dockerfile
@@ -1,170 +1,36 @@
|
||||
# TimeSafari Docker Build
|
||||
# Author: Matthew Raymer
|
||||
# Description: Multi-stage Docker build for TimeSafari web application
|
||||
#
|
||||
# Build Process:
|
||||
# 1. Base stage: Node.js with build dependencies
|
||||
# 2. Builder stage: Copy pre-built web assets from host
|
||||
# 3. Production stage: Nginx server with optimized assets
|
||||
#
|
||||
# Note: Web assets are built on the host using npm scripts before Docker build
|
||||
#
|
||||
# Security Features:
|
||||
# - Non-root user execution
|
||||
# - Minimal attack surface with Alpine Linux
|
||||
# - Multi-stage build to reduce image size
|
||||
# - No build dependencies in final image
|
||||
#
|
||||
# Usage:
|
||||
# IMPORTANT: Build web assets first, then build Docker image
|
||||
#
|
||||
# Using npm scripts (recommended):
|
||||
# Production: npm run build:web:docker:prod
|
||||
# Test: npm run build:web:docker:test
|
||||
# Development: npm run build:web:docker
|
||||
#
|
||||
# Manual workflow:
|
||||
# 1. Build web assets: npm run build:web:build -- --mode production
|
||||
# 2. Build Docker: docker build -t timesafari:latest .
|
||||
#
|
||||
# Note: For development, use npm run build:web directly (no Docker needed)
|
||||
#
|
||||
# Build Arguments:
|
||||
# BUILD_MODE: development, test, or production (default: production)
|
||||
# NODE_ENV: node environment (default: production)
|
||||
#
|
||||
# Environment Variables:
|
||||
# NODE_ENV: Build environment (development/production)
|
||||
# BUILD_MODE: Build mode for asset selection (development/test/production)
|
||||
#
|
||||
# Build Context:
|
||||
# This Dockerfile is designed to work when the build context is set to
|
||||
# ./crowd-funder-for-time-pwa from the parent directory (where docker-compose.yml is located)
|
||||
# Build stage
|
||||
FROM node:22-alpine3.20 AS builder
|
||||
|
||||
# =============================================================================
|
||||
# BASE STAGE - Common dependencies and setup
|
||||
# =============================================================================
|
||||
FROM node:22-alpine3.20 AS base
|
||||
# Install build dependencies
|
||||
|
||||
# Install system dependencies for build process
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
git \
|
||||
python3 \
|
||||
py3-pip \
|
||||
py3-setuptools \
|
||||
make \
|
||||
g++ \
|
||||
gcc \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Create non-root user for security
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S nextjs -u 1001
|
||||
RUN apk add --no-cache bash git python3 py3-pip py3-setuptools make g++ gcc
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files for dependency installation
|
||||
# Note: These files are in the project root (crowd-funder-for-time-pwa directory)
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies with security audit
|
||||
RUN npm ci --only=production --audit --fund=false && \
|
||||
npm audit fix --audit-level=moderate || true
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# =============================================================================
|
||||
# BUILDER STAGE - Copy pre-built assets
|
||||
# =============================================================================
|
||||
FROM base AS builder
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Define build arguments with defaults
|
||||
ARG BUILD_MODE=production
|
||||
ARG NODE_ENV=production
|
||||
# Build the application
|
||||
RUN npm run build:web
|
||||
|
||||
# Set environment variables from build arguments
|
||||
ENV BUILD_MODE=${BUILD_MODE}
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
|
||||
# Copy pre-built assets from host
|
||||
# Note: dist/ directory is in the project root (crowd-funder-for-time-pwa directory)
|
||||
COPY dist/ ./dist/
|
||||
|
||||
# Verify build output exists
|
||||
RUN ls -la dist/ || (echo "Build output not found in dist/ directory" && exit 1)
|
||||
|
||||
# =============================================================================
|
||||
# PRODUCTION STAGE - Nginx server
|
||||
# =============================================================================
|
||||
FROM nginx:alpine AS production
|
||||
|
||||
# Define build arguments for production stage
|
||||
ARG BUILD_MODE=production
|
||||
ARG NODE_ENV=production
|
||||
|
||||
# Set environment variables
|
||||
ENV BUILD_MODE=${BUILD_MODE}
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
|
||||
# Install security updates and clean cache
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add --no-cache \
|
||||
curl \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Use existing nginx user from base image (nginx user and group already exist)
|
||||
# No need to create new user as nginx:alpine already has nginx user
|
||||
|
||||
# Copy main nginx configuration
|
||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# Copy production nginx configuration
|
||||
COPY docker/default.conf /etc/nginx/conf.d/default.conf
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy built assets from builder stage
|
||||
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Create necessary directories with proper permissions
|
||||
RUN mkdir -p /var/cache/nginx /var/log/nginx /tmp && \
|
||||
chown -R nginx:nginx /var/cache/nginx /var/log/nginx /tmp && \
|
||||
chown -R nginx:nginx /usr/share/nginx/html
|
||||
|
||||
# Switch to non-root user
|
||||
USER nginx
|
||||
# Copy nginx configuration if needed
|
||||
# COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
# Start nginx with proper signal handling
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
# =============================================================================
|
||||
# TEST STAGE - For test environment testing
|
||||
# =============================================================================
|
||||
FROM production AS test
|
||||
|
||||
# Define build arguments for test stage
|
||||
ARG BUILD_MODE=test
|
||||
ARG NODE_ENV=test
|
||||
|
||||
# Set environment variables
|
||||
ENV BUILD_MODE=${BUILD_MODE}
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
|
||||
# Copy test-specific nginx configuration
|
||||
COPY docker/staging.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
# Health check for staging
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/health || exit 1
|
||||
|
||||
# Start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
187
Gemfile.lock
@@ -22,7 +22,26 @@ GEM
|
||||
algoliasearch (1.27.5)
|
||||
httpclient (~> 2.8, >= 2.8.3)
|
||||
json (>= 1.5.1)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.2)
|
||||
aws-partitions (1.1066.0)
|
||||
aws-sdk-core (3.220.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.182.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
@@ -64,13 +83,96 @@ GEM
|
||||
nap (>= 0.8, < 2.0)
|
||||
netrc (~> 0.11)
|
||||
cocoapods-try (1.2.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander (4.6.0)
|
||||
highline (~> 2.0.0)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.0)
|
||||
declarative (0.0.20)
|
||||
digest-crc (0.7.0)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.6.20240107)
|
||||
dotenv (2.8.1)
|
||||
drb (2.2.1)
|
||||
emoji_regex (3.2.3)
|
||||
escape (0.0.4)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
excon (0.112.0)
|
||||
faraday (1.10.4)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-httpclient (~> 1.0)
|
||||
faraday-multipart (~> 1.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.0)
|
||||
faraday-patron (~> 1.0)
|
||||
faraday-rack (~> 1.0)
|
||||
faraday-retry (~> 1.0)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-httpclient (1.0.1)
|
||||
faraday-multipart (1.1.0)
|
||||
multipart-post (~> 2.0)
|
||||
faraday-net_http (1.0.2)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.1)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.4.0)
|
||||
fastlane (2.227.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored (~> 1.2)
|
||||
commander (~> 4.6)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
fastlane-sirp (>= 1.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-apis-androidpublisher_v3 (~> 0.3)
|
||||
google-apis-playcustomapp_v1 (~> 0.1)
|
||||
google-cloud-env (>= 1.6.0, < 2.0.0)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
http-cookie (~> 1.0.5)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (>= 0.1.1, < 1.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.5)
|
||||
simctl (~> 1.6.3)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (~> 3)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.4.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||
fastlane-sirp (1.0.0)
|
||||
sysrandom (~> 1.0)
|
||||
ffi (1.17.1)
|
||||
ffi (1.17.1-aarch64-linux-gnu)
|
||||
ffi (1.17.1-aarch64-linux-musl)
|
||||
@@ -85,27 +187,107 @@ GEM
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.3)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
httpclient (>= 2.8.1, < 3.a)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.a)
|
||||
rexml
|
||||
google-apis-iamcredentials_v1 (0.17.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-playcustomapp_v1 (0.13.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.8.0)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.5.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.31.0)
|
||||
google-cloud-core (~> 1.6)
|
||||
googleauth (>= 0.16.2, < 2.a)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (1.8.1)
|
||||
faraday (>= 0.17.3, < 3.a)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (>= 0.16, < 2.a)
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.10.2)
|
||||
jwt (2.10.1)
|
||||
base64
|
||||
logger (1.6.6)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.5)
|
||||
molinillo (0.8.0)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.4.0)
|
||||
nap (1.1.0)
|
||||
naturally (2.2.1)
|
||||
netrc (0.11.0)
|
||||
nkf (0.2.0)
|
||||
optparse (0.6.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.2)
|
||||
public_suffix (4.0.7)
|
||||
rake (13.2.1)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.4.1)
|
||||
rouge (3.28.0)
|
||||
ruby-macho (2.5.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.4.1)
|
||||
securerandom (0.4.1)
|
||||
security (0.1.5)
|
||||
signet (0.19.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.10)
|
||||
CFPropertyList
|
||||
naturally
|
||||
sysrandom (1.0.5)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
trailblazer-option (0.1.2)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.2)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
typhoeus (1.4.1)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uber (0.1.0)
|
||||
unicode-display_width (2.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.27.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
@@ -113,6 +295,10 @@ GEM
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.4.0)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
xcpretty (0.4.0)
|
||||
rouge (~> 3.28.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux-gnu
|
||||
@@ -129,6 +315,7 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
cocoapods
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
2.6.5
|
||||
|
||||
128
README.md
@@ -3,131 +3,22 @@
|
||||
[Time Safari](https://timesafari.org/) 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.
|
||||
|
||||
## Database Migration Status
|
||||
|
||||
**Current Status**: The application is undergoing a migration from Dexie (IndexedDB) to SQLite using absurd-sql. This migration is in **Phase 2** with a well-defined migration fence in place.
|
||||
|
||||
### Migration Progress
|
||||
- ✅ **SQLite Database Service**: Fully implemented with absurd-sql
|
||||
- ✅ **Platform Service Layer**: Unified database interface across platforms
|
||||
- ✅ **Settings Migration**: Core user settings transferred
|
||||
- ✅ **Account Migration**: Identity and key management
|
||||
- 🔄 **Contact Migration**: User contact data (via import interface)
|
||||
- 📋 **Code Cleanup**: Remove unused Dexie imports
|
||||
|
||||
### Migration Fence
|
||||
The migration is controlled by a **migration fence** that separates legacy Dexie code from the new SQLite implementation. See [Migration Fence Definition](doc/migration-fence-definition.md) for complete details.
|
||||
|
||||
**Key Points**:
|
||||
- Legacy Dexie database is disabled by default
|
||||
- All database operations go through `PlatformServiceMixin`
|
||||
- Migration tools provide controlled access to both databases
|
||||
- Clear separation between legacy and new code
|
||||
|
||||
### Migration Documentation
|
||||
- [Migration Guide](doc/migration-to-wa-sqlite.md) - Complete migration process
|
||||
- [Migration Fence Definition](doc/migration-fence-definition.md) - Fence boundaries and rules
|
||||
- [Database Migration Guide](doc/database-migration-guide.md) - User-facing migration tools
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [project.task.yaml](project.task.yaml) for current priorities.
|
||||
(Numbers at the beginning of lines are estimated hours. See [taskyaml.org](https://taskyaml.org/) for details.)
|
||||
See [ClickUp](https://sharing.clickup.com/9014278710/l/h/8cmnyhp-174/10573fec74e2ba0) for current priorities.
|
||||
|
||||
## Setup & Building
|
||||
|
||||
Quick start:
|
||||
|
||||
* For setup, we recommend [pkgx](https://pkgx.dev), which installs what you need (either automatically or with the `dev` command). 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.
|
||||
* For setup, we recommend [pkgx](https://pkgx.dev), which installs what you need (either automatically or with the `dev` command). Core dependencies are typescript & npm; when building for other platforms, you'll need other things such as those in the pkgx.yaml & doc/BUILDING.md files.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
NODE_ENV=dev npm run start:web
|
||||
```
|
||||
|
||||
See [BUILDING.md](BUILDING.md) for comprehensive build instructions for all platforms (Web, Electron, iOS, Android, Docker).
|
||||
|
||||
## Development Database Clearing
|
||||
|
||||
TimeSafari provides a simple script-based approach to clear the database for development purposes.
|
||||
|
||||
### Quick Usage
|
||||
```bash
|
||||
# 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**
|
||||
```bash
|
||||
# Linux
|
||||
rm -rf ~/.config/TimeSafari/*
|
||||
|
||||
# macOS
|
||||
rm -rf ~/Library/Application\ Support/TimeSafari/*
|
||||
|
||||
# Windows
|
||||
rmdir /s /q %APPDATA%\TimeSafari
|
||||
```
|
||||
|
||||
#### **Web Browser (Custom Data Directory)**
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
- [Domain Configuration System](docs/domain-configuration.md) - Complete guide
|
||||
- [Constants and Configuration](src/constants/app.ts) - Core constants
|
||||
See [BUILDING.md](doc/BUILDING.md) for more details.
|
||||
|
||||
## Tests
|
||||
|
||||
@@ -170,22 +61,15 @@ Key principles:
|
||||
|
||||
### Database Architecture
|
||||
|
||||
The application uses a platform-agnostic database layer with Vue mixins for service access:
|
||||
The application uses a platform-agnostic database layer:
|
||||
|
||||
* `src/services/PlatformService.ts` - Database interface definition
|
||||
* `src/services/PlatformServiceFactory.ts` - Platform-specific service factory
|
||||
* `src/services/AbsurdSqlDatabaseService.ts` - SQLite implementation
|
||||
* `src/utils/PlatformServiceMixin.ts` - Vue mixin for database access with caching
|
||||
* `src/db/` - Legacy Dexie database (migration in progress)
|
||||
|
||||
**Development Guidelines**:
|
||||
|
||||
- Always use `PlatformServiceMixin` for database operations in components
|
||||
- Test with PlatformServiceMixin for new features
|
||||
- Use migration tools for data transfer between systems
|
||||
- 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](doc/architecture-decisions.md) for detailed rationale.
|
||||
- Always use `PlatformService` for database operations
|
||||
|
||||
### Kudos
|
||||
|
||||
|
||||
7
android/.gitignore
vendored
@@ -84,6 +84,13 @@ freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
|
||||
@@ -64,14 +64,6 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
pickFirsts += ['**/lib/x86_64/libbarhopper_v3.so', '**/lib/x86_64/libimage_processing_util_jni.so', '**/lib/x86_64/libsqlcipher.so']
|
||||
}
|
||||
}
|
||||
|
||||
// Configure for 16 KB page size compatibility
|
||||
|
||||
|
||||
// Enable bundle builds (without which it doesn't work right for bundleDebug vs bundleRelease)
|
||||
bundle {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"appId": "app.timesafari",
|
||||
"appName": "TimeSafari",
|
||||
"webDir": "dist",
|
||||
"bundledWebRuntime": false,
|
||||
"server": {
|
||||
"cleartext": true
|
||||
},
|
||||
@@ -16,32 +17,18 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"SplashScreen": {
|
||||
"launchShowDuration": 3000,
|
||||
"launchAutoHide": true,
|
||||
"backgroundColor": "#ffffff",
|
||||
"androidSplashResourceName": "splash",
|
||||
"androidScaleType": "CENTER_CROP",
|
||||
"showSpinner": false,
|
||||
"androidSpinnerStyle": "large",
|
||||
"iosSpinnerStyle": "small",
|
||||
"spinnerColor": "#999999",
|
||||
"splashFullScreen": true,
|
||||
"splashImmersive": true
|
||||
},
|
||||
"CapacitorSQLite": {
|
||||
"SQLite": {
|
||||
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
||||
"iosIsEncryption": false,
|
||||
"iosIsEncryption": true,
|
||||
"iosBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricAuth": true,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"androidIsEncryption": false,
|
||||
"androidIsEncryption": true,
|
||||
"androidBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricAuth": true,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"electronIsEncryption": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
@@ -57,65 +44,13 @@
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"allowMixedContent": true,
|
||||
"allowMixedContent": false,
|
||||
"captureInput": true,
|
||||
"webContentsDebuggingEnabled": false,
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch",
|
||||
"10.0.2.2:3000"
|
||||
"api.endorser.ch"
|
||||
]
|
||||
},
|
||||
"electron": {
|
||||
"deepLinking": {
|
||||
"schemes": [
|
||||
"timesafari"
|
||||
]
|
||||
},
|
||||
"buildOptions": {
|
||||
"appId": "app.timesafari",
|
||||
"productName": "TimeSafari",
|
||||
"directories": {
|
||||
"output": "dist-electron-packages"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"electron/**/*"
|
||||
],
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"target": [
|
||||
{
|
||||
"target": "dmg",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": "Utility"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
android/app/src/main/assets/public/cordova.js
vendored
Normal file
0
android/app/src/main/assets/public/cordova_plugins.js
vendored
Normal file
BIN
android/app/src/main/assets/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 463 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 70 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 46 KiB |
BIN
android/app/src/main/assets/public/img/icons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2480 4005 c-25 -7 -58 -20 -75 -29 -16 -9 -40 -16 -52 -16 -17 0
|
||||
-24 -7 -28 -27 -3 -16 -14 -45 -24 -65 -21 -41 -13 -55 18 -38 25 13 67 13 92
|
||||
-1 15 -8 35 -4 87 17 99 39 130 41 197 10 64 -29 77 -31 107 -15 20 11 20 11
|
||||
-3 35 -12 13 -30 24 -38 24 -24 1 -132 38 -148 51 -8 7 -11 20 -7 32 12 37
|
||||
-40 47 -126 22z"/>
|
||||
<path d="M1450 3775 c-7 -8 -18 -15 -24 -15 -7 0 -31 -14 -54 -32 -29 -22 -38
|
||||
-34 -29 -40 17 -11 77 -10 77 1 0 5 16 16 35 25 60 29 220 19 290 -18 17 -9
|
||||
33 -16 37 -16 4 0 31 -15 60 -34 108 -70 224 -215 282 -353 30 -71 53 -190 42
|
||||
-218 -10 -27 -23 -8 -52 75 -30 90 -88 188 -120 202 -13 6 -26 9 -29 6 -3 -2
|
||||
11 -51 30 -108 28 -83 35 -119 35 -179 0 -120 -22 -127 -54 -17 -11 37 -13 21
|
||||
-18 -154 -5 -180 -8 -200 -32 -264 -51 -132 -129 -245 -199 -288 -21 -12 -79
|
||||
-49 -129 -80 -161 -102 -294 -141 -473 -141 -228 0 -384 76 -535 259 -81 99
|
||||
-118 174 -154 312 -31 121 -35 273 -11 437 19 127 19 125 -4 125 -23 0 -51
|
||||
-34 -87 -104 -14 -28 -33 -64 -41 -81 -19 -34 -22 -253 -7 -445 9 -106 12
|
||||
-119 44 -170 19 -30 42 -67 50 -81 64 -113 85 -140 130 -169 28 -18 53 -44 61
|
||||
-62 8 -20 36 -45 83 -76 62 -39 80 -46 151 -54 44 -5 96 -13 115 -18 78 -20
|
||||
238 -31 282 -19 24 6 66 8 95 5 76 -9 169 24 319 114 32 19 80 56 106 82 27
|
||||
26 52 48 58 48 5 0 27 26 50 58 48 66 56 70 132 71 62 1 165 29 238 64 112 55
|
||||
177 121 239 245 37 76 39 113 10 267 -12 61 -23 131 -26 156 -5 46 -5 47 46
|
||||
87 92 73 182 70 263 -8 l51 -49 -6 -61 c-4 -34 -13 -85 -21 -113 -28 -103 -30
|
||||
-161 -4 -228 16 -44 32 -67 55 -83 18 -11 39 -37 47 -58 10 -23 37 -53 73 -81
|
||||
32 -25 69 -57 82 -71 14 -14 34 -26 47 -26 12 0 37 -7 56 -15 20 -8 66 -17
|
||||
104 -20 107 -10 110 -11 150 -71 50 -75 157 -177 197 -187 18 -5 53 -24 78
|
||||
-42 71 -51 176 -82 304 -89 61 -4 127 -12 147 -18 29 -9 45 -8 77 6 23 9 50
|
||||
16 60 16 31 0 163 46 216 76 28 15 75 46 105 69 30 23 69 49 85 58 17 8 46 31
|
||||
64 51 19 20 40 36 47 36 18 0 77 70 100 120 32 66 45 108 55 173 5 32 16 71
|
||||
24 87 43 84 43 376 0 549 -27 105 -43 127 -135 188 -30 21 -65 46 -77 57 -13
|
||||
11 -23 17 -23 14 0 -3 21 -46 47 -94 79 -151 85 -166 115 -263 25 -83 28 -110
|
||||
28 -226 0 -144 -17 -221 -75 -335 -39 -77 -208 -244 -304 -299 -451 -263 -975
|
||||
-67 -1138 426 -23 70 -26 95 -28 254 -1 108 -7 183 -14 196 -6 12 -11 31 -11
|
||||
43 0 32 31 122 52 149 10 13 18 28 18 34 0 5 25 40 56 78 60 73 172 170 219
|
||||
190 30 12 30 13 6 17 -15 2 -29 -2 -37 -12 -6 -9 -16 -16 -22 -16 -6 0 -23
|
||||
-11 -39 -24 -15 -12 -33 -25 -40 -27 -17 -6 -82 -60 -117 -97 -65 -70 -75 -82
|
||||
-107 -133 -23 -34 -35 -46 -37 -35 -3 16 20 87 44 134 6 12 9 34 6 48 -4 22
|
||||
-8 25 -31 19 -14 -3 -38 -15 -53 -26 -34 -24 -34 -21 -6 28 65 112 184 206
|
||||
291 227 15 3 39 9 55 12 l27 6 -24 9 c-90 35 -304 -66 -478 -225 -39 -36 -74
|
||||
-66 -77 -66 -22 0 18 82 72 148 19 23 32 46 28 49 -4 4 -26 13 -49 19 -73 21
|
||||
-161 54 -171 64 -6 6 -20 10 -32 10 -21 0 -21 -1 -8 -40 45 -130 8 -247 -93
|
||||
-299 -25 -13 -31 0 -14 29 15 22 1 33 -22 17 -56 -36 -117 -22 -117 28 0 13
|
||||
-16 47 -35 76 -22 34 -33 60 -29 73 4 16 -3 26 -26 39 -16 10 -30 21 -30 25 1
|
||||
18 54 64 87 76 l38 13 -33 5 c-30 4 -115 -18 -154 -42 -13 -7 -20 -5 -27 8 -9
|
||||
16 -12 16 -53 1 -160 -61 -258 -104 -258 -114 0 -7 10 -20 21 -31 103 -91 217
|
||||
-297 249 -449 28 -135 41 -237 35 -276 -14 -91 -48 -170 -97 -220 -44 -47 -68
|
||||
-60 -68 -40 0 6 4 12 8 15 5 3 24 35 42 72 l33 67 -6 141 c-4 103 -11 158 -26
|
||||
205 -12 35 -21 70 -21 77 0 7 -20 56 -45 108 -82 173 -227 322 -392 401 -67
|
||||
33 -90 39 -163 42 -108 5 -130 10 -130 28 0 20 -63 20 -80 0z"/>
|
||||
<path d="M3710 3765 c0 -20 8 -28 39 -41 22 -8 42 -22 45 -30 5 -14 42 -19 70
|
||||
-8 10 4 -7 21 -58 55 -41 27 -79 49 -85 49 -6 0 -11 -11 -11 -25z"/>
|
||||
<path d="M3173 3734 c-9 -25 10 -36 35 -18 12 8 22 19 22 25 0 16 -50 10 -57
|
||||
-7z"/>
|
||||
<path d="M1982 3728 c6 -16 36 -34 44 -26 3 4 4 14 1 23 -7 17 -51 21 -45 3z"/>
|
||||
<path d="M1540 3620 c0 -5 7 -10 16 -10 8 0 12 5 9 10 -3 6 -10 10 -16 10 -5
|
||||
0 -9 -4 -9 -10z"/>
|
||||
<path d="M4467 3624 c-4 -4 23 -27 60 -50 84 -56 99 -58 67 -9 -28 43 -107 79
|
||||
-127 59z"/>
|
||||
<path d="M655 3552 c-11 -2 -26 -9 -33 -14 -7 -6 -27 -18 -45 -27 -36 -18 -58
|
||||
-64 -39 -83 9 -9 25 1 70 43 53 48 78 78 70 84 -2 1 -12 -1 -23 -3z"/>
|
||||
<path d="M1015 3460 c-112 -24 -247 -98 -303 -165 -53 -65 -118 -214 -136
|
||||
-311 -20 -113 -20 -145 -1 -231 20 -88 49 -153 102 -230 79 -113 186 -182 331
|
||||
-214 108 -24 141 -24 247 1 130 30 202 72 316 181 102 100 153 227 152 384 0
|
||||
142 -58 293 -150 395 -60 67 -180 145 -261 171 -75 23 -232 34 -297 19z m340
|
||||
-214 c91 -43 174 -154 175 -234 0 -18 -9 -51 -21 -73 -19 -37 -19 -42 -5 -64
|
||||
35 -54 12 -121 -48 -142 -22 -7 -47 -19 -55 -27 -9 -8 -41 -27 -71 -42 -50
|
||||
-26 -64 -29 -155 -29 -111 0 -152 14 -206 68 -49 49 -63 85 -64 162 0 59 4 78
|
||||
28 118 31 52 96 105 141 114 23 5 33 17 56 68 46 103 121 130 225 81z"/>
|
||||
<path d="M3985 3464 c-44 -7 -154 -44 -200 -67 -55 -28 -138 -96 -162 -132
|
||||
-10 -16 -39 -75 -64 -130 l-44 -100 0 -160 0 -160 45 -90 c53 -108 152 -214
|
||||
245 -264 59 -31 215 -71 281 -71 53 0 206 40 255 67 98 53 203 161 247 253 53
|
||||
113 74 193 74 280 -1 304 -253 564 -557 575 -49 2 -103 1 -120 -1z m311 -220
|
||||
c129 -68 202 -209 160 -309 -15 -35 -15 -42 -1 -72 26 -55 -3 -118 -59 -129
|
||||
-19 -3 -43 -15 -53 -26 -26 -29 -99 -64 -165 -78 -45 -10 -69 -10 -120 -1 -74
|
||||
15 -113 37 -161 91 -110 120 -50 331 109 385 24 8 44 23 52 39 6 14 18 38 25
|
||||
53 33 72 127 93 213 47z"/>
|
||||
<path d="M487 3394 c-21 -12 -27 -21 -25 -40 2 -14 7 -26 12 -27 14 -3 48 48
|
||||
44 66 -3 14 -6 14 -31 1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 705 KiB |
@@ -0,0 +1,11 @@
|
||||
Model Information:
|
||||
* title: Lupine Plant
|
||||
* source: https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439
|
||||
* author: rufusrockwell (https://sketchfab.com/rufusrockwell)
|
||||
|
||||
Model License:
|
||||
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
* requirements: Author must be credited. Commercial use is allowed.
|
||||
|
||||
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||
This work is based on "Lupine Plant" (https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439) by rufusrockwell (https://sketchfab.com/rufusrockwell) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
BIN
android/app/src/main/assets/public/models/lupine_plant/scene.bin
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 2,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
41.3074951171875,
|
||||
40.37548828125,
|
||||
87.85917663574219
|
||||
],
|
||||
"min": [
|
||||
-35.245540618896484,
|
||||
-36.895416259765625,
|
||||
-0.9094290137290955
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 33108,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9999382495880127,
|
||||
0.9986748695373535,
|
||||
0.9985831379890442
|
||||
],
|
||||
"min": [
|
||||
-0.9998949766159058,
|
||||
-0.9975876212120056,
|
||||
-0.411094069480896
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9987699389457703,
|
||||
0.9998998045921326,
|
||||
0.9577858448028564,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-0.9987726807594299,
|
||||
-0.9990445971488953,
|
||||
-0.999801516532898,
|
||||
1.0
|
||||
],
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
1.0061479806900024,
|
||||
0.9993550181388855
|
||||
],
|
||||
"min": [
|
||||
0.00279300007969141,
|
||||
0.0011620000004768372
|
||||
],
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5125,
|
||||
"count": 6378,
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"extras": {
|
||||
"author": "rufusrockwell (https://sketchfab.com/rufusrockwell)",
|
||||
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
|
||||
"source": "https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439",
|
||||
"title": "Lupine Plant"
|
||||
},
|
||||
"generator": "Sketchfab-12.68.0",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 25512,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 22072,
|
||||
"byteOffset": 25512,
|
||||
"byteStride": 8,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 66216,
|
||||
"byteOffset": 47584,
|
||||
"byteStride": 12,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 44144,
|
||||
"byteOffset": 113800,
|
||||
"byteStride": 16,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 157944,
|
||||
"uri": "scene.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "textures/lambert2SG_baseColor.png"
|
||||
},
|
||||
{
|
||||
"uri": "textures/lambert2SG_normal.png"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"alphaCutoff": 0.2,
|
||||
"alphaMode": "MASK",
|
||||
"doubleSided": true,
|
||||
"name": "lambert2SG",
|
||||
"normalTexture": {
|
||||
"index": 1
|
||||
},
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"name": "Object_0",
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 0,
|
||||
"TANGENT": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 4,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
2.220446049250313e-16,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
2.220446049250313e-16,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "Sketchfab_model"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
2
|
||||
],
|
||||
"name": "LupineSF.obj.cleaner.materialmerger.gles"
|
||||
},
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": "Object_2"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9987,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"name": "Sketchfab_Scene",
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 4.7 MiB |
2
android/app/src/main/assets/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
||||
170
android/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.12.0'
|
||||
classpath 'com.android.tools.build:gradle:8.9.1'
|
||||
classpath 'com.google.gms:google-services:4.4.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -20,4 +20,4 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.suppressUnsupportedCompileSdk=36
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ext {
|
||||
minSdkVersion = 22
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 36
|
||||
compileSdkVersion = 34
|
||||
targetSdkVersion = 34
|
||||
androidxActivityVersion = '1.8.0'
|
||||
androidxAppCompatVersion = '1.6.1'
|
||||
androidxCoordinatorLayoutVersion = '1.2.0'
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"icon": {
|
||||
"ios": {
|
||||
"source": "resources/ios/icon/icon.png",
|
||||
"target": "ios/App/App/Assets.xcassets/AppIcon.appiconset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/icon/icon.png",
|
||||
"target": "android/app/src/main/res"
|
||||
},
|
||||
"web": {
|
||||
"source": "resources/web/icon/icon.png",
|
||||
"target": "public/img/icons"
|
||||
}
|
||||
},
|
||||
"splash": {
|
||||
"ios": {
|
||||
"source": "resources/ios/splash/splash.png",
|
||||
"target": "ios/App/App/Assets.xcassets/Splash.imageset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/splash/splash.png",
|
||||
"target": "android/app/src/main/res"
|
||||
}
|
||||
},
|
||||
"splashDark": {
|
||||
"ios": {
|
||||
"source": "resources/ios/splash/splash_dark.png",
|
||||
"target": "ios/App/App/Assets.xcassets/SplashDark.imageset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/splash/splash_dark.png",
|
||||
"target": "android/app/src/main/res"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
"appId": "app.timesafari",
|
||||
"appName": "TimeSafari",
|
||||
"webDir": "dist",
|
||||
"bundledWebRuntime": false,
|
||||
"server": {
|
||||
"cleartext": true
|
||||
},
|
||||
@@ -16,32 +17,18 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"SplashScreen": {
|
||||
"launchShowDuration": 3000,
|
||||
"launchAutoHide": true,
|
||||
"backgroundColor": "#ffffff",
|
||||
"androidSplashResourceName": "splash",
|
||||
"androidScaleType": "CENTER_CROP",
|
||||
"showSpinner": false,
|
||||
"androidSpinnerStyle": "large",
|
||||
"iosSpinnerStyle": "small",
|
||||
"spinnerColor": "#999999",
|
||||
"splashFullScreen": true,
|
||||
"splashImmersive": true
|
||||
},
|
||||
"CapacitorSQLite": {
|
||||
"SQLite": {
|
||||
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
||||
"iosIsEncryption": false,
|
||||
"iosIsEncryption": true,
|
||||
"iosBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricAuth": true,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"androidIsEncryption": false,
|
||||
"androidIsEncryption": true,
|
||||
"androidBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricAuth": true,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"electronIsEncryption": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
@@ -57,56 +44,13 @@
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"allowMixedContent": true,
|
||||
"allowMixedContent": false,
|
||||
"captureInput": true,
|
||||
"webContentsDebuggingEnabled": false,
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch",
|
||||
"10.0.2.2:3000"
|
||||
"api.endorser.ch"
|
||||
]
|
||||
},
|
||||
"electron": {
|
||||
"deepLinking": {
|
||||
"schemes": ["timesafari"]
|
||||
},
|
||||
"buildOptions": {
|
||||
"appId": "app.timesafari",
|
||||
"productName": "TimeSafari",
|
||||
"directories": {
|
||||
"output": "dist-electron-packages"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"electron/**/*"
|
||||
],
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"target": [
|
||||
{
|
||||
"target": "dmg",
|
||||
"arch": ["x64", "arm64"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": ["x64"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": ["x64"]
|
||||
}
|
||||
],
|
||||
"category": "Utility"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
479
doc/BUILDING.md
Normal file
@@ -0,0 +1,479 @@
|
||||
# Building TimeSafari
|
||||
|
||||
This guide explains how to build TimeSafari for different platforms.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
For a quick dev environment setup, use [pkgx](https://pkgx.dev).
|
||||
|
||||
- Node.js (LTS version recommended)
|
||||
- npm (comes with Node.js)
|
||||
- Git
|
||||
- For desktop builds: Additional build tools based on your OS
|
||||
|
||||
## Initial Setup
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Web Dev Locally
|
||||
|
||||
```bash
|
||||
NODE_ENV=dev npm run start:web
|
||||
```
|
||||
|
||||
## Web Build for Server
|
||||
|
||||
1. Run the production build:
|
||||
|
||||
```bash
|
||||
rm -rf dist
|
||||
NODE_ENV=prod npm run build:web
|
||||
```
|
||||
|
||||
The built files will be in the `dist` directory.
|
||||
|
||||
2. To test the production build locally:
|
||||
|
||||
You'll likely want to use test locations for the Endorser & image & partner servers; see "DEFAULT_ENDORSER_API_SERVER" & "DEFAULT_IMAGE_API_SERVER" & "DEFAULT_PARTNER_API_SERVER" below.
|
||||
|
||||
```bash
|
||||
NODE_ENV=dev npm run serve:web
|
||||
```
|
||||
|
||||
### Compile and minify for test & production
|
||||
|
||||
* If there are DB changes: before updating the test server, open browser(s) with current version to test DB migrations.
|
||||
|
||||
* `npx prettier --write ./sw_scripts/`
|
||||
|
||||
* Update the ClickUp tasks & CHANGELOG.md & the version in package.json, run `npm install`.
|
||||
|
||||
* Run a build to make sure package-lock version is updated, linting works, etc: `npm install && npm run build:web`
|
||||
|
||||
* Commit everything (since the commit hash is used the app).
|
||||
|
||||
* Put the commit hash in the changelog (which will help you remember to bump the version in the step later).
|
||||
|
||||
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 1.0.2 && git push origin 1.0.2`.
|
||||
|
||||
* For test, build the app (because test server is not yet set up to build):
|
||||
|
||||
```bash
|
||||
NODE_ENV=test TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.app VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app VITE_PASSKEYS_ENABLED=true npm run build:web
|
||||
```
|
||||
|
||||
... and transfer to the test server:
|
||||
|
||||
```bash
|
||||
rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari
|
||||
```
|
||||
|
||||
(Let's replace that with a .env.development or .env.staging file.)
|
||||
|
||||
(Note: The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there.)
|
||||
|
||||
* For prod, get on the server and run the correct build:
|
||||
|
||||
... and log onto the server:
|
||||
|
||||
* `pkgx +npm sh`
|
||||
|
||||
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 1.0.2 && npm install && npm run build:web && cd -`
|
||||
|
||||
(The plain `npm run build:web` uses the .env.production file.)
|
||||
|
||||
* Back up the time-safari/dist folder & deploy: `mv time-safari/dist time-safari-dist-prev-2 && mv crowd-funder-for-time-pwa/dist time-safari/`
|
||||
|
||||
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, commit, and push. Also record what version is on production.
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
The application can be containerized using Docker for consistent deployment across environments.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker installed on your system
|
||||
- Docker Compose (optional, for multi-container setups)
|
||||
|
||||
### Building the Docker Image
|
||||
|
||||
1. Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build -t timesafari:latest .
|
||||
```
|
||||
|
||||
2. For development builds with specific environment variables:
|
||||
|
||||
```bash
|
||||
docker build --build-arg NODE_ENV=development -t timesafari:dev .
|
||||
```
|
||||
|
||||
### Running the Container
|
||||
|
||||
1. Run the container:
|
||||
|
||||
```bash
|
||||
docker run -d -p 80:80 timesafari:latest
|
||||
```
|
||||
|
||||
2. For development with hot-reloading:
|
||||
|
||||
```bash
|
||||
docker run -d -p 80:80 -v $(pwd):/app timesafari:dev
|
||||
```
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
timesafari:
|
||||
build: .
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
Run with Docker Compose:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
|
||||
For production deployment, consider the following:
|
||||
|
||||
1. Use specific version tags instead of 'latest'
|
||||
2. Implement health checks
|
||||
3. Configure proper logging
|
||||
4. Set up reverse proxy with SSL termination
|
||||
5. Use Docker secrets for sensitive data
|
||||
|
||||
Example production deployment:
|
||||
|
||||
```bash
|
||||
# Build with specific version
|
||||
docker build -t timesafari:1.0.0 .
|
||||
|
||||
# Run with production settings
|
||||
docker run -d \
|
||||
--name timesafari \
|
||||
-p 80:80 \
|
||||
--restart unless-stopped \
|
||||
-e NODE_ENV=production \
|
||||
timesafari:1.0.0
|
||||
```
|
||||
|
||||
### Troubleshooting Docker
|
||||
|
||||
1. **Container fails to start**
|
||||
- Check logs: `docker logs <container_id>`
|
||||
- Verify port availability
|
||||
- Check environment variables
|
||||
|
||||
2. **Build fails**
|
||||
- Ensure all dependencies are in package.json
|
||||
- Check Dockerfile syntax
|
||||
- Verify build context
|
||||
|
||||
3. **Performance issues**
|
||||
- Monitor container resources: `docker stats`
|
||||
- Check nginx configuration
|
||||
- Verify caching settings
|
||||
|
||||
## Desktop Build (Electron)
|
||||
|
||||
### Linux Build
|
||||
|
||||
1. Build the electron app in production mode:
|
||||
|
||||
```bash
|
||||
npm run build:electron-prod
|
||||
```
|
||||
|
||||
2. Package the Electron app for Linux:
|
||||
|
||||
```bash
|
||||
# For AppImage (recommended)
|
||||
npm run build:electron-linux
|
||||
|
||||
# For .deb package
|
||||
npm run build:electron-linux-deb
|
||||
```
|
||||
|
||||
3. The packaged applications will be in `dist-electron-packages/`:
|
||||
- AppImage: `dist-electron-packages/TimeSafari-x.x.x.AppImage`
|
||||
- DEB: `dist-electron-packages/timesafari_x.x.x_amd64.deb`
|
||||
|
||||
### macOS Build
|
||||
|
||||
1. Build the electron app in production mode:
|
||||
|
||||
```bash
|
||||
NODE_ENV=prod npm run build:web
|
||||
npm run build:electron
|
||||
npm run build:electron-mac
|
||||
```
|
||||
|
||||
2. Package the Electron app for macOS:
|
||||
|
||||
```bash
|
||||
# For Intel Macs
|
||||
npm run build:electron-mac
|
||||
|
||||
# For Universal build (Intel + Apple Silicon)
|
||||
npm run build:electron-mac-universal
|
||||
```
|
||||
|
||||
3. The packaged applications will be in `dist-electron-packages/`:
|
||||
- `.app` bundle: `TimeSafari.app`
|
||||
- `.dmg` installer: `TimeSafari-x.x.x.dmg`
|
||||
- `.zip` archive: `TimeSafari-x.x.x-mac.zip`
|
||||
|
||||
### Code Signing and Notarization (macOS)
|
||||
|
||||
For public distribution on macOS, you need to code sign and notarize your app:
|
||||
|
||||
1. Set up environment variables:
|
||||
```bash
|
||||
export CSC_LINK=/path/to/your/certificate.p12
|
||||
export CSC_KEY_PASSWORD=your_certificate_password
|
||||
export APPLE_ID=your_apple_id
|
||||
export APPLE_ID_PASSWORD=your_app_specific_password
|
||||
```
|
||||
|
||||
2. Build with signing:
|
||||
```bash
|
||||
npm run build:electron-mac
|
||||
```
|
||||
|
||||
### Running the Packaged App
|
||||
|
||||
- **Linux**:
|
||||
- AppImage: Make executable and run
|
||||
```bash
|
||||
chmod +x dist-electron-packages/TimeSafari-*.AppImage
|
||||
./dist-electron-packages/TimeSafari-*.AppImage
|
||||
```
|
||||
- DEB: Install and run
|
||||
```bash
|
||||
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
|
||||
timesafari
|
||||
```
|
||||
|
||||
- **macOS**:
|
||||
- `.app` bundle: Double-click `TimeSafari.app` in Finder
|
||||
- `.dmg` installer:
|
||||
1. Double-click the `.dmg` file
|
||||
2. Drag the app to your Applications folder
|
||||
3. Launch from Applications
|
||||
- `.zip` archive:
|
||||
1. Extract the `.zip` file
|
||||
2. Move `TimeSafari.app` to your Applications folder
|
||||
3. Launch from Applications
|
||||
|
||||
Note: If you get a security warning when running the app:
|
||||
1. Right-click the app
|
||||
2. Select "Open"
|
||||
3. Click "Open" in the security dialog
|
||||
|
||||
### Development Testing
|
||||
|
||||
For testing the Electron build before packaging:
|
||||
|
||||
```bash
|
||||
# Build and run in development mode (includes DevTools)
|
||||
npm run build:electron
|
||||
|
||||
# Build in production mode and test
|
||||
npm run build:electron-prod && npm run start:electron
|
||||
```
|
||||
|
||||
## Mobile Builds (Capacitor)
|
||||
|
||||
### iOS Build
|
||||
|
||||
Prerequisites: macOS with Xcode installed
|
||||
|
||||
#### First-time iOS Configuration
|
||||
|
||||
- Generate certificates inside XCode.
|
||||
|
||||
- Right-click on App and under Signing & Capabilities set the Team.
|
||||
|
||||
#### Each Release
|
||||
|
||||
0. First time (or if dependencies change):
|
||||
|
||||
- `pkgx +rubygems.org sh`
|
||||
|
||||
- ... and you may have to fix these, especially with pkgx:
|
||||
|
||||
```bash
|
||||
gem_path=$(which gem)
|
||||
shortened_path="${gem_path:h:h}"
|
||||
export GEM_HOME=$shortened_path
|
||||
export GEM_PATH=$shortened_path
|
||||
```
|
||||
|
||||
1. Build the web assets & update ios:
|
||||
|
||||
```bash
|
||||
rm -rf dist
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
npx cap sync ios
|
||||
```
|
||||
|
||||
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
|
||||
|
||||
3. Copy the assets:
|
||||
|
||||
```bash
|
||||
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents.
|
||||
mkdir -p ios/App/App/Assets.xcassets/AppIcon.appiconset
|
||||
echo '{"images":[]}' > ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
|
||||
mkdir -p ios/App/App/Assets.xcassets/Splash.imageset
|
||||
echo '{"images":[]}' > ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
|
||||
npx capacitor-assets generate --ios
|
||||
```
|
||||
|
||||
4. Bump the version to match Android & package.json:
|
||||
|
||||
```
|
||||
cd ios/App && xcrun agvtool new-version 35 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.2;/g" App.xcodeproj/project.pbxproj && cd -
|
||||
# Unfortunately this edits Info.plist directly.
|
||||
#xcrun agvtool new-marketing-version 0.4.5
|
||||
```
|
||||
|
||||
5. Open the project in Xcode:
|
||||
|
||||
```bash
|
||||
npx cap open ios
|
||||
```
|
||||
|
||||
6. Use Xcode to build and run on simulator or device.
|
||||
|
||||
* Select Product -> Destination with some Simulator version. Then click the run arrow.
|
||||
|
||||
7. Release
|
||||
|
||||
* Someday: Under "General" we want to rename a bunch of things to "Time Safari"
|
||||
* Choose Product -> Destination -> Any iOS Device
|
||||
* Choose Product -> Archive
|
||||
* This will trigger a build and take time, needing user's "login" keychain password (user's login password), repeatedly.
|
||||
* If it fails with `building for 'iOS', but linking in dylib (.../.pkgx/zlib.net/v1.3.0/lib/libz.1.3.dylib) built for 'macOS'` then run XCode outside that terminal (ie. not with `npx cap open ios`).
|
||||
* Click Distribute -> App Store Connect
|
||||
* In AppStoreConnect, add the build to the distribution: remove the current build with the "-" when you hover over it, then "Add Build" with the new build.
|
||||
* May have to go to App Review, click Submission, then hover over the build and click "-".
|
||||
* It can take 15 minutes for the build to show up in the list of builds.
|
||||
* You'll probably have to "Manage" something about encryption, disallowed in France.
|
||||
* Then "Save" and "Add to Review" and "Resubmit to App Review".
|
||||
|
||||
### Android Build
|
||||
|
||||
Prerequisites: Android Studio with Java SDK installed
|
||||
|
||||
1. Build the web assets:
|
||||
|
||||
```bash
|
||||
rm -rf dist
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
```
|
||||
|
||||
2. Update Android project with latest build:
|
||||
|
||||
```bash
|
||||
npx cap sync android
|
||||
```
|
||||
|
||||
3. Copy the assets
|
||||
|
||||
```bash
|
||||
npx capacitor-assets generate --android
|
||||
```
|
||||
|
||||
4. Bump version to match iOS & package.json: android/app/build.gradle
|
||||
|
||||
5. Open the project in Android Studio:
|
||||
|
||||
```bash
|
||||
npx cap open android
|
||||
```
|
||||
|
||||
6. Use Android Studio to build and run on emulator or device.
|
||||
|
||||
## Android Build from the console
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew clean
|
||||
./gradlew build -Dlint.baselines.continue=true
|
||||
cd -
|
||||
```
|
||||
|
||||
... or, to create the `aab` file, `bundle` instead of `build`:
|
||||
|
||||
```bash
|
||||
./gradlew bundleDebug -Dlint.baselines.continue=true
|
||||
```
|
||||
|
||||
... or, to create a signed release:
|
||||
|
||||
* Setup by adding the app/gradle.properties.secrets file (see properties at top of app/build.gradle) and the app/time-safari-upload-key-pkcs12.jks file
|
||||
* In app/build.gradle, bump the versionCode and maybe the versionName
|
||||
* Then `bundleRelease`:
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew bundleRelease -Dlint.baselines.continue=true
|
||||
cd -
|
||||
```
|
||||
|
||||
... and find your `aab` file at app/build/outputs/bundle/release
|
||||
|
||||
At play.google.com/console:
|
||||
|
||||
- Go to the Testing Track (eg. Closed).
|
||||
- Click "Create new release".
|
||||
- Upload the `aab` file.
|
||||
- Hit "Next".
|
||||
- Save, go to "Publishing Overview" as prompted, and click "Send changes for review".
|
||||
|
||||
- Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
|
||||
|
||||
|
||||
## Android Configuration for deep links
|
||||
|
||||
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
|
||||
|
||||
```xml
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="timesafari" />
|
||||
</intent-filter>
|
||||
```
|
||||
|
||||
... though when we tried that most recently it failed to 'build' the APK with: http(s) scheme and host attribute are missing, but are required for Android App Links [AppLinkUrlError]
|
||||
|
||||
## Forks
|
||||
|
||||
If you have forked this to make your own app, you'll want to customize the iOS & Android files. You can either edit existing ones, or you can remove the `ios` and `android` directories and regenerate them before the `npx cap sync` step in each setup.
|
||||
|
||||
```bash
|
||||
npx cap add android
|
||||
npx cap add ios
|
||||
```
|
||||
@@ -1,381 +0,0 @@
|
||||
# Worker-Only Database Implementation for Web Platform
|
||||
|
||||
## Overview
|
||||
|
||||
This implementation fixes the double migration issue in the TimeSafari web platform by implementing worker-only database access, similar to the Capacitor platform architecture.
|
||||
|
||||
## Problem Solved
|
||||
|
||||
**Before:** Web platform had dual database contexts:
|
||||
|
||||
- Worker thread: `registerSQLWorker.js` → `AbsurdSqlDatabaseService.initialize()` → migrations run
|
||||
- Main thread: `WebPlatformService.dbQuery()` → `databaseService.query()` → migrations run **AGAIN**
|
||||
|
||||
**After:** Single database context:
|
||||
|
||||
- Worker thread: Handles ALL database operations and initializes once
|
||||
- Main thread: Sends messages to worker, no direct database access
|
||||
|
||||
## Architecture Changes
|
||||
|
||||
### 1. Message-Based Communication
|
||||
|
||||
```typescript
|
||||
// Main Thread (WebPlatformService)
|
||||
await this.sendWorkerMessage<QueryResult>({
|
||||
type: "query",
|
||||
sql: "SELECT * FROM users",
|
||||
params: []
|
||||
});
|
||||
|
||||
// Worker Thread (registerSQLWorker.js)
|
||||
onmessage = async (event) => {
|
||||
const { id, type, sql, params } = event.data;
|
||||
if (type === "query") {
|
||||
const result = await databaseService.query(sql, params);
|
||||
postMessage({ id, type: "success", data: { result } });
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Type-Safe Worker Messages
|
||||
|
||||
```typescript
|
||||
// src/interfaces/worker-messages.ts
|
||||
export interface QueryRequest extends BaseWorkerMessage {
|
||||
type: "query";
|
||||
sql: string;
|
||||
params?: unknown[];
|
||||
}
|
||||
|
||||
export type WorkerRequest =
|
||||
| QueryRequest
|
||||
| ExecRequest
|
||||
| GetOneRowRequest
|
||||
| InitRequest
|
||||
| PingRequest;
|
||||
```
|
||||
|
||||
### 3. Circular Dependency Resolution
|
||||
|
||||
#### 🔥 Critical Fix: Stack Overflow Prevention
|
||||
|
||||
**Problem**: Circular module dependency caused infinite recursion:
|
||||
|
||||
- `WebPlatformService` constructor → creates Worker
|
||||
- Worker loads `registerSQLWorker.js` → imports `databaseService`
|
||||
- Module resolution creates circular dependency → Stack Overflow
|
||||
|
||||
**Solution**: Lazy Loading in Worker
|
||||
|
||||
```javascript
|
||||
// Before (caused stack overflow)
|
||||
import databaseService from "./services/AbsurdSqlDatabaseService";
|
||||
|
||||
// After (fixed)
|
||||
let databaseService = null;
|
||||
|
||||
async function getDatabaseService() {
|
||||
if (!databaseService) {
|
||||
// Dynamic import prevents circular dependency
|
||||
const { default: service } = await import("./services/AbsurdSqlDatabaseService");
|
||||
databaseService = service;
|
||||
}
|
||||
return databaseService;
|
||||
}
|
||||
```
|
||||
|
||||
**Key Changes for Stack Overflow Fix:**
|
||||
|
||||
- ✅ Removed top-level import of database service
|
||||
- ✅ Added lazy loading with dynamic import
|
||||
- ✅ Updated all handlers to use `await getDatabaseService()`
|
||||
- ✅ Removed auto-initialization that triggered immediate loading
|
||||
- ✅ Database service only loads when first database operation occurs
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. WebPlatformService Changes
|
||||
|
||||
- Removed direct database imports
|
||||
- Added worker message handling
|
||||
- Implemented timeout and error handling
|
||||
- All database methods now proxy to worker
|
||||
|
||||
### 2. Worker Thread Changes
|
||||
|
||||
- Added message-based operation handling
|
||||
- Implemented lazy loading for database service
|
||||
- Added proper error handling and response formatting
|
||||
- Fixed circular dependency with dynamic imports
|
||||
|
||||
### 3. Main Thread Changes
|
||||
|
||||
- Removed duplicate worker creation in `main.web.ts`
|
||||
- WebPlatformService now manages single worker instance
|
||||
- Added Safari compatibility with `initBackend()`
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **src/interfaces/worker-messages.ts** *(NEW)*
|
||||
- Type definitions for worker communication
|
||||
- Request and response message interfaces
|
||||
|
||||
2. **src/registerSQLWorker.js** *(MAJOR REWRITE)*
|
||||
- Message-based operation handling
|
||||
- **Fixed circular dependency with lazy loading**
|
||||
- Proper error handling and response formatting
|
||||
|
||||
3. **src/services/platforms/WebPlatformService.ts** *(MAJOR REWRITE)*
|
||||
- Worker-only database access
|
||||
- Message sending and response handling
|
||||
- Timeout and error management
|
||||
|
||||
4. **src/main.web.ts** *(SIMPLIFIED)*
|
||||
- Removed duplicate worker creation
|
||||
- Simplified initialization flow
|
||||
|
||||
5. **WORKER_ONLY_DATABASE_IMPLEMENTATION.md** *(NEW)*
|
||||
- Complete documentation of changes
|
||||
|
||||
## Benefits
|
||||
|
||||
### ✅ Fixes Double Migration Issue
|
||||
|
||||
- Database migrations now run only once in worker thread
|
||||
- No duplicate initialization between main thread and worker
|
||||
|
||||
### ✅ Prevents Stack Overflow
|
||||
|
||||
- Circular dependency resolved with lazy loading
|
||||
- Worker loads immediately without triggering database import
|
||||
- Database service loads on-demand when first operation occurs
|
||||
|
||||
### ✅ Improved Performance
|
||||
|
||||
- Single database connection
|
||||
- No redundant operations
|
||||
- Better resource utilization
|
||||
|
||||
### ✅ Better Error Handling
|
||||
|
||||
- Centralized error handling in worker
|
||||
- Type-safe message communication
|
||||
- Proper timeout handling
|
||||
|
||||
### ✅ Consistent Architecture
|
||||
|
||||
- Matches Capacitor platform pattern
|
||||
- Single-threaded database access
|
||||
- Clear separation of concerns
|
||||
|
||||
## Testing Verification
|
||||
|
||||
After implementation, you should see:
|
||||
|
||||
1. **Worker Loading**:
|
||||
|
||||
```text
|
||||
[SQLWorker] Worker loaded, ready to receive messages
|
||||
```
|
||||
|
||||
2. **Database Initialization** (only on first operation):
|
||||
|
||||
```text
|
||||
[SQLWorker] Starting database initialization...
|
||||
[SQLWorker] Database initialization completed successfully
|
||||
```
|
||||
|
||||
3. **No Stack Overflow**: Application starts without infinite recursion
|
||||
4. **Single Migration Run**: Database migrations execute only once
|
||||
5. **Functional Database**: All queries, inserts, and updates work correctly
|
||||
|
||||
## Migration from Previous Implementation
|
||||
|
||||
If upgrading from the dual-context implementation:
|
||||
|
||||
1. **Remove Direct Database Imports**: No more `import databaseService` in main thread
|
||||
2. **Update Database Calls**: Use platform service methods instead of direct database calls
|
||||
3. **Handle Async Operations**: All database operations are now async message-based
|
||||
4. **Error Handling**: Update error handling to work with worker responses
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Worker thread isolates database operations
|
||||
- Message validation prevents malformed requests
|
||||
- Timeout handling prevents hanging operations
|
||||
- Type safety reduces runtime errors
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- Initial worker creation has minimal overhead
|
||||
- Database operations have message passing overhead (negligible)
|
||||
- Single database connection is more efficient than dual connections
|
||||
- Lazy loading reduces startup time
|
||||
|
||||
## Migration Execution Flow
|
||||
|
||||
### Before (Problematic)
|
||||
|
||||
```chart
|
||||
┌────────────── ───┐ ┌─────────────────┐
|
||||
│ Main Thread │ │ Worker Thread │
|
||||
│ │ │ │
|
||||
│ WebPlatformService│ │registerSQLWorker│
|
||||
│ ↓ │ │ ↓ │
|
||||
│ databaseService │ │ databaseService │
|
||||
│ (Instance A) │ │ (Instance B) │
|
||||
│ ↓ │ │ ↓ │
|
||||
│ [Run Migrations] │ │[Run Migrations] │ ← DUPLICATE!
|
||||
└─────────────── ──┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### After (Fixed)
|
||||
|
||||
```text
|
||||
┌─────────────── ──┐ ┌─────────────────┐
|
||||
│ Main Thread │ │ Worker Thread │
|
||||
│ │ │ │
|
||||
│ WebPlatformService │───→│registerSQLWorker│
|
||||
│ │ │ ↓ │
|
||||
│ [Send Messages] │ │ databaseService │
|
||||
│ │ │(Single Instance)│
|
||||
│ │ │ ↓ │
|
||||
│ │ │[Run Migrations] │ ← ONCE ONLY!
|
||||
└─────────────── ──┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## New Security Considerations
|
||||
|
||||
### 1. **Message Validation**
|
||||
|
||||
- All worker messages validated for required fields
|
||||
- Unknown message types rejected with errors
|
||||
- Proper error responses prevent information leakage
|
||||
|
||||
### 2. **Timeout Protection**
|
||||
|
||||
- 30-second timeout prevents hung operations
|
||||
- Automatic cleanup of pending messages
|
||||
- Worker health checks via ping/pong
|
||||
|
||||
### 3. **Error Sanitization**
|
||||
|
||||
- Error messages logged but not exposed raw to main thread
|
||||
- Stack traces included only in development
|
||||
- Graceful handling of worker failures
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
### 1. **Unit Tests Needed**
|
||||
|
||||
- Worker message handling
|
||||
- WebPlatformService worker communication
|
||||
- Error handling and timeouts
|
||||
- Migration execution (should run once only)
|
||||
|
||||
### 2. **Integration Tests**
|
||||
|
||||
- End-to-end database operations
|
||||
- Worker lifecycle management
|
||||
- Cross-browser compatibility (especially Safari)
|
||||
|
||||
### 3. **Performance Tests**
|
||||
|
||||
- Message passing overhead
|
||||
- Database operation throughput
|
||||
- Memory usage with worker communication
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
### 1. **Modern Browsers**
|
||||
|
||||
- Chrome/Edge: Full SharedArrayBuffer support
|
||||
- Firefox: Full SharedArrayBuffer support (with headers)
|
||||
- Safari: Uses IndexedDB fallback via `initBackend()`
|
||||
|
||||
### 2. **Required Headers**
|
||||
|
||||
```text
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
```
|
||||
|
||||
## Deployment Notes
|
||||
|
||||
### 1. **Development**
|
||||
|
||||
- Enhanced logging shows worker message flow
|
||||
- Clear separation between worker and main thread logs
|
||||
- Easy debugging via browser DevTools
|
||||
|
||||
### 2. **Production**
|
||||
|
||||
- Reduced logging overhead
|
||||
- Optimized message passing
|
||||
- Proper error reporting without sensitive data
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### 1. **Potential Optimizations**
|
||||
|
||||
- Message batching for bulk operations
|
||||
- Connection pooling simulation
|
||||
- Persistent worker state management
|
||||
|
||||
### 2. **Additional Features**
|
||||
|
||||
- Database backup/restore via worker
|
||||
- Schema introspection commands
|
||||
- Performance monitoring hooks
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If issues arise, rollback involves:
|
||||
|
||||
1. Restore original `WebPlatformService.ts`
|
||||
2. Restore original `registerSQLWorker.js`
|
||||
3. Restore original `main.web.ts`
|
||||
4. Remove `worker-messages.ts` interface
|
||||
|
||||
## Commit Messages
|
||||
|
||||
```bash
|
||||
git add src/interfaces/worker-messages.ts
|
||||
git commit -m "Add worker message interface for type-safe database communication
|
||||
|
||||
- Define TypeScript interfaces for worker request/response messages
|
||||
- Include query, exec, getOneRow, init, and ping message types
|
||||
- Provide type safety for web platform worker messaging"
|
||||
|
||||
git add src/registerSQLWorker.js
|
||||
git commit -m "Implement message-based worker for single-point database access
|
||||
|
||||
- Replace simple auto-init with comprehensive message handler
|
||||
- Add support for query, exec, getOneRow, init, ping operations
|
||||
- Implement proper error handling and response management
|
||||
- Ensure single database initialization point to prevent double migrations"
|
||||
|
||||
git add src/services/platforms/WebPlatformService.ts
|
||||
git commit -m "Migrate WebPlatformService to worker-only database access
|
||||
|
||||
- Remove direct databaseService import to prevent dual context issue
|
||||
- Implement worker-based messaging for all database operations
|
||||
- Add worker lifecycle management with initialization tracking
|
||||
- Include message timeout and error handling for reliability
|
||||
- Add Safari compatibility with initBackend call"
|
||||
|
||||
git add src/main.web.ts
|
||||
git commit -m "Remove duplicate worker creation from main.web.ts
|
||||
|
||||
- Worker initialization now handled by WebPlatformService
|
||||
- Prevents duplicate worker creation and database contexts
|
||||
- Simplifies main thread initialization"
|
||||
|
||||
git add WORKER_ONLY_DATABASE_IMPLEMENTATION.md
|
||||
git commit -m "Document worker-only database implementation
|
||||
|
||||
- Comprehensive documentation of architecture changes
|
||||
- Explain problem solved and benefits achieved
|
||||
- Include security considerations and testing requirements"
|
||||
```
|
||||
@@ -1,125 +0,0 @@
|
||||
# Architecture Decisions
|
||||
|
||||
This document records key architectural decisions made during the development of TimeSafari.
|
||||
|
||||
## Platform Service Architecture: Mixins over Composables
|
||||
|
||||
**Date:** July 2, 2025
|
||||
**Status:** Accepted
|
||||
**Context:** Need for consistent platform service access across Vue components
|
||||
|
||||
### Decision
|
||||
|
||||
**Use Vue mixins for platform service access instead of Vue 3 Composition API composables.**
|
||||
|
||||
### Rationale
|
||||
|
||||
#### Why Mixins Were Chosen
|
||||
|
||||
1. **Existing Architecture Consistency**
|
||||
- The entire codebase uses class-based components with `vue-facing-decorator`
|
||||
- All components follow the established pattern of extending Vue class
|
||||
- Mixins integrate seamlessly with the existing architecture
|
||||
|
||||
2. **Performance Benefits**
|
||||
- **Caching Layer**: `PlatformServiceMixin` provides smart TTL-based caching
|
||||
- **Ultra-Concise Methods**: Short methods like `$db()`, `$exec()`, `$one()` reduce boilerplate
|
||||
- **Settings Shortcuts**: `$saveSettings()`, `$saveMySettings()` eliminate 90% of update boilerplate
|
||||
- **Memory Management**: WeakMap-based caching prevents memory leaks
|
||||
|
||||
3. **Developer Experience**
|
||||
- **Familiar Pattern**: Mixins are well-understood by the team
|
||||
- **Type Safety**: Full TypeScript support with proper interfaces
|
||||
- **Error Handling**: Centralized error handling across components
|
||||
- **Code Reduction**: Reduces database code by up to 80%
|
||||
|
||||
4. **Production Readiness**
|
||||
- **Mature Implementation**: `PlatformServiceMixin` is actively used and tested
|
||||
- **Comprehensive Features**: Includes transaction support, cache management, settings shortcuts
|
||||
- **Security**: Proper input validation and error handling
|
||||
|
||||
#### Why Composables Were Rejected
|
||||
|
||||
1. **Architecture Mismatch**
|
||||
- Would require rewriting all components to use Composition API
|
||||
- Breaks consistency with existing class-based component pattern
|
||||
- Requires significant refactoring effort
|
||||
|
||||
2. **Limited Features**
|
||||
- Basic platform service access without caching
|
||||
- No settings management shortcuts
|
||||
- No ultra-concise database methods
|
||||
- Would require additional development to match mixin capabilities
|
||||
|
||||
3. **Performance Considerations**
|
||||
- No built-in caching layer
|
||||
- Would require manual implementation of performance optimizations
|
||||
- More verbose for common operations
|
||||
|
||||
### Implementation
|
||||
|
||||
#### Current Usage
|
||||
|
||||
```typescript
|
||||
// Component implementation
|
||||
@Component({
|
||||
mixins: [PlatformServiceMixin],
|
||||
})
|
||||
export default class HomeView extends Vue {
|
||||
async mounted() {
|
||||
// Ultra-concise cached settings loading
|
||||
const settings = await this.$settings({
|
||||
apiServer: "",
|
||||
activeDid: "",
|
||||
isRegistered: false,
|
||||
});
|
||||
|
||||
// Cached contacts loading
|
||||
this.allContacts = await this.$contacts();
|
||||
|
||||
// Settings update with automatic cache invalidation
|
||||
await this.$saveMySettings({ isRegistered: true });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Cached Database Operations**: `$contacts()`, `$settings()`, `$accountSettings()`
|
||||
- **Settings Shortcuts**: `$saveSettings()`, `$saveMySettings()`, `$saveUserSettings()`
|
||||
- **Ultra-Concise Methods**: `$db()`, `$exec()`, `$one()`, `$query()`, `$first()`
|
||||
- **Cache Management**: `$refreshSettings()`, `$clearAllCaches()`
|
||||
- **Transaction Support**: `$withTransaction()` with automatic rollback
|
||||
|
||||
### Consequences
|
||||
|
||||
#### Positive
|
||||
|
||||
- **Consistent Architecture**: All components follow the same pattern
|
||||
- **High Performance**: Smart caching reduces database calls by 80%+
|
||||
- **Developer Productivity**: Ultra-concise methods reduce boilerplate by 90%
|
||||
- **Type Safety**: Full TypeScript support with proper interfaces
|
||||
- **Memory Safety**: WeakMap-based caching prevents memory leaks
|
||||
|
||||
#### Negative
|
||||
|
||||
- **Vue 2 Pattern**: Uses older mixin pattern instead of modern Composition API
|
||||
- **Tight Coupling**: Components are coupled to the mixin implementation
|
||||
- **Testing Complexity**: Mixins can make unit testing more complex
|
||||
|
||||
### Future Considerations
|
||||
|
||||
1. **Migration Path**: If Vue 4 or future versions deprecate mixins, we may need to migrate
|
||||
2. **Performance Monitoring**: Continue monitoring caching performance and adjust TTL values
|
||||
3. **Feature Expansion**: Add new ultra-concise methods as needed
|
||||
4. **Testing Strategy**: Develop comprehensive testing strategies for mixin-based components
|
||||
|
||||
### Related Documentation
|
||||
|
||||
- [PlatformServiceMixin Implementation](../src/utils/PlatformServiceMixin.ts)
|
||||
- [TimeSafari Cross-Platform Architecture Guide](./build-modernization-context.md)
|
||||
- [Database Migration Guide](./database-migration-guide.md)
|
||||
|
||||
---
|
||||
|
||||
*This decision was made based on the current codebase architecture and team expertise. The mixin approach provides the best balance of performance, developer experience, and architectural consistency for the TimeSafari application.*
|
||||
@@ -1,51 +0,0 @@
|
||||
# TimeSafari Build Modernization Context
|
||||
|
||||
**Author:** Matthew Raymer
|
||||
|
||||
## Motivation
|
||||
- Eliminate manual hacks and post-build scripts for Electron builds
|
||||
- Ensure maintainability, reproducibility, and security of build outputs
|
||||
- Unify build, test, and deployment scripts for developer experience and CI/CD
|
||||
|
||||
## Key Technical Decisions
|
||||
- **Vite is the single source of truth for build output**
|
||||
- All Electron build output (main process, preload, renderer HTML/CSS/JS) is managed by `vite.config.electron.mts`
|
||||
- **CSS injection for Electron is handled by a Vite plugin**
|
||||
- No more manual HTML/CSS edits or post-build scripts
|
||||
- **Build scripts are unified and robust**
|
||||
- Use `./scripts/build-electron.sh` for all Electron builds
|
||||
- No more `fix-inject-css.js` or similar hacks
|
||||
- **Output structure is deterministic and ASAR-friendly**
|
||||
- Main process: `dist-electron/main.js`
|
||||
- Preload: `dist-electron/preload.js`
|
||||
- Renderer assets: `dist-electron/www/` (HTML, CSS, JS)
|
||||
|
||||
## Security & Maintenance Checklist
|
||||
- [x] All scripts and configs are committed and documented
|
||||
- [x] No manual file hacks remain
|
||||
- [x] All build output is deterministic and reproducible
|
||||
- [x] No sensitive data is exposed in the build process
|
||||
- [x] Documentation (`BUILDING.md`) is up to date
|
||||
|
||||
## How to Build Electron
|
||||
1. Run:
|
||||
```bash
|
||||
./scripts/build-electron.sh
|
||||
```
|
||||
2. Output will be in `dist-electron/`:
|
||||
- `main.js`, `preload.js` in root
|
||||
- `www/` contains all renderer assets
|
||||
3. No manual post-processing is required
|
||||
|
||||
## Customization
|
||||
- **Vite config:** All build output and asset handling is controlled in `vite.config.electron.mts`
|
||||
- **CSS/HTML injection:** Use Vite plugins (see `electron-css-injection` in the config) for further customization
|
||||
- **Build scripts:** All orchestration is in `scripts/` and documented in `BUILDING.md`
|
||||
|
||||
## For Future Developers
|
||||
- Always use Vite plugins/config for build output changes
|
||||
- Never manually edit built files or inject assets post-build
|
||||
- Keep documentation and scripts in sync with the build process
|
||||
|
||||
---
|
||||
This file documents the context and rationale for the build modernization and should be included in the repository for onboarding and future reference.
|
||||
@@ -1,163 +0,0 @@
|
||||
# Circular Dependency Analysis
|
||||
|
||||
## Overview
|
||||
|
||||
This document analyzes the current state of circular dependencies in the TimeSafari codebase, particularly focusing on the migration from Dexie to SQLite and the PlatformServiceMixin implementation.
|
||||
|
||||
## Current Circular Dependency Status
|
||||
|
||||
### ✅ **EXCELLENT NEWS: All Circular Dependencies RESOLVED**
|
||||
|
||||
The codebase currently has **no active circular dependencies** that are causing runtime or compilation errors. All circular dependency issues have been successfully resolved.
|
||||
|
||||
### 🔍 **Resolved Dependency Patterns**
|
||||
|
||||
#### 1. **Logger → PlatformServiceFactory → Logger** (RESOLVED)
|
||||
- **Status**: ✅ **RESOLVED**
|
||||
- **Previous Issue**: Logger imported `logToDb` from databaseUtil, which imported logger
|
||||
- **Solution**: Logger now uses direct database access via PlatformServiceFactory
|
||||
- **Implementation**: Self-contained `logToDatabase()` function in logger.ts
|
||||
|
||||
#### 2. **PlatformServiceMixin → databaseUtil → logger → PlatformServiceMixin** (RESOLVED)
|
||||
- **Status**: ✅ **RESOLVED**
|
||||
- **Previous Issue**: PlatformServiceMixin imported `memoryLogs` from databaseUtil
|
||||
- **Solution**: Created self-contained `_memoryLogs` array in PlatformServiceMixin
|
||||
- **Implementation**: Self-contained memory logs implementation
|
||||
|
||||
#### 3. **databaseUtil → logger → PlatformServiceFactory → databaseUtil** (RESOLVED)
|
||||
- **Status**: ✅ **RESOLVED**
|
||||
- **Previous Issue**: databaseUtil imported logger, which could create loops
|
||||
- **Solution**: Logger is now self-contained and doesn't import from databaseUtil
|
||||
|
||||
#### 4. **Utility Files → databaseUtil → PlatformServiceMixin** (RESOLVED)
|
||||
- **Status**: ✅ **RESOLVED**
|
||||
- **Previous Issue**: `src/libs/util.ts` and `src/services/deepLinks.ts` imported from databaseUtil
|
||||
- **Solution**: Replaced with self-contained implementations and PlatformServiceFactory usage
|
||||
- **Implementation**:
|
||||
- Self-contained `parseJsonField()` and `mapQueryResultToValues()` functions
|
||||
- Direct PlatformServiceFactory usage for database operations
|
||||
- Console logging instead of databaseUtil logging functions
|
||||
|
||||
## Detailed Dependency Analysis
|
||||
|
||||
### ✅ **All Critical Dependencies Resolved**
|
||||
|
||||
#### PlatformServiceMixin Independence
|
||||
- **Status**: ✅ **COMPLETE**
|
||||
- **Achievement**: PlatformServiceMixin has no external dependencies on databaseUtil
|
||||
- **Implementation**: Self-contained memory logs and utility functions
|
||||
- **Impact**: Enables complete migration of databaseUtil functions to PlatformServiceMixin
|
||||
|
||||
#### Logger Independence
|
||||
- **Status**: ✅ **COMPLETE**
|
||||
- **Achievement**: Logger is completely self-contained
|
||||
- **Implementation**: Direct database access via PlatformServiceFactory
|
||||
- **Impact**: Eliminates all circular dependency risks
|
||||
|
||||
#### Utility Files Independence
|
||||
- **Status**: ✅ **COMPLETE**
|
||||
- **Achievement**: All utility files no longer depend on databaseUtil
|
||||
- **Implementation**: Self-contained functions and direct platform service access
|
||||
- **Impact**: Enables complete databaseUtil migration
|
||||
|
||||
### 🎯 **Migration Readiness Status**
|
||||
|
||||
#### Files Ready for Migration (52 files)
|
||||
1. **Components** (15 files):
|
||||
- `PhotoDialog.vue`
|
||||
- `FeedFilters.vue`
|
||||
- `UserNameDialog.vue`
|
||||
- `ImageMethodDialog.vue`
|
||||
- `OfferDialog.vue`
|
||||
- `OnboardingDialog.vue`
|
||||
- `PushNotificationPermission.vue`
|
||||
- `GiftedPrompts.vue`
|
||||
- `GiftedDialog.vue`
|
||||
- `World/components/objects/landmarks.js`
|
||||
- And 5 more...
|
||||
|
||||
2. **Views** (30+ files):
|
||||
- `IdentitySwitcherView.vue`
|
||||
- `ContactEditView.vue`
|
||||
- `ContactGiftingView.vue`
|
||||
- `ImportAccountView.vue`
|
||||
- `OnboardMeetingMembersView.vue`
|
||||
- `RecentOffersToUserProjectsView.vue`
|
||||
- `ClaimCertificateView.vue`
|
||||
- `NewActivityView.vue`
|
||||
- `HelpView.vue`
|
||||
- `NewEditProjectView.vue`
|
||||
- And 20+ more...
|
||||
|
||||
3. **Services** (5 files):
|
||||
- `deepLinks.ts` ✅ **MIGRATED**
|
||||
- `endorserServer.ts`
|
||||
- `libs/util.ts` ✅ **MIGRATED**
|
||||
- `test/index.ts`
|
||||
|
||||
### 🟢 **Healthy Dependencies**
|
||||
|
||||
#### Logger Usage (80+ files)
|
||||
- **Status**: ✅ **HEALTHY**
|
||||
- **Pattern**: All files import logger from `@/utils/logger`
|
||||
- **Impact**: No circular dependencies, logger is self-contained
|
||||
- **Benefit**: Centralized logging with database integration
|
||||
|
||||
## Resolution Strategy - COMPLETED
|
||||
|
||||
### ✅ **Phase 1: Complete PlatformServiceMixin Independence (COMPLETE)**
|
||||
1. **Removed memoryLogs import** from PlatformServiceMixin ✅
|
||||
2. **Created self-contained memoryLogs** implementation ✅
|
||||
3. **Added missing utility methods** to PlatformServiceMixin ✅
|
||||
|
||||
### ✅ **Phase 2: Utility Files Migration (COMPLETE)**
|
||||
1. **Migrated deepLinks.ts** - Replaced databaseUtil logging with console logging ✅
|
||||
2. **Migrated util.ts** - Replaced databaseUtil functions with self-contained implementations ✅
|
||||
3. **Updated all PlatformServiceFactory calls** to use async pattern ✅
|
||||
|
||||
### 🎯 **Phase 3: File-by-File Migration (READY TO START)**
|
||||
1. **High-usage files first** (views, core components)
|
||||
2. **Replace databaseUtil imports** with PlatformServiceMixin
|
||||
3. **Update function calls** to use mixin methods
|
||||
|
||||
### 🎯 **Phase 4: Cleanup (FUTURE)**
|
||||
1. **Remove unused databaseUtil functions**
|
||||
2. **Update TypeScript interfaces**
|
||||
3. **Remove databaseUtil imports** from all files
|
||||
|
||||
## Current Status Summary
|
||||
|
||||
### ✅ **Resolved Issues**
|
||||
1. **Logger circular dependency** - Fixed with self-contained implementation
|
||||
2. **PlatformServiceMixin circular dependency** - Fixed with self-contained memoryLogs
|
||||
3. **Utility files circular dependency** - Fixed with self-contained implementations
|
||||
4. **TypeScript compilation** - No circular dependency errors
|
||||
5. **Runtime stability** - No circular dependency crashes
|
||||
|
||||
### 🎯 **Ready for Next Phase**
|
||||
1. **52 files** ready for databaseUtil migration
|
||||
2. **PlatformServiceMixin** fully independent and functional
|
||||
3. **Clear migration path** - Well-defined targets and strategy
|
||||
|
||||
## Benefits of Current State
|
||||
|
||||
### ✅ **Achieved**
|
||||
1. **No runtime circular dependencies** - Application runs without crashes
|
||||
2. **Self-contained logger** - No more logger/databaseUtil loops
|
||||
3. **PlatformServiceMixin ready** - All methods implemented and independent
|
||||
4. **Utility files independent** - No more databaseUtil dependencies
|
||||
5. **Clear migration path** - Well-defined targets and strategy
|
||||
|
||||
### 🎯 **Expected After Migration**
|
||||
1. **Complete databaseUtil migration** - Single source of truth
|
||||
2. **Eliminated circular dependencies** - Clean architecture
|
||||
3. **Improved performance** - Caching and optimization
|
||||
4. **Better maintainability** - Centralized database operations
|
||||
|
||||
---
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Created**: 2025-07-05
|
||||
**Status**: ✅ **COMPLETE - All Circular Dependencies Resolved**
|
||||
**Last Updated**: 2025-01-06
|
||||
**Note**: PlatformServiceMixin circular dependency completely resolved. Ready for Phase 2: File-by-File Migration
|
||||
@@ -1,314 +0,0 @@
|
||||
# Component Communication Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide establishes our preferred patterns for component communication in Vue.js applications, with a focus on maintainability, type safety, and developer experience.
|
||||
|
||||
## Core Principle: Function Props Over $emit
|
||||
|
||||
**Preference**: Use function props for business logic and data operations, reserve $emit for DOM-like events.
|
||||
|
||||
### Why Function Props?
|
||||
|
||||
1. **Better TypeScript Support**: Full type checking of parameters and return values
|
||||
2. **Superior IDE Navigation**: Ctrl+click takes you directly to implementation
|
||||
3. **Explicit Contracts**: Clear declaration of what functions a component needs
|
||||
4. **Easier Testing**: Simple to mock and test in isolation
|
||||
5. **Flexibility**: Can pass any function, not just event handlers
|
||||
|
||||
### When to Use $emit
|
||||
|
||||
1. **DOM-like Events**: `@click`, `@input`, `@submit`, `@change`
|
||||
2. **Lifecycle Events**: `@mounted`, `@before-unmount`, `@updated`
|
||||
3. **Form Validation**: `@validation-error`, `@validation-success`
|
||||
4. **Event Bubbling**: When events need to bubble through multiple components
|
||||
5. **Vue DevTools Integration**: When you want events visible in DevTools timeline
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### Function Props Pattern
|
||||
|
||||
```typescript
|
||||
// Child Component
|
||||
@Component({
|
||||
name: "MyComponent"
|
||||
})
|
||||
export default class MyComponent extends Vue {
|
||||
@Prop({ required: true }) onSave!: (data: SaveData) => Promise<void>;
|
||||
@Prop({ required: true }) onCancel!: () => void;
|
||||
@Prop({ required: false }) onValidate?: (data: FormData) => boolean;
|
||||
|
||||
async handleSave() {
|
||||
const data = this.collectFormData();
|
||||
await this.onSave(data);
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
this.onCancel();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- Parent Template -->
|
||||
<MyComponent
|
||||
:on-save="handleSave"
|
||||
:on-cancel="handleCancel"
|
||||
:on-validate="validateForm"
|
||||
/>
|
||||
```
|
||||
|
||||
### $emit Pattern (for DOM-like events)
|
||||
|
||||
```typescript
|
||||
// Child Component
|
||||
@Component({
|
||||
name: "FormComponent"
|
||||
})
|
||||
export default class FormComponent extends Vue {
|
||||
@Emit("submit")
|
||||
handleSubmit() {
|
||||
return this.formData;
|
||||
}
|
||||
|
||||
@Emit("input")
|
||||
handleInput(value: string) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- Parent Template -->
|
||||
<FormComponent
|
||||
@submit="handleFormSubmit"
|
||||
@input="handleInputChange"
|
||||
/>
|
||||
```
|
||||
|
||||
## Automatic Code Generation Guidelines
|
||||
|
||||
### Component Template Generation
|
||||
|
||||
When generating component templates, follow these patterns:
|
||||
|
||||
#### Function Props Template
|
||||
```vue
|
||||
<template>
|
||||
<div class="component-name">
|
||||
<!-- Component content -->
|
||||
<button @click="handleAction">
|
||||
{{ buttonText }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-facing-decorator";
|
||||
|
||||
@Component({
|
||||
name: "ComponentName"
|
||||
})
|
||||
export default class ComponentName extends Vue {
|
||||
@Prop({ required: true }) onAction!: () => void;
|
||||
@Prop({ required: true }) buttonText!: string;
|
||||
@Prop({ required: false }) disabled?: boolean;
|
||||
|
||||
handleAction() {
|
||||
if (!this.disabled) {
|
||||
this.onAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
#### $emit Template (for DOM events)
|
||||
```vue
|
||||
<template>
|
||||
<div class="component-name">
|
||||
<!-- Component content -->
|
||||
<button @click="handleClick">
|
||||
{{ buttonText }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
|
||||
|
||||
@Component({
|
||||
name: "ComponentName"
|
||||
})
|
||||
export default class ComponentName extends Vue {
|
||||
@Prop({ required: true }) buttonText!: string;
|
||||
@Prop({ required: false }) disabled?: boolean;
|
||||
|
||||
@Emit("click")
|
||||
handleClick() {
|
||||
return { disabled: this.disabled };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Code Generation Rules
|
||||
|
||||
#### 1. Function Props for Business Logic
|
||||
- **Data operations**: Save, delete, update, validate
|
||||
- **Navigation**: Route changes, modal opening/closing
|
||||
- **State management**: Store actions, state updates
|
||||
- **API calls**: Data fetching, form submissions
|
||||
|
||||
#### 2. $emit for User Interactions
|
||||
- **Click events**: Button clicks, link navigation
|
||||
- **Form events**: Input changes, form submissions
|
||||
- **Lifecycle events**: Component mounting, unmounting
|
||||
- **UI events**: Focus, blur, scroll, resize
|
||||
|
||||
#### 3. Naming Conventions
|
||||
|
||||
**Function Props:**
|
||||
```typescript
|
||||
// Action-oriented names
|
||||
onSave: (data: SaveData) => Promise<void>
|
||||
onDelete: (id: string) => Promise<void>
|
||||
onUpdate: (item: Item) => void
|
||||
onValidate: (data: FormData) => boolean
|
||||
onNavigate: (route: string) => void
|
||||
```
|
||||
|
||||
**$emit Events:**
|
||||
```typescript
|
||||
// Event-oriented names
|
||||
@click: (event: MouseEvent) => void
|
||||
@input: (value: string) => void
|
||||
@submit: (data: FormData) => void
|
||||
@focus: (event: FocusEvent) => void
|
||||
@mounted: () => void
|
||||
```
|
||||
|
||||
### TypeScript Integration
|
||||
|
||||
#### Function Prop Types
|
||||
```typescript
|
||||
// Define reusable function types
|
||||
interface SaveHandler {
|
||||
(data: SaveData): Promise<void>;
|
||||
}
|
||||
|
||||
interface ValidationHandler {
|
||||
(data: FormData): boolean;
|
||||
}
|
||||
|
||||
// Use in components
|
||||
@Prop({ required: true }) onSave!: SaveHandler;
|
||||
@Prop({ required: true }) onValidate!: ValidationHandler;
|
||||
```
|
||||
|
||||
#### Event Types
|
||||
```typescript
|
||||
// Define event payload types
|
||||
interface ClickEvent {
|
||||
target: HTMLElement;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
@Emit("click")
|
||||
handleClick(): ClickEvent {
|
||||
return {
|
||||
target: this.$el,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
### Function Props Testing
|
||||
```typescript
|
||||
// Easy to mock and test
|
||||
const mockOnSave = jest.fn();
|
||||
const wrapper = mount(MyComponent, {
|
||||
propsData: {
|
||||
onSave: mockOnSave
|
||||
}
|
||||
});
|
||||
|
||||
await wrapper.vm.handleSave();
|
||||
expect(mockOnSave).toHaveBeenCalledWith(expectedData);
|
||||
```
|
||||
|
||||
### $emit Testing
|
||||
```typescript
|
||||
// Requires event simulation
|
||||
const wrapper = mount(MyComponent);
|
||||
await wrapper.find('button').trigger('click');
|
||||
expect(wrapper.emitted('click')).toBeTruthy();
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### From $emit to Function Props
|
||||
|
||||
1. **Identify business logic events** (not DOM events)
|
||||
2. **Add function props** to component interface
|
||||
3. **Update parent components** to pass functions
|
||||
4. **Remove $emit decorators** and event handlers
|
||||
5. **Update tests** to use function mocks
|
||||
|
||||
### Example Migration
|
||||
|
||||
**Before ($emit):**
|
||||
```typescript
|
||||
@Emit("save")
|
||||
handleSave() {
|
||||
return this.formData;
|
||||
}
|
||||
```
|
||||
|
||||
**After (Function Props):**
|
||||
```typescript
|
||||
@Prop({ required: true }) onSave!: (data: FormData) => void;
|
||||
|
||||
handleSave() {
|
||||
this.onSave(this.formData);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
1. **Use function props** for business logic, data operations, and complex interactions
|
||||
2. **Use $emit** for DOM-like events, lifecycle events, and simple user interactions
|
||||
3. **Be consistent** within your codebase
|
||||
4. **Document your patterns** for team alignment
|
||||
5. **Consider TypeScript** when choosing between approaches
|
||||
6. **Test both patterns** appropriately
|
||||
|
||||
## Code Generation Templates
|
||||
|
||||
### Component Generator Input
|
||||
```typescript
|
||||
interface ComponentSpec {
|
||||
name: string;
|
||||
props: Array<{
|
||||
name: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
isFunction: boolean;
|
||||
}>;
|
||||
events: Array<{
|
||||
name: string;
|
||||
payloadType?: string;
|
||||
}>;
|
||||
template: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Generated Output
|
||||
```typescript
|
||||
// Generator should automatically choose function props vs $emit
|
||||
// based on the nature of the interaction (business logic vs DOM event)
|
||||
```
|
||||
|
||||
This guide ensures consistent, maintainable component communication patterns across the application.
|
||||
@@ -1,116 +0,0 @@
|
||||
# CORS Disabled for Universal Image Support
|
||||
|
||||
## Decision Summary
|
||||
|
||||
CORS headers have been **disabled** to support Time Safari's core mission: enabling users to share images from any domain without restrictions.
|
||||
|
||||
## What Changed
|
||||
|
||||
### ❌ Removed CORS Headers
|
||||
- `Cross-Origin-Opener-Policy: same-origin`
|
||||
- `Cross-Origin-Embedder-Policy: require-corp`
|
||||
|
||||
### ✅ Results
|
||||
- Images from **any domain** now work in development and production
|
||||
- No proxy configuration needed
|
||||
- No whitelist of supported image hosts
|
||||
- True community-driven image sharing
|
||||
|
||||
## Technical Tradeoffs
|
||||
|
||||
### 🔻 Lost: SharedArrayBuffer Performance
|
||||
- **Before**: Fast SQLite operations via SharedArrayBuffer
|
||||
- **After**: Slightly slower IndexedDB fallback mode
|
||||
- **Impact**: Minimal for typical usage - absurd-sql automatically falls back
|
||||
|
||||
### 🔺 Gained: Universal Image Support
|
||||
- **Before**: Only specific domains worked (TimeSafari, Flickr, Imgur, etc.)
|
||||
- **After**: Any image URL works immediately
|
||||
- **Impact**: Massive improvement for user experience
|
||||
|
||||
## Architecture Impact
|
||||
|
||||
### Database Operations
|
||||
```typescript
|
||||
// absurd-sql automatically detects SharedArrayBuffer availability
|
||||
if (typeof SharedArrayBuffer === "undefined") {
|
||||
// Uses IndexedDB backend (current state)
|
||||
console.log("Using IndexedDB fallback mode");
|
||||
} else {
|
||||
// Uses SharedArrayBuffer (not available due to disabled CORS)
|
||||
console.log("Using SharedArrayBuffer mode");
|
||||
}
|
||||
```
|
||||
|
||||
### Image Loading
|
||||
```typescript
|
||||
// All images load directly now
|
||||
export function transformImageUrlForCors(imageUrl: string): string {
|
||||
return imageUrl; // No transformation needed
|
||||
}
|
||||
```
|
||||
|
||||
## Why This Was The Right Choice
|
||||
|
||||
### Time Safari's Use Case
|
||||
- **Community platform** where users share content from anywhere
|
||||
- **User-generated content** includes images from arbitrary websites
|
||||
- **Flexibility** is more important than marginal performance gains
|
||||
|
||||
### Alternative Would Require
|
||||
- Pre-configuring proxies for every possible image hosting service
|
||||
- Constantly updating proxy list as users find new sources
|
||||
- Poor user experience when images fail to load
|
||||
- Impossible to support the "any domain" requirement
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
### Database Operations
|
||||
- **SharedArrayBuffer**: ~2x faster for large operations
|
||||
- **IndexedDB**: Still very fast for typical Time Safari usage
|
||||
- **Real Impact**: Negligible for typical user operations
|
||||
|
||||
### Image Loading
|
||||
- **With CORS**: Many images failed to load in development
|
||||
- **Without CORS**: All images load immediately
|
||||
- **Real Impact**: Massive improvement in user experience
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
| Browser | SharedArrayBuffer | IndexedDB | Image Loading |
|
||||
|---------|------------------|-----------|---------------|
|
||||
| Chrome | ❌ (CORS disabled) | ✅ Works | ✅ Any domain |
|
||||
| Firefox | ❌ (CORS disabled) | ✅ Works | ✅ Any domain |
|
||||
| Safari | ❌ (CORS disabled) | ✅ Works | ✅ Any domain |
|
||||
| Edge | ❌ (CORS disabled) | ✅ Works | ✅ Any domain |
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### For Developers
|
||||
- No code changes needed
|
||||
- `transformImageUrlForCors()` still exists but returns original URL
|
||||
- All existing image references work without modification
|
||||
|
||||
### For Users
|
||||
- Images from any website now work immediately
|
||||
- No more "image failed to load" issues in development
|
||||
- Consistent behavior between development and production
|
||||
|
||||
## Future Considerations
|
||||
|
||||
### If Performance Becomes Critical
|
||||
1. **Selective CORS**: Enable only for specific operations
|
||||
2. **Service Worker**: Handle image proxying at service worker level
|
||||
3. **Build-time Processing**: Pre-process images during build
|
||||
4. **User Education**: Guide users toward optimized image hosting
|
||||
|
||||
### Monitoring
|
||||
- Track database operation performance
|
||||
- Monitor for any user-reported slowness
|
||||
- Consider re-enabling SharedArrayBuffer if usage patterns change
|
||||
|
||||
## Conclusion
|
||||
|
||||
This change prioritizes **user experience** and **community functionality** over marginal performance gains. The database still works efficiently via IndexedDB, while images now work universally without configuration.
|
||||
|
||||
For a community platform like Time Safari, the ability to share images from any domain is fundamental to the user experience and mission.
|
||||
@@ -1,240 +0,0 @@
|
||||
# CORS Image Loading Solution
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the implementation of a comprehensive image loading solution that works in a cross-origin isolated environment (required for SharedArrayBuffer support) while accepting images from any domain.
|
||||
|
||||
## Problem Statement
|
||||
|
||||
When using SharedArrayBuffer (required for absurd-sql), browsers enforce a cross-origin isolated environment with these headers:
|
||||
- `Cross-Origin-Opener-Policy: same-origin`
|
||||
- `Cross-Origin-Embedder-Policy: require-corp`
|
||||
|
||||
This isolation prevents loading external resources (including images) unless they have proper CORS headers, which most image hosting services don't provide.
|
||||
|
||||
## Solution Architecture
|
||||
|
||||
### 1. Multi-Tier Proxy System
|
||||
|
||||
The solution uses a multi-tier approach to handle images from various sources:
|
||||
|
||||
#### Tier 1: Specific Domain Proxies (Development Only)
|
||||
- **TimeSafari Images**: `/image-proxy/` → `https://image.timesafari.app/`
|
||||
- **Flickr Images**: `/flickr-proxy/` → `https://live.staticflickr.com/`
|
||||
- **Imgur Images**: `/imgur-proxy/` → `https://i.imgur.com/`
|
||||
- **GitHub Raw**: `/github-proxy/` → `https://raw.githubusercontent.com/`
|
||||
- **Unsplash**: `/unsplash-proxy/` → `https://images.unsplash.com/`
|
||||
|
||||
#### Tier 2: Universal CORS Proxy (Development Only)
|
||||
- **Any External Domain**: Uses `https://api.allorigins.win/raw?url=` for arbitrary domains
|
||||
|
||||
#### Tier 3: Direct Loading (Production)
|
||||
- **Production Mode**: All images load directly without proxying
|
||||
|
||||
### 2. Smart URL Transformation
|
||||
|
||||
The `transformImageUrlForCors` function automatically:
|
||||
- Detects the image source domain
|
||||
- Routes through appropriate proxy in development
|
||||
- Preserves original URLs in production
|
||||
- Handles edge cases (data URLs, relative paths, etc.)
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Configuration Files
|
||||
|
||||
#### `vite.config.common.mts`
|
||||
```typescript
|
||||
server: {
|
||||
headers: {
|
||||
// Required for SharedArrayBuffer support
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp'
|
||||
},
|
||||
proxy: {
|
||||
// Specific domain proxies with CORS headers
|
||||
'/image-proxy': { /* TimeSafari images */ },
|
||||
'/flickr-proxy': { /* Flickr images */ },
|
||||
'/imgur-proxy': { /* Imgur images */ },
|
||||
'/github-proxy': { /* GitHub raw images */ },
|
||||
'/unsplash-proxy': { /* Unsplash images */ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `src/libs/util.ts`
|
||||
```typescript
|
||||
export function transformImageUrlForCors(imageUrl: string): string {
|
||||
// Development mode: Transform URLs to use proxies
|
||||
// Production mode: Return original URLs
|
||||
|
||||
// Handle specific domains with dedicated proxies
|
||||
// Fall back to universal CORS proxy for arbitrary domains
|
||||
}
|
||||
```
|
||||
|
||||
### Usage in Components
|
||||
|
||||
All image loading in components uses the transformation function:
|
||||
|
||||
```typescript
|
||||
// In Vue components
|
||||
import { transformImageUrlForCors } from "../libs/util";
|
||||
|
||||
// Transform image URL before using
|
||||
const imageUrl = transformImageUrlForCors(originalImageUrl);
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- In templates -->
|
||||
<img :src="transformImageUrlForCors(imageUrl)" alt="Description" />
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
### ✅ SharedArrayBuffer Support
|
||||
- Maintains cross-origin isolation required for SharedArrayBuffer
|
||||
- Enables fast SQLite database operations via absurd-sql
|
||||
- Provides better performance than IndexedDB fallback
|
||||
|
||||
### ✅ Universal Image Support
|
||||
- Handles images from any domain
|
||||
- No need to pre-configure every possible image source
|
||||
- Graceful fallback for unknown domains
|
||||
|
||||
### ✅ Development/Production Flexibility
|
||||
- Proxy system only active in development
|
||||
- Production uses direct URLs for maximum performance
|
||||
- No proxy server required in production
|
||||
|
||||
### ✅ Automatic Detection
|
||||
- Smart URL transformation based on domain patterns
|
||||
- Preserves relative URLs and data URLs
|
||||
- Handles edge cases gracefully
|
||||
|
||||
## Testing
|
||||
|
||||
### Automated Testing
|
||||
Run the test suite to verify URL transformation:
|
||||
|
||||
```typescript
|
||||
import { testCorsImageTransformation } from './libs/test-cors-images';
|
||||
|
||||
// Console output shows transformation results
|
||||
testCorsImageTransformation();
|
||||
```
|
||||
|
||||
### Visual Testing
|
||||
Create test image elements to verify loading:
|
||||
|
||||
```typescript
|
||||
import { createTestImageElements } from './libs/test-cors-images';
|
||||
|
||||
// Creates visual test panel in browser
|
||||
createTestImageElements();
|
||||
```
|
||||
|
||||
### Manual Testing
|
||||
1. Start development server: `npm run dev`
|
||||
2. Open browser console to see transformation logs
|
||||
3. Check Network tab for proxy requests
|
||||
4. Verify images load correctly from various domains
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Development Environment
|
||||
- CORS proxies are only used in development
|
||||
- External proxy services (allorigins.win) are used for testing
|
||||
- No sensitive data is exposed through proxies
|
||||
|
||||
### Production Environment
|
||||
- All images load directly without proxying
|
||||
- No dependency on external proxy services
|
||||
- Original security model maintained
|
||||
|
||||
### Privacy
|
||||
- Image URLs are not logged or stored by proxy services
|
||||
- Proxy requests are only made during development
|
||||
- No tracking or analytics in proxy chain
|
||||
|
||||
## Performance Impact
|
||||
|
||||
### Development
|
||||
- Slight latency from proxy requests
|
||||
- Additional network hops for external domains
|
||||
- More verbose logging for debugging
|
||||
|
||||
### Production
|
||||
- No performance impact
|
||||
- Direct image loading as before
|
||||
- No proxy overhead
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Images Not Loading in Development
|
||||
1. Check console for proxy errors
|
||||
2. Verify CORS headers are set
|
||||
3. Test with different image URLs
|
||||
4. Check network connectivity to proxy services
|
||||
|
||||
#### SharedArrayBuffer Not Available
|
||||
1. Verify CORS headers are set in server configuration
|
||||
2. Check that site is served over HTTPS (or localhost)
|
||||
3. Ensure browser supports SharedArrayBuffer
|
||||
|
||||
#### Proxy Service Unavailable
|
||||
1. Check if allorigins.win is accessible
|
||||
2. Consider using alternative CORS proxy services
|
||||
3. Temporarily disable CORS headers for testing
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check if SharedArrayBuffer is available
|
||||
console.log(typeof SharedArrayBuffer !== 'undefined');
|
||||
|
||||
# Test URL transformation
|
||||
import { transformImageUrlForCors } from './libs/util';
|
||||
console.log(transformImageUrlForCors('https://example.com/image.jpg'));
|
||||
|
||||
# Run comprehensive tests
|
||||
import { testCorsImageTransformation } from './libs/test-cors-images';
|
||||
testCorsImageTransformation();
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From Previous Implementation
|
||||
1. CORS headers are now required for SharedArrayBuffer
|
||||
2. Image URLs automatically transformed in development
|
||||
3. No changes needed to existing image loading code
|
||||
4. Test thoroughly in both development and production
|
||||
|
||||
### Adding New Image Sources
|
||||
1. Add specific proxy for frequently used domains
|
||||
2. Update `transformImageUrlForCors` function
|
||||
3. Add CORS headers to proxy configuration
|
||||
4. Test with sample images
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Possible Improvements
|
||||
1. **Local Proxy Server**: Run dedicated proxy server for development
|
||||
2. **Caching**: Cache proxy responses for better performance
|
||||
3. **Fallback Chain**: Multiple proxy services for reliability
|
||||
4. **Image Optimization**: Compress/resize images through proxy
|
||||
5. **Analytics**: Track image loading success/failure rates
|
||||
|
||||
### Alternative Approaches
|
||||
1. **Service Worker**: Intercept image requests at service worker level
|
||||
2. **Build-time Processing**: Pre-process images during build
|
||||
3. **CDN Integration**: Use CDN with proper CORS headers
|
||||
4. **Local Storage**: Cache images in browser storage
|
||||
|
||||
## Conclusion
|
||||
|
||||
This solution provides a robust, scalable approach to image loading in a cross-origin isolated environment while maintaining the benefits of SharedArrayBuffer support. The multi-tier proxy system ensures compatibility with any image source while optimizing for performance and security.
|
||||
|
||||
For questions or issues, refer to the troubleshooting section or consult the development team.
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
The Database Migration feature allows you to compare and migrate data between Dexie (IndexedDB) and SQLite databases in the TimeSafari application. This is particularly useful during the transition from the old Dexie-based storage system to the new SQLite-based system.
|
||||
|
||||
**⚠️ UPDATE**: The migration is now controlled through the **PlatformServiceMixin** rather than a `USE_DEXIE_DB` constant. This provides a cleaner, more maintainable approach to database access control.
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Database Comparison
|
||||
@@ -29,13 +27,44 @@ The Database Migration feature allows you to compare and migrate data between De
|
||||
- Clear success and error messaging
|
||||
- Export functionality for comparison data
|
||||
|
||||
## Database Migration Status
|
||||
|
||||
**Current Status**: The application is undergoing a migration from Dexie (IndexedDB) to SQLite using absurd-sql. This migration is in **Phase 2** with a well-defined migration fence in place.
|
||||
|
||||
### Migration Progress
|
||||
- ✅ **SQLite Database Service**: Fully implemented with absurd-sql
|
||||
- ✅ **Platform Service Layer**: Unified database interface across platforms
|
||||
- ✅ **Settings Migration**: Core user settings transferred
|
||||
- ✅ **Account Migration**: Identity and key management
|
||||
- 🔄 **Contact Migration**: User contact data (via import interface)
|
||||
- 📋 **Code Cleanup**: Remove unused Dexie imports
|
||||
|
||||
### Migration Fence
|
||||
The migration is controlled by a **migration fence** that separates legacy Dexie code from the new SQLite implementation. See [Migration Fence Definition](doc/migration-fence-definition.md) for complete details.
|
||||
|
||||
**Key Points**:
|
||||
- Legacy Dexie database is disabled by default (`USE_DEXIE_DB = false`)
|
||||
- All database operations go through `PlatformService`
|
||||
- Migration tools provide controlled access to both databases
|
||||
- Clear separation between legacy and new code
|
||||
|
||||
### Migration Documentation
|
||||
- [Migration Guide](doc/migration-to-wa-sqlite.md) - Complete migration process
|
||||
- [Migration Fence Definition](doc/migration-fence-definition.md) - Fence boundaries and rules
|
||||
- [Database Migration Guide](doc/database-migration-guide.md) - User-facing migration tools
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Enable Dexie Database Access
|
||||
### Enable Dexie Database
|
||||
|
||||
Before using the migration features, you must ensure the Dexie database is accessible for migration purposes. The migration tools will automatically handle database access through the PlatformServiceMixin.
|
||||
Before using the migration features, you must enable the Dexie database by setting:
|
||||
|
||||
**Note**: The migration tools are designed to work with both databases simultaneously during the migration process.
|
||||
```typescript
|
||||
// In constants/app.ts
|
||||
export const USE_DEXIE_DB = true;
|
||||
```
|
||||
|
||||
**Note**: This should only be enabled temporarily during migration. Remember to set it back to `false` after migration is complete.
|
||||
|
||||
## Accessing the Migration Interface
|
||||
|
||||
@@ -137,6 +166,11 @@ The settings migration process:
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Dexie Database Not Enabled
|
||||
|
||||
**Error**: "Dexie database is not enabled"
|
||||
**Solution**: Set `USE_DEXIE_DB = true` in `constants/app.ts`
|
||||
|
||||
#### Database Connection Issues
|
||||
|
||||
**Error**: "Failed to retrieve Dexie contacts"
|
||||
@@ -180,7 +214,7 @@ The settings migration process:
|
||||
|
||||
1. **Verify** that data was migrated correctly
|
||||
2. **Test** the application functionality
|
||||
3. **Use PlatformServiceMixin** for all new database operations
|
||||
3. **Disable** Dexie database (`USE_DEXIE_DB = false`)
|
||||
4. **Clean up** any temporary files or exports
|
||||
|
||||
## Technical Details
|
||||
@@ -282,23 +316,6 @@ For issues with the Database Migration feature:
|
||||
- **Data Integrity**: Migration preserves data integrity and handles conflicts gracefully
|
||||
- **Audit Trail**: Export functionality provides an audit trail of migration operations
|
||||
|
||||
## PlatformServiceMixin Integration
|
||||
|
||||
After migration, all database operations should use the PlatformServiceMixin:
|
||||
|
||||
```typescript
|
||||
// Use mixin methods for database access
|
||||
const contacts = await this.$contacts();
|
||||
const settings = await this.$settings();
|
||||
const result = await this.$db("SELECT * FROM contacts WHERE did = ?", [accountDid]);
|
||||
```
|
||||
|
||||
This provides:
|
||||
- **Caching**: Automatic caching for performance
|
||||
- **Error Handling**: Consistent error handling
|
||||
- **Type Safety**: Enhanced TypeScript integration
|
||||
- **Code Reduction**: Up to 80% reduction in boilerplate
|
||||
|
||||
---
|
||||
|
||||
**Note**: This migration tool is designed for the transition period between database systems. Once migration is complete and verified, the Dexie database should be disabled to avoid confusion and potential data conflicts. All new development should use the PlatformServiceMixin for database operations.
|
||||
**Note**: This migration tool is designed for the transition period between database systems. Once migration is complete and verified, the Dexie database should be disabled to avoid confusion and potential data conflicts.
|
||||
|
||||
@@ -1,362 +0,0 @@
|
||||
# DatabaseUtil to PlatformServiceMixin Migration Plan
|
||||
|
||||
## Migration Overview
|
||||
|
||||
This plan migrates database utility functions from `src/db/databaseUtil.ts` to `src/utils/PlatformServiceMixin.ts` to consolidate database operations and reduce boilerplate code across the application.
|
||||
|
||||
## Priority Levels
|
||||
|
||||
### 🔴 **PRIORITY 1 (Critical - Migrate First)**
|
||||
|
||||
Functions used in 50+ files that are core to application functionality
|
||||
|
||||
### 🟡 **PRIORITY 2 (High - Migrate Second)**
|
||||
|
||||
Functions used in 10-50 files that are important but not critical
|
||||
|
||||
### 🟢 **PRIORITY 3 (Medium - Migrate Third)**
|
||||
|
||||
Functions used in 5-10 files that provide utility but aren't frequently used
|
||||
|
||||
### 🔵 **PRIORITY 4 (Low - Migrate Last)**
|
||||
|
||||
Functions used in <5 files or specialized functions
|
||||
|
||||
## Detailed Migration Plan
|
||||
|
||||
### 🔴 **PRIORITY 1 - Critical Functions**
|
||||
|
||||
#### 1. `retrieveSettingsForActiveAccount()`
|
||||
|
||||
- **Usage**: 60+ files
|
||||
- **Current**: `databaseUtil.retrieveSettingsForActiveAccount()`
|
||||
- **Target**: `this.$settings()` (already exists in PlatformServiceMixin)
|
||||
- **Migration**: Replace all calls with `this.$settings()`
|
||||
- **Files to migrate**: All view files, components, and services
|
||||
|
||||
#### 2. `logConsoleAndDb()` and `logToDb()`
|
||||
|
||||
- **Usage**: 40+ files
|
||||
- **Current**: `databaseUtil.logConsoleAndDb()` / `databaseUtil.logToDb()`
|
||||
- **Target**: Add `$log()` and `$logError()` methods to PlatformServiceMixin
|
||||
- **Migration**: Replace with `this.$log()` and `this.$logError()`
|
||||
- **Files to migrate**: All error handling and logging code
|
||||
|
||||
#### 3. `mapQueryResultToValues()` and `mapColumnsToValues()`
|
||||
|
||||
- **Usage**: 30+ files
|
||||
- **Current**: `databaseUtil.mapQueryResultToValues()` / `databaseUtil.mapColumnsToValues()`
|
||||
- **Target**: `this.$mapResults()` (already exists in PlatformServiceMixin)
|
||||
- **Migration**: Replace with `this.$mapResults()`
|
||||
- **Files to migrate**: All data processing components
|
||||
|
||||
### 🟡 **PRIORITY 2 - High Priority Functions**
|
||||
|
||||
#### 4. `updateDefaultSettings()` and `updateDidSpecificSettings()`
|
||||
|
||||
- **Usage**: 20+ files
|
||||
- **Current**: `databaseUtil.updateDefaultSettings()` / `databaseUtil.updateDidSpecificSettings()`
|
||||
- **Target**: `this.$saveSettings()` and `this.$saveUserSettings()` (already exist)
|
||||
- **Migration**: Replace with existing mixin methods
|
||||
- **Files to migrate**: Settings management components
|
||||
|
||||
#### 5. `parseJsonField()`
|
||||
|
||||
- **Usage**: 15+ files
|
||||
- **Current**: `databaseUtil.parseJsonField()` or direct import
|
||||
- **Target**: Add `$parseJson()` method to PlatformServiceMixin
|
||||
- **Migration**: Replace with `this.$parseJson()`
|
||||
- **Files to migrate**: Data processing components
|
||||
|
||||
#### 6. `generateInsertStatement()` and `generateUpdateStatement()`
|
||||
|
||||
- **Usage**: 10+ files
|
||||
- **Current**: `databaseUtil.generateInsertStatement()` / `databaseUtil.generateUpdateStatement()`
|
||||
- **Target**: `this.$insertEntity()` and `this.$updateEntity()` (expand existing methods)
|
||||
- **Migration**: Replace with high-level entity methods
|
||||
- **Files to migrate**: Data manipulation components
|
||||
|
||||
### 🟢 **PRIORITY 3 - Medium Priority Functions**
|
||||
|
||||
#### 7. `insertDidSpecificSettings()`
|
||||
|
||||
- **Usage**: 8 files
|
||||
- **Current**: `databaseUtil.insertDidSpecificSettings()`
|
||||
- **Target**: `this.$insertUserSettings()` (new method)
|
||||
- **Migration**: Replace with new mixin method
|
||||
- **Files to migrate**: Account creation and import components
|
||||
|
||||
#### 8. `debugSettingsData()`
|
||||
|
||||
- **Usage**: 5 files
|
||||
- **Current**: `databaseUtil.debugSettingsData()`
|
||||
- **Target**: `this.$debugSettings()` (new method)
|
||||
- **Migration**: Replace with new mixin method
|
||||
- **Files to migrate**: Debug and testing components
|
||||
|
||||
### 🔵 **PRIORITY 4 - Low Priority Functions**
|
||||
|
||||
#### 9. `retrieveSettingsForDefaultAccount()`
|
||||
|
||||
- **Usage**: 3 files
|
||||
- **Current**: `databaseUtil.retrieveSettingsForDefaultAccount()`
|
||||
- **Target**: `this.$getDefaultSettings()` (new method)
|
||||
- **Migration**: Replace with new mixin method
|
||||
- **Files to migrate**: Settings management components
|
||||
|
||||
#### 10. Memory logs and cleanup functions
|
||||
|
||||
- **Usage**: 2 files
|
||||
- **Current**: `databaseUtil.memoryLogs`, cleanup functions
|
||||
- **Target**: `this.$memoryLogs` and `this.$cleanupLogs()` (new methods)
|
||||
- **Migration**: Replace with new mixin methods
|
||||
- **Files to migrate**: Log management components
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase 0: Untangle Logger and DatabaseUtil (Prerequisite)
|
||||
|
||||
**This must be done FIRST to eliminate circular dependencies before any mixin migration.**
|
||||
|
||||
1. **Create self-contained logger.ts**:
|
||||
- Remove `import { logToDb } from "../db/databaseUtil"`
|
||||
- Add direct database access via `PlatformServiceFactory.getInstance()`
|
||||
- Implement `logger.toDb()` and `logger.toConsoleAndDb()` methods
|
||||
|
||||
2. **Remove databaseUtil imports from PlatformServiceMixin**:
|
||||
- Remove `import { mapColumnsToValues, parseJsonField } from "@/db/databaseUtil"`
|
||||
- Remove `import * as databaseUtil from "@/db/databaseUtil"`
|
||||
- Add self-contained implementations of utility methods
|
||||
|
||||
3. **Test logger independence**:
|
||||
- Verify logger works without databaseUtil
|
||||
- Ensure no circular dependencies exist
|
||||
- Test all logging functionality
|
||||
|
||||
### Phase 1: Add Missing Methods to PlatformServiceMixin
|
||||
|
||||
1. **Add logging methods** (now using independent logger):
|
||||
|
||||
```typescript
|
||||
$log(message: string, level?: string): Promise<void>
|
||||
$logError(message: string): Promise<void>
|
||||
```
|
||||
|
||||
2. **Add JSON parsing method** (self-contained):
|
||||
|
||||
```typescript
|
||||
$parseJson<T>(value: unknown, defaultValue: T): T
|
||||
```
|
||||
|
||||
3. **Add entity update method**:
|
||||
|
||||
```typescript
|
||||
$updateEntity(tableName: string, entity: Record<string, unknown>, whereClause: string, whereParams: unknown[]): Promise<boolean>
|
||||
```
|
||||
|
||||
4. **Add user settings insertion**:
|
||||
|
||||
```typescript
|
||||
$insertUserSettings(did: string, settings: Partial<Settings>): Promise<boolean>
|
||||
```
|
||||
|
||||
### Phase 2: File-by-File Migration
|
||||
|
||||
#### Migration Order (by priority)
|
||||
|
||||
**Prerequisite**: Phase 0 (Logger/DatabaseUtil untangling) must be completed first.
|
||||
|
||||
1. **Start with most critical files**:
|
||||
- `src/App.vue` (main application)
|
||||
- `src/views/AccountViewView.vue` (core account management)
|
||||
- `src/views/ContactsView.vue` (core contact management)
|
||||
|
||||
2. **Migrate high-usage components**:
|
||||
- All view files in `src/views/`
|
||||
- Core components in `src/components/`
|
||||
|
||||
3. **Migrate services and utilities**:
|
||||
- `src/libs/util.ts`
|
||||
- `src/services/` files
|
||||
- `src/utils/logger.ts`
|
||||
|
||||
4. **Migrate remaining components**:
|
||||
- Specialized components
|
||||
- Test files
|
||||
|
||||
### Phase 3: Cleanup and Validation
|
||||
|
||||
1. **Remove databaseUtil imports** from migrated files
|
||||
2. **Update TypeScript interfaces** to reflect new methods
|
||||
3. **Run comprehensive tests** to ensure functionality
|
||||
4. **Remove unused databaseUtil functions** after all migrations complete
|
||||
|
||||
## Migration Commands Template
|
||||
|
||||
For each file migration:
|
||||
|
||||
```bash
|
||||
# 1. Update imports
|
||||
# Remove: import * as databaseUtil from "../db/databaseUtil";
|
||||
# Add: import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
|
||||
# 2. Add mixin to component
|
||||
# Add: mixins: [PlatformServiceMixin],
|
||||
|
||||
# 3. Replace function calls
|
||||
# Replace: databaseUtil.retrieveSettingsForActiveAccount()
|
||||
# With: this.$settings()
|
||||
|
||||
# 4. Test the migration
|
||||
npm run test
|
||||
|
||||
# 5. Commit the change
|
||||
git add .
|
||||
git commit -m "Migrate [filename] from databaseUtil to PlatformServiceMixin"
|
||||
```
|
||||
|
||||
## Benefits of Migration
|
||||
|
||||
1. **Reduced Boilerplate**: Eliminate repeated `PlatformServiceFactory.getInstance()` calls
|
||||
2. **Better Caching**: Leverage existing caching in PlatformServiceMixin
|
||||
3. **Consistent Error Handling**: Centralized error handling and logging
|
||||
4. **Type Safety**: Better TypeScript integration with mixin methods
|
||||
5. **Performance**: Cached platform service access and optimized database operations
|
||||
6. **Maintainability**: Single source of truth for database operations
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
1. **Incremental Migration**: Migrate one file at a time to minimize risk
|
||||
2. **Comprehensive Testing**: Test each migration thoroughly
|
||||
3. **Rollback Plan**: Keep databaseUtil.ts until all migrations are complete
|
||||
4. **Documentation**: Update documentation as methods are migrated
|
||||
|
||||
## Smart Logging Integration Strategy
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
#### Current Logging Architecture
|
||||
|
||||
1. **`src/utils/logger.ts`** - Main logger with console + database logging
|
||||
2. **`src/db/databaseUtil.ts`** - Database-specific logging (`logToDb`, `logConsoleAndDb`)
|
||||
3. **Circular dependency** - logger.ts imports logToDb from databaseUtil.ts
|
||||
|
||||
#### Current Issues
|
||||
|
||||
- **Circular dependency** between logger and databaseUtil
|
||||
- **Duplicate functionality** - both systems log to database
|
||||
- **Inconsistent interfaces** - different method signatures
|
||||
- **Scattered logging logic** - logging rules spread across multiple files
|
||||
|
||||
### Recommended Solution: Hybrid Approach (Option 3)
|
||||
|
||||
**Core Concept**: Enhanced logger + PlatformServiceMixin convenience methods with **zero circular dependencies**.
|
||||
|
||||
#### Implementation
|
||||
|
||||
```typescript
|
||||
// 1. Enhanced logger.ts (single source of truth - NO databaseUtil imports)
|
||||
export const logger = {
|
||||
// Existing methods...
|
||||
|
||||
// New database-focused methods (self-contained)
|
||||
toDb: async (message: string, level?: string) => {
|
||||
// Direct database access without databaseUtil dependency
|
||||
const platform = PlatformServiceFactory.getInstance();
|
||||
await platform.dbExec("INSERT INTO logs (date, message) VALUES (?, ?)", [
|
||||
new Date().toDateString(),
|
||||
`[${level?.toUpperCase() || 'INFO'}] ${message}`
|
||||
]);
|
||||
},
|
||||
|
||||
toConsoleAndDb: async (message: string, isError?: boolean) => {
|
||||
// Console output
|
||||
if (isError) {
|
||||
console.error(message);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
// Database output
|
||||
await logger.toDb(message, isError ? 'error' : 'info');
|
||||
},
|
||||
|
||||
// Component context methods
|
||||
withContext: (componentName?: string) => ({
|
||||
log: (message: string, level?: string) => logger.toDb(`[${componentName}] ${message}`, level),
|
||||
error: (message: string) => logger.toDb(`[${componentName}] ${message}`, 'error')
|
||||
})
|
||||
};
|
||||
|
||||
// 2. PlatformServiceMixin convenience methods (NO databaseUtil imports)
|
||||
methods: {
|
||||
$log(message: string, level?: string): Promise<void> {
|
||||
return logger.toDb(message, level);
|
||||
},
|
||||
|
||||
$logError(message: string): Promise<void> {
|
||||
return logger.toDb(message, 'error');
|
||||
},
|
||||
|
||||
$logAndConsole(message: string, isError = false): Promise<void> {
|
||||
return logger.toConsoleAndDb(message, isError);
|
||||
},
|
||||
|
||||
// Self-contained utility methods (no databaseUtil dependency)
|
||||
$mapResults<T>(results: QueryExecResult | undefined, mapper: (row: unknown[]) => T): T[] {
|
||||
if (!results) return [];
|
||||
return results.values.map(mapper);
|
||||
},
|
||||
|
||||
$parseJson<T>(value: unknown, defaultValue: T): T {
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return value as T || defaultValue;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Benefits
|
||||
|
||||
1. **Single source of truth** - logger.ts handles all database logging
|
||||
2. **No circular dependencies** - logger.ts doesn't import from databaseUtil
|
||||
3. **Component convenience** - PlatformServiceMixin provides easy access
|
||||
4. **Backward compatibility** - existing code can be migrated gradually
|
||||
5. **Context awareness** - logging can include component context
|
||||
6. **Performance optimized** - caching and batching in logger
|
||||
|
||||
#### Migration Strategy
|
||||
|
||||
1. **Phase 1**: Create self-contained logger.ts with direct database access (no databaseUtil imports)
|
||||
2. **Phase 2**: Add self-contained convenience methods to PlatformServiceMixin (no databaseUtil imports)
|
||||
3. **Phase 3**: Migrate existing code to use new methods
|
||||
4. **Phase 4**: Remove old logging methods from databaseUtil
|
||||
5. **Phase 5**: Remove databaseUtil imports from PlatformServiceMixin
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Smart filtering** - prevent logging loops and initialization noise
|
||||
- **Context tracking** - include component names in logs
|
||||
- **Performance optimization** - batch database writes
|
||||
- **Error handling** - graceful fallback when database unavailable
|
||||
- **Platform awareness** - different behavior for web/mobile/desktop
|
||||
|
||||
### Integration with Migration Plan
|
||||
|
||||
This logging integration will be implemented as part of **Phase 1** of the migration plan, specifically:
|
||||
|
||||
1. **Add logging methods to PlatformServiceMixin** (Priority 1, Item 2)
|
||||
2. **Migrate logConsoleAndDb and logToDb usage** across all files
|
||||
3. **Consolidate logging logic** in logger.ts
|
||||
4. **Remove circular dependencies** between logger and databaseUtil
|
||||
|
||||
---
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Created**: 2025-07-05
|
||||
**Status**: Planning Phase
|
||||
**Last Updated**: 2025-07-05
|
||||
@@ -1,304 +0,0 @@
|
||||
# Electron Platform Cleanup Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This document summarizes the comprehensive cleanup and improvements made to the TimeSafari Electron implementation. The changes resolve platform detection issues, improve build consistency, and provide a clear architecture for desktop development.
|
||||
|
||||
## Key Issues Resolved
|
||||
|
||||
### 1. Platform Detection Problems
|
||||
- **Before**: `PlatformServiceFactory` only supported "capacitor" and "web" platforms
|
||||
- **After**: Added proper "electron" platform support with dedicated `ElectronPlatformService`
|
||||
|
||||
### 2. Build Configuration Confusion
|
||||
- **Before**: Electron builds used `VITE_PLATFORM=capacitor`, causing confusion
|
||||
- **After**: Electron builds now properly use `VITE_PLATFORM=electron`
|
||||
|
||||
### 3. Missing Platform Service Methods
|
||||
- **Before**: Platform services lacked proper `isElectron()`, `isCapacitor()`, `isWeb()` methods
|
||||
- **After**: All platform services implement complete interface with proper detection
|
||||
|
||||
### 4. Inconsistent Build Scripts
|
||||
- **Before**: Mixed platform settings in build scripts
|
||||
- **After**: Clean, consistent electron-specific build process
|
||||
|
||||
## Architecture Changes
|
||||
|
||||
### Platform Service Factory Enhancement
|
||||
|
||||
```typescript
|
||||
// src/services/PlatformServiceFactory.ts
|
||||
export class PlatformServiceFactory {
|
||||
public static getInstance(): PlatformService {
|
||||
const platform = process.env.VITE_PLATFORM || "web";
|
||||
|
||||
switch (platform) {
|
||||
case "capacitor":
|
||||
return new CapacitorPlatformService();
|
||||
case "electron":
|
||||
return new ElectronPlatformService(); // NEW
|
||||
case "web":
|
||||
default:
|
||||
return new WebPlatformService();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### New ElectronPlatformService
|
||||
|
||||
- Extends `CapacitorPlatformService` for SQLite compatibility
|
||||
- Overrides capabilities for desktop-specific features
|
||||
- Provides proper platform detection methods
|
||||
|
||||
```typescript
|
||||
class ElectronPlatformService extends CapacitorPlatformService {
|
||||
getCapabilities() {
|
||||
return {
|
||||
hasFileSystem: true,
|
||||
hasCamera: false, // Desktop typically doesn't have integrated cameras
|
||||
isMobile: false, // Electron is desktop, not mobile
|
||||
isIOS: false,
|
||||
hasFileDownload: true, // Desktop supports direct file downloads
|
||||
needsFileHandlingInstructions: false, // Desktop users familiar with file handling
|
||||
isNativeApp: true,
|
||||
};
|
||||
}
|
||||
|
||||
isElectron(): boolean { return true; }
|
||||
isCapacitor(): boolean { return false; }
|
||||
isWeb(): boolean { return false; }
|
||||
}
|
||||
```
|
||||
|
||||
### Enhanced Platform Service Interface
|
||||
|
||||
```typescript
|
||||
// src/services/PlatformService.ts
|
||||
export interface PlatformService {
|
||||
// Platform detection methods
|
||||
isCapacitor(): boolean;
|
||||
isElectron(): boolean;
|
||||
isWeb(): boolean;
|
||||
|
||||
// ... existing methods
|
||||
}
|
||||
```
|
||||
|
||||
## Build System Improvements
|
||||
|
||||
### New Electron Vite Configuration
|
||||
|
||||
- Created `vite.config.electron.mts` for electron-specific builds
|
||||
- Proper platform environment variables
|
||||
- Desktop-optimized build settings
|
||||
- Electron-specific entry point handling
|
||||
|
||||
```bash
|
||||
# Before
|
||||
npm run build:capacitor # Used for electron builds (confusing)
|
||||
|
||||
# After
|
||||
npm run build:electron # Dedicated electron build
|
||||
```
|
||||
|
||||
### Updated Build Scripts
|
||||
|
||||
- `package.json`: Updated electron scripts to use proper electron build
|
||||
- `scripts/common.sh`: Fixed electron environment setup
|
||||
- `scripts/build-electron.sh`: Updated to use electron build instead of capacitor
|
||||
- `scripts/electron-dev.sh`: Updated for proper electron development workflow
|
||||
|
||||
### Electron-Specific Entry Point
|
||||
|
||||
- Created `src/main.electron.ts` for electron-specific initialization
|
||||
- Automatic entry point replacement in vite builds
|
||||
- Electron-specific logging and error handling
|
||||
|
||||
## Configuration Updates
|
||||
|
||||
### Vite Configuration
|
||||
|
||||
```typescript
|
||||
// vite.config.electron.mts
|
||||
export default defineConfig(async () => {
|
||||
const baseConfig = await createBuildConfig("electron");
|
||||
|
||||
return {
|
||||
...baseConfig,
|
||||
plugins: [
|
||||
// Plugin to replace main entry point for electron builds
|
||||
{
|
||||
name: 'electron-entry-point',
|
||||
transformIndexHtml(html) {
|
||||
return html.replace('/src/main.web.ts', '/src/main.electron.ts');
|
||||
}
|
||||
}
|
||||
],
|
||||
define: {
|
||||
'process.env.VITE_PLATFORM': JSON.stringify('electron'),
|
||||
'__ELECTRON__': JSON.stringify(true),
|
||||
'__IS_DESKTOP__': JSON.stringify(true),
|
||||
// ... other electron-specific flags
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
### Common Configuration Updates
|
||||
|
||||
```typescript
|
||||
// vite.config.common.mts
|
||||
const isElectron = mode === "electron";
|
||||
const isNative = isCapacitor || isElectron;
|
||||
|
||||
// Updated environment variables and build settings for electron support
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Development Workflow
|
||||
|
||||
```bash
|
||||
# Setup electron environment (first time only)
|
||||
npm run electron:setup
|
||||
|
||||
# Development build and run
|
||||
npm run electron:dev
|
||||
|
||||
# Alternative development workflow
|
||||
npm run electron:dev-full
|
||||
```
|
||||
|
||||
### Production Builds
|
||||
|
||||
```bash
|
||||
# Build web assets for electron
|
||||
npm run build:electron
|
||||
|
||||
# Build and package electron app
|
||||
npm run electron:build
|
||||
|
||||
# Build specific package types
|
||||
npm run electron:build:appimage
|
||||
npm run electron:build:deb
|
||||
|
||||
# Using the comprehensive build script
|
||||
npm run build:electron:all
|
||||
```
|
||||
|
||||
### Platform Detection in Code
|
||||
|
||||
```typescript
|
||||
import { PlatformServiceFactory } from '@/services/PlatformServiceFactory';
|
||||
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
|
||||
if (platformService.isElectron()) {
|
||||
// Desktop-specific logic
|
||||
console.log('Running on Electron desktop');
|
||||
} else if (platformService.isCapacitor()) {
|
||||
// Mobile-specific logic
|
||||
console.log('Running on mobile device');
|
||||
} else if (platformService.isWeb()) {
|
||||
// Web-specific logic
|
||||
console.log('Running in web browser');
|
||||
}
|
||||
|
||||
// Or check capabilities
|
||||
const capabilities = platformService.getCapabilities();
|
||||
if (capabilities.hasFileDownload) {
|
||||
// Enable direct file downloads (available on desktop)
|
||||
}
|
||||
```
|
||||
|
||||
## File Structure Changes
|
||||
|
||||
### New Files
|
||||
- `vite.config.electron.mts` - Electron-specific Vite configuration
|
||||
- `src/main.electron.ts` - Electron main entry point
|
||||
- `doc/electron-cleanup-summary.md` - This documentation
|
||||
|
||||
### Modified Files
|
||||
- `src/services/PlatformServiceFactory.ts` - Added electron platform support
|
||||
- `src/services/PlatformService.ts` - Added platform detection methods
|
||||
- `src/services/platforms/CapacitorPlatformService.ts` - Added missing interface methods
|
||||
- `vite.config.common.mts` - Enhanced electron support
|
||||
- `package.json` - Updated electron build scripts
|
||||
- `scripts/common.sh` - Fixed electron environment setup
|
||||
- `scripts/build-electron.sh` - Updated for electron builds
|
||||
- `scripts/electron-dev.sh` - Updated development workflow
|
||||
- `experiment.sh` - Updated for electron builds
|
||||
|
||||
## Testing
|
||||
|
||||
### Platform Detection Testing
|
||||
|
||||
```bash
|
||||
# Test web platform
|
||||
npm run dev
|
||||
|
||||
# Test electron platform
|
||||
npm run electron:dev
|
||||
|
||||
# Verify platform detection in console logs
|
||||
```
|
||||
|
||||
### Build Testing
|
||||
|
||||
```bash
|
||||
# Test electron build
|
||||
npm run build:electron
|
||||
|
||||
# Test electron packaging
|
||||
npm run electron:build:appimage
|
||||
|
||||
# Verify platform-specific features work correctly
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Clear Platform Separation**: Each platform has dedicated configuration and services
|
||||
2. **Consistent Build Process**: No more mixing capacitor/electron configurations
|
||||
3. **Better Developer Experience**: Clear commands and proper logging
|
||||
4. **Type Safety**: Complete interface implementation across all platforms
|
||||
5. **Desktop Optimization**: Electron builds optimized for desktop usage patterns
|
||||
6. **Maintainability**: Clean architecture makes future updates easier
|
||||
|
||||
## Migration Guide
|
||||
|
||||
For developers working with the previous implementation:
|
||||
|
||||
1. **Update Build Commands**:
|
||||
- Replace `npm run build:capacitor` with `npm run build:electron` for electron builds
|
||||
- Use `npm run electron:dev` for development
|
||||
|
||||
2. **Platform Detection**:
|
||||
- Use `platformService.isElectron()` instead of checking environment variables
|
||||
- Leverage the `getCapabilities()` method for feature detection
|
||||
|
||||
3. **Configuration**:
|
||||
- Electron-specific settings are now in `vite.config.electron.mts`
|
||||
- Environment variables are automatically set correctly
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Platform detection is based on build-time environment variables
|
||||
- No runtime platform detection that could be spoofed
|
||||
- Electron-specific security settings in vite configuration
|
||||
- Proper isolation between platform implementations
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- Electron builds exclude web-specific dependencies (PWA, service workers)
|
||||
- Desktop-optimized chunk sizes and module bundling
|
||||
- Faster build times due to reduced bundle size
|
||||
- Better runtime performance on desktop
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Add Electron-specific IPC communication helpers
|
||||
- [ ] Implement desktop-specific UI components
|
||||
- [ ] Add Electron auto-updater integration
|
||||
- [ ] Create platform-specific testing utilities
|
||||
- [ ] Add desktop notification system integration
|
||||
@@ -1,188 +0,0 @@
|
||||
# Electron Console Cleanup Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This document summarizes the comprehensive changes made to reduce excessive console logging in the TimeSafari Electron application. The cleanup focused on reducing database operation noise, API configuration issues, and platform-specific logging while maintaining error visibility.
|
||||
|
||||
## Issues Addressed
|
||||
|
||||
### 1. Excessive Database Logging (Major Issue - 90% Reduction)
|
||||
**Problem:** Every database operation was logging detailed parameter information, creating hundreds of lines of console output.
|
||||
|
||||
**Solution:** Modified `src/services/platforms/CapacitorPlatformService.ts`:
|
||||
- Changed `logger.warn` to `logger.debug` for routine SQL operations
|
||||
- Reduced migration logging verbosity
|
||||
- Made database integrity checks use debug-level logging
|
||||
- Kept error and completion messages at appropriate log levels
|
||||
|
||||
### 2. Enhanced Logger Configuration
|
||||
**Problem:** No platform-specific logging controls, causing noise in Electron.
|
||||
|
||||
**Solution:** Updated `src/utils/logger.ts`:
|
||||
- Added platform detection for Electron vs Web
|
||||
- Suppressed debug and verbose logs for Electron
|
||||
- Filtered out routine database operations from database logging
|
||||
- Maintained error and warning visibility
|
||||
- Added intelligent filtering for CapacitorPlatformService messages
|
||||
|
||||
### 3. API Configuration Issues (Major Fix)
|
||||
**Problem:** Electron was trying to use local development endpoints (localhost:3000) from saved user settings, which don't exist in desktop environment, causing:
|
||||
- 400 status errors from missing local development servers
|
||||
- JSON parsing errors (HTML error pages instead of JSON responses)
|
||||
|
||||
**Solution:**
|
||||
- Updated `src/constants/app.ts` to provide Electron-specific API endpoints
|
||||
- **Critical Fix:** Modified `src/db/databaseUtil.ts` in `retrieveSettingsForActiveAccount()` to force Electron to use production API endpoints regardless of saved user settings
|
||||
- This ensures Electron never uses localhost development servers that users might have saved
|
||||
|
||||
### 4. SharedArrayBuffer Logging Noise
|
||||
**Problem:** Web-specific SharedArrayBuffer detection was running in Electron, creating unnecessary debug output.
|
||||
|
||||
**Solution:** Modified `src/main.web.ts`:
|
||||
- Made SharedArrayBuffer logging conditional on web platform only
|
||||
- Converted console.log statements to logger.debug
|
||||
- Only show in development mode for web platform
|
||||
- Reduced platform detection noise
|
||||
|
||||
### 5. Missing Source Maps Warnings
|
||||
**Problem:** Electron DevTools was complaining about missing source maps for external dependencies.
|
||||
|
||||
**Solution:** Updated `vite.config.electron.mts`:
|
||||
- Disabled source maps for Electron builds (`sourcemap: false`)
|
||||
- Added build configuration to suppress external dependency warnings
|
||||
- Prevents DevTools from looking for non-existent source map files
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **src/services/platforms/CapacitorPlatformService.ts**
|
||||
- Reduced database operation logging verbosity
|
||||
- Changed routine operations from `logger.warn` to `logger.debug`
|
||||
- Reduced migration and integrity check logging
|
||||
|
||||
2. **src/utils/logger.ts**
|
||||
- Added platform-specific logging controls
|
||||
- Suppressed verbose logging for Electron
|
||||
- Filtered database operations from logs
|
||||
- Enhanced log level management
|
||||
|
||||
3. **src/constants/app.ts**
|
||||
- Fixed API endpoints for Electron platform
|
||||
- Prevented localhost API connection errors
|
||||
- Configured proper production endpoints
|
||||
|
||||
4. **src/db/databaseUtil.ts** (Critical Fix)
|
||||
- Added Electron-specific logic in `retrieveSettingsForActiveAccount()`
|
||||
- Forces Electron to use production API endpoints regardless of saved settings
|
||||
- Prevents localhost development server connection attempts
|
||||
|
||||
5. **src/main.web.ts**
|
||||
- Reduced SharedArrayBuffer logging noise
|
||||
- Made logging conditional on platform
|
||||
- Converted console statements to logger calls
|
||||
|
||||
6. **vite.config.electron.mts**
|
||||
- Disabled source maps for Electron builds
|
||||
- Added configuration to suppress external dependency warnings
|
||||
- Configured build-time warning suppression
|
||||
|
||||
## Impact
|
||||
|
||||
### Before Cleanup:
|
||||
- 500+ lines of console output per minute
|
||||
- Detailed SQL parameter logging for every operation
|
||||
- API connection errors every few seconds (400 status, JSON parsing errors)
|
||||
- SharedArrayBuffer warnings on every startup
|
||||
- DevTools source map warnings
|
||||
|
||||
### After Cleanup:
|
||||
- **~95% reduction** in console output
|
||||
- Only errors and important status messages visible
|
||||
- **No API connection errors** - Electron uses proper production endpoints
|
||||
- **No JSON parsing errors** - API returns valid JSON responses
|
||||
- Minimal startup logging
|
||||
- Clean DevTools console
|
||||
- Preserved all error handling and functionality
|
||||
|
||||
## Technical Details
|
||||
|
||||
### API Configuration Fix
|
||||
The most critical fix was in `src/db/databaseUtil.ts` where we added:
|
||||
|
||||
```typescript
|
||||
// **ELECTRON-SPECIFIC FIX**: Force production API endpoints for Electron
|
||||
if (process.env.VITE_PLATFORM === "electron") {
|
||||
const { DEFAULT_ENDORSER_API_SERVER } = await import("../constants/app");
|
||||
settings = {
|
||||
...settings,
|
||||
apiServer: DEFAULT_ENDORSER_API_SERVER,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
This ensures that even if users have localhost development endpoints saved in their settings, Electron will override them with production endpoints.
|
||||
|
||||
### Logger Enhancement
|
||||
Enhanced the logger with platform-specific behavior:
|
||||
|
||||
```typescript
|
||||
const isElectron = process.env.VITE_PLATFORM === "electron";
|
||||
// Suppress verbose logging for Electron while preserving errors
|
||||
if (!isElectron || !message.includes("[CapacitorPlatformService]")) {
|
||||
console.warn(message, ...args);
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
The changes were tested with:
|
||||
- `npm run lint-fix` - 0 errors, warnings only (pre-existing)
|
||||
- Electron development environment
|
||||
- Web platform (unchanged functionality)
|
||||
- All platform detection working correctly
|
||||
|
||||
## Future Improvements
|
||||
|
||||
1. **Conditional Compilation**: Consider using build-time flags to completely remove debug statements in production builds
|
||||
2. **Structured Logging**: Implement structured logging with log levels and categories
|
||||
3. **Log Rotation**: Add log file rotation for long-running Electron sessions
|
||||
4. **Performance Monitoring**: Add performance logging for database operations in debug builds only
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
All changes maintain backward compatibility:
|
||||
- Web platform logging unchanged
|
||||
- Capacitor platform logging unchanged
|
||||
- Error handling preserved
|
||||
- API functionality preserved
|
||||
- Database operations unchanged
|
||||
|
||||
## Security Audit
|
||||
|
||||
✅ **No security implications** - Changes only affect logging verbosity and API endpoint selection
|
||||
✅ **No data exposure** - Actually reduces data logging
|
||||
✅ **Improved security** - Forces production API endpoints instead of potentially insecure localhost
|
||||
✅ **No authentication changes** - Platform detection only
|
||||
✅ **No database changes** - Only logging changes
|
||||
|
||||
## Git Commit Message
|
||||
|
||||
```
|
||||
feat: eliminate console noise in Electron builds
|
||||
|
||||
- Suppress excessive database operation logging (95% reduction)
|
||||
- Fix API configuration to force production endpoints for Electron
|
||||
- Prevent JSON parsing errors from localhost development servers
|
||||
- Reduce SharedArrayBuffer detection noise
|
||||
- Disable source maps for cleaner DevTools
|
||||
- Add platform-specific logger configuration
|
||||
|
||||
Resolves database console spam, API connection errors, and JSON parsing issues
|
||||
Tests: lint passes, Web/Capacitor functionality preserved
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Test the fixes** - Run `npm run electron:dev` to verify console noise is eliminated
|
||||
2. **Monitor for remaining issues** - Check for any other console noise sources
|
||||
3. **Performance monitoring** - Verify the reduced logging doesn't impact functionality
|
||||
4. **Documentation updates** - Update any development guides that reference the old logging behavior
|
||||
@@ -1,83 +0,0 @@
|
||||
# Error Diagnostics Log
|
||||
|
||||
This file tracks console errors observed during development for future investigation.
|
||||
|
||||
## 2025-07-07 08:56 UTC - ProjectsView.vue Migration Session
|
||||
|
||||
### Migration Context
|
||||
- **Current Work**: Completed ProjectsView.vue Triple Migration Pattern
|
||||
- **Migration Status**: 21 complete, 4 appropriately incomplete components
|
||||
- **Recent Changes**:
|
||||
- ProjectsView.vue: databaseUtil → PlatformServiceMixin
|
||||
- Added notification constants and literal string extraction
|
||||
- Template logic streamlining with computed properties
|
||||
|
||||
### Observed Errors
|
||||
|
||||
#### 1. HomeView.vue API Rate Limit Errors
|
||||
```
|
||||
GET https://api.endorser.ch/api/report/rateLimits 400 (Bad Request)
|
||||
Source: endorserServer.ts:1494, HomeView.vue:593, HomeView.vue:742
|
||||
```
|
||||
|
||||
**Analysis**:
|
||||
- API server returning 400 for rate limit checks
|
||||
- Occurs during identity initialization and registration status checks
|
||||
- **Migration Impact**: None - HomeView.vue was migrated and tested earlier
|
||||
- **Likely Cause**: Server-side authentication or API configuration issue
|
||||
|
||||
**Action Items**:
|
||||
- [ ] Check endorser.ch API documentation for rate limit endpoint changes
|
||||
- [ ] Verify authentication headers being sent correctly
|
||||
- [ ] Consider fallback handling for rate limit API failures
|
||||
|
||||
#### 2. ProjectViewView.vue Project Not Found Error
|
||||
```
|
||||
GET https://api.endorser.ch/api/claim/byHandle/...01JY2Q5D90E8P267ABB963S71D 404 (Not Found)
|
||||
Source: ProjectViewView.vue:830 loadProject() method
|
||||
```
|
||||
|
||||
**Analysis**:
|
||||
- Attempting to load project ID: `01JY2Q5D90E8P267ABB963S71D`
|
||||
- **Migration Impact**: None - error handling working correctly
|
||||
- **Likely Cause**: User navigated to non-existent project or stale link
|
||||
|
||||
**Action Items**:
|
||||
- [ ] Consider adding better user messaging for missing projects
|
||||
- [ ] Investigate if project IDs are being generated/stored correctly
|
||||
- [ ] Add breadcrumb or "return to projects" option on 404s
|
||||
|
||||
#### 3. Axios Request Stack Traces
|
||||
Multiple stack traces showing Vue router navigation and component mounting cycles.
|
||||
|
||||
**Analysis**:
|
||||
- Normal Vue.js lifecycle and routing behavior
|
||||
- No obvious memory leaks or infinite loops
|
||||
- **Migration Impact**: None - expected framework behavior
|
||||
|
||||
### System Health Indicators
|
||||
|
||||
#### ✅ Working Correctly
|
||||
- Database migrations: `Migration process complete! Summary: 0 applied, 2 skipped`
|
||||
- Platform service factory initialization: `Creating singleton instance for platform: development`
|
||||
- SQL worker loading: `Worker loaded, ready to receive messages`
|
||||
- Database connection: `Opened!`
|
||||
|
||||
#### 🔄 For Investigation
|
||||
- API authentication/authorization with endorser.ch
|
||||
- Project ID validation and error handling
|
||||
- Rate limiting strategy
|
||||
|
||||
### Migration Validation
|
||||
- **ProjectsView.vue**: Appropriately incomplete (3 helpers + 1 complex modal)
|
||||
- **Error Handling**: Migrated components showing proper error handling
|
||||
- **No Migration-Related Errors**: All errors appear to be infrastructure/data issues
|
||||
|
||||
### Next Steps
|
||||
1. Continue migration slog with next component
|
||||
2. Monitor these same error patterns in future sessions
|
||||
3. Address API/server issues in separate debugging session
|
||||
|
||||
---
|
||||
*Log Entry by: Migration Assistant*
|
||||
*Session: ProjectsView.vue Triple Migration Pattern*
|
||||
@@ -1,180 +0,0 @@
|
||||
# Image Hosting Guide for Cross-Origin Isolated Environment
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### ✅ Supported Image Sources (Work in Development)
|
||||
|
||||
| Service | Proxy Endpoint | Example URL |
|
||||
|---------|---------------|-------------|
|
||||
| TimeSafari | `/image-proxy/` | `https://image.timesafari.app/abc123.jpg` |
|
||||
| Flickr | `/flickr-proxy/` | `https://live.staticflickr.com/123/456.jpg` |
|
||||
| Imgur | `/imgur-proxy/` | `https://i.imgur.com/example.jpg` |
|
||||
| GitHub Raw | `/github-proxy/` | `https://raw.githubusercontent.com/user/repo/main/image.png` |
|
||||
| Unsplash | `/unsplash-proxy/` | `https://images.unsplash.com/photo-123456` |
|
||||
| Facebook | `/facebook-proxy/` | `https://www.facebook.com/images/groups/...` |
|
||||
| Medium | `/medium-proxy/` | `https://miro.medium.com/v2/resize:fit:180/...` |
|
||||
| Meetup | `/meetup-proxy/` | `https://secure.meetupstatic.com/photos/...` |
|
||||
|
||||
### ⚠️ Problematic Image Sources (May Not Work in Development)
|
||||
|
||||
- Random external websites without CORS headers
|
||||
- WordPress uploads from arbitrary domains
|
||||
- Custom CDNs without proper CORS configuration
|
||||
- Any service that doesn't send `Cross-Origin-Resource-Policy: cross-origin`
|
||||
|
||||
## Why This Happens
|
||||
|
||||
In development mode, we enable SharedArrayBuffer for fast SQLite operations, which requires:
|
||||
- `Cross-Origin-Opener-Policy: same-origin`
|
||||
- `Cross-Origin-Embedder-Policy: require-corp`
|
||||
|
||||
These headers create a **cross-origin isolated environment** that blocks resources unless they have proper CORS headers.
|
||||
|
||||
## Solutions
|
||||
|
||||
### 1. Use Supported Image Hosting Services
|
||||
|
||||
**Recommended services that work well:**
|
||||
- **Imgur**: Free, no registration required, direct links
|
||||
- **GitHub**: If you have images in repositories
|
||||
- **Unsplash**: For stock photos
|
||||
- **TimeSafari Image Server**: For app-specific images
|
||||
|
||||
### 2. Add New Image Hosting Proxies
|
||||
|
||||
If you frequently use images from a specific domain, add a proxy:
|
||||
|
||||
#### Step 1: Add Proxy to `vite.config.common.mts`
|
||||
```typescript
|
||||
'/yourservice-proxy': {
|
||||
target: 'https://yourservice.com',
|
||||
changeOrigin: true,
|
||||
secure: true,
|
||||
followRedirects: true,
|
||||
rewrite: (path) => path.replace(/^\/yourservice-proxy/, ''),
|
||||
configure: (proxy) => {
|
||||
proxy.on('proxyRes', (proxyRes, req, res) => {
|
||||
proxyRes.headers['Access-Control-Allow-Origin'] = '*';
|
||||
proxyRes.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS';
|
||||
proxyRes.headers['Cross-Origin-Resource-Policy'] = 'cross-origin';
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 2: Update Transform Function in `src/libs/util.ts`
|
||||
```typescript
|
||||
// Transform YourService URLs to use proxy
|
||||
if (imageUrl.startsWith("https://yourservice.com/")) {
|
||||
const imagePath = imageUrl.replace("https://yourservice.com/", "");
|
||||
return `/yourservice-proxy/${imagePath}`;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use Alternative Image Sources
|
||||
|
||||
For frequently failing domains, consider:
|
||||
- Upload images to Imgur or GitHub
|
||||
- Use a CDN with proper CORS headers
|
||||
- Host images on your own domain with CORS enabled
|
||||
|
||||
## Development vs Production
|
||||
|
||||
### Development Mode
|
||||
- Images from supported services work through proxies
|
||||
- Unsupported images may fail to load
|
||||
- Console warnings show which images have issues
|
||||
|
||||
### Production Mode
|
||||
- All images load directly without proxies
|
||||
- No CORS restrictions in production
|
||||
- Better performance without proxy overhead
|
||||
|
||||
## Testing Image Sources
|
||||
|
||||
### Check if an Image Source Works
|
||||
```bash
|
||||
# Test in browser console:
|
||||
fetch('https://example.com/image.jpg', { mode: 'cors' })
|
||||
.then(response => console.log('✅ Works:', response.status))
|
||||
.catch(error => console.log('❌ Blocked:', error));
|
||||
```
|
||||
|
||||
### Visual Testing
|
||||
```typescript
|
||||
import { createTestImageElements } from './libs/test-cors-images';
|
||||
createTestImageElements(); // Creates visual test panel
|
||||
```
|
||||
|
||||
## Common Error Messages
|
||||
|
||||
### `ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep`
|
||||
**Cause**: Image source doesn't send required CORS headers
|
||||
**Solution**: Use a supported image hosting service or add a proxy
|
||||
|
||||
### `ERR_NETWORK` or `ERR_INTERNET_DISCONNECTED`
|
||||
**Cause**: Proxy service is unavailable
|
||||
**Solution**: Check internet connection or use alternative image source
|
||||
|
||||
### Images Load in Production but Not Development
|
||||
**Cause**: Normal behavior - development has stricter CORS requirements
|
||||
**Solution**: Use supported image sources for development testing
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For New Projects
|
||||
1. Use supported image hosting services from the start
|
||||
2. Upload user images to Imgur or similar service
|
||||
3. Host critical images on your own domain with CORS enabled
|
||||
|
||||
### For Existing Projects
|
||||
1. Identify frequently used image domains in console warnings
|
||||
2. Add proxies for the most common domains
|
||||
3. Gradually migrate to supported image hosting services
|
||||
|
||||
### For User-Generated Content
|
||||
1. Provide upload functionality to supported services
|
||||
2. Validate image URLs against supported domains
|
||||
3. Show helpful error messages for unsupported sources
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Image Not Loading?
|
||||
1. Check browser console for error messages
|
||||
2. Verify the domain is in the supported list
|
||||
3. Test if the image loads in production mode
|
||||
4. Consider adding a proxy for that domain
|
||||
|
||||
### Proxy Not Working?
|
||||
1. Check if the target service allows proxying
|
||||
2. Verify CORS headers are being set correctly
|
||||
3. Test with a simpler image URL from the same domain
|
||||
|
||||
### Performance Issues?
|
||||
1. Proxies add latency in development only
|
||||
2. Production uses direct image loading
|
||||
3. Consider using a local image cache for development
|
||||
|
||||
## Quick Fixes
|
||||
|
||||
### For Immediate Issues
|
||||
```typescript
|
||||
// Temporary fallback: disable CORS headers for testing
|
||||
// In vite.config.common.mts, comment out:
|
||||
// headers: {
|
||||
// 'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
// 'Cross-Origin-Embedder-Policy': 'require-corp'
|
||||
// },
|
||||
```
|
||||
**Note**: This disables SharedArrayBuffer performance benefits.
|
||||
|
||||
### For Long-term Solution
|
||||
- Use supported image hosting services
|
||||
- Add proxies for frequently used domains
|
||||
- Migrate critical images to your own CORS-enabled CDN
|
||||
|
||||
## Summary
|
||||
|
||||
The cross-origin isolated environment is necessary for SharedArrayBuffer performance but requires careful image source management. Use the supported services, add proxies for common domains, and accept that some external images may not work in development mode.
|
||||
|
||||
This is a development-only limitation - production deployments work with any image source.
|
||||
@@ -4,14 +4,11 @@
|
||||
|
||||
This document defines the **migration fence** - the boundary between the legacy Dexie (IndexedDB) storage system and the new SQLite-based storage system in TimeSafari. The fence ensures controlled migration while maintaining data integrity and application stability.
|
||||
|
||||
**⚠️ UPDATE**: The migration fence is now implemented through the **PlatformServiceMixin** rather than a `USE_DEXIE_DB` constant. This provides a cleaner, more maintainable approach to database access control.
|
||||
|
||||
## Current Migration Status
|
||||
|
||||
### ✅ Completed Components
|
||||
- **SQLite Database Service**: Fully implemented with absurd-sql
|
||||
- **Platform Service Layer**: Unified database interface across platforms
|
||||
- **PlatformServiceMixin**: Centralized database access with caching and utilities
|
||||
- **Migration Tools**: Data comparison and transfer utilities
|
||||
- **Schema Migration**: Complete table structure migration
|
||||
- **Data Export/Import**: Backup and restore functionality
|
||||
@@ -20,7 +17,6 @@ This document defines the **migration fence** - the boundary between the legacy
|
||||
- **Settings Migration**: Core user settings transferred
|
||||
- **Account Migration**: Identity and key management
|
||||
- **Contact Migration**: User contact data (via import interface)
|
||||
- **DatabaseUtil Migration**: Moving functions to PlatformServiceMixin
|
||||
|
||||
### ❌ Legacy Components (Fence Boundary)
|
||||
- **Dexie Database**: Legacy IndexedDB storage (disabled by default)
|
||||
@@ -29,27 +25,22 @@ This document defines the **migration fence** - the boundary between the legacy
|
||||
|
||||
## Migration Fence Definition
|
||||
|
||||
### 1. PlatformServiceMixin Boundary
|
||||
### 1. Configuration Boundary
|
||||
|
||||
```typescript
|
||||
// src/utils/PlatformServiceMixin.ts
|
||||
export const PlatformServiceMixin = {
|
||||
computed: {
|
||||
platformService(): PlatformService {
|
||||
// FENCE: All database operations go through platform service
|
||||
// No direct Dexie access outside migration tools
|
||||
return PlatformServiceFactory.getInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
// src/constants/app.ts
|
||||
export const USE_DEXIE_DB = false; // FENCE: Controls legacy database access
|
||||
```
|
||||
|
||||
**Fence Rule**: All database operations must use:
|
||||
- `this.$db()` for read operations
|
||||
- `this.$exec()` for write operations
|
||||
- `this.$settings()` for settings access
|
||||
- `this.$contacts()` for contact access
|
||||
- No direct `db.` or `accountsDBPromise` access in application code
|
||||
**Fence Rule**: When `USE_DEXIE_DB = false`:
|
||||
- All new data operations use SQLite
|
||||
- Legacy Dexie database is not initialized
|
||||
- Migration tools are the only path to legacy data
|
||||
|
||||
**Fence Rule**: When `USE_DEXIE_DB = true`:
|
||||
- Legacy database is available for migration
|
||||
- Dual-write operations may be enabled
|
||||
- Migration tools can access both databases
|
||||
|
||||
### 2. Service Layer Boundary
|
||||
|
||||
@@ -72,10 +63,12 @@ export class PlatformServiceFactory {
|
||||
|
||||
#### ✅ Allowed (Inside Fence)
|
||||
```typescript
|
||||
// Use PlatformServiceMixin for all database operations
|
||||
const contacts = await this.$contacts();
|
||||
const settings = await this.$settings();
|
||||
const result = await this.$db("SELECT * FROM contacts WHERE did = ?", [accountDid]);
|
||||
// Use platform service for all database operations
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const contacts = await platformService.dbQuery(
|
||||
"SELECT * FROM contacts WHERE did = ?",
|
||||
[accountDid]
|
||||
);
|
||||
```
|
||||
|
||||
#### ❌ Forbidden (Outside Fence)
|
||||
@@ -107,9 +100,9 @@ export async function compareDatabases(): Promise<DataComparison> {
|
||||
### 1. Code Development Rules
|
||||
|
||||
#### New Feature Development
|
||||
- **Always** use `PlatformServiceMixin` for database operations
|
||||
- **Always** use `PlatformService` for database operations
|
||||
- **Never** import or reference Dexie directly
|
||||
- **Always** use mixin methods like `this.$settings()`, `this.$contacts()`
|
||||
- **Always** test with `USE_DEXIE_DB = false`
|
||||
|
||||
#### Legacy Code Maintenance
|
||||
- **Only** modify Dexie code for migration purposes
|
||||
@@ -135,10 +128,11 @@ export async function compareDatabases(): Promise<DataComparison> {
|
||||
// Required test pattern for migration
|
||||
describe('Database Migration', () => {
|
||||
it('should migrate data without loss', async () => {
|
||||
// 1. Create test data in Dexie
|
||||
// 2. Run migration
|
||||
// 3. Verify data integrity in SQLite
|
||||
// 4. Verify PlatformServiceMixin access
|
||||
// 1. Enable Dexie
|
||||
// 2. Create test data
|
||||
// 3. Run migration
|
||||
// 4. Verify data integrity
|
||||
// 5. Disable Dexie
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -147,9 +141,9 @@ describe('Database Migration', () => {
|
||||
```typescript
|
||||
// Required test pattern for application features
|
||||
describe('Feature with Database', () => {
|
||||
it('should work with PlatformServiceMixin', async () => {
|
||||
// Test with PlatformServiceMixin methods
|
||||
// Verify all operations use mixin methods
|
||||
it('should work with SQLite only', async () => {
|
||||
// Test with USE_DEXIE_DB = false
|
||||
// Verify all operations use PlatformService
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -168,7 +162,7 @@ describe('Feature with Database', () => {
|
||||
"patterns": [
|
||||
{
|
||||
"group": ["../db/index"],
|
||||
"message": "Use PlatformServiceMixin instead of direct Dexie access"
|
||||
"message": "Use PlatformService instead of direct Dexie access"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -192,52 +186,87 @@ describe('Feature with Database', () => {
|
||||
#### Development Mode Validation
|
||||
```typescript
|
||||
// Development-only fence validation
|
||||
if (import.meta.env.DEV) {
|
||||
console.warn('⚠️ Using PlatformServiceMixin for all database operations');
|
||||
if (import.meta.env.DEV && USE_DEXIE_DB) {
|
||||
console.warn('⚠️ Dexie is enabled - migration mode active');
|
||||
}
|
||||
```
|
||||
|
||||
#### Production Safety
|
||||
```typescript
|
||||
// Production fence enforcement
|
||||
if (import.meta.env.PROD) {
|
||||
// All database operations must go through PlatformServiceMixin
|
||||
// Direct Dexie access is not allowed
|
||||
if (import.meta.env.PROD && USE_DEXIE_DB) {
|
||||
throw new Error('Dexie cannot be enabled in production');
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Status Checklist
|
||||
## Migration Fence Timeline
|
||||
|
||||
### ✅ Completed
|
||||
- [x] PlatformServiceMixin implementation
|
||||
- [x] SQLite database service
|
||||
- [x] Migration tools
|
||||
- [x] Settings migration
|
||||
- [x] Account migration
|
||||
- [x] ActiveDid migration
|
||||
### Phase 1: Fence Establishment ✅
|
||||
- [x] Define migration fence boundaries
|
||||
- [x] Implement PlatformService layer
|
||||
- [x] Create migration tools
|
||||
- [x] Set `USE_DEXIE_DB = false` by default
|
||||
|
||||
### 🔄 In Progress
|
||||
- [ ] Contact migration
|
||||
- [ ] DatabaseUtil to PlatformServiceMixin migration
|
||||
- [ ] File-by-file migration
|
||||
### Phase 2: Data Migration 🔄
|
||||
- [x] Migrate core settings
|
||||
- [x] Migrate account data
|
||||
- [ ] Complete contact migration
|
||||
- [ ] Verify all data integrity
|
||||
|
||||
### ❌ Not Started
|
||||
- [ ] Legacy Dexie removal
|
||||
- [ ] Final cleanup and validation
|
||||
### Phase 3: Code Cleanup 📋
|
||||
- [ ] Remove unused Dexie imports
|
||||
- [ ] Clean up legacy database code
|
||||
- [ ] Update all documentation
|
||||
- [ ] Remove migration tools
|
||||
|
||||
## Benefits of PlatformServiceMixin Approach
|
||||
### Phase 4: Fence Removal 🎯
|
||||
- [ ] Remove `USE_DEXIE_DB` constant
|
||||
- [ ] Remove Dexie dependencies
|
||||
- [ ] Remove migration service
|
||||
- [ ] Finalize SQLite-only architecture
|
||||
|
||||
1. **Centralized Access**: Single point of control for all database operations
|
||||
2. **Caching**: Built-in caching for performance optimization
|
||||
3. **Type Safety**: Enhanced TypeScript integration
|
||||
4. **Error Handling**: Consistent error handling across components
|
||||
5. **Code Reduction**: Up to 80% reduction in database boilerplate
|
||||
6. **Maintainability**: Single source of truth for database patterns
|
||||
## Security Considerations
|
||||
|
||||
---
|
||||
### 1. Data Protection
|
||||
- **Encryption**: Maintain encryption standards across migration
|
||||
- **Access Control**: Preserve user privacy during migration
|
||||
- **Audit Trail**: Log all migration operations
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Created**: 2025-07-05
|
||||
**Status**: Active Migration Phase
|
||||
**Last Updated**: 2025-07-05
|
||||
**Note**: Migration fence now implemented through PlatformServiceMixin instead of USE_DEXIE_DB constant
|
||||
### 2. Error Handling
|
||||
- **Graceful Degradation**: Handle migration failures gracefully
|
||||
- **User Communication**: Clear messaging about migration status
|
||||
- **Recovery Options**: Provide rollback mechanisms
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### 1. Migration Performance
|
||||
- **Batch Operations**: Use transactions for bulk data transfer
|
||||
- **Progress Indicators**: Show migration progress to users
|
||||
- **Background Processing**: Non-blocking migration operations
|
||||
|
||||
### 2. Application Performance
|
||||
- **Query Optimization**: Optimize SQLite queries for performance
|
||||
- **Indexing Strategy**: Maintain proper database indexes
|
||||
- **Memory Management**: Efficient memory usage during migration
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
### 1. Code Documentation
|
||||
- **Migration Fence Comments**: Document fence boundaries in code
|
||||
- **API Documentation**: Update all database API documentation
|
||||
- **Migration Guides**: Comprehensive migration documentation
|
||||
|
||||
### 2. User Documentation
|
||||
- **Migration Instructions**: Clear user migration steps
|
||||
- **Troubleshooting**: Common migration issues and solutions
|
||||
- **Rollback Instructions**: How to revert if needed
|
||||
|
||||
## Conclusion
|
||||
|
||||
The migration fence provides a controlled boundary between legacy and new database systems, ensuring:
|
||||
- **Data Integrity**: No data loss during migration
|
||||
- **Application Stability**: Consistent behavior across platforms
|
||||
- **Development Clarity**: Clear guidelines for code development
|
||||
- **Migration Safety**: Controlled and reversible migration process
|
||||
|
||||
This fence will remain in place until all data is successfully migrated and verified, at which point the legacy system can be safely removed.
|
||||
@@ -1,424 +0,0 @@
|
||||
# Migration Progress Tracker: PlatformServiceMixin & 52-File Migration
|
||||
|
||||
## Per-File Migration Workflow (MANDATORY)
|
||||
|
||||
For each file migrated:
|
||||
1. **First**, migrate to PlatformServiceMixin (replace all databaseUtil usage, etc.).
|
||||
2. **Immediately after**, standardize notify helper usage (property + created() pattern) and fix any related linter/type errors.
|
||||
|
||||
**This two-step process is to be followed for every file, not as a global sweep at the end.**
|
||||
|
||||
Anyone picking up this migration should follow this workflow for consistency and completeness.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks the progress of the 2-day sprint to complete PlatformServiceMixin implementation and migrate all 52 files from databaseUtil imports to PlatformServiceMixin usage.
|
||||
|
||||
**Last Updated**: $(date)
|
||||
**Current Phase**: ✅ **DAY 1 COMPLETE** - PlatformServiceMixin Circular Dependency Resolved
|
||||
**Overall Progress**: 69% (64/92 components migrated)
|
||||
|
||||
---
|
||||
|
||||
## ✅ **DAY 1: PlatformServiceMixin Completion (COMPLETE)**
|
||||
|
||||
### **Phase 1: Remove Circular Dependency (COMPLETE)**
|
||||
**Status**: ✅ **COMPLETE**
|
||||
**Issue**: PlatformServiceMixin imports `memoryLogs` from databaseUtil
|
||||
**Solution**: Create self-contained memoryLogs implementation
|
||||
|
||||
#### **Tasks**:
|
||||
- [x] **Step 1.1**: Remove `memoryLogs` import from PlatformServiceMixin.ts ✅
|
||||
- [x] **Step 1.2**: Add self-contained `_memoryLogs` array to PlatformServiceMixin ✅
|
||||
- [x] **Step 1.3**: Add `$appendToMemoryLogs()` method to PlatformServiceMixin ✅
|
||||
- [x] **Step 1.4**: Update logger.ts to use self-contained memoryLogs ✅
|
||||
- [x] **Step 1.5**: Test memoryLogs functionality ✅
|
||||
|
||||
#### **Files Modified**:
|
||||
- `src/utils/PlatformServiceMixin.ts` ✅
|
||||
- `src/utils/logger.ts` ✅
|
||||
|
||||
#### **Validation**:
|
||||
- [x] No circular dependency errors ✅
|
||||
- [x] memoryLogs functionality works correctly ✅
|
||||
- [x] Linting passes ✅
|
||||
|
||||
---
|
||||
|
||||
### **Phase 2: Add Missing Utility Functions (COMPLETE)**
|
||||
**Status**: ✅ **COMPLETE**
|
||||
**Missing Functions**: `generateInsertStatement`, `generateUpdateStatement`
|
||||
|
||||
#### **Tasks**:
|
||||
- [x] **Step 2.1**: Add `_generateInsertStatement()` private method to PlatformServiceMixin ✅
|
||||
- [x] **Step 2.2**: Add `_generateUpdateStatement()` private method to PlatformServiceMixin ✅
|
||||
- [x] **Step 2.3**: Add `$generateInsertStatement()` public wrapper method ✅
|
||||
- [x] **Step 2.4**: Add `$generateUpdateStatement()` public wrapper method ✅
|
||||
- [x] **Step 2.5**: Test both utility functions ✅
|
||||
|
||||
#### **Files Modified**:
|
||||
- `src/utils/PlatformServiceMixin.ts` ✅
|
||||
|
||||
#### **Validation**:
|
||||
- [x] Both functions generate correct SQL ✅
|
||||
- [x] Parameter handling works correctly ✅
|
||||
- [x] Type safety maintained ✅
|
||||
|
||||
---
|
||||
|
||||
### **Phase 3: Update Type Definitions (COMPLETE)**
|
||||
**Status**: ✅ **COMPLETE**
|
||||
**Goal**: Add new methods to TypeScript interfaces
|
||||
|
||||
#### **Tasks**:
|
||||
- [x] **Step 3.1**: Add new methods to `IPlatformServiceMixin` interface ✅
|
||||
- [x] **Step 3.2**: Add new methods to `ComponentCustomProperties` interface ✅
|
||||
- [x] **Step 3.3**: Verify TypeScript compilation ✅
|
||||
|
||||
#### **Files Modified**:
|
||||
- `src/utils/PlatformServiceMixin.ts` (interface definitions) ✅
|
||||
|
||||
#### **Validation**:
|
||||
- [x] TypeScript compilation passes ✅
|
||||
- [x] All new methods properly typed ✅
|
||||
- [x] No type errors in existing code ✅
|
||||
|
||||
---
|
||||
|
||||
### **Phase 4: Testing & Validation (COMPLETE)**
|
||||
**Status**: ✅ **COMPLETE**
|
||||
**Goal**: Ensure PlatformServiceMixin is fully functional
|
||||
|
||||
#### **Tasks**:
|
||||
- [x] **Step 4.1**: Create test component to verify all methods ✅
|
||||
- [x] **Step 4.2**: Run comprehensive linting ✅
|
||||
- [x] **Step 4.3**: Run TypeScript type checking ✅
|
||||
- [x] **Step 4.4**: Test caching functionality ✅
|
||||
- [x] **Step 4.5**: Test database operations ✅
|
||||
|
||||
#### **Validation**:
|
||||
- [x] All tests pass ✅
|
||||
- [x] No linting errors ✅
|
||||
- [x] No TypeScript errors ✅
|
||||
- [x] Caching works correctly ✅
|
||||
- [x] Database operations work correctly ✅
|
||||
|
||||
---
|
||||
|
||||
### **Phase 5: Utility Files Migration (COMPLETE)**
|
||||
**Status**: ✅ **COMPLETE**
|
||||
**Goal**: Remove all remaining databaseUtil imports from utility files
|
||||
|
||||
#### **Tasks**:
|
||||
- [x] **Step 5.1**: Migrate `src/services/deepLinks.ts` ✅
|
||||
- Replaced `logConsoleAndDb` with `console.error`
|
||||
- Removed databaseUtil import
|
||||
- [x] **Step 5.2**: Migrate `src/libs/util.ts` ✅
|
||||
- Added self-contained `parseJsonField()` and `mapQueryResultToValues()` functions
|
||||
- Replaced all databaseUtil calls with PlatformServiceFactory usage
|
||||
- Updated all async calls to use proper async pattern
|
||||
- [x] **Step 5.3**: Verify no remaining databaseUtil imports ✅
|
||||
|
||||
#### **Validation**:
|
||||
- [x] No databaseUtil imports in any TypeScript files ✅
|
||||
- [x] No databaseUtil imports in any Vue files ✅
|
||||
- [x] All functions work correctly ✅
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **DAY 2: Migrate All 52 Files (READY TO START)**
|
||||
|
||||
### **Migration Strategy**
|
||||
**Priority Order**:
|
||||
1. **Views** (25 files) - User-facing components
|
||||
2. **Components** (15 files) - Reusable UI components
|
||||
3. **Services** (8 files) - Business logic
|
||||
4. **Utils** (4 files) - Utility functions
|
||||
|
||||
### **Migration Pattern for Each File**
|
||||
```typescript
|
||||
// 1. Add PlatformServiceMixin
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
export default class ComponentName extends Vue {
|
||||
mixins = [PlatformServiceMixin];
|
||||
}
|
||||
|
||||
// 2. Replace databaseUtil imports
|
||||
// Remove: import { ... } from "@/db/databaseUtil";
|
||||
// Use mixin methods instead
|
||||
|
||||
// 3. Update method calls
|
||||
// Before: generateInsertStatement(contact, 'contacts')
|
||||
// After: this.$generateInsertStatement(contact, 'contacts')
|
||||
```
|
||||
|
||||
### **Common Replacements**
|
||||
- `generateInsertStatement` → `this.$generateInsertStatement`
|
||||
- `generateUpdateStatement` → `this.$generateUpdateStatement`
|
||||
- `parseJsonField` → `this._parseJsonField`
|
||||
- `mapColumnsToValues` → `this._mapColumnsToValues`
|
||||
- `logToDb` → `this.$log`
|
||||
- `logConsoleAndDb` → `this.$logAndConsole`
|
||||
- `memoryLogs` → `this.$memoryLogs`
|
||||
|
||||
---
|
||||
|
||||
## 📋 **File Migration Checklist**
|
||||
|
||||
### **Views (25 files) - Priority 1**
|
||||
**Progress**: 6/25 (24%)
|
||||
|
||||
- [ ] QuickActionBvcEndView.vue
|
||||
- [ ] ProjectsView.vue
|
||||
- [x] ClaimCertificateView.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- [ ] NewEditAccountView.vue
|
||||
- [ ] OnboardMeetingSetupView.vue
|
||||
- [ ] SearchAreaView.vue
|
||||
- [ ] TestView.vue
|
||||
- [ ] InviteOneView.vue
|
||||
- [ ] IdentitySwitcherView.vue
|
||||
- [ ] HelpNotificationsView.vue
|
||||
- [ ] StartView.vue
|
||||
- [ ] OfferDetailsView.vue
|
||||
- [ ] ContactEditView.vue
|
||||
- [ ] SharedPhotoView.vue
|
||||
- [x] ContactQRScanShowView.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- [ ] ContactGiftingView.vue
|
||||
- [x] DiscoverView.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- [ ] ImportAccountView.vue
|
||||
- [ ] ConfirmGiftView.vue
|
||||
- [ ] SeedBackupView.vue
|
||||
- [ ] ContactAmountsView.vue
|
||||
- [x] ContactQRScanFullView.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- [ ] ContactsView.vue
|
||||
- [ ] DIDView.vue
|
||||
- [ ] GiftedDetailsView.vue
|
||||
- [x] HelpView.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- [ ] ImportDerivedAccountView.vue
|
||||
- [ ] InviteOneAcceptView.vue
|
||||
- [ ] NewActivityView.vue
|
||||
- [x] NewEditProjectView.vue ✅ **MIGRATED**
|
||||
- [ ] OnboardMeetingListView.vue
|
||||
- [ ] OnboardMeetingMembersView.vue
|
||||
- [ ] ProjectViewView.vue
|
||||
- [ ] QuickActionBvcBeginView.vue
|
||||
- [ ] RecentOffersToUserProjectsView.vue
|
||||
- [ ] RecentOffersToUserView.vue
|
||||
- [ ] UserProfileView.vue
|
||||
|
||||
### **Components (15 files) - Priority 2**
|
||||
**Progress**: 9/15 (60%)
|
||||
|
||||
- [x] UserNameDialog.vue ✅ **MIGRATED**
|
||||
- [x] AmountInput.vue ✅ **REVIEWED (no migration needed)**
|
||||
- Pure UI component, no databaseUtil or notification usage.
|
||||
- [x] ImageMethodDialog.vue ✅ **MIGRATED & HUMAN TESTED**
|
||||
- Completed 2025-07-09 07:04 AM UTC (19 minutes)
|
||||
- All 4 phases completed: Database migration, SQL abstraction, notification standardization, template streamlining
|
||||
- 20 long CSS classes extracted to computed properties
|
||||
- [x] ChoiceButtonDialog.vue ✅ MIGRATED 2025-07-09 (7 min, all phases complete, template streamlined, no DB/SQL needed)
|
||||
- [x] ContactNameDialog.vue ✅ MIGRATED 2025-07-09 (2 min, all phases complete, template streamlined, no DB/SQL needed)
|
||||
- [x] DataExportSection.vue ✅ MIGRATED & HUMAN TESTED 2025-07-09 (3 min, all phases complete, template streamlined, already had DB/notifications)
|
||||
- [x] EntityGrid.vue ✅ MIGRATED 2024-12-19 (3 min, Phase 4 only - template streamlined, no DB/SQL needed)
|
||||
- [x] EntityIcon.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (2 min, documentation enhancement, no DB/SQL needed)
|
||||
- [x] EntitySelectionStep.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (3 min, Phase 4 only - template streamlined, no DB/SQL needed)
|
||||
- [x] EntitySummaryButton.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (3 min, Phase 4 only - template streamlined, no DB/SQL needed)
|
||||
- [x] FeedFilters.vue ✅ **MIGRATED**
|
||||
- [x] GiftDetailsStep.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (4 min, Phase 4 only - template streamlined, no DB/SQL needed)
|
||||
- [x] GiftedDialog.vue ✅ **MIGRATED**
|
||||
- [x] GiftedPrompts.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (3 min, Phase 4 only - template streamlined, no DB/SQL needed)
|
||||
- [x] HiddenDidDialog.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (5 min, Phase 3 & 4 - notification modernized, template streamlined, no DB/SQL needed)
|
||||
- [x] IconRenderer.vue ✅ MIGRATED & HUMAN TESTED 2024-12-19 (0 min, no migration needed - already compliant)
|
||||
|
||||
### **Services (8 files) - Priority 3**
|
||||
**Progress**: 2/8 (25%)
|
||||
|
||||
- [x] api.ts ✅ MIGRATED 2024-12-19 (0 min, no migration needed - already compliant)
|
||||
- [x] endorserServer.ts ✅ MIGRATED 2024-12-19 (35 min, all phases complete - database, SQL, notification migration)
|
||||
- [ ] partnerServer.ts
|
||||
- [ ] deepLinks.ts
|
||||
|
||||
### **Utils (4 files) - Priority 4**
|
||||
**Progress**: 1/4 (25%)
|
||||
|
||||
- [ ] LogCollector.ts
|
||||
- [x] util.ts ✅ MIGRATED 2024-12-19 (no migration needed, utility module decoupled from Vue, reviewed and confirmed)
|
||||
- [x] test/index.ts ✅ MIGRATED 2024-12-19 (5 min, database migration with dynamic import pattern, enhanced documentation)
|
||||
- [ ] PlatformServiceMixin.ts (remove circular dependency)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ **Migration Tools**
|
||||
|
||||
### **Migration Helper Script**
|
||||
```bash
|
||||
# Track progress
|
||||
./scripts/migration-helper.sh progress
|
||||
|
||||
# Show remaining files
|
||||
./scripts/migration-helper.sh files
|
||||
|
||||
# Show replacement patterns
|
||||
./scripts/migration-helper.sh patterns
|
||||
|
||||
# Show migration template
|
||||
./scripts/migration-helper.sh template
|
||||
|
||||
# Validate migration
|
||||
./scripts/migration-helper.sh validate
|
||||
|
||||
# Show next steps
|
||||
./scripts/migration-helper.sh next
|
||||
|
||||
# Run all checks
|
||||
./scripts/migration-helper.sh all
|
||||
```
|
||||
|
||||
### **Validation Commands**
|
||||
```bash
|
||||
# Check for remaining databaseUtil imports
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil"
|
||||
|
||||
# Run linting
|
||||
npm run lint
|
||||
|
||||
# Run type checking
|
||||
npx tsc --noEmit
|
||||
|
||||
# Count remaining files
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" | wc -l
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **Progress Tracking**
|
||||
|
||||
### **Day 1 Progress**
|
||||
- [ ] Phase 1: Circular dependency resolved
|
||||
- [ ] Phase 2: Utility functions added
|
||||
- [ ] Phase 3: Type definitions updated
|
||||
- [ ] Phase 4: Testing completed
|
||||
|
||||
### **Day 2 Progress**
|
||||
- [ ] Views migrated (0/25)
|
||||
- [ ] Components migrated (0/15)
|
||||
- [ ] Services migrated (0/8)
|
||||
- [ ] Utils migrated (0/4)
|
||||
- [ ] Validation completed
|
||||
|
||||
### **Overall Progress**
|
||||
- **Total files to migrate**: 52
|
||||
- **Files migrated**: 3
|
||||
- **Progress**: 6%
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Success Criteria**
|
||||
|
||||
### **Day 1 Success Criteria**
|
||||
- [ ] PlatformServiceMixin has no circular dependencies
|
||||
- [ ] All utility functions implemented and tested
|
||||
- [ ] Type definitions complete and accurate
|
||||
- [ ] Linting passes with no errors
|
||||
- [ ] TypeScript compilation passes
|
||||
|
||||
### **Day 2 Success Criteria**
|
||||
- [ ] 0 files importing databaseUtil
|
||||
- [ ] All 52 files migrated to PlatformServiceMixin
|
||||
- [ ] No runtime errors in migrated components
|
||||
- [ ] All tests passing
|
||||
- [ ] Performance maintained or improved
|
||||
|
||||
### **Overall Success Criteria**
|
||||
- [ ] Complete elimination of databaseUtil dependency
|
||||
- [ ] PlatformServiceMixin is the single source of truth for database operations
|
||||
- [ ] Migration fence is fully implemented
|
||||
- [ ] Ready for Phase 3: Cleanup and Optimization
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Post-Migration Benefits**
|
||||
|
||||
1. **80% reduction** in database boilerplate code
|
||||
2. **Centralized caching** for improved performance
|
||||
3. **Type-safe** database operations
|
||||
4. **Eliminated circular dependencies**
|
||||
5. **Simplified testing** with mockable mixin
|
||||
6. **Consistent error handling** across all components
|
||||
7. **Ready for SQLite-only mode**
|
||||
|
||||
---
|
||||
|
||||
## 📝 **Notes & Issues**
|
||||
|
||||
### **Current Issues**
|
||||
- None identified yet
|
||||
|
||||
### **Decisions Made**
|
||||
- PlatformServiceMixin approach chosen over USE_DEXIE_DB constant
|
||||
- Self-contained utility functions preferred over imports
|
||||
- Priority order: Views → Components → Services → Utils
|
||||
|
||||
### **Lessons Learned**
|
||||
- To be filled as migration progresses
|
||||
|
||||
---
|
||||
|
||||
## 🔄 **Daily Updates**
|
||||
|
||||
### **Day 1 Updates**
|
||||
- [ ] Start time: _____
|
||||
- [ ] Phase 1 completion: _____
|
||||
- [ ] Phase 2 completion: _____
|
||||
- [ ] Phase 3 completion: _____
|
||||
- [ ] Phase 4 completion: _____
|
||||
- [ ] End time: _____
|
||||
|
||||
### **Day 2 Updates**
|
||||
- [ ] Start time: _____
|
||||
- [ ] Views migration completion: _____
|
||||
- [ ] Components migration completion: _____
|
||||
- [ ] Services migration completion: _____
|
||||
- [ ] Utils migration completion: _____
|
||||
- [ ] Final validation completion: _____
|
||||
- [ ] End time: _____
|
||||
|
||||
---
|
||||
|
||||
## 🆘 **Contingency Plans**
|
||||
|
||||
### **If Day 1 Takes Longer**
|
||||
- Focus on core functionality first
|
||||
- Defer advanced utility functions to Day 2
|
||||
- Prioritize circular dependency resolution
|
||||
|
||||
### **If Day 2 Takes Longer**
|
||||
- Focus on high-impact views first
|
||||
- Batch similar components together
|
||||
- Use automated scripts for common patterns
|
||||
|
||||
### **If Issues Arise**
|
||||
- Document specific problems in Notes section
|
||||
- Create targeted fixes
|
||||
- Maintain backward compatibility during transition
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Notification Best Practices and Nuances**
|
||||
|
||||
- **All user-facing notification messages must be defined as constants** in `src/constants/notifications.ts`. Do not hardcode notification strings in components.
|
||||
- **All notification durations/timeouts must use the `TIMEOUTS` constants** from `src/utils/notify.ts`. Do not hardcode durations.
|
||||
- **Notification helpers (`this.notify`) must be initialized as a property in `created()`** using `createNotifyHelpers(this.$notify)`.
|
||||
- **Never hardcode notification strings or durations in components.**
|
||||
- **When using `notifyWhyCannotConfirm` or similar utilities, pass a wrapper function** if the signature expects a raw notify function (e.g., `(msg, timeout) => this.notify.info(msg.text ?? '', timeout)`).
|
||||
- **Declare `$notify` as a property on the class** to satisfy the type checker, since Vue injects it at runtime.
|
||||
- **Use type guards or `as any` for unknown notification payloads** when necessary, but prefer type safety where possible.
|
||||
|
||||
These practices ensure maintainability, consistency, and type safety for all notification-related code during and after migration.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: $(date)
|
||||
**Next Review**: After each phase completion
|
||||
@@ -1,94 +0,0 @@
|
||||
# Migration Quick Reference Card
|
||||
|
||||
## 🚀 **Quick Start Commands**
|
||||
|
||||
```bash
|
||||
# Check current progress
|
||||
./scripts/migration-helper.sh progress
|
||||
|
||||
# See what files need migration
|
||||
./scripts/migration-helper.sh files
|
||||
|
||||
# Get migration patterns
|
||||
./scripts/migration-helper.sh patterns
|
||||
|
||||
# Validate current state
|
||||
./scripts/migration-helper.sh validate
|
||||
```
|
||||
|
||||
## 📊 **Current Status**
|
||||
|
||||
- **Total Files**: 52
|
||||
- **Migrated**: 0
|
||||
- **Progress**: 0%
|
||||
- **Current Phase**: Day 1 - PlatformServiceMixin Completion
|
||||
|
||||
## 🔄 **Migration Pattern (Copy-Paste Template)**
|
||||
|
||||
```typescript
|
||||
// 1. Add import
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
|
||||
// 2. Add to component
|
||||
export default class ComponentName extends Vue {
|
||||
mixins = [PlatformServiceMixin];
|
||||
|
||||
// 3. Replace method calls
|
||||
async someMethod() {
|
||||
// Before: generateInsertStatement(contact, 'contacts')
|
||||
// After: this.$generateInsertStatement(contact, 'contacts')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 **Common Replacements**
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `generateInsertStatement` | `this.$generateInsertStatement` |
|
||||
| `generateUpdateStatement` | `this.$generateUpdateStatement` |
|
||||
| `parseJsonField` | `this._parseJsonField` |
|
||||
| `mapColumnsToValues` | `this._mapColumnsToValues` |
|
||||
| `logToDb` | `this.$log` |
|
||||
| `logConsoleAndDb` | `this.$logAndConsole` |
|
||||
| `memoryLogs` | `this.$memoryLogs` |
|
||||
|
||||
## 🎯 **Priority Order**
|
||||
|
||||
1. **Views** (25 files) - User-facing components
|
||||
2. **Components** (15 files) - Reusable UI components
|
||||
3. **Services** (8 files) - Business logic
|
||||
4. **Utils** (4 files) - Utility functions
|
||||
|
||||
## ✅ **Validation Checklist**
|
||||
|
||||
After each file migration:
|
||||
- [ ] No databaseUtil imports
|
||||
- [ ] PlatformServiceMixin added
|
||||
- [ ] Method calls updated
|
||||
- [ ] Linting passes
|
||||
- [ ] TypeScript compiles
|
||||
|
||||
## 📋 **Key Files to Track**
|
||||
|
||||
- **Progress Tracker**: `doc/migration-progress-tracker.md`
|
||||
- **Completion Plan**: `doc/platformservicemixin-completion-plan.md`
|
||||
- **Helper Script**: `scripts/migration-helper.sh`
|
||||
|
||||
## 🆘 **Quick Help**
|
||||
|
||||
```bash
|
||||
# Show all migration info
|
||||
./scripts/migration-helper.sh all
|
||||
|
||||
# Count remaining files
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" | wc -l
|
||||
|
||||
# Run validation
|
||||
npm run lint && npx tsc --noEmit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: $(date)
|
||||
**Full Documentation**: `doc/migration-progress-tracker.md`
|
||||
@@ -1,213 +0,0 @@
|
||||
# Migration Readiness Summary
|
||||
|
||||
## ✅ **READY TO START: 2-Day Migration Sprint**
|
||||
|
||||
**Date**: $(date)
|
||||
**Status**: All systems ready for migration
|
||||
**Target**: Complete PlatformServiceMixin + migrate 52 files
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Migration Overview**
|
||||
|
||||
### **Goal**
|
||||
Complete the TimeSafari database migration from Dexie to SQLite by:
|
||||
1. **Day 1**: Finish PlatformServiceMixin implementation (4-6 hours)
|
||||
2. **Day 2**: Migrate all 52 files to PlatformServiceMixin (6-8 hours)
|
||||
|
||||
### **Current Status**
|
||||
- ✅ **PlatformServiceMixin**: 95% complete (1,301 lines)
|
||||
- ✅ **Migration Tools**: Ready and tested
|
||||
- ✅ **Documentation**: Complete and cross-machine accessible
|
||||
- ✅ **Tracking System**: Automated progress monitoring
|
||||
- ⚠️ **Remaining**: 52 files need migration
|
||||
|
||||
---
|
||||
|
||||
## 📊 **File Breakdown**
|
||||
|
||||
### **Views (42 files) - Priority 1**
|
||||
User-facing components that need immediate attention:
|
||||
- 25 files from original list
|
||||
- 17 additional files identified by migration helper
|
||||
|
||||
### **Components (9 files) - Priority 2**
|
||||
Reusable UI components:
|
||||
- FeedFilters.vue, GiftedDialog.vue, GiftedPrompts.vue
|
||||
- ImageMethodDialog.vue, OfferDialog.vue, OnboardingDialog.vue
|
||||
- PhotoDialog.vue, PushNotificationPermission.vue, UserNameDialog.vue
|
||||
|
||||
### **Services (1 file) - Priority 3**
|
||||
Business logic:
|
||||
- deepLinks.ts
|
||||
|
||||
### **Utils (3 files) - Priority 4**
|
||||
Utility functions:
|
||||
- util.ts, test/index.ts, PlatformServiceMixin.ts (circular dependency fix)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ **Available Tools**
|
||||
|
||||
### **Migration Helper Script**
|
||||
```bash
|
||||
./scripts/migration-helper.sh [command]
|
||||
```
|
||||
**Commands**: progress, files, patterns, template, validate, next, all
|
||||
|
||||
### **Progress Tracking**
|
||||
- **Main Tracker**: `doc/migration-progress-tracker.md`
|
||||
- **Quick Reference**: `doc/migration-quick-reference.md`
|
||||
- **Completion Plan**: `doc/platformservicemixin-completion-plan.md`
|
||||
|
||||
### **Validation Commands**
|
||||
```bash
|
||||
# Check progress
|
||||
./scripts/migration-helper.sh progress
|
||||
|
||||
# Validate current state
|
||||
./scripts/migration-helper.sh validate
|
||||
|
||||
# Count remaining files
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" | wc -l
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 **Migration Pattern**
|
||||
|
||||
### **Standard Template**
|
||||
```typescript
|
||||
// 1. Add import
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
|
||||
// 2. Add to component
|
||||
export default class ComponentName extends Vue {
|
||||
mixins = [PlatformServiceMixin];
|
||||
|
||||
// 3. Replace method calls
|
||||
async someMethod() {
|
||||
// Before: generateInsertStatement(contact, 'contacts')
|
||||
// After: this.$generateInsertStatement(contact, 'contacts')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Common Replacements**
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `generateInsertStatement` | `this.$generateInsertStatement` |
|
||||
| `generateUpdateStatement` | `this.$generateUpdateStatement` |
|
||||
| `parseJsonField` | `this._parseJsonField` |
|
||||
| `mapColumnsToValues` | `this._mapColumnsToValues` |
|
||||
| `logToDb` | `this.$log` |
|
||||
| `logConsoleAndDb` | `this.$logAndConsole` |
|
||||
| `memoryLogs` | `this.$memoryLogs` |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Day 1 Plan: PlatformServiceMixin Completion**
|
||||
|
||||
### **Phase 1: Remove Circular Dependency (30 min)**
|
||||
- Remove `memoryLogs` import from PlatformServiceMixin
|
||||
- Add self-contained memoryLogs implementation
|
||||
- Update logger.ts
|
||||
|
||||
### **Phase 2: Add Missing Functions (1 hour)**
|
||||
- Add `generateInsertStatement` and `generateUpdateStatement`
|
||||
- Test both utility functions
|
||||
|
||||
### **Phase 3: Update Types (30 min)**
|
||||
- Add new methods to TypeScript interfaces
|
||||
- Verify compilation
|
||||
|
||||
### **Phase 4: Testing (1 hour)**
|
||||
- Comprehensive testing and validation
|
||||
- Ensure no circular dependencies
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Day 2 Plan: File Migration**
|
||||
|
||||
### **Strategy**
|
||||
1. **Views First** (42 files) - High impact, user-facing
|
||||
2. **Components** (9 files) - Reusable UI elements
|
||||
3. **Services** (1 file) - Business logic
|
||||
4. **Utils** (3 files) - Utility functions
|
||||
|
||||
### **Batch Processing**
|
||||
- Process similar files together
|
||||
- Use automated scripts for common patterns
|
||||
- Validate after each batch
|
||||
|
||||
### **Success Criteria**
|
||||
- 0 files importing databaseUtil
|
||||
- All tests passing
|
||||
- No runtime errors
|
||||
- Performance maintained
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Expected Benefits**
|
||||
|
||||
### **Immediate Benefits**
|
||||
- **80% reduction** in database boilerplate code
|
||||
- **Eliminated circular dependencies**
|
||||
- **Centralized caching** for performance
|
||||
- **Type-safe** database operations
|
||||
|
||||
### **Long-term Benefits**
|
||||
- **Simplified testing** with mockable mixin
|
||||
- **Consistent error handling** across components
|
||||
- **Ready for SQLite-only mode**
|
||||
- **Improved maintainability**
|
||||
|
||||
---
|
||||
|
||||
## 📋 **Pre-Migration Checklist**
|
||||
|
||||
### **Environment Ready**
|
||||
- [x] Migration helper script tested and working
|
||||
- [x] Progress tracking system operational
|
||||
- [x] Documentation complete and accessible
|
||||
- [x] Validation commands working
|
||||
|
||||
### **Tools Available**
|
||||
- [x] Automated progress tracking
|
||||
- [x] Migration pattern templates
|
||||
- [x] Validation scripts
|
||||
- [x] Cross-machine documentation
|
||||
|
||||
### **Knowledge Base**
|
||||
- [x] Common replacement patterns documented
|
||||
- [x] Migration templates ready
|
||||
- [x] Troubleshooting guides available
|
||||
- [x] Success criteria defined
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Ready to Begin**
|
||||
|
||||
**All systems are ready for the 2-day migration sprint.**
|
||||
|
||||
### **Next Steps**
|
||||
1. **Start Day 1**: Complete PlatformServiceMixin
|
||||
2. **Use tracking tools**: Monitor progress with helper script
|
||||
3. **Follow documentation**: Use provided templates and patterns
|
||||
4. **Validate frequently**: Run checks after each phase
|
||||
|
||||
### **Success Metrics**
|
||||
- **Day 1**: PlatformServiceMixin 100% complete, no circular dependencies
|
||||
- **Day 2**: 0 files importing databaseUtil, all tests passing
|
||||
- **Overall**: Ready for Phase 3 cleanup and optimization
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ **READY TO START**
|
||||
**Confidence Level**: High
|
||||
**Estimated Success Rate**: 95%
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: $(date)
|
||||
**Next Review**: After Day 1 completion
|
||||
@@ -1,290 +0,0 @@
|
||||
# Migration Roadmap: Next Steps
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the immediate next steps for completing the TimeSafari database migration from Dexie to SQLite, based on the current status and progress documented across the codebase.
|
||||
|
||||
## Current Status Summary
|
||||
|
||||
### ✅ **Completed Achievements**
|
||||
1. **Circular Dependencies Resolved** - No active circular dependencies blocking development
|
||||
2. **PlatformServiceMixin Implemented** - Core functionality with caching and utilities
|
||||
3. **Migration Tools Ready** - Data comparison and transfer utilities functional
|
||||
4. **Core Data Migrated** - Settings, accounts, and ActiveDid migration completed
|
||||
5. **Documentation Updated** - All docs reflect current PlatformServiceMixin approach
|
||||
|
||||
### 🔄 **Current Phase: Phase 2 - Active Migration**
|
||||
- **DatabaseUtil Migration**: 52 files still importing databaseUtil
|
||||
- **Contact Migration**: Framework ready, implementation in progress
|
||||
- **File-by-File Migration**: Ready to begin systematic migration
|
||||
|
||||
## Immediate Next Steps (This Week)
|
||||
|
||||
### 🔴 **Priority 1: Complete PlatformServiceMixin Independence**
|
||||
|
||||
#### **Step 1.1: Remove memoryLogs Dependency**
|
||||
```typescript
|
||||
// Current: PlatformServiceMixin imports from databaseUtil
|
||||
import { memoryLogs } from "@/db/databaseUtil";
|
||||
|
||||
// Solution: Create self-contained implementation
|
||||
const memoryLogs: string[] = [];
|
||||
```
|
||||
|
||||
**Files to modify**:
|
||||
- `src/utils/PlatformServiceMixin.ts` - Remove import, add self-contained implementation
|
||||
|
||||
**Estimated time**: 30 minutes
|
||||
|
||||
#### **Step 1.2: Add Missing Utility Methods**
|
||||
Add these methods to PlatformServiceMixin:
|
||||
- `$parseJson()` - Self-contained JSON parsing
|
||||
- `$generateInsertStatement()` - SQL generation
|
||||
- `$generateUpdateStatement()` - SQL generation
|
||||
- `$logConsoleAndDb()` - Enhanced logging
|
||||
|
||||
**Estimated time**: 2 hours
|
||||
|
||||
### 🟡 **Priority 2: Start File-by-File Migration**
|
||||
|
||||
#### **Step 2.1: Migrate Critical Files First**
|
||||
Based on the migration plan, start with these high-priority files:
|
||||
|
||||
1. **`src/App.vue`** - Main application (highest impact)
|
||||
2. **`src/views/AccountViewView.vue`** - Core account management
|
||||
3. **`src/views/ContactsView.vue`** - Core contact management
|
||||
4. **`src/libs/util.ts`** - Utility functions used by many components
|
||||
5. **`src/services/deepLinks.ts`** - Service layer
|
||||
|
||||
**Migration pattern for each file**:
|
||||
```typescript
|
||||
// 1. Remove databaseUtil import
|
||||
// Remove: import * as databaseUtil from "../db/databaseUtil";
|
||||
|
||||
// 2. Add PlatformServiceMixin
|
||||
// Add: mixins: [PlatformServiceMixin],
|
||||
|
||||
// 3. Replace function calls
|
||||
// Replace: databaseUtil.retrieveSettingsForActiveAccount()
|
||||
// With: this.$settings()
|
||||
|
||||
// Replace: databaseUtil.logConsoleAndDb(message, isError)
|
||||
// With: this.$logAndConsole(message, isError)
|
||||
|
||||
// Replace: databaseUtil.parseJsonField(value, defaultValue)
|
||||
// With: this.$parseJson(value, defaultValue)
|
||||
```
|
||||
|
||||
**Estimated time**: 1-2 hours per file (5 files = 5-10 hours)
|
||||
|
||||
## Medium-Term Goals (Next 2 Weeks)
|
||||
|
||||
### 🟡 **Priority 3: Systematic File Migration**
|
||||
|
||||
#### **Step 3.1: Migrate High-Usage Components (15 files)**
|
||||
Target components with databaseUtil imports:
|
||||
- `PhotoDialog.vue`
|
||||
- `FeedFilters.vue`
|
||||
- `UserNameDialog.vue`
|
||||
- `ImageMethodDialog.vue`
|
||||
- `OfferDialog.vue`
|
||||
- `OnboardingDialog.vue`
|
||||
- `PushNotificationPermission.vue`
|
||||
- `GiftedPrompts.vue`
|
||||
- `GiftedDialog.vue`
|
||||
- And 6 more...
|
||||
|
||||
**Estimated time**: 15-30 hours
|
||||
|
||||
#### **Step 3.2: Migrate High-Usage Views (20 files)**
|
||||
Target views with databaseUtil imports:
|
||||
- `IdentitySwitcherView.vue`
|
||||
- `ContactEditView.vue`
|
||||
- `ContactGiftingView.vue`
|
||||
- `ImportAccountView.vue`
|
||||
- `OnboardMeetingMembersView.vue`
|
||||
- `RecentOffersToUserProjectsView.vue`
|
||||
- `ClaimCertificateView.vue`
|
||||
- `NewActivityView.vue`
|
||||
- `HelpView.vue`
|
||||
- `NewEditProjectView.vue`
|
||||
- And 10+ more...
|
||||
|
||||
**Estimated time**: 20-40 hours
|
||||
|
||||
#### **Step 3.3: Migrate Remaining Files (27 files)**
|
||||
Complete migration of all remaining files with databaseUtil imports.
|
||||
|
||||
**Estimated time**: 27-54 hours
|
||||
|
||||
### 🟢 **Priority 4: Contact Migration Completion**
|
||||
|
||||
#### **Step 4.1: Complete Contact Migration Framework**
|
||||
- Implement contact import/export functionality
|
||||
- Add contact validation and error handling
|
||||
- Test contact migration with real data
|
||||
|
||||
**Estimated time**: 4-8 hours
|
||||
|
||||
#### **Step 4.2: User Testing and Validation**
|
||||
- Test migration with various data scenarios
|
||||
- Validate data integrity after migration
|
||||
- Performance testing with large datasets
|
||||
|
||||
**Estimated time**: 8-16 hours
|
||||
|
||||
## Long-Term Goals (Next Month)
|
||||
|
||||
### 🔵 **Priority 5: Cleanup and Optimization**
|
||||
|
||||
#### **Step 5.1: Remove Unused databaseUtil Functions**
|
||||
After all files are migrated:
|
||||
- Remove unused functions from databaseUtil.ts
|
||||
- Update TypeScript interfaces
|
||||
- Clean up legacy code
|
||||
|
||||
**Estimated time**: 4-8 hours
|
||||
|
||||
#### **Step 5.2: Performance Optimization**
|
||||
- Optimize PlatformServiceMixin caching
|
||||
- Add performance monitoring
|
||||
- Implement database query optimization
|
||||
|
||||
**Estimated time**: 8-16 hours
|
||||
|
||||
#### **Step 5.3: Legacy Dexie Removal**
|
||||
- Remove Dexie dependencies
|
||||
- Clean up migration tools
|
||||
- Update build configurations
|
||||
|
||||
**Estimated time**: 4-8 hours
|
||||
|
||||
## Migration Commands and Tools
|
||||
|
||||
### **Automated Migration Script**
|
||||
Create a script to help with bulk migrations:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# migrate-file.sh - Automated file migration helper
|
||||
|
||||
FILE=$1
|
||||
if [ -z "$FILE" ]; then
|
||||
echo "Usage: ./migrate-file.sh <filename>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Migrating $FILE..."
|
||||
|
||||
# 1. Backup original file
|
||||
cp "$FILE" "$FILE.backup"
|
||||
|
||||
# 2. Remove databaseUtil imports
|
||||
sed -i '/import.*databaseUtil/d' "$FILE"
|
||||
|
||||
# 3. Add PlatformServiceMixin import
|
||||
sed -i '1i import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";' "$FILE"
|
||||
|
||||
# 4. Add mixin to component
|
||||
sed -i '/mixins:/a \ PlatformServiceMixin,' "$FILE"
|
||||
|
||||
echo "Migration completed for $FILE"
|
||||
echo "Please review and test the changes"
|
||||
```
|
||||
|
||||
### **Migration Testing Commands**
|
||||
```bash
|
||||
# Test individual file migration
|
||||
npm run test -- --grep "ComponentName"
|
||||
|
||||
# Test database operations
|
||||
npm run test:database
|
||||
|
||||
# Test migration tools
|
||||
npm run test:migration
|
||||
|
||||
# Lint check
|
||||
npm run lint
|
||||
|
||||
# TypeScript check
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### **Incremental Migration Strategy**
|
||||
1. **One file at a time** - Minimize risk of breaking changes
|
||||
2. **Comprehensive testing** - Test each migration thoroughly
|
||||
3. **Rollback capability** - Keep databaseUtil.ts until migration complete
|
||||
4. **Documentation updates** - Update docs as methods are migrated
|
||||
|
||||
### **Testing Strategy**
|
||||
1. **Unit tests** - Test individual component functionality
|
||||
2. **Integration tests** - Test database operations
|
||||
3. **End-to-end tests** - Test complete user workflows
|
||||
4. **Performance tests** - Ensure no performance regression
|
||||
|
||||
### **Rollback Plan**
|
||||
1. **Git branches** - Each migration in separate branch
|
||||
2. **Backup files** - Keep original files until migration verified
|
||||
3. **Feature flags** - Ability to switch back to databaseUtil if needed
|
||||
4. **Monitoring** - Watch for errors and performance issues
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### **Short-Term (This Week)**
|
||||
- [ ] PlatformServiceMixin completely independent
|
||||
- [ ] 5 critical files migrated
|
||||
- [ ] No new circular dependencies
|
||||
- [ ] All tests passing
|
||||
|
||||
### **Medium-Term (Next 2 Weeks)**
|
||||
- [ ] 35+ files migrated (70% completion)
|
||||
- [ ] Contact migration framework complete
|
||||
- [ ] Performance maintained or improved
|
||||
- [ ] User testing completed
|
||||
|
||||
### **Long-Term (Next Month)**
|
||||
- [ ] All 52 files migrated (100% completion)
|
||||
- [ ] databaseUtil.ts removed or minimal
|
||||
- [ ] Legacy Dexie code removed
|
||||
- [ ] Migration tools cleaned up
|
||||
|
||||
## Resource Requirements
|
||||
|
||||
### **Development Time**
|
||||
- **Immediate (This Week)**: 8-12 hours
|
||||
- **Medium-Term (Next 2 Weeks)**: 35-70 hours
|
||||
- **Long-Term (Next Month)**: 16-32 hours
|
||||
- **Total Estimated**: 59-114 hours
|
||||
|
||||
### **Testing Time**
|
||||
- **Unit Testing**: 20-30 hours
|
||||
- **Integration Testing**: 10-15 hours
|
||||
- **User Testing**: 8-12 hours
|
||||
- **Performance Testing**: 5-8 hours
|
||||
- **Total Testing**: 43-65 hours
|
||||
|
||||
### **Total Project Time**
|
||||
- **Development**: 59-114 hours
|
||||
- **Testing**: 43-65 hours
|
||||
- **Documentation**: 5-10 hours
|
||||
- **Total**: 107-189 hours (2-4 weeks full-time)
|
||||
|
||||
## Conclusion
|
||||
|
||||
The migration is well-positioned for completion with:
|
||||
- ✅ **No blocking circular dependencies**
|
||||
- ✅ **PlatformServiceMixin mostly complete**
|
||||
- ✅ **Clear migration path defined**
|
||||
- ✅ **Comprehensive documentation available**
|
||||
|
||||
The next steps focus on systematic file-by-file migration with proper testing and validation at each stage. The estimated timeline is 2-4 weeks for complete migration with thorough testing.
|
||||
|
||||
---
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Created**: 2025-07-05
|
||||
**Status**: Active Planning
|
||||
**Last Updated**: 2025-07-05
|
||||
**Note**: This roadmap is based on current codebase analysis and documented progress
|
||||
@@ -6,8 +6,6 @@ This document outlines the migration process from Dexie.js to absurd-sql for the
|
||||
|
||||
**Current Status**: The migration is in **Phase 2** with a well-defined migration fence in place. Core settings and account data have been migrated, with contact migration in progress. **ActiveDid migration has been implemented** to ensure user identity continuity.
|
||||
|
||||
**⚠️ UPDATE**: The migration fence is now implemented through the **PlatformServiceMixin** rather than a `USE_DEXIE_DB` constant. This provides a cleaner, more maintainable approach to database access control.
|
||||
|
||||
## Migration Goals
|
||||
|
||||
1. **Data Integrity**
|
||||
@@ -29,10 +27,9 @@ This document outlines the migration process from Dexie.js to absurd-sql for the
|
||||
## Migration Architecture
|
||||
|
||||
### Migration Fence
|
||||
The migration fence is now defined by the **PlatformServiceMixin** in `src/utils/PlatformServiceMixin.ts`:
|
||||
- **PlatformServiceMixin**: Centralized database access with caching and utilities
|
||||
- **Migration Tools**: Exclusive interface between legacy and new databases
|
||||
- **Service Layer**: All database operations go through PlatformService
|
||||
The migration fence is defined by the `USE_DEXIE_DB` constant in `src/constants/app.ts`:
|
||||
- `USE_DEXIE_DB = false` (default): Uses SQLite database
|
||||
- `USE_DEXIE_DB = true`: Uses Dexie database (for migration purposes)
|
||||
|
||||
### Migration Order
|
||||
The migration follows a specific order to maintain data integrity:
|
||||
@@ -72,8 +69,8 @@ export async function migrateActiveDid(): Promise<MigrationResult> {
|
||||
|
||||
// 3. Update SQLite master settings
|
||||
await updateDefaultSettings({ activeDid: dexieActiveDid });
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
#### Enhanced `migrateSettings()` Function
|
||||
The settings migration now includes activeDid handling:
|
||||
@@ -98,7 +95,7 @@ const activeDidResult = await migrateActiveDid();
|
||||
## Migration Process
|
||||
|
||||
### Phase 1: Preparation ✅
|
||||
- [x] PlatformServiceMixin implementation
|
||||
- [x] Enable Dexie database access
|
||||
- [x] Implement data comparison tools
|
||||
- [x] Create migration service structure
|
||||
|
||||
@@ -135,15 +132,6 @@ const comparison = await compareDatabases();
|
||||
console.log('Migration differences:', comparison.differences);
|
||||
```
|
||||
|
||||
### PlatformServiceMixin Integration
|
||||
After migration, use the mixin for all database operations:
|
||||
```typescript
|
||||
// Use mixin methods for database access
|
||||
const contacts = await this.$contacts();
|
||||
const settings = await this.$settings();
|
||||
const result = await this.$db("SELECT * FROM contacts WHERE did = ?", [accountDid]);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### ActiveDid Migration Errors
|
||||
@@ -172,6 +160,9 @@ const result = await this.$db("SELECT * FROM contacts WHERE did = ?", [accountDi
|
||||
|
||||
### Migration Testing
|
||||
```bash
|
||||
# Enable Dexie for testing
|
||||
# Set USE_DEXIE_DB = true in constants/app.ts
|
||||
|
||||
# Run migration
|
||||
npm run migrate
|
||||
|
||||
@@ -180,26 +171,13 @@ npm run test:migration
|
||||
```
|
||||
|
||||
### ActiveDid Testing
|
||||
```typescript
|
||||
```typescript
|
||||
// Test activeDid migration specifically
|
||||
const result = await migrateActiveDid();
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.warnings).toContain('Successfully migrated activeDid');
|
||||
```
|
||||
|
||||
### PlatformServiceMixin Testing
|
||||
```typescript
|
||||
// Test mixin integration
|
||||
describe('PlatformServiceMixin', () => {
|
||||
it('should provide database access methods', async () => {
|
||||
const contacts = await this.$contacts();
|
||||
const settings = await this.$settings();
|
||||
expect(contacts).toBeDefined();
|
||||
expect(settings).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
@@ -218,53 +196,31 @@ describe('PlatformServiceMixin', () => {
|
||||
- Re-run migration if necessary
|
||||
- Check for duplicate or conflicting records
|
||||
|
||||
4. **PlatformServiceMixin Issues**
|
||||
- Ensure mixin is properly imported and used
|
||||
- Check that all database operations use mixin methods
|
||||
- Verify caching and error handling work correctly
|
||||
|
||||
### Debugging
|
||||
```typescript
|
||||
// Debug migration process
|
||||
import { logger } from '../utils/logger';
|
||||
// Enable detailed logging
|
||||
logger.setLevel('debug');
|
||||
|
||||
logger.debug('[Migration] Starting migration process...');
|
||||
const result = await migrateAll();
|
||||
logger.debug('[Migration] Migration completed:', result);
|
||||
```
|
||||
// Check migration status
|
||||
const comparison = await compareDatabases();
|
||||
console.log('Settings differences:', comparison.differences.settings);
|
||||
```
|
||||
|
||||
## Benefits of PlatformServiceMixin Approach
|
||||
## Future Enhancements
|
||||
|
||||
1. **Centralized Access**: Single point of control for all database operations
|
||||
2. **Caching**: Built-in caching for performance optimization
|
||||
3. **Type Safety**: Enhanced TypeScript integration
|
||||
4. **Error Handling**: Consistent error handling across components
|
||||
5. **Code Reduction**: Up to 80% reduction in database boilerplate
|
||||
6. **Maintainability**: Single source of truth for database patterns
|
||||
### Planned Improvements
|
||||
1. **Batch Processing**: Optimize for large datasets
|
||||
2. **Incremental Migration**: Support partial migrations
|
||||
3. **Rollback Capability**: Ability to revert migration
|
||||
4. **Progress Tracking**: Real-time migration progress
|
||||
|
||||
## Migration Status Checklist
|
||||
### Performance Optimizations
|
||||
1. **Parallel Processing**: Migrate independent data concurrently
|
||||
2. **Memory Management**: Optimize for large datasets
|
||||
3. **Transaction Batching**: Reduce database round trips
|
||||
|
||||
### ✅ Completed
|
||||
- [x] PlatformServiceMixin implementation
|
||||
- [x] SQLite database service
|
||||
- [x] Migration tools
|
||||
- [x] Settings migration
|
||||
- [x] Account migration
|
||||
- [x] ActiveDid migration
|
||||
## Conclusion
|
||||
|
||||
### 🔄 In Progress
|
||||
- [ ] Contact migration
|
||||
- [ ] DatabaseUtil to PlatformServiceMixin migration
|
||||
- [ ] File-by-file migration
|
||||
The Dexie to SQLite migration provides a robust, secure, and user-friendly transition path. The addition of activeDid migration ensures that users maintain their identity continuity throughout the migration process, significantly improving the user experience.
|
||||
|
||||
### ❌ Not Started
|
||||
- [ ] Legacy Dexie removal
|
||||
- [ ] Final cleanup and validation
|
||||
|
||||
---
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Created**: 2025-07-05
|
||||
**Status**: Active Migration Phase
|
||||
**Last Updated**: 2025-07-05
|
||||
**Note**: Migration fence now implemented through PlatformServiceMixin instead of USE_DEXIE_DB constant
|
||||
The migration fence architecture allows for controlled, reversible migration while maintaining application stability and data integrity.
|
||||
@@ -1,418 +0,0 @@
|
||||
# PlatformServiceMixin Completion Plan: 2-Day Sprint
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the complete plan to finish PlatformServiceMixin implementation and migrate all 52 remaining files from databaseUtil imports to PlatformServiceMixin usage within 2 days.
|
||||
|
||||
## Current Status
|
||||
|
||||
### ✅ **PlatformServiceMixin - 95% Complete**
|
||||
- **Core functionality**: ✅ Implemented
|
||||
- **Caching system**: ✅ Implemented
|
||||
- **Database methods**: ✅ Implemented
|
||||
- **Utility methods**: ✅ Implemented
|
||||
- **Type definitions**: ✅ Implemented
|
||||
|
||||
### ⚠️ **Remaining Issues**
|
||||
1. **Single circular dependency**: `memoryLogs` import from databaseUtil
|
||||
2. **Missing utility functions**: `generateInsertStatement`, `generateUpdateStatement`
|
||||
3. **52 files** still importing databaseUtil
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **DAY 1: Complete PlatformServiceMixin (4-6 hours)**
|
||||
|
||||
### **Phase 1: Remove Circular Dependency (30 minutes)**
|
||||
|
||||
#### **Step 1.1: Create Self-Contained memoryLogs**
|
||||
```typescript
|
||||
// In PlatformServiceMixin.ts - Replace line 50:
|
||||
// Remove: import { memoryLogs } from "@/db/databaseUtil";
|
||||
|
||||
// Add self-contained implementation:
|
||||
const _memoryLogs: string[] = [];
|
||||
|
||||
// Update $memoryLogs computed property:
|
||||
$memoryLogs(): string[] {
|
||||
return _memoryLogs;
|
||||
},
|
||||
|
||||
// Add method to append to memory logs:
|
||||
$appendToMemoryLogs(message: string): void {
|
||||
_memoryLogs.push(`${new Date().toISOString()}: ${message}`);
|
||||
// Keep only last 1000 entries to prevent memory leaks
|
||||
if (_memoryLogs.length > 1000) {
|
||||
_memoryLogs.splice(0, _memoryLogs.length - 1000);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
#### **Step 1.2: Update logger.ts**
|
||||
```typescript
|
||||
// In logger.ts - Replace memoryLogs usage:
|
||||
// Remove: import { memoryLogs } from "@/db/databaseUtil";
|
||||
|
||||
// Add self-contained implementation:
|
||||
const _memoryLogs: string[] = [];
|
||||
|
||||
export function appendToMemoryLogs(message: string): void {
|
||||
_memoryLogs.push(`${new Date().toISOString()}: ${message}`);
|
||||
if (_memoryLogs.length > 1000) {
|
||||
_memoryLogs.splice(0, _memoryLogs.length - 1000);
|
||||
}
|
||||
}
|
||||
|
||||
export function getMemoryLogs(): string[] {
|
||||
return [..._memoryLogs];
|
||||
}
|
||||
```
|
||||
|
||||
### **Phase 2: Add Missing Utility Functions (1 hour)**
|
||||
|
||||
#### **Step 2.1: Add generateInsertStatement to PlatformServiceMixin**
|
||||
```typescript
|
||||
// Add to PlatformServiceMixin methods:
|
||||
_generateInsertStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
): { sql: string; params: unknown[] } {
|
||||
const columns = Object.keys(model).filter((key) => model[key] !== undefined);
|
||||
const values = Object.values(model)
|
||||
.filter((value) => value !== undefined)
|
||||
.map((value) => {
|
||||
if (value === null || value === undefined) return null;
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
if (typeof value === "boolean") return value ? 1 : 0;
|
||||
return value;
|
||||
});
|
||||
const placeholders = values.map(() => "?").join(", ");
|
||||
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
|
||||
|
||||
return { sql: insertSql, params: values };
|
||||
},
|
||||
```
|
||||
|
||||
#### **Step 2.2: Add generateUpdateStatement to PlatformServiceMixin**
|
||||
```typescript
|
||||
// Add to PlatformServiceMixin methods:
|
||||
_generateUpdateStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
whereClause: string,
|
||||
whereParams: unknown[] = [],
|
||||
): { sql: string; params: unknown[] } {
|
||||
const setClauses: string[] = [];
|
||||
const params: unknown[] = [];
|
||||
|
||||
Object.entries(model).forEach(([key, value]) => {
|
||||
setClauses.push(`${key} = ?`);
|
||||
let convertedValue = value ?? null;
|
||||
if (convertedValue !== null) {
|
||||
if (typeof convertedValue === "object") {
|
||||
convertedValue = JSON.stringify(convertedValue);
|
||||
} else if (typeof convertedValue === "boolean") {
|
||||
convertedValue = convertedValue ? 1 : 0;
|
||||
}
|
||||
}
|
||||
params.push(convertedValue);
|
||||
});
|
||||
|
||||
if (setClauses.length === 0) {
|
||||
throw new Error("No valid fields to update");
|
||||
}
|
||||
|
||||
const sql = `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE ${whereClause}`;
|
||||
return { sql, params: [...params, ...whereParams] };
|
||||
},
|
||||
```
|
||||
|
||||
#### **Step 2.3: Add Public Wrapper Methods**
|
||||
```typescript
|
||||
// Add to PlatformServiceMixin methods:
|
||||
$generateInsertStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
): { sql: string; params: unknown[] } {
|
||||
return this._generateInsertStatement(model, tableName);
|
||||
},
|
||||
|
||||
$generateUpdateStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
whereClause: string,
|
||||
whereParams: unknown[] = [],
|
||||
): { sql: string; params: unknown[] } {
|
||||
return this._generateUpdateStatement(model, tableName, whereClause, whereParams);
|
||||
},
|
||||
```
|
||||
|
||||
### **Phase 3: Update Type Definitions (30 minutes)**
|
||||
|
||||
#### **Step 3.1: Update IPlatformServiceMixin Interface**
|
||||
```typescript
|
||||
// Add to IPlatformServiceMixin interface:
|
||||
$generateInsertStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
): { sql: string; params: unknown[] };
|
||||
$generateUpdateStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
whereClause: string,
|
||||
whereParams?: unknown[],
|
||||
): { sql: string; params: unknown[] };
|
||||
$appendToMemoryLogs(message: string): void;
|
||||
```
|
||||
|
||||
#### **Step 3.2: Update ComponentCustomProperties**
|
||||
```typescript
|
||||
// Add to ComponentCustomProperties interface:
|
||||
$generateInsertStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
): { sql: string; params: unknown[] };
|
||||
$generateUpdateStatement(
|
||||
model: Record<string, unknown>,
|
||||
tableName: string,
|
||||
whereClause: string,
|
||||
whereParams?: unknown[],
|
||||
): { sql: string; params: unknown[] };
|
||||
$appendToMemoryLogs(message: string): void;
|
||||
```
|
||||
|
||||
### **Phase 4: Test PlatformServiceMixin (1 hour)**
|
||||
|
||||
#### **Step 4.1: Create Test Component**
|
||||
```typescript
|
||||
// Create test file: src/test/PlatformServiceMixin.test.ts
|
||||
// Test all methods including new utility functions
|
||||
```
|
||||
|
||||
#### **Step 4.2: Run Linting and Type Checking**
|
||||
```bash
|
||||
npm run lint
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **DAY 2: Migrate All 52 Files (6-8 hours)**
|
||||
|
||||
### **Migration Strategy**
|
||||
|
||||
#### **Priority Order:**
|
||||
1. **Views** (25 files) - User-facing components
|
||||
2. **Components** (15 files) - Reusable UI components
|
||||
3. **Services** (8 files) - Business logic
|
||||
4. **Utils** (4 files) - Utility functions
|
||||
|
||||
#### **Migration Pattern for Each File:**
|
||||
|
||||
**Step 1: Add PlatformServiceMixin**
|
||||
```typescript
|
||||
// Add to component imports:
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
|
||||
// Add to component definition:
|
||||
export default class ComponentName extends Vue {
|
||||
// Add mixin
|
||||
mixins = [PlatformServiceMixin];
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: Replace databaseUtil Imports**
|
||||
```typescript
|
||||
// Remove:
|
||||
import {
|
||||
generateInsertStatement,
|
||||
generateUpdateStatement,
|
||||
parseJsonField,
|
||||
mapColumnsToValues,
|
||||
logToDb,
|
||||
logConsoleAndDb
|
||||
} from "@/db/databaseUtil";
|
||||
|
||||
// Replace with mixin methods:
|
||||
// generateInsertStatement → this.$generateInsertStatement
|
||||
// generateUpdateStatement → this.$generateUpdateStatement
|
||||
// parseJsonField → this._parseJsonField
|
||||
// mapColumnsToValues → this._mapColumnsToValues
|
||||
// logToDb → this.$log
|
||||
// logConsoleAndDb → this.$logAndConsole
|
||||
```
|
||||
|
||||
**Step 3: Update Method Calls**
|
||||
```typescript
|
||||
// Before:
|
||||
const { sql, params } = generateInsertStatement(contact, 'contacts');
|
||||
|
||||
// After:
|
||||
const { sql, params } = this.$generateInsertStatement(contact, 'contacts');
|
||||
```
|
||||
|
||||
### **File Migration Checklist**
|
||||
|
||||
#### **Views (25 files) - Priority 1**
|
||||
- [ ] QuickActionBvcEndView.vue
|
||||
- [ ] ProjectsView.vue
|
||||
- [ ] ClaimReportCertificateView.vue
|
||||
- [ ] NewEditAccountView.vue
|
||||
- [ ] OnboardMeetingSetupView.vue
|
||||
- [ ] SearchAreaView.vue
|
||||
- [ ] TestView.vue
|
||||
- [ ] InviteOneView.vue
|
||||
- [ ] IdentitySwitcherView.vue
|
||||
- [ ] HelpNotificationsView.vue
|
||||
- [ ] StartView.vue
|
||||
- [ ] OfferDetailsView.vue
|
||||
- [ ] ContactEditView.vue
|
||||
- [ ] SharedPhotoView.vue
|
||||
- [ ] ContactQRScanShowView.vue
|
||||
- [ ] ContactGiftingView.vue
|
||||
- [ ] DiscoverView.vue
|
||||
- [ ] ImportAccountView.vue
|
||||
- [ ] ConfirmGiftView.vue
|
||||
- [ ] SeedBackupView.vue
|
||||
- [ ] [5 more view files]
|
||||
|
||||
#### **Components (15 files) - Priority 2**
|
||||
- [ ] ActivityListItem.vue
|
||||
- [ ] AmountInput.vue
|
||||
- [ ] ChoiceButtonDialog.vue
|
||||
- [ ] ContactNameDialog.vue
|
||||
- [ ] DataExportSection.vue
|
||||
- [ ] EntityGrid.vue
|
||||
- [ ] EntityIcon.vue
|
||||
- [ ] EntitySelectionStep.vue
|
||||
- [ ] EntitySummaryButton.vue
|
||||
- [ ] FeedFilters.vue
|
||||
- [ ] GiftDetailsStep.vue
|
||||
- [ ] GiftedDialog.vue
|
||||
- [ ] GiftedPrompts.vue
|
||||
- [ ] HiddenDidDialog.vue
|
||||
- [ ] IconRenderer.vue
|
||||
|
||||
#### **Services (8 files) - Priority 3**
|
||||
- [ ] api.ts
|
||||
- [ ] endorserServer.ts
|
||||
- [ ] partnerServer.ts
|
||||
- [ ] [5 more service files]
|
||||
|
||||
#### **Utils (4 files) - Priority 4**
|
||||
- [ ] LogCollector.ts
|
||||
- [ ] [3 more util files]
|
||||
|
||||
### **Migration Tools**
|
||||
|
||||
#### **Automated Script for Common Patterns**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# migration-helper.sh
|
||||
|
||||
# Find all databaseUtil imports
|
||||
echo "Files with databaseUtil imports:"
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil"
|
||||
|
||||
# Common replacement patterns
|
||||
echo "Common replacement patterns:"
|
||||
echo "generateInsertStatement → this.\$generateInsertStatement"
|
||||
echo "generateUpdateStatement → this.\$generateUpdateStatement"
|
||||
echo "parseJsonField → this._parseJsonField"
|
||||
echo "mapColumnsToValues → this._mapColumnsToValues"
|
||||
echo "logToDb → this.\$log"
|
||||
echo "logConsoleAndDb → this.\$logAndConsole"
|
||||
```
|
||||
|
||||
#### **Validation Script**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# validate-migration.sh
|
||||
|
||||
# Check for remaining databaseUtil imports
|
||||
echo "Checking for remaining databaseUtil imports..."
|
||||
find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil"
|
||||
|
||||
# Run linting
|
||||
echo "Running linting..."
|
||||
npm run lint
|
||||
|
||||
# Run type checking
|
||||
echo "Running type checking..."
|
||||
npx tsc --noEmit
|
||||
|
||||
echo "Migration validation complete!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Success Criteria**
|
||||
|
||||
### **Day 1 Success Criteria:**
|
||||
- [ ] PlatformServiceMixin has no circular dependencies
|
||||
- [ ] All utility functions implemented and tested
|
||||
- [ ] Type definitions complete and accurate
|
||||
- [ ] Linting passes with no errors
|
||||
- [ ] TypeScript compilation passes
|
||||
|
||||
### **Day 2 Success Criteria:**
|
||||
- [ ] 0 files importing databaseUtil
|
||||
- [ ] All 52 files migrated to PlatformServiceMixin
|
||||
- [ ] No runtime errors in migrated components
|
||||
- [ ] All tests passing
|
||||
- [ ] Performance maintained or improved
|
||||
|
||||
### **Overall Success Criteria:**
|
||||
- [ ] Complete elimination of databaseUtil dependency
|
||||
- [ ] PlatformServiceMixin is the single source of truth for database operations
|
||||
- [ ] Migration fence is fully implemented
|
||||
- [ ] Ready for Phase 3: Cleanup and Optimization
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Post-Migration Benefits**
|
||||
|
||||
1. **80% reduction** in database boilerplate code
|
||||
2. **Centralized caching** for improved performance
|
||||
3. **Type-safe** database operations
|
||||
4. **Eliminated circular dependencies**
|
||||
5. **Simplified testing** with mockable mixin
|
||||
6. **Consistent error handling** across all components
|
||||
7. **Ready for SQLite-only mode**
|
||||
|
||||
---
|
||||
|
||||
## 📋 **Daily Progress Tracking**
|
||||
|
||||
### **Day 1 Progress:**
|
||||
- [ ] Phase 1: Circular dependency resolved
|
||||
- [ ] Phase 2: Utility functions added
|
||||
- [ ] Phase 3: Type definitions updated
|
||||
- [ ] Phase 4: Testing completed
|
||||
|
||||
### **Day 2 Progress:**
|
||||
- [ ] Views migrated (0/25)
|
||||
- [ ] Components migrated (0/15)
|
||||
- [ ] Services migrated (0/8)
|
||||
- [ ] Utils migrated (0/4)
|
||||
- [ ] Validation completed
|
||||
|
||||
---
|
||||
|
||||
## 🆘 **Contingency Plans**
|
||||
|
||||
### **If Day 1 Takes Longer:**
|
||||
- Focus on core functionality first
|
||||
- Defer advanced utility functions to Day 2
|
||||
- Prioritize circular dependency resolution
|
||||
|
||||
### **If Day 2 Takes Longer:**
|
||||
- Focus on high-impact views first
|
||||
- Batch similar components together
|
||||
- Use automated scripts for common patterns
|
||||
|
||||
### **If Issues Arise:**
|
||||
- Document specific problems
|
||||
- Create targeted fixes
|
||||
- Maintain backward compatibility during transition
|
||||
@@ -168,7 +168,7 @@ export async function createBuildConfig(mode: string) {
|
||||
return defineConfig({
|
||||
define: {
|
||||
'process.env.VITE_PLATFORM': JSON.stringify(mode),
|
||||
// PWA is automatically enabled for web platforms via build configuration
|
||||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative),
|
||||
__IS_MOBILE__: JSON.stringify(isCapacitor),
|
||||
__USE_QR_READER__: JSON.stringify(!isCapacitor)
|
||||
},
|
||||
|
||||
@@ -130,9 +130,10 @@ async function getAccount(did: string): Promise<Account | undefined> {
|
||||
[did]
|
||||
);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
account = await db.accounts.get(did);
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
@@ -155,9 +156,10 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
|
||||
);
|
||||
result = databaseUtil.mapQueryResultToValues(result);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
result = await db.table.where("field").equals(value).first();
|
||||
}
|
||||
```
|
||||
|
||||
2. **Update Operations**
|
||||
@@ -178,9 +180,10 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
|
||||
[changes.field1, changes.field2, id]
|
||||
);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
await db.table.where("id").equals(id).modify(changes);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Insert Operations**
|
||||
@@ -196,9 +199,10 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
|
||||
const sql = `INSERT INTO table (${columns.join(', ')}) VALUES (${placeholders})`;
|
||||
await platform.dbExec(sql, values);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
await db.table.add(item);
|
||||
}
|
||||
```
|
||||
|
||||
4. **Delete Operations**
|
||||
@@ -210,9 +214,10 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
|
||||
const platform = PlatformServiceFactory.getInstance();
|
||||
await platform.dbExec("DELETE FROM table WHERE id = ?", [id]);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
await db.table.where("id").equals(id).delete();
|
||||
}
|
||||
```
|
||||
|
||||
5. **Result Processing**
|
||||
@@ -225,9 +230,10 @@ When converting from Dexie.js to SQL-based implementation, follow these patterns
|
||||
let items = await platform.dbQuery("SELECT * FROM table");
|
||||
items = databaseUtil.mapQueryResultToValues(items);
|
||||
|
||||
// Fallback to Dexie if needed (migration period only)
|
||||
// Note: This fallback is only used during the migration period
|
||||
// and will be removed once migration is complete
|
||||
// Fallback to Dexie if needed
|
||||
if (USE_DEXIE_DB) {
|
||||
items = await db.table.toArray();
|
||||
}
|
||||
```
|
||||
|
||||
6. **Using Utility Methods**
|
||||
@@ -249,9 +255,9 @@ await databaseUtil.logConsoleAndDb(message, showInConsole);
|
||||
Key Considerations:
|
||||
- Always use `databaseUtil.mapQueryResultToValues()` to process SQL query results
|
||||
- Use utility methods from `db/index.ts` when available instead of direct SQL
|
||||
- Keep Dexie fallbacks wrapped in migration period checks
|
||||
- Keep Dexie fallbacks wrapped in `if (USE_DEXIE_DB)` checks
|
||||
- For queries that return results, use `let` variables to allow Dexie fallback to override
|
||||
- For updates/inserts/deletes, execute both SQL and Dexie operations during migration period
|
||||
- For updates/inserts/deletes, execute both SQL and Dexie operations when `USE_DEXIE_DB` is true
|
||||
|
||||
Example Migration:
|
||||
```typescript
|
||||
@@ -279,8 +285,8 @@ Remember to:
|
||||
|
||||
- For creates & updates & deletes, the duplicate code is fine.
|
||||
|
||||
- For queries where we use the results, make the setting from SQL into a 'let' variable, then wrap the Dexie code in a migration period check and if
|
||||
it's during migration then use that result instead of the SQL code's result.
|
||||
- For queries where we use the results, make the setting from SQL into a 'let' variable, then wrap the Dexie code in a check for USE_DEXIE_DB from app.ts and if
|
||||
it's true then use that result instead of the SQL code's result.
|
||||
|
||||
- Consider data migration needs, and warn if there are any potential migration problems
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
|
||||
# SharedArrayBuffer, Spectre, and Cross-Origin Isolation Concerns
|
||||
|
||||
## 1. Introduction to SharedArrayBuffer
|
||||
|
||||
### Overview
|
||||
- `SharedArrayBuffer` is a JavaScript object that enables **shared memory** access between the main thread and Web Workers.
|
||||
- Unlike `ArrayBuffer`, the memory is **not copied** between threads—allowing **true parallelism**.
|
||||
- Paired with `Atomics`, it allows low-level memory synchronization (e.g., locks, waits).
|
||||
|
||||
### Example Use
|
||||
```js
|
||||
const sab = new SharedArrayBuffer(1024);
|
||||
const sharedArray = new Uint8Array(sab);
|
||||
sharedArray[0] = 42;
|
||||
```
|
||||
|
||||
## 2. Browser Security Requirements
|
||||
|
||||
### Security Headers Required to Use SharedArrayBuffer
|
||||
Modern browsers **restrict access** to `SharedArrayBuffer` due to Spectre-class vulnerabilities.
|
||||
|
||||
The following **HTTP headers must be set** to enable it:
|
||||
|
||||
```
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
```
|
||||
|
||||
### HTTPS Requirement
|
||||
- Must be served over **HTTPS** (except `localhost` for dev).
|
||||
- These headers enforce **cross-origin isolation**.
|
||||
|
||||
### Role of CORS
|
||||
- CORS **alone is not sufficient**.
|
||||
- However, embedded resources (like scripts and iframes) must still include proper CORS headers if they are to be loaded in a cross-origin isolated context.
|
||||
|
||||
## 3. Spectre Vulnerability
|
||||
|
||||
### What is Spectre?
|
||||
- A class of **side-channel attacks** exploiting **speculative execution** in CPUs.
|
||||
- Allows an attacker to read arbitrary memory from the same address space.
|
||||
|
||||
### Affected Architectures
|
||||
- Intel, AMD, ARM — essentially **all modern processors**.
|
||||
|
||||
### Why It's Still a Concern
|
||||
- It's a **hardware flaw**, not just a software bug.
|
||||
- Can't be fully fixed in software without performance penalties.
|
||||
- New Spectre **variants** (e.g., v2, RSB, BranchScope) continue to emerge.
|
||||
|
||||
## 4. Mitigations and Current Limitations
|
||||
|
||||
### Browser Mitigations
|
||||
- **Restricted precision** for `performance.now()`.
|
||||
- **Disabled or gated** access to `SharedArrayBuffer`.
|
||||
- **Reduced or removed** fine-grained timers.
|
||||
|
||||
### OS/Hardware Mitigations
|
||||
- **Kernel Page Table Isolation (KPTI)**
|
||||
- **Microcode updates**
|
||||
- **Retpoline** compiler mitigations
|
||||
|
||||
### Developer Responsibilities
|
||||
- Avoid sharing sensitive data across threads unless necessary.
|
||||
- Use **constant-time cryptographic functions**.
|
||||
- Assume timing attacks are **still possible**.
|
||||
- Opt into **cross-origin isolation** only when absolutely required.
|
||||
|
||||
## 5. Practical Development Notes
|
||||
|
||||
### Using SharedArrayBuffer Safely
|
||||
- Ensure the site is **cross-origin isolated**:
|
||||
- Serve all resources with appropriate **CORS policies** (`Cross-Origin-Resource-Policy`, `Access-Control-Allow-Origin`)
|
||||
- Set the required **COOP/COEP headers**
|
||||
- Validate support using:
|
||||
```js
|
||||
if (window.crossOriginIsolated) {
|
||||
// Safe to use SharedArrayBuffer
|
||||
}
|
||||
```
|
||||
|
||||
### Testing and Fallback
|
||||
- Provide fallbacks to `ArrayBuffer` if isolation is not available.
|
||||
- Document use cases clearly (e.g., high-performance WebAssembly applications or real-time audio/video processing).
|
||||
|
||||
## 6. Summary of Concerns and Advisements
|
||||
|
||||
| Topic | Concern / Consideration | Advisory |
|
||||
|-------------------------------|------------------------------------------------------|--------------------------------------------------------|
|
||||
| Shared Memory | Can expose sensitive data across threads | Use only in cross-origin isolated environments |
|
||||
| Spectre Vulnerabilities | Still viable, evolving with new attack vectors | Do not assume complete mitigation; minimize attack surfaces |
|
||||
| Cross-Origin Isolation | Required for `SharedArrayBuffer` | Must serve with COOP/COEP headers + HTTPS |
|
||||
| CORS | Not sufficient alone | Must combine with full isolation policies |
|
||||
| Developer Security Practices | Timing attacks and shared state remain risky | Favor safer primitives; avoid unnecessary complexity |
|
||||
@@ -1,152 +0,0 @@
|
||||
# TimeSafari Docker Compose Configuration
|
||||
# Author: Matthew Raymer
|
||||
# Description: Multi-environment Docker Compose setup for TimeSafari
|
||||
#
|
||||
# IMPORTANT: Build web assets first using npm scripts before running docker-compose
|
||||
#
|
||||
# Usage:
|
||||
# Development: npm run build:web:build -- --mode development && docker-compose up dev
|
||||
# Test: npm run build:web:build -- --mode test && docker-compose up test
|
||||
# Production: npm run build:web:build -- --mode production && docker-compose up production
|
||||
# Custom: BUILD_MODE=test npm run build:web:build -- --mode test && docker-compose up custom
|
||||
#
|
||||
# Environment Variables:
|
||||
# BUILD_MODE: development, test, or production (default: production)
|
||||
# NODE_ENV: node environment (default: production)
|
||||
# PORT: port to expose (default: 80 for production, 8080 for test)
|
||||
# ENV_FILE: environment file to use (default: .env.production)
|
||||
#
|
||||
# Note: For development, use npm run build:web directly (no Docker needed)
|
||||
|
||||
version: '3.8'
|
||||
|
||||
# Default values that can be overridden
|
||||
x-defaults: &defaults
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
BUILD_MODE: ${BUILD_MODE:-production}
|
||||
NODE_ENV: ${NODE_ENV:-production}
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
services:
|
||||
# Test service for testing environment
|
||||
test:
|
||||
<<: *defaults
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: test
|
||||
args:
|
||||
BUILD_MODE: test
|
||||
NODE_ENV: test
|
||||
ports:
|
||||
- "${TEST_PORT:-8080}:80"
|
||||
environment:
|
||||
- NODE_ENV=test
|
||||
- BUILD_MODE=test
|
||||
env_file:
|
||||
- ${TEST_ENV_FILE:-.env.test}
|
||||
|
||||
# Production service
|
||||
production:
|
||||
<<: *defaults
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: production
|
||||
args:
|
||||
BUILD_MODE: production
|
||||
NODE_ENV: production
|
||||
ports:
|
||||
- "${PROD_PORT:-80}:80"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- BUILD_MODE=production
|
||||
env_file:
|
||||
- ${PROD_ENV_FILE:-.env.production}
|
||||
|
||||
# Production service with SSL (requires certificates)
|
||||
production-ssl:
|
||||
<<: *defaults
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: production
|
||||
args:
|
||||
BUILD_MODE: production
|
||||
NODE_ENV: production
|
||||
ports:
|
||||
- "${SSL_PORT:-443}:443"
|
||||
- "${HTTP_PORT:-80}:80"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- BUILD_MODE=production
|
||||
env_file:
|
||||
- ${PROD_ENV_FILE:-.env.production}
|
||||
volumes:
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
- ./docker/nginx-ssl.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "https://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# Custom service - configurable via environment variables
|
||||
custom:
|
||||
<<: *defaults
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: ${BUILD_TARGET:-production}
|
||||
args:
|
||||
BUILD_MODE: ${BUILD_MODE:-production}
|
||||
NODE_ENV: ${NODE_ENV:-production}
|
||||
ports:
|
||||
- "${CUSTOM_PORT:-8080}:${CUSTOM_INTERNAL_PORT:-80}"
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV:-production}
|
||||
- BUILD_MODE=${BUILD_MODE:-production}
|
||||
env_file:
|
||||
- ${CUSTOM_ENV_FILE:-.env.production}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:${CUSTOM_INTERNAL_PORT:-80}/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# Load balancer for production (optional)
|
||||
nginx-lb:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "${LB_PORT:-80}:80"
|
||||
- "${LB_SSL_PORT:-443}:443"
|
||||
volumes:
|
||||
- ./docker/nginx-lb.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
depends_on:
|
||||
- production
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
507
docker/README.md
@@ -1,507 +0,0 @@
|
||||
# TimeSafari Docker Setup
|
||||
|
||||
## Overview
|
||||
|
||||
This directory contains Docker configuration files for building and deploying TimeSafari across different environments with full configurability.
|
||||
|
||||
## Files
|
||||
|
||||
- `Dockerfile` - Multi-stage Docker build for TimeSafari
|
||||
- `nginx.conf` - Main nginx configuration with security headers
|
||||
- `default.conf` - Production server configuration
|
||||
- `staging.conf` - Staging server configuration with relaxed caching
|
||||
- `docker-compose.yml` - Multi-environment Docker Compose setup
|
||||
- `.dockerignore` - Optimizes build context
|
||||
- `run.sh` - Convenient script to run different configurations
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using the Run Script (Recommended)
|
||||
|
||||
```bash
|
||||
# Development mode with hot reloading
|
||||
./docker/run.sh dev
|
||||
|
||||
# Staging mode for testing
|
||||
./docker/run.sh staging
|
||||
|
||||
# Production mode
|
||||
./docker/run.sh production
|
||||
|
||||
# Custom mode with environment variables
|
||||
BUILD_MODE=staging ./docker/run.sh custom
|
||||
|
||||
# Show build arguments for a mode
|
||||
./docker/run.sh dev --build-args
|
||||
|
||||
# Custom port and environment file
|
||||
./docker/run.sh staging --port 9000 --env .env.test
|
||||
```
|
||||
|
||||
### Using Docker Compose
|
||||
|
||||
```bash
|
||||
# Development environment with hot reloading
|
||||
docker-compose up dev
|
||||
|
||||
# Staging environment
|
||||
docker-compose up staging
|
||||
|
||||
# Production environment
|
||||
docker-compose up production
|
||||
|
||||
# Custom environment with variables
|
||||
BUILD_MODE=staging docker-compose up custom
|
||||
```
|
||||
|
||||
## Build Commands
|
||||
|
||||
### Manual Docker Build
|
||||
|
||||
```bash
|
||||
# Build production image (default)
|
||||
docker build -t timesafari:latest .
|
||||
|
||||
# Build staging image
|
||||
docker build --build-arg BUILD_MODE=staging -t timesafari:staging .
|
||||
|
||||
# Build development image
|
||||
docker build --build-arg BUILD_MODE=development -t timesafari:dev .
|
||||
|
||||
# Build with custom arguments
|
||||
docker build \
|
||||
--build-arg BUILD_MODE=staging \
|
||||
--build-arg NODE_ENV=staging \
|
||||
|
||||
-t timesafari:custom .
|
||||
```
|
||||
|
||||
### Run Container
|
||||
|
||||
```bash
|
||||
# Run production container
|
||||
docker run -d -p 80:80 timesafari:latest
|
||||
|
||||
# Run with environment file
|
||||
docker run -d -p 80:80 --env-file .env.production timesafari:latest
|
||||
|
||||
# Run with custom environment variables
|
||||
docker run -d -p 80:80 \
|
||||
-e VITE_APP_SERVER=https://myapp.com \
|
||||
-e VITE_DEFAULT_ENDORSER_API_SERVER=https://api.myapp.com \
|
||||
timesafari:latest
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Build Arguments
|
||||
|
||||
The Dockerfile supports these build arguments:
|
||||
|
||||
| Argument | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `BUILD_MODE` | `production` | Build mode: development, staging, or production |
|
||||
| `NODE_ENV` | `production` | Node.js environment |
|
||||
| `VITE_PLATFORM` | `web` | Vite platform type |
|
||||
| PWA | `enabled` | Automatically enabled for web platforms |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Docker Compose supports these environment variables:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `BUILD_MODE` | `production` | Build mode |
|
||||
| `NODE_ENV` | `production` | Node environment |
|
||||
| `VITE_PLATFORM` | `web` | Vite platform |
|
||||
| PWA | `enabled` | Automatically enabled for web platforms |
|
||||
| `DEV_PORT` | `5173` | Development port |
|
||||
| `STAGING_PORT` | `8080` | Staging port |
|
||||
| `PROD_PORT` | `80` | Production port |
|
||||
| `DEV_ENV_FILE` | `.env.development` | Development env file |
|
||||
| `TEST_ENV_FILE` | `.env.test` | Test env file |
|
||||
| `PROD_ENV_FILE` | `.env.production` | Production env file |
|
||||
|
||||
### Environment Files
|
||||
|
||||
Create environment files for different deployments:
|
||||
|
||||
```bash
|
||||
# .env.development
|
||||
VITE_APP_SERVER=https://dev.timesafari.app
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://dev-api.endorser.ch
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://dev-image-api.timesafari.app
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=https://dev-partner-api.endorser.ch
|
||||
VITE_DEFAULT_PUSH_SERVER=https://dev.timesafari.app
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
|
||||
# .env.test
|
||||
VITE_APP_SERVER=https://staging.timesafari.app
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://staging-api.endorser.ch
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://staging-image-api.timesafari.app
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=https://staging-partner-api.endorser.ch
|
||||
VITE_DEFAULT_PUSH_SERVER=https://staging.timesafari.app
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
|
||||
# .env.production
|
||||
VITE_APP_SERVER=https://timesafari.app
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
|
||||
VITE_DEFAULT_PUSH_SERVER=https://timesafari.app
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
```
|
||||
|
||||
## Build Modes
|
||||
|
||||
### Development Mode
|
||||
- **Target**: `development`
|
||||
- **Features**: Hot reloading, development server
|
||||
- **Port**: 5173
|
||||
- **Caching**: Disabled
|
||||
- **Use Case**: Local development
|
||||
|
||||
```bash
|
||||
./docker/run.sh dev
|
||||
# or
|
||||
docker build --target development -t timesafari:dev .
|
||||
```
|
||||
|
||||
### Staging Mode
|
||||
- **Target**: `staging`
|
||||
- **Features**: Production build with relaxed caching
|
||||
- **Port**: 8080 (mapped from 80)
|
||||
- **Caching**: Short-term (1 hour)
|
||||
- **Use Case**: Testing and QA
|
||||
|
||||
```bash
|
||||
./docker/run.sh staging
|
||||
# or
|
||||
docker build --build-arg BUILD_MODE=staging -t timesafari:staging .
|
||||
```
|
||||
|
||||
### Production Mode
|
||||
- **Target**: `production`
|
||||
- **Features**: Optimized production build
|
||||
- **Port**: 80
|
||||
- **Caching**: Long-term (1 year for assets)
|
||||
- **Use Case**: Live deployment
|
||||
|
||||
```bash
|
||||
./docker/run.sh production
|
||||
# or
|
||||
docker build -t timesafari:latest .
|
||||
```
|
||||
|
||||
### Custom Mode
|
||||
- **Target**: Configurable via `BUILD_TARGET`
|
||||
- **Features**: Fully configurable
|
||||
- **Port**: Configurable via `CUSTOM_PORT`
|
||||
- **Use Case**: Special deployments
|
||||
|
||||
```bash
|
||||
BUILD_MODE=staging NODE_ENV=staging ./docker/run.sh custom
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Build Configuration
|
||||
|
||||
```bash
|
||||
# Build with specific environment
|
||||
docker build \
|
||||
--build-arg BUILD_MODE=staging \
|
||||
--build-arg NODE_ENV=staging \
|
||||
|
||||
-t timesafari:staging-no-pwa .
|
||||
|
||||
# Run with custom configuration
|
||||
docker run -d -p 9000:80 \
|
||||
-e VITE_APP_SERVER=https://test.example.com \
|
||||
timesafari:staging-no-pwa
|
||||
```
|
||||
|
||||
### Docker Compose with Custom Variables
|
||||
|
||||
```bash
|
||||
# Set environment variables
|
||||
export BUILD_MODE=staging
|
||||
export NODE_ENV=staging
|
||||
export STAGING_PORT=9000
|
||||
export STAGING_ENV_FILE=.env.test
|
||||
|
||||
# Run staging with custom config
|
||||
docker-compose up staging
|
||||
```
|
||||
|
||||
### Multi-Environment Deployment
|
||||
|
||||
```bash
|
||||
# Development
|
||||
./docker/run.sh dev
|
||||
|
||||
# Staging in another terminal
|
||||
./docker/run.sh staging --port 8081
|
||||
|
||||
# Production in another terminal
|
||||
./docker/run.sh production --port 8082
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
### Built-in Security
|
||||
- **Non-root user execution**: All containers run as non-root users
|
||||
- **Security headers**: XSS protection, content type options, frame options
|
||||
- **Rate limiting**: API request rate limiting
|
||||
- **File access restrictions**: Hidden files and backup files blocked
|
||||
- **Minimal attack surface**: Alpine Linux base images
|
||||
|
||||
### Security Headers
|
||||
- `X-Frame-Options: SAMEORIGIN`
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-XSS-Protection: 1; mode=block`
|
||||
- `Referrer-Policy: strict-origin-when-cross-origin`
|
||||
- `Content-Security-Policy`: Comprehensive CSP policy
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Caching Strategy
|
||||
- **Static assets**: 1 year cache with immutable flag (production)
|
||||
- **HTML files**: 1 hour cache (production) / no cache (staging)
|
||||
- **Service worker**: No cache
|
||||
- **Manifest**: 1 day cache (production) / 1 hour cache (staging)
|
||||
|
||||
### Compression
|
||||
- **Gzip compression**: Enabled for text-based files
|
||||
- **Compression level**: 6 (balanced)
|
||||
- **Minimum size**: 1024 bytes
|
||||
|
||||
### Nginx Optimizations
|
||||
- **Sendfile**: Enabled for efficient file serving
|
||||
- **TCP optimizations**: nopush and nodelay enabled
|
||||
- **Keepalive**: 65 second timeout
|
||||
- **Worker processes**: Auto-detected based on CPU cores
|
||||
|
||||
## Health Checks
|
||||
|
||||
### Built-in Health Checks
|
||||
All services include health checks that:
|
||||
- Check every 30 seconds
|
||||
- Timeout after 10 seconds
|
||||
- Retry 3 times before marking unhealthy
|
||||
- Start checking after 40 seconds
|
||||
|
||||
### Health Check Endpoints
|
||||
- **Production/Staging**: `http://localhost/health`
|
||||
- **Development**: `http://localhost:5173`
|
||||
|
||||
## SSL/HTTPS Setup
|
||||
|
||||
### SSL Certificates
|
||||
For SSL deployment, create an `ssl` directory with certificates:
|
||||
|
||||
```bash
|
||||
mkdir ssl
|
||||
# Copy your certificates to ssl/ directory
|
||||
cp your-cert.pem ssl/
|
||||
cp your-key.pem ssl/
|
||||
```
|
||||
|
||||
### SSL Configuration
|
||||
Use the `production-ssl` service in docker-compose:
|
||||
|
||||
```bash
|
||||
docker-compose up production-ssl
|
||||
```
|
||||
|
||||
## Monitoring and Logging
|
||||
|
||||
### Log Locations
|
||||
- **Access logs**: `/var/log/nginx/access.log`
|
||||
- **Error logs**: `/var/log/nginx/error.log`
|
||||
|
||||
### Log Format
|
||||
```
|
||||
$remote_addr - $remote_user [$time_local] "$request"
|
||||
$status $body_bytes_sent "$http_referer"
|
||||
"$http_user_agent" "$http_x_forwarded_for"
|
||||
```
|
||||
|
||||
### Log Levels
|
||||
- **Production**: `warn` level
|
||||
- **Staging**: `debug` level
|
||||
- **Development**: Full logging
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Build Failures
|
||||
```bash
|
||||
# Check build logs
|
||||
docker build -t timesafari:latest . 2>&1 | tee build.log
|
||||
|
||||
# Verify dependencies
|
||||
docker run --rm timesafari:latest npm list --depth=0
|
||||
|
||||
# Check build arguments
|
||||
./docker/run.sh dev --build-args
|
||||
```
|
||||
|
||||
#### Container Won't Start
|
||||
```bash
|
||||
# Check container logs
|
||||
docker logs <container_id>
|
||||
|
||||
# Check health status
|
||||
docker inspect <container_id> | grep -A 10 "Health"
|
||||
|
||||
# Verify port availability
|
||||
netstat -tulpn | grep :80
|
||||
```
|
||||
|
||||
#### Environment Variables Not Set
|
||||
```bash
|
||||
# Check environment in container
|
||||
docker exec <container_id> env | grep VITE_
|
||||
|
||||
# Verify .env file
|
||||
cat .env.production
|
||||
|
||||
# Check build arguments
|
||||
./docker/run.sh production --build-args
|
||||
```
|
||||
|
||||
#### Performance Issues
|
||||
```bash
|
||||
# Check container resources
|
||||
docker stats <container_id>
|
||||
|
||||
# Check nginx configuration
|
||||
docker exec <container_id> nginx -t
|
||||
|
||||
# Monitor access logs
|
||||
docker exec <container_id> tail -f /var/log/nginx/access.log
|
||||
```
|
||||
|
||||
### Debug Commands
|
||||
|
||||
#### Container Debugging
|
||||
```bash
|
||||
# Enter running container
|
||||
docker exec -it <container_id> /bin/sh
|
||||
|
||||
# Check nginx status
|
||||
docker exec <container_id> nginx -t
|
||||
|
||||
# Check file permissions
|
||||
docker exec <container_id> ls -la /usr/share/nginx/html
|
||||
```
|
||||
|
||||
#### Network Debugging
|
||||
```bash
|
||||
# Check container network
|
||||
docker network inspect bridge
|
||||
|
||||
# Test connectivity
|
||||
docker exec <container_id> curl -I http://localhost
|
||||
|
||||
# Check DNS resolution
|
||||
docker exec <container_id> nslookup google.com
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Recommended Production Setup
|
||||
1. **Use specific version tags**: `timesafari:1.0.0`
|
||||
2. **Implement health checks**: Already included
|
||||
3. **Configure proper logging**: Use external log aggregation
|
||||
4. **Set up reverse proxy**: Use nginx-lb service
|
||||
5. **Use Docker secrets**: For sensitive data
|
||||
|
||||
### Production Commands
|
||||
```bash
|
||||
# Build with specific version
|
||||
docker build -t timesafari:1.0.0 .
|
||||
|
||||
# Run with production settings
|
||||
docker run -d \
|
||||
--name timesafari \
|
||||
-p 80:80 \
|
||||
--restart unless-stopped \
|
||||
--env-file .env.production \
|
||||
timesafari:1.0.0
|
||||
|
||||
# Update production deployment
|
||||
docker stop timesafari
|
||||
docker rm timesafari
|
||||
docker build -t timesafari:1.0.1 .
|
||||
docker run -d --name timesafari -p 80:80 --restart unless-stopped --env-file .env.production timesafari:1.0.1
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Start development environment
|
||||
./docker/run.sh dev
|
||||
|
||||
# Make changes to code (hot reloading enabled)
|
||||
# Access at http://localhost:5173
|
||||
|
||||
# Stop development environment
|
||||
docker-compose down dev
|
||||
```
|
||||
|
||||
### Testing Changes
|
||||
```bash
|
||||
# Build and test staging
|
||||
./docker/run.sh staging
|
||||
|
||||
# Test production build locally
|
||||
./docker/run.sh production
|
||||
```
|
||||
|
||||
### Continuous Integration
|
||||
```bash
|
||||
# Build and test in CI
|
||||
docker build -t timesafari:test .
|
||||
docker run -d --name timesafari-test -p 8080:80 timesafari:test
|
||||
|
||||
# Run tests against container
|
||||
curl -f http://localhost:8080/health
|
||||
|
||||
# Cleanup
|
||||
docker stop timesafari-test
|
||||
docker rm timesafari-test
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Security
|
||||
- Always use non-root users
|
||||
- Keep base images updated
|
||||
- Scan images for vulnerabilities
|
||||
- Use secrets for sensitive data
|
||||
- Implement proper access controls
|
||||
|
||||
### Performance
|
||||
- Use multi-stage builds
|
||||
- Optimize layer caching
|
||||
- Minimize image size
|
||||
- Use appropriate base images
|
||||
- Implement proper caching
|
||||
|
||||
### Monitoring
|
||||
- Use health checks
|
||||
- Monitor resource usage
|
||||
- Set up log aggregation
|
||||
- Implement metrics collection
|
||||
- Use proper error handling
|
||||
|
||||
### Maintenance
|
||||
- Regular security updates
|
||||
- Monitor for vulnerabilities
|
||||
- Keep dependencies updated
|
||||
- Document configuration changes
|
||||
- Test deployment procedures
|
||||
@@ -1,112 +0,0 @@
|
||||
# TimeSafari Default Server Configuration
|
||||
# Author: Matthew Raymer
|
||||
# Description: Production server configuration for TimeSafari web application
|
||||
#
|
||||
# Features:
|
||||
# - Vue.js SPA routing support
|
||||
# - Static file caching optimization
|
||||
# - Security hardening
|
||||
# - Performance optimization
|
||||
# - Proper error handling
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||||
|
||||
# Handle Vue.js SPA routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary "Accept-Encoding";
|
||||
}
|
||||
|
||||
# Cache HTML files for a shorter time
|
||||
location ~* \.html$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, must-revalidate";
|
||||
}
|
||||
}
|
||||
|
||||
# Handle service worker
|
||||
location /sw.js {
|
||||
expires 0;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
|
||||
# Handle manifest file
|
||||
location /manifest.json {
|
||||
expires 1d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# Handle API requests (if needed)
|
||||
# Note: Backend API is not currently deployed
|
||||
# Uncomment and configure when backend service is available
|
||||
# location /api/ {
|
||||
# limit_req zone=api burst=20 nodelay;
|
||||
# proxy_pass http://backend:3000;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
|
||||
# Handle health check
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Handle robots.txt
|
||||
location /robots.txt {
|
||||
expires 1d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# Handle favicon
|
||||
location /favicon.ico {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Security: Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Security: Deny access to backup files
|
||||
location ~ ~$ {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Error pages
|
||||
error_page 404 /index.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
# TimeSafari Nginx Configuration
|
||||
# Author: Matthew Raymer
|
||||
# Description: Main nginx configuration for TimeSafari web application
|
||||
#
|
||||
# Features:
|
||||
# - Security headers for web application
|
||||
# - Gzip compression for better performance
|
||||
# - Proper handling of Vue.js SPA routing
|
||||
# - Static file caching optimization
|
||||
# - Security hardening
|
||||
|
||||
# user nginx; # Commented out - nginx runs as non-root user in container
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /tmp/nginx.pid; # Use /tmp for PID file to avoid permission issues
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging format
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance optimizations
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 16M;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'self';" always;
|
||||
|
||||
# SharedArrayBuffer support headers for absurd-sql
|
||||
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||
add_header Cross-Origin-Embedder-Policy "require-corp" always;
|
||||
|
||||
# Rate limiting
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
|
||||
|
||||
# Include server configurations
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
266
docker/run.sh
@@ -1,266 +0,0 @@
|
||||
#!/bin/bash
|
||||
# TimeSafari Docker Run Script
|
||||
# Author: Matthew Raymer
|
||||
# Description: Convenient script to run TimeSafari in different Docker configurations
|
||||
#
|
||||
# Usage:
|
||||
# ./docker/run.sh dev # Run development mode
|
||||
# ./docker/run.sh staging # Run staging mode
|
||||
# ./docker/run.sh production # Run production mode
|
||||
# ./docker/run.sh custom # Run custom mode with environment variables
|
||||
#
|
||||
# Environment Variables:
|
||||
# BUILD_MODE: development, staging, or production
|
||||
# NODE_ENV: node environment
|
||||
# VITE_PLATFORM: vite platform
|
||||
# PWA: automatically enabled for web platforms
|
||||
# PORT: port to expose
|
||||
# ENV_FILE: environment file to use
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] [INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] [WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Function to show usage
|
||||
show_usage() {
|
||||
echo "TimeSafari Docker Run Script"
|
||||
echo ""
|
||||
echo "Usage: $0 <mode> [options]"
|
||||
echo ""
|
||||
echo "Modes:"
|
||||
echo " dev - Development mode with hot reloading"
|
||||
echo " staging - Staging mode for testing"
|
||||
echo " production - Production mode"
|
||||
echo " custom - Custom mode with environment variables"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --port <port> - Custom port (default: 5173 for dev, 8080 for staging, 80 for production)"
|
||||
echo " --env <file> - Environment file (default: .env.<mode>)"
|
||||
echo " --build-args - Show build arguments for the mode"
|
||||
echo " --help - Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 dev"
|
||||
echo " $0 staging --port 9000"
|
||||
echo " $0 production --env .env.prod"
|
||||
echo " BUILD_MODE=staging $0 custom"
|
||||
echo ""
|
||||
echo "Environment Variables:"
|
||||
echo " BUILD_MODE: development, staging, or production"
|
||||
echo " NODE_ENV: node environment"
|
||||
echo " VITE_PLATFORM: vite platform"
|
||||
echo " PWA: automatically enabled for web platforms"
|
||||
echo " PORT: port to expose"
|
||||
echo " ENV_FILE: environment file to use"
|
||||
}
|
||||
|
||||
# Function to show build arguments for a mode
|
||||
show_build_args() {
|
||||
local mode=$1
|
||||
echo "Build arguments for $mode mode:"
|
||||
echo ""
|
||||
case $mode in
|
||||
dev)
|
||||
echo " BUILD_MODE: development"
|
||||
echo " NODE_ENV: development"
|
||||
echo " VITE_PLATFORM: web"
|
||||
echo " PWA: enabled (web platform)"
|
||||
echo " Target: development"
|
||||
echo " Port: 5173"
|
||||
;;
|
||||
staging)
|
||||
echo " BUILD_MODE: staging"
|
||||
echo " NODE_ENV: staging"
|
||||
echo " VITE_PLATFORM: web"
|
||||
echo " PWA: enabled (web platform)"
|
||||
echo " Target: staging"
|
||||
echo " Port: 80 (mapped to 8080)"
|
||||
;;
|
||||
production)
|
||||
echo " BUILD_MODE: production"
|
||||
echo " NODE_ENV: production"
|
||||
echo " VITE_PLATFORM: web"
|
||||
echo " PWA: enabled (web platform)"
|
||||
echo " Target: production"
|
||||
echo " Port: 80"
|
||||
;;
|
||||
custom)
|
||||
echo " BUILD_MODE: \${BUILD_MODE:-production}"
|
||||
echo " NODE_ENV: \${NODE_ENV:-production}"
|
||||
echo " VITE_PLATFORM: \${VITE_PLATFORM:-web}"
|
||||
echo " PWA: enabled for web platforms"
|
||||
echo " Target: \${BUILD_TARGET:-production}"
|
||||
echo " Port: \${CUSTOM_PORT:-8080}:\${CUSTOM_INTERNAL_PORT:-80}"
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown mode: $mode"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to check if Docker is running
|
||||
check_docker() {
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
log_error "Docker is not running. Please start Docker and try again."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if docker-compose is available
|
||||
check_docker_compose() {
|
||||
if ! command -v docker-compose > /dev/null 2>&1; then
|
||||
log_error "docker-compose is not installed. Please install docker-compose and try again."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if required files exist
|
||||
check_files() {
|
||||
local mode=$1
|
||||
local env_file=$2
|
||||
|
||||
if [ ! -f "Dockerfile" ]; then
|
||||
log_error "Dockerfile not found. Please run this script from the project root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "docker-compose.yml" ]; then
|
||||
log_error "docker-compose.yml not found. Please run this script from the project root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$env_file" ] && [ ! -f "$env_file" ]; then
|
||||
log_warn "Environment file $env_file not found. Using defaults."
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to run the container
|
||||
run_container() {
|
||||
local mode=$1
|
||||
local port=$2
|
||||
local env_file=$3
|
||||
|
||||
log_info "Starting TimeSafari in $mode mode..."
|
||||
|
||||
# Set environment variables based on mode
|
||||
case $mode in
|
||||
dev)
|
||||
export DEV_PORT=${port:-5173}
|
||||
if [ -n "$env_file" ]; then
|
||||
export DEV_ENV_FILE="$env_file"
|
||||
fi
|
||||
docker-compose up dev
|
||||
;;
|
||||
staging)
|
||||
export STAGING_PORT=${port:-8080}
|
||||
if [ -n "$env_file" ]; then
|
||||
export STAGING_ENV_FILE="$env_file"
|
||||
fi
|
||||
docker-compose up staging
|
||||
;;
|
||||
production)
|
||||
export PROD_PORT=${port:-80}
|
||||
if [ -n "$env_file" ]; then
|
||||
export PROD_ENV_FILE="$env_file"
|
||||
fi
|
||||
docker-compose up production
|
||||
;;
|
||||
custom)
|
||||
export CUSTOM_PORT=${port:-8080}
|
||||
if [ -n "$env_file" ]; then
|
||||
export CUSTOM_ENV_FILE="$env_file"
|
||||
fi
|
||||
docker-compose up custom
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown mode: $mode"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Main script
|
||||
main() {
|
||||
local mode=""
|
||||
local port=""
|
||||
local env_file=""
|
||||
local show_args=false
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
dev|staging|production|custom)
|
||||
mode="$1"
|
||||
shift
|
||||
;;
|
||||
--port)
|
||||
port="$2"
|
||||
shift 2
|
||||
;;
|
||||
--env)
|
||||
env_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
--build-args)
|
||||
show_args=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
show_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if mode is provided
|
||||
if [ -z "$mode" ]; then
|
||||
log_error "No mode specified."
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show build arguments if requested
|
||||
if [ "$show_args" = true ]; then
|
||||
show_build_args "$mode"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check prerequisites
|
||||
check_docker
|
||||
check_docker_compose
|
||||
check_files "$mode" "$env_file"
|
||||
|
||||
# Run the container
|
||||
run_container "$mode" "$port" "$env_file"
|
||||
}
|
||||
|
||||
# Run main function with all arguments
|
||||
main "$@"
|
||||
@@ -1,112 +0,0 @@
|
||||
# TimeSafari Staging Server Configuration
|
||||
# Author: Matthew Raymer
|
||||
# Description: Staging server configuration for TimeSafari web application
|
||||
#
|
||||
# Features:
|
||||
# - Relaxed caching for testing
|
||||
# - Debug-friendly settings
|
||||
# - Same security as production
|
||||
# - Development-friendly error handling
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Security headers (same as production)
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
||||
|
||||
# Handle Vue.js SPA routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
|
||||
# Relaxed caching for staging
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, must-revalidate";
|
||||
add_header Vary "Accept-Encoding";
|
||||
}
|
||||
|
||||
# No caching for HTML files in staging
|
||||
location ~* \.html$ {
|
||||
expires 0;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
}
|
||||
|
||||
# Handle service worker (no caching)
|
||||
location /sw.js {
|
||||
expires 0;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
}
|
||||
|
||||
# Handle manifest file (short cache)
|
||||
location /manifest.json {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, must-revalidate";
|
||||
}
|
||||
|
||||
# Handle API requests (if needed)
|
||||
# Note: Backend API is not currently deployed
|
||||
# Uncomment and configure when backend service is available
|
||||
# location /api/ {
|
||||
# limit_req zone=api burst=20 nodelay;
|
||||
# proxy_pass http://backend:3000;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
|
||||
# Handle health check
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy-staging\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# Handle robots.txt (no caching in staging)
|
||||
location /robots.txt {
|
||||
expires 0;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
|
||||
# Handle favicon (short cache)
|
||||
location /favicon.ico {
|
||||
expires 1h;
|
||||
add_header Cache-Control "public, must-revalidate";
|
||||
}
|
||||
|
||||
# Security: Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Security: Deny access to backup files
|
||||
location ~ ~$ {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Error pages (more verbose for staging)
|
||||
error_page 404 /index.html;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
# Enhanced logging for staging
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log debug;
|
||||
}
|
||||
115
docs/README.md
@@ -1,115 +0,0 @@
|
||||
# TimeSafari Documentation
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-01-27
|
||||
**Status**: 🎯 **COMPLETE** - Documentation organized and structured
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
This documentation is organized into logical categories to ensure easy navigation and maintenance. Each folder contains no more than 7 items to maintain clarity and usability.
|
||||
|
||||
### 📚 User Guides (`user-guides/`)
|
||||
Documentation for end users and potential users of TimeSafari:
|
||||
- User Guide - Comprehensive explanation of TimeSafari's purpose and features
|
||||
- Quick Start Guide - Immediate actionable steps for new users
|
||||
- Real-World Examples - Concrete stories of community transformation
|
||||
|
||||
### 🔧 Build System (`build-system/`)
|
||||
Documentation for building and deploying TimeSafari across platforms:
|
||||
- Build Systems Overview - Complete architecture of build processes
|
||||
- Build Troubleshooting - Common issues and solutions
|
||||
- Platform-specific build scripts and configurations
|
||||
- Auto-run and automation guides
|
||||
|
||||
### 🔄 Migration (`migration/`)
|
||||
Documentation for the database migration from Dexie to SQLite:
|
||||
- Migration progress tracking and assessments
|
||||
- Migration templates and best practices
|
||||
- Component migration testing and validation
|
||||
- Migration tools and utilities
|
||||
|
||||
### 💻 Development (`development/`)
|
||||
Documentation for developers working on TimeSafari:
|
||||
- Domain configuration and setup
|
||||
- Development tools and utilities
|
||||
- Code standards and templates
|
||||
- Testing frameworks and practices
|
||||
|
||||
### 🏗️ Architecture (`architecture/`)
|
||||
High-level system design and architectural decisions:
|
||||
- System architecture overview
|
||||
- Design patterns and principles
|
||||
- Integration guides
|
||||
- Performance considerations
|
||||
|
||||
### 🧪 Testing (`testing/`)
|
||||
Testing documentation and procedures:
|
||||
- Test frameworks and tools
|
||||
- Testing strategies and methodologies
|
||||
- Quality assurance processes
|
||||
- Performance testing guidelines
|
||||
|
||||
### 📖 Examples (`examples/`)
|
||||
Code examples and implementation patterns:
|
||||
- Implementation examples
|
||||
- Best practice demonstrations
|
||||
- Integration examples
|
||||
- Troubleshooting examples
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
### File Organization
|
||||
- **Maximum 7 items per folder**: Ensures easy navigation and maintenance
|
||||
- **Logical grouping**: Related documents are grouped together
|
||||
- **Clear naming**: File names clearly indicate content and purpose
|
||||
- **Version control**: All changes are tracked in git with proper commit messages
|
||||
|
||||
### Documentation Quality
|
||||
- **Rich documentation**: Comprehensive coverage at file, class, and method levels
|
||||
- **Consistent formatting**: Follows established markdown standards
|
||||
- **Regular updates**: Documentation is updated as code changes
|
||||
- **User-focused**: Content is written for the intended audience
|
||||
|
||||
### Maintenance
|
||||
- **Regular reviews**: Documentation is reviewed and updated regularly
|
||||
- **Feedback integration**: User feedback is incorporated into documentation
|
||||
- **Cross-references**: Related documents are properly linked
|
||||
- **Searchability**: Content is organized for easy discovery
|
||||
|
||||
## Getting Started
|
||||
|
||||
### For Users
|
||||
1. Start with the [Quick Start Guide](user-guides/quick-start-guide.md)
|
||||
2. Read the [User Guide](user-guides/user-guide.md) for comprehensive understanding
|
||||
3. Explore [Real-World Examples](user-guides/real-world-examples.md) for inspiration
|
||||
|
||||
### For Developers
|
||||
1. Review the [Build System Overview](build-system/build-systems-overview.md)
|
||||
2. Check [Development Setup](development/) for environment configuration
|
||||
3. Understand the [Migration Process](migration/) if working on database changes
|
||||
|
||||
### For Contributors
|
||||
1. Read the [Development Guidelines](development/)
|
||||
2. Review [Testing Procedures](testing/)
|
||||
3. Check [Architecture Decisions](architecture/)
|
||||
|
||||
## Contributing to Documentation
|
||||
|
||||
When adding or updating documentation:
|
||||
|
||||
1. **Choose the right folder**: Place documents in the most appropriate category
|
||||
2. **Follow naming conventions**: Use clear, descriptive file names
|
||||
3. **Maintain folder limits**: Create sub-folders if a folder exceeds 7 items
|
||||
4. **Update this README**: Add new categories or reorganize as needed
|
||||
5. **Version in git**: Commit documentation changes with clear messages
|
||||
|
||||
## Documentation Tools
|
||||
|
||||
- **Markdown**: All documentation uses markdown format
|
||||
- **Git**: Version control for all documentation changes
|
||||
- **Linting**: Markdown linting ensures consistent formatting
|
||||
- **Validation**: Regular checks ensure documentation accuracy
|
||||
|
||||
---
|
||||
|
||||
*This documentation structure is designed to scale with the project while maintaining clarity and usability.*
|
||||
@@ -1,405 +0,0 @@
|
||||
# Auto-Run Guide
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-07-12
|
||||
**Status**: 🎯 **ACTIVE** - In Use
|
||||
|
||||
## Overview
|
||||
|
||||
The TimeSafari auto-run system intelligently detects available devices and
|
||||
automatically builds and launches the app on the best available target. It
|
||||
supports Android devices/emulators, iOS devices/simulators, and Electron
|
||||
desktop apps.
|
||||
|
||||
## Features
|
||||
|
||||
### Smart Device Detection
|
||||
- **Android**: Detects real devices vs emulators using ADB
|
||||
- **iOS**: Detects real devices vs simulators using xcrun
|
||||
- **Electron**: Checks for Electron availability
|
||||
- **Priority**: Real devices preferred over simulators/emulators
|
||||
|
||||
### Build Mode Support
|
||||
- **Development**: Default mode for daily development
|
||||
- **Test**: Optimized for testing with test data
|
||||
- **Production**: Production-ready builds
|
||||
|
||||
### Platform Targeting
|
||||
- **All platforms**: Automatically detects and runs on all available
|
||||
- **Specific platform**: Target only iOS, Android, or Electron
|
||||
- **Cross-platform**: Works on macOS, Linux, and Windows
|
||||
|
||||
### Auto-Run Options
|
||||
- **Build + Auto-Run**: Single command to build and launch
|
||||
- **Smart Detection**: Automatically chooses best available target
|
||||
- **Error Handling**: Graceful fallbacks when devices unavailable
|
||||
|
||||
## Usage
|
||||
|
||||
### Auto-Run Script (Recommended)
|
||||
|
||||
```bash
|
||||
# Auto-detect and run on all available platforms (development mode)
|
||||
npm run auto-run
|
||||
|
||||
# Run in test mode
|
||||
npm run auto-run:test
|
||||
|
||||
# Run in production mode
|
||||
npm run auto-run:prod
|
||||
|
||||
# Target specific platforms
|
||||
npm run auto-run:ios
|
||||
npm run auto-run:android
|
||||
npm run auto-run:electron
|
||||
```
|
||||
|
||||
### Build Script Auto-Run
|
||||
|
||||
#### iOS Auto-Run Commands
|
||||
|
||||
```bash
|
||||
# Test build + auto-run
|
||||
npm run build:ios:test:run
|
||||
|
||||
# Production build + auto-run
|
||||
npm run build:ios:prod:run
|
||||
|
||||
# Debug build + auto-run
|
||||
npm run build:ios:debug:run
|
||||
|
||||
# Release build + auto-run
|
||||
npm run build:ios:release:run
|
||||
```
|
||||
|
||||
#### Android Auto-Run Commands
|
||||
|
||||
```bash
|
||||
# Test build + auto-run
|
||||
npm run build:android:test:run
|
||||
|
||||
# Production build + auto-run
|
||||
npm run build:android:prod:run
|
||||
|
||||
# Debug build + auto-run
|
||||
npm run build:android:debug:run
|
||||
|
||||
# Release build + auto-run
|
||||
npm run build:android:release:run
|
||||
```
|
||||
|
||||
#### Electron Auto-Run Commands
|
||||
|
||||
```bash
|
||||
# Development build + auto-run
|
||||
npm run build:electron:dev:run
|
||||
|
||||
# Test build + auto-run
|
||||
npm run build:electron:test:run
|
||||
|
||||
# Production build + auto-run
|
||||
npm run build:electron:prod:run
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
```bash
|
||||
# Direct script usage with options
|
||||
./scripts/auto-run.sh --test --platform=ios
|
||||
./scripts/auto-run.sh --prod --platform=android
|
||||
./scripts/auto-run.sh --auto # Skip confirmation prompts
|
||||
|
||||
# Build script with auto-run flag
|
||||
./scripts/build-ios.sh --test --auto-run
|
||||
./scripts/build-android.sh --prod --auto-run
|
||||
./scripts/build-electron.sh --test --auto-run
|
||||
|
||||
# Combine options
|
||||
./scripts/auto-run.sh --test --platform=all --auto
|
||||
```
|
||||
|
||||
### Command Line Options
|
||||
|
||||
| Option | Description | Example |
|
||||
|--------|-------------|---------|
|
||||
| `--test` | Build and run in test mode | `--test` |
|
||||
| `--prod` | Build and run in production mode | `--prod` |
|
||||
| `--platform=PLATFORM` | Target specific platform | `--platform=ios` |
|
||||
| `--auto` | Skip confirmation prompts | `--auto` |
|
||||
| `--auto-run` | Auto-run after build | `--auto-run` |
|
||||
| `--help` | Show help message | `--help` |
|
||||
|
||||
**Platform Options:**
|
||||
- `ios` - iOS devices/simulators only
|
||||
- `android` - Android devices/emulators only
|
||||
- `electron` - Electron desktop app only
|
||||
- `all` - All available platforms (default)
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Device Detection
|
||||
|
||||
**Android Detection:**
|
||||
```bash
|
||||
# Uses ADB to list devices
|
||||
adb devices
|
||||
|
||||
# Parses output to distinguish:
|
||||
# - Real devices: Physical Android phones/tablets
|
||||
# - Emulators: Android emulator instances
|
||||
```
|
||||
|
||||
**iOS Detection:**
|
||||
```bash
|
||||
# Uses xcrun to list devices
|
||||
xcrun xctrace list devices
|
||||
|
||||
# Parses output to distinguish:
|
||||
# - Real devices: Physical iPhones/iPads
|
||||
# - Simulators: iOS Simulator instances
|
||||
```
|
||||
|
||||
### 2. Build Process
|
||||
|
||||
The script automatically calls the appropriate build commands:
|
||||
|
||||
```bash
|
||||
# Development mode
|
||||
npm run build:ios:dev
|
||||
npm run build:android:dev
|
||||
npm run build:electron:dev
|
||||
|
||||
# Test mode
|
||||
npm run build:ios:test
|
||||
npm run build:android:test
|
||||
npm run build:electron:test
|
||||
|
||||
# Production mode
|
||||
npm run build:ios:prod
|
||||
npm run build:android:prod
|
||||
npm run build:electron:prod
|
||||
```
|
||||
|
||||
### 3. Launch Process
|
||||
|
||||
**Android:**
|
||||
- Real devices: Install APK and launch via ADB
|
||||
- Emulators: Use `npx cap run android`
|
||||
|
||||
**iOS:**
|
||||
- Real devices: Build release version (requires Xcode setup)
|
||||
- Simulators: Use `npx cap run ios`
|
||||
|
||||
**Electron:**
|
||||
- Launch via `npm run electron:start`
|
||||
|
||||
## Examples
|
||||
|
||||
### Development Workflow
|
||||
|
||||
```bash
|
||||
# Quick development run
|
||||
npm run auto-run
|
||||
|
||||
# Output:
|
||||
# ✅ Found 1 real Android device: ABC123DEF456
|
||||
# ✅ Found 1 iOS simulator: iPhone 15 Pro
|
||||
# ✅ Electron: available
|
||||
#
|
||||
# Available targets:
|
||||
# Android: real:ABC123DEF456
|
||||
# iOS: simulator:iPhone 15 Pro
|
||||
# Electron: available
|
||||
#
|
||||
# Continue with auto-run? (y/N): y
|
||||
#
|
||||
# 🔄 Building and running Android (real: ABC123DEF456)...
|
||||
# 🔄 Building and running iOS (simulator: iPhone 15 Pro)...
|
||||
# 🔄 Building and running Electron...
|
||||
#
|
||||
# ✅ Auto-run completed successfully! 3 platform(s) launched.
|
||||
```
|
||||
|
||||
### Test Mode with Build Scripts
|
||||
|
||||
```bash
|
||||
# iOS test build + auto-run
|
||||
npm run build:ios:test:run
|
||||
|
||||
# Android test build + auto-run
|
||||
npm run build:android:test:run
|
||||
|
||||
# Electron test build + auto-run
|
||||
npm run build:electron:test:run
|
||||
|
||||
# Output:
|
||||
# === TimeSafari iOS Build Process ===
|
||||
# 🔄 Building Capacitor version (test)...
|
||||
# 🔄 Syncing with Capacitor...
|
||||
# 🔄 Building iOS app...
|
||||
# 🔄 Auto-running iOS app...
|
||||
# ✅ iOS app launched successfully!
|
||||
# ✅ iOS build completed successfully!
|
||||
```
|
||||
|
||||
### Production Mode
|
||||
|
||||
```bash
|
||||
# Production build and run
|
||||
npm run auto-run:prod
|
||||
|
||||
# Output:
|
||||
# 🔄 Building Android (production)...
|
||||
# 🔄 Building iOS (production)...
|
||||
# 🔄 Building Electron (production)...
|
||||
#
|
||||
# ✅ Auto-run completed successfully! 3 platform(s) launched.
|
||||
```
|
||||
|
||||
## Comparison: Auto-Run Script vs Build Scripts
|
||||
|
||||
### Auto-Run Script (`auto-run.sh`)
|
||||
**Best for:**
|
||||
- Multi-platform development
|
||||
- Quick testing across devices
|
||||
- Automated workflows
|
||||
- CI/CD integration
|
||||
|
||||
**Features:**
|
||||
- Smart device detection
|
||||
- Multi-platform support
|
||||
- Interactive confirmation
|
||||
- Error recovery
|
||||
|
||||
### Build Scripts with `--auto-run`
|
||||
**Best for:**
|
||||
- Single platform development
|
||||
- Specific build configurations
|
||||
- Non-interactive workflows
|
||||
- Build customization
|
||||
|
||||
**Features:**
|
||||
- Platform-specific optimization
|
||||
- Build customization options
|
||||
- Direct control over build process
|
||||
- Integration with existing workflows
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**No devices detected:**
|
||||
```bash
|
||||
# Check Android devices
|
||||
adb devices
|
||||
|
||||
# Check iOS devices (macOS only)
|
||||
xcrun xctrace list devices
|
||||
|
||||
# Check Electron availability
|
||||
which electron
|
||||
```
|
||||
|
||||
**Build failures:**
|
||||
```bash
|
||||
# Clean and rebuild
|
||||
npm run clean:android
|
||||
npm run clean:ios
|
||||
npm run clean:electron
|
||||
|
||||
# Then retry auto-run
|
||||
npm run auto-run
|
||||
```
|
||||
|
||||
**Permission issues:**
|
||||
```bash
|
||||
# Make script executable
|
||||
chmod +x scripts/auto-run.sh
|
||||
|
||||
# Check ADB permissions (Android)
|
||||
adb kill-server
|
||||
adb start-server
|
||||
```
|
||||
|
||||
### Platform-Specific Issues
|
||||
|
||||
**Android:**
|
||||
- Ensure ADB is in PATH
|
||||
- Enable USB debugging on device
|
||||
- Accept device authorization prompt
|
||||
- Check device is in "device" state (not "unauthorized")
|
||||
|
||||
**iOS:**
|
||||
- Requires macOS with Xcode
|
||||
- Ensure Xcode command line tools installed
|
||||
- Check iOS Simulator is available
|
||||
- For real devices: Requires proper certificates
|
||||
|
||||
**Electron:**
|
||||
- Ensure Electron is installed globally or locally
|
||||
- Check Node.js version compatibility
|
||||
- Verify build dependencies are installed
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable verbose logging by modifying the script:
|
||||
|
||||
```bash
|
||||
# Add debug logging to auto-run.sh
|
||||
set -x # Enable debug mode
|
||||
```
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
The auto-run script can be integrated into CI/CD pipelines:
|
||||
|
||||
```yaml
|
||||
# Example GitHub Actions workflow
|
||||
- name: Auto-run tests
|
||||
run: |
|
||||
npm run auto-run:test --auto
|
||||
env:
|
||||
# Set environment variables for CI
|
||||
CI: true
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Development Workflow
|
||||
1. **Daily development**: Use `npm run auto-run` for quick testing
|
||||
2. **Testing**: Use `npm run auto-run:test` before commits
|
||||
3. **Production**: Use `npm run auto-run:prod` for final testing
|
||||
4. **Single platform**: Use `npm run build:ios:test:run` for focused work
|
||||
|
||||
### Device Management
|
||||
1. **Keep devices connected**: Reduces detection time
|
||||
2. **Use consistent device names**: Helps with identification
|
||||
3. **Regular cleanup**: Clear old builds and caches
|
||||
|
||||
### Performance Tips
|
||||
1. **Use --auto flag**: Skip prompts in automated workflows
|
||||
2. **Target specific platforms**: Use `--platform=ios` for faster runs
|
||||
3. **Parallel execution**: Script runs platforms in sequence (can be optimized)
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- **Parallel execution**: Run multiple platforms simultaneously
|
||||
- **Device selection**: Choose specific devices when multiple available
|
||||
- **Custom build configurations**: Support for custom build modes
|
||||
- **Integration with IDEs**: VS Code and other IDE integration
|
||||
- **Performance monitoring**: Track build and launch times
|
||||
|
||||
### Contributing
|
||||
To add new features or fix issues:
|
||||
1. Modify `scripts/auto-run.sh`
|
||||
2. Update this documentation
|
||||
3. Test on multiple platforms
|
||||
4. Submit pull request
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [iOS Simulator Build and Icons](./ios-simulator-build-and-icons.md)
|
||||
- [Android Build Guide](./android-build-guide.md)
|
||||
- [Electron Build Guide](./electron-build-guide.md)
|
||||
- [Testing Guide](./testing-guide.md)
|
||||
@@ -1,379 +0,0 @@
|
||||
# CEFPython Implementation Guide (Revised)
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-07-12
|
||||
**Status**: ✨ **PLANNING** - Ready for Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This guide outlines the implementation of CEFPython to deliver the TimeSafari Vue.js application as a native desktop experience. It details the integration of Chromium Embedded Framework (CEF) with a Python backend for desktop-specific operations.
|
||||
|
||||
## Architecture
|
||||
|
||||
### High-Level Diagram
|
||||
|
||||
```
|
||||
TimeSafari CEFPython Architecture
|
||||
├── Python Backend (CEFPython)
|
||||
│ ├── CEF Browser Window
|
||||
│ ├── SQLite Database Access
|
||||
│ ├── File System Operations
|
||||
│ └── Native OS Integration
|
||||
├── Vue.js Frontend (Unchanged)
|
||||
│ ├── Existing Components
|
||||
│ ├── Platform Service Integration
|
||||
│ └── Database Operations
|
||||
└── Platform Service Bridge
|
||||
├── CEFPython Platform Service
|
||||
├── IPC Communication
|
||||
└── Native API Exposure
|
||||
```
|
||||
|
||||
### Platform Service
|
||||
|
||||
A TypeScript class will act as the interface between the Vue frontend and the Python backend:
|
||||
|
||||
```typescript
|
||||
export class CEFPythonPlatformService implements PlatformService {
|
||||
async dbQuery(sql: string, params?: any[]): Promise<any[]> {
|
||||
// Call Python backend via IPC
|
||||
}
|
||||
|
||||
async exportData(fileName: string, data: string): Promise<ExportResult> {
|
||||
// Call file export via IPC
|
||||
}
|
||||
|
||||
async getPlatformInfo(): Promise<PlatformInfo> {
|
||||
return {
|
||||
platform: 'cefpython',
|
||||
capabilities: ['sqlite', 'filesystem', 'native-ui']
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Foundation Setup (Week 1)
|
||||
- [ ] Install CEFPython dependencies
|
||||
- [ ] Create Python virtual environment
|
||||
- [ ] Set up development and build tools
|
||||
- [ ] Create and test minimal CEFPython app
|
||||
- [ ] Create IPC and platform service skeleton
|
||||
|
||||
### Phase 2: SQLite Database (Week 2)
|
||||
- [ ] Implement Python SQLite wrapper
|
||||
- [ ] Setup schema initialization
|
||||
- [ ] Bridge database ops over IPC
|
||||
- [ ] Test queries and data integrity
|
||||
|
||||
### Phase 3: Native OS Integration (Week 3)
|
||||
- [ ] Implement file import/export
|
||||
- [ ] Add system tray and notifications
|
||||
- [ ] Test native menu hooks and permissions
|
||||
|
||||
### Phase 4: Build & Packaging (Week 4)
|
||||
- [ ] Create packaging and build scripts
|
||||
- [ ] Integrate with existing npm build
|
||||
- [ ] Automate cross-platform distribution
|
||||
|
||||
## Backend Implementation
|
||||
|
||||
### Main Entry
|
||||
|
||||
```python
|
||||
# main.py
|
||||
import cefpython3.cefpython as cef
|
||||
from platform_service import CEFPythonPlatformService
|
||||
from ipc_bridge import IPCBridge
|
||||
|
||||
class TimeSafariApp:
|
||||
def __init__(self):
|
||||
self.platform_service = CEFPythonPlatformService()
|
||||
self.cef_settings = {
|
||||
"debug": False,
|
||||
"log_severity": cef.LOGSEVERITY_ERROR,
|
||||
"log_file": "cef.log",
|
||||
"multi_threaded_message_loop": True,
|
||||
}
|
||||
|
||||
def initialize(self):
|
||||
cef.Initialize(settings=self.cef_settings)
|
||||
self.browser = cef.CreateBrowserSync(
|
||||
url=f"file://{os.path.abspath('dist/index.html')}"
|
||||
)
|
||||
self.ipc = IPCBridge(self.browser, self.platform_service)
|
||||
|
||||
def run(self):
|
||||
cef.MessageLoop()
|
||||
cef.Shutdown()
|
||||
```
|
||||
|
||||
### Platform Service (Python)
|
||||
|
||||
Handles local database and file system access:
|
||||
|
||||
```python
|
||||
class CEFPythonPlatformService:
|
||||
def __init__(self):
|
||||
self.db_path = self._get_db_path()
|
||||
self._init_schema()
|
||||
|
||||
def db_query(self, sql, params=None):
|
||||
with sqlite3.connect(self.db_path, check_same_thread=False) as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
return [dict(row) for row in conn.execute(sql, params or [])]
|
||||
|
||||
def db_exec(self, sql, params=None):
|
||||
with sqlite3.connect(self.db_path, check_same_thread=False) as conn:
|
||||
cur = conn.execute(sql, params or [])
|
||||
conn.commit()
|
||||
return {"changes": cur.rowcount, "lastId": cur.lastrowid}
|
||||
|
||||
def export_data(self, file_name, data):
|
||||
try:
|
||||
path = os.path.join(self._get_downloads(), file_name)
|
||||
with open(path, 'w') as f:
|
||||
f.write(data)
|
||||
return {"success": True, "path": path}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
```
|
||||
|
||||
### IPC Bridge
|
||||
|
||||
Handles communication from JavaScript:
|
||||
|
||||
```python
|
||||
class IPCBridge:
|
||||
def __init__(self, browser, platform_service):
|
||||
self.browser = browser
|
||||
self.platform_service = platform_service
|
||||
bindings = cef.JavascriptBindings()
|
||||
bindings.SetFunction("callPython", self.call)
|
||||
self.browser.SetJavascriptBindings(bindings)
|
||||
|
||||
def call(self, name, args):
|
||||
handlers = {
|
||||
"dbQuery": self.platform_service.db_query,
|
||||
"dbExec": self.platform_service.db_exec,
|
||||
"exportData": self.platform_service.export_data
|
||||
}
|
||||
try:
|
||||
return {"success": True, "data": handlers[name](*args)}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
```
|
||||
|
||||
## Build & Packaging
|
||||
|
||||
Shell script with build modes:
|
||||
|
||||
```bash
|
||||
npm run build:web:dev
|
||||
./scripts/build-cefpython.sh --dev
|
||||
```
|
||||
|
||||
Includes PyInstaller packaging:
|
||||
|
||||
```bash
|
||||
pyinstaller --onefile --windowed --name TimeSafari main.py
|
||||
```
|
||||
|
||||
## Package.json Integration
|
||||
|
||||
### CEFPython Build Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
// CEFPython builds
|
||||
"build:cefpython": "./scripts/build-cefpython.sh",
|
||||
"build:cefpython:dev": "./scripts/build-cefpython.sh --dev",
|
||||
"build:cefpython:test": "./scripts/build-cefpython.sh --test",
|
||||
"build:cefpython:prod": "./scripts/build-cefpython.sh --prod",
|
||||
"build:cefpython:package": "./scripts/build-cefpython.sh --prod --package",
|
||||
|
||||
// Legacy aliases
|
||||
"build:desktop:cef": "npm run build:cefpython",
|
||||
"build:desktop:cef:dev": "npm run build:cefpython:dev",
|
||||
"build:desktop:cef:prod": "npm run build:cefpython:prod"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Platform Service Factory Integration
|
||||
|
||||
### Update PlatformServiceFactory
|
||||
|
||||
```typescript
|
||||
// src/services/PlatformServiceFactory.ts
|
||||
export class PlatformServiceFactory {
|
||||
private static instance: PlatformService | null = null;
|
||||
|
||||
public static getInstance(): PlatformService {
|
||||
if (!PlatformServiceFactory.instance) {
|
||||
const platform = process.env.VITE_PLATFORM || "web";
|
||||
|
||||
switch (platform) {
|
||||
case "cefpython":
|
||||
PlatformServiceFactory.instance = new CEFPythonPlatformService();
|
||||
break;
|
||||
case "electron":
|
||||
PlatformServiceFactory.instance = new ElectronPlatformService();
|
||||
break;
|
||||
case "capacitor":
|
||||
PlatformServiceFactory.instance = new CapacitorPlatformService();
|
||||
break;
|
||||
default:
|
||||
PlatformServiceFactory.instance = new WebPlatformService();
|
||||
}
|
||||
}
|
||||
return PlatformServiceFactory.instance;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
```bash
|
||||
cd cefpython
|
||||
pip install -r requirements.txt
|
||||
npm run build:cefpython:dev
|
||||
```
|
||||
|
||||
## Platform Considerations
|
||||
|
||||
### Windows
|
||||
- VC++ Redistributable
|
||||
- Registry for settings
|
||||
|
||||
### macOS
|
||||
- macOS 10.14+
|
||||
- Handle App Sandbox
|
||||
|
||||
### Linux
|
||||
- GTK dependencies
|
||||
- Provide `.desktop` launcher
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- CEF sandboxing
|
||||
- File and IPC validation
|
||||
- Data encryption & key management
|
||||
- Code signing & integrity checks
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### 1. Memory Management
|
||||
|
||||
- Implement proper cleanup
|
||||
- Monitor memory usage
|
||||
- Optimize database queries
|
||||
- Handle large datasets
|
||||
|
||||
### 2. Startup Time
|
||||
|
||||
- Optimize application startup
|
||||
- Implement lazy loading
|
||||
- Cache frequently used data
|
||||
- Minimize initialization overhead
|
||||
|
||||
### 3. Resource Usage
|
||||
|
||||
- Monitor CPU usage
|
||||
- Optimize rendering
|
||||
- Handle background tasks
|
||||
- Implement resource limits
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit tests for each service
|
||||
- Integration for IPC and file access
|
||||
- End-to-end for user workflows
|
||||
|
||||
## Issues & Suggestions for Improvement
|
||||
|
||||
### 1. IPC Registration Missing in Initial Version
|
||||
You must explicitly bind Python functions to JS:
|
||||
```python
|
||||
bindings.SetFunction("callPython", self.call)
|
||||
```
|
||||
|
||||
### 2. Incorrect `IPCBridge` Constructor in Early Draft
|
||||
Original:
|
||||
```python
|
||||
def __init__(self, browser):
|
||||
```
|
||||
Fixed:
|
||||
```python
|
||||
def __init__(self, browser, platform_service):
|
||||
```
|
||||
|
||||
### 3. SQLite Threading Caveat
|
||||
Add `check_same_thread=False` or use a threading queue to avoid crashes from multi-threaded access.
|
||||
|
||||
### 4. No Vue IPC Access Description
|
||||
Specify the frontend JS API for calling Python:
|
||||
```javascript
|
||||
window.callPython('dbQuery', ['SELECT * FROM accounts'])
|
||||
```
|
||||
|
||||
### 5. Missing Cleanup in Unit Tests
|
||||
Add teardown for exported files to avoid clutter and permissions issues.
|
||||
|
||||
### 6. Logging
|
||||
Add `logging` or `structlog` to the Python service and bridge for auditability.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. CEF Initialization Failures
|
||||
|
||||
```bash
|
||||
# Check CEF installation
|
||||
python -c "import cefpython3; print('CEF installed')"
|
||||
|
||||
# Verify dependencies
|
||||
pip list | grep cefpython3
|
||||
```
|
||||
|
||||
#### 2. Database Access Issues
|
||||
|
||||
```bash
|
||||
# Check database permissions
|
||||
ls -la ~/.local/share/timesafari/
|
||||
|
||||
# Verify SQLite installation
|
||||
python -c "import sqlite3; print('SQLite available')"
|
||||
```
|
||||
|
||||
#### 3. Build Failures
|
||||
|
||||
```bash
|
||||
# Clean and rebuild
|
||||
rm -rf cefpython/dist/
|
||||
rm -rf cefpython/build/
|
||||
npm run build:cefpython:dev
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```python
|
||||
# Enable debug logging
|
||||
cef_settings = {
|
||||
"debug": True,
|
||||
"log_severity": cef.LOGSEVERITY_VERBOSE,
|
||||
"log_file": "cef_debug.log",
|
||||
}
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
This guide offers a clear and technically complete roadmap for integrating CEFPython with TimeSafari. By implementing the suggestions above, the solution will be production-ready with complete platform service integration, desktop capability, and a stable build process.
|
||||
|
||||
**Effort**: 4 weeks
|
||||
**Priority**: Medium
|
||||
**Dependencies**: Python 3.8+, CEFPython
|
||||
**Stakeholders**: Desktop development team, users
|
||||
@@ -1,616 +0,0 @@
|
||||
# Build Pattern Conversion Plan
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-07-09
|
||||
**Status**: **PLANNING** - Ready for Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
Convert TimeSafari's build instruction pattern from the current script-based
|
||||
approach to a new Vite `mode`-based pattern that provides better environment
|
||||
management and consistency across all build targets.
|
||||
|
||||
## Why Vite Mode Instead of NODE_ENV?
|
||||
|
||||
### Vite's Native Mode System
|
||||
|
||||
Vite is designed to work with `mode`, which:
|
||||
|
||||
- Determines the `.env` file to load (e.g. `.env.production`, `.env.test`, etc.)
|
||||
- Is passed to `defineConfig(({ mode }) => {...})` in `vite.config.ts`
|
||||
- Is used to set behavior for dev/prod/test at config level
|
||||
- Provides better integration with Vite's build system
|
||||
|
||||
### NODE_ENV Limitations
|
||||
|
||||
`NODE_ENV` is legacy from Webpack-era tooling:
|
||||
|
||||
- You can't change `NODE_ENV` manually and expect Vite to adapt
|
||||
- Vite does not map `NODE_ENV` back to `mode`
|
||||
- It's redundant with `mode` and might conflict with assumptions
|
||||
- Limited integration with Vite's environment loading system
|
||||
|
||||
### Usage Pattern
|
||||
|
||||
```bash
|
||||
# Correct: Use Vite's mode system
|
||||
vite build --mode production
|
||||
vite build --mode development
|
||||
vite build --mode test
|
||||
|
||||
# Only if third-party libraries require NODE_ENV
|
||||
NODE_ENV=production vite build --mode production
|
||||
```
|
||||
|
||||
### Development vs Build Environments
|
||||
|
||||
**Development Environment:**
|
||||
|
||||
- **Build with defaults**: `npm run build:*` - Uses `--mode development` by default
|
||||
- **Purpose**: Development builds for testing and debugging
|
||||
- **Output**: Bundled files with development optimizations
|
||||
|
||||
**Testing/Production Environments:**
|
||||
|
||||
- **Build with explicit mode**: `npm run build:* -- --mode test/production`
|
||||
- **Purpose**: Validate and deploy the bundled application
|
||||
- **Output**: Optimized, bundled files for specific environment
|
||||
|
||||
### Mode Override Behavior
|
||||
|
||||
**How `--mode` Override Works:**
|
||||
|
||||
```bash
|
||||
# Base script (no hardcoded mode)
|
||||
"build:electron": "vite build --config vite.config.electron.mts"
|
||||
|
||||
# Development (uses Vite's default: --mode development)
|
||||
npm run build:electron
|
||||
# Executes: vite build --config vite.config.electron.mts
|
||||
|
||||
# Testing (explicitly overrides with --mode test)
|
||||
npm run build:electron -- --mode test
|
||||
# Executes: vite build --config vite.config.electron.mts --mode test
|
||||
|
||||
# Production (explicitly overrides with --mode production)
|
||||
npm run build:electron -- --mode production
|
||||
# Executes: vite build --config vite.config.electron.mts --mode production
|
||||
```
|
||||
|
||||
**Key Points:**
|
||||
|
||||
- Base scripts have **no hardcoded `--mode`** to allow override
|
||||
- `npm run build:electron` defaults to `--mode development`
|
||||
- `npm run build:electron -- --mode test` overrides to `--mode test`
|
||||
- Vite uses the **last `--mode` argument** if multiple are provided
|
||||
|
||||
### Capacitor Platform-Specific Commands
|
||||
|
||||
Capacitor requires platform-specific sync commands after building:
|
||||
|
||||
```bash
|
||||
# General sync (copies web assets to all platforms)
|
||||
npm run build:capacitor && npx cap sync
|
||||
|
||||
# Platform-specific sync
|
||||
npm run build:capacitor && npx cap sync android
|
||||
npm run build:capacitor && npx cap sync ios
|
||||
|
||||
# Environment-specific with platform sync
|
||||
npm run build:capacitor -- --mode production && npx cap sync android
|
||||
npm run build:capacitor -- --mode development && npx cap sync ios
|
||||
```
|
||||
|
||||
### Docker Build Commands
|
||||
|
||||
Docker builds include both Vite asset generation and Docker image creation:
|
||||
|
||||
```bash
|
||||
# General Docker build (Vite build + Docker image)
|
||||
npm run build:web:docker
|
||||
|
||||
# Environment-specific Docker builds
|
||||
npm run build:web:docker:test # Test environment + Docker image
|
||||
npm run build:web:docker:prod # Production environment + Docker image
|
||||
|
||||
# Manual mode overrides for Docker builds
|
||||
npm run build:web:docker -- --mode test
|
||||
npm run build:web:docker -- --mode production
|
||||
```
|
||||
|
||||
**Docker Build Process:**
|
||||
|
||||
1. **Vite Build**: Creates optimized web assets with environment-specific variables
|
||||
2. **Docker Build**: Creates Docker image using `Dockerfile` in project root
|
||||
3. **Image Tagging**: Images are tagged as `timesafari-web` for consistent management
|
||||
|
||||
**Key Features:**
|
||||
|
||||
- Complete end-to-end Docker workflow in single command
|
||||
- Environment-aware builds (test/production configurations)
|
||||
- Consistent image tagging for deployment
|
||||
- Mode override flexibility for custom environments
|
||||
|
||||
### Electron Platform-Specific Commands
|
||||
|
||||
Electron requires platform-specific build commands after the Vite build:
|
||||
|
||||
```bash
|
||||
# General Electron build (Vite build only)
|
||||
npm run build:electron
|
||||
|
||||
# Platform-specific builds
|
||||
npm run build:electron:windows # Windows executable
|
||||
npm run build:electron:mac # macOS app bundle
|
||||
npm run build:electron:linux # Linux executable
|
||||
|
||||
# Package-specific builds
|
||||
npm run build:electron:appimage # Linux AppImage
|
||||
npm run build:electron:dmg # macOS DMG installer
|
||||
|
||||
# Environment-specific builds
|
||||
npm run build:electron -- --mode development
|
||||
npm run build:electron -- --mode test
|
||||
npm run build:electron -- --mode production
|
||||
|
||||
# Environment-specific with platform builds
|
||||
npm run build:electron:windows -- --mode development
|
||||
npm run build:electron:windows -- --mode test
|
||||
npm run build:electron:windows -- --mode production
|
||||
|
||||
npm run build:electron:mac -- --mode development
|
||||
npm run build:electron:mac -- --mode test
|
||||
npm run build:electron:mac -- --mode production
|
||||
|
||||
npm run build:electron:linux -- --mode development
|
||||
npm run build:electron:linux -- --mode test
|
||||
npm run build:electron:linux -- --mode production
|
||||
|
||||
# Environment-specific with package builds
|
||||
npm run build:electron:appimage -- --mode development
|
||||
npm run build:electron:appimage -- --mode test
|
||||
npm run build:electron:appimage -- --mode production
|
||||
|
||||
npm run build:electron:dmg -- --mode development
|
||||
npm run build:electron:dmg -- --mode test
|
||||
npm run build:electron:dmg -- --mode production
|
||||
```
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Existing Build Scripts
|
||||
|
||||
- **Web**: `build:web` - Uses vite.config.web.mts
|
||||
- **Capacitor**: `build:capacitor` - Uses vite.config.capacitor.mts
|
||||
- **Android**: `build:android` - Shell script wrapper
|
||||
- **iOS**: `build:ios` - Shell script wrapper
|
||||
- **Electron**: `build:electron` - Uses vite.config.electron.mts
|
||||
- **Windows**: `build:electron:windows` - Windows executable
|
||||
- **macOS**: `build:electron:mac` - macOS app bundle
|
||||
- **Linux**: `build:electron:linux` - Linux executable
|
||||
- **AppImage**: `build:electron:appimage` - Linux AppImage
|
||||
- **DMG**: `build:electron:dmg` - macOS DMG installer
|
||||
|
||||
### Current `package.json` Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts",
|
||||
"build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts",
|
||||
"build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode electron --config vite.config.electron.mts"
|
||||
}
|
||||
```
|
||||
|
||||
## Target Pattern
|
||||
|
||||
### New Vite Mode-Based Pattern
|
||||
|
||||
```bash
|
||||
# Development builds (defaults to --mode development)
|
||||
npm run build:web-dev
|
||||
npm run build:capacitor-dev
|
||||
npm run build:electron-dev
|
||||
|
||||
# Testing builds (bundle required)
|
||||
npm run build:web -- --mode test
|
||||
npm run build:capacitor -- --mode test && npx cap sync
|
||||
npm run build:electron -- --mode test
|
||||
|
||||
# Production builds (bundle required)
|
||||
npm run build:web -- --mode production
|
||||
npm run build:capacitor -- --mode production && npx cap sync
|
||||
npm run build:electron -- --mode production
|
||||
|
||||
# Docker builds
|
||||
npm run build:web:docker -- --mode test
|
||||
npm run build:web:docker -- --mode production
|
||||
|
||||
# Docker environment-specific builds
|
||||
npm run build:web:docker:test
|
||||
npm run build:web:docker:prod
|
||||
|
||||
# Capacitor platform-specific builds
|
||||
npm run build:capacitor:android -- --mode test
|
||||
npm run build:capacitor:android -- --mode production
|
||||
|
||||
npm run build:capacitor:ios -- --mode test
|
||||
npm run build:capacitor:ios -- --mode production
|
||||
|
||||
# Electron platform-specific builds
|
||||
npm run build:electron:windows -- --mode test
|
||||
npm run build:electron:windows -- --mode production
|
||||
|
||||
npm run build:electron:mac -- --mode test
|
||||
npm run build:electron:mac -- --mode production
|
||||
|
||||
npm run build:electron:linux -- --mode test
|
||||
npm run build:electron:linux -- --mode production
|
||||
|
||||
# Electron package-specific builds
|
||||
npm run build:electron:appimage -- --mode test
|
||||
npm run build:electron:appimage -- --mode production
|
||||
|
||||
npm run build:electron:dmg -- --mode test
|
||||
npm run build:electron:dmg -- --mode production
|
||||
```
|
||||
|
||||
### New `package.json` Scripts Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite --mode development --config vite.config.web.mts",
|
||||
"build:web:dev": "npm run build:web",
|
||||
"build:web:build": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode development --config vite.config.web.mts",
|
||||
"build:web:test": "npm run build:web:build -- --mode test",
|
||||
"build:web:prod": "npm run build:web:build -- --mode production",
|
||||
"build:web:docker": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts && docker build -t timesafari-web .",
|
||||
"build:web:docker:test": "npm run build:web:docker -- --mode test",
|
||||
"build:web:docker:prod": "npm run build:web:docker -- --mode production",
|
||||
|
||||
"build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts",
|
||||
"build:capacitor-dev": "npm run build:capacitor",
|
||||
"build:capacitor:sync": "npm run build:capacitor && npx cap sync",
|
||||
"build:capacitor:android": "npm run build:capacitor:sync && npx cap sync android",
|
||||
"build:capacitor:ios": "npm run build:capacitor:sync && npx cap sync ios",
|
||||
|
||||
"build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.electron.mts",
|
||||
"build:electron:dev": "npm run build:electron && cd electron && npm run electron:start",
|
||||
"build:electron:windows": "npm run build:electron && cd electron && npm run build:windows",
|
||||
"build:electron:mac": "npm run build:electron && cd electron && npm run build:mac",
|
||||
"build:electron:linux": "npm run build:electron && cd electron && npm run build:linux",
|
||||
"build:electron:appimage": "npm run build:electron:linux && cd electron && npm run build:appimage",
|
||||
"build:electron:dmg": "npm run build:electron:mac && cd electron && npm run build:dmg"
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Environment Configuration (Day 1)
|
||||
|
||||
#### 1.1 Update Vite Configurations
|
||||
|
||||
- [ ] **vite.config.web.mts**: Add mode-based configuration
|
||||
- [ ] **vite.config.capacitor.mts**: Add mode-based configuration
|
||||
- [ ] **vite.config.electron.mts**: Add mode-based configuration
|
||||
- [ ] **vite.config.common.mts**: Add environment-specific variables
|
||||
|
||||
#### 1.2 Environment Variables Setup
|
||||
|
||||
- [ ] Create `.env.development` file for development settings
|
||||
- [ ] Create `.env.test` file for testing settings
|
||||
- [ ] Create `.env.production` file for production settings
|
||||
- [ ] Update `.env.example` with new pattern
|
||||
|
||||
#### 1.3 Environment Detection Logic
|
||||
|
||||
```typescript
|
||||
// vite.config.common.mts
|
||||
export default defineConfig(({ mode }) => {
|
||||
const getEnvironmentConfig = (mode: string) => {
|
||||
switch (mode) {
|
||||
case 'production':
|
||||
return { /* production settings */ };
|
||||
case 'test':
|
||||
return { /* testing settings */ };
|
||||
default:
|
||||
return { /* development settings */ };
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
define: {
|
||||
__DEV__: mode === 'development',
|
||||
__TEST__: mode === 'test',
|
||||
__PROD__: mode === 'production'
|
||||
},
|
||||
// ... other config
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
### Phase 2: Package.json Scripts Update (Day 1)
|
||||
|
||||
#### 2.1 Web Build Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"build:web": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts",
|
||||
"build:web-dev": "npm run build:web",
|
||||
"build:web-test": "npm run build:web -- --mode test",
|
||||
"build:web-prod": "npm run build:web -- --mode production"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Capacitor Build Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"build:capacitor": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --mode capacitor --config vite.config.capacitor.mts",
|
||||
"build:capacitor-dev": "npm run build:capacitor",
|
||||
"build:capacitor:sync": "npm run build:capacitor && npx cap sync",
|
||||
"build:capacitor:android": "npm run build:capacitor:sync && npx cap sync android",
|
||||
"build:capacitor:ios": "npm run build:capacitor:sync && npx cap sync ios",
|
||||
"build:capacitor-test": "npm run build:capacitor -- --mode test && npx cap sync",
|
||||
"build:capacitor-prod": "npm run build:capacitor -- --mode production && npx cap sync",
|
||||
"build:capacitor:android-test": "npm run build:capacitor -- --mode test && npx cap sync android",
|
||||
"build:capacitor:android-prod": "npm run build:capacitor -- --mode production && npx cap sync android",
|
||||
"build:capacitor:ios-test": "npm run build:capacitor -- --mode test && npx cap sync ios",
|
||||
"build:capacitor:ios-prod": "npm run build:capacitor -- --mode production && npx cap sync ios"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 Electron Build Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"build:electron": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.electron.mts",
|
||||
"build:electron-dev": "npm run build:electron",
|
||||
"build:electron:windows": "npm run build:electron && cd electron && npm run build:windows",
|
||||
"build:electron:mac": "npm run build:electron && cd electron && npm run build:mac",
|
||||
"build:electron:linux": "npm run build:electron && cd electron && npm run build:linux",
|
||||
"build:electron:appimage": "npm run build:electron:linux && cd electron && npm run build:appimage",
|
||||
"build:electron:dmg": "npm run build:electron:mac && cd electron && npm run build:dmg",
|
||||
"build:electron-test": "npm run build:electron -- --mode test",
|
||||
"build:electron-prod": "npm run build:electron -- --mode production",
|
||||
"build:electron:windows-test": "npm run build:electron -- --mode test && cd electron && npm run build:windows",
|
||||
"build:electron:windows-prod": "npm run build:electron -- --mode production && cd electron && npm run build:windows",
|
||||
"build:electron:mac-dev": "npm run build:electron -- --mode development && cd electron && npm run build:mac",
|
||||
"build:electron:mac-test": "npm run build:electron -- --mode test && cd electron && npm run build:mac",
|
||||
"build:electron:mac-prod": "npm run build:electron -- --mode production && cd electron && npm run build:mac",
|
||||
"build:electron:linux-test": "npm run build:electron -- --mode test && cd electron && npm run build:linux",
|
||||
"build:electron:linux-prod": "npm run build:electron -- --mode production && cd electron && npm run build:linux"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4 Docker Build Scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"build:web:docker": "VITE_GIT_HASH=`git log -1 --pretty=format:%h` vite build --config vite.config.web.mts && docker build -t timesafari-web .",
|
||||
"build:web:docker:test": "npm run build:web:docker -- --mode test",
|
||||
"build:web:docker:prod": "npm run build:web:docker -- --mode production"
|
||||
}
|
||||
```
|
||||
|
||||
**Docker Build Features:**
|
||||
|
||||
- Complete Vite build + Docker image creation workflow
|
||||
- Environment-specific configurations (test/production)
|
||||
- Consistent image tagging (`timesafari-web`)
|
||||
- Mode override flexibility for custom environments
|
||||
|
||||
### Phase 3: Shell Script Updates (Day 2)
|
||||
|
||||
#### 3.1 Update build-electron.sh
|
||||
|
||||
- [ ] Add mode-based environment support
|
||||
- [ ] Update environment loading logic
|
||||
- [ ] Add environment-specific build paths
|
||||
- [ ] Update logging to show environment
|
||||
|
||||
#### 3.2 Update build-android.sh
|
||||
|
||||
- [ ] Add mode-based environment support
|
||||
- [ ] Update environment detection
|
||||
- [ ] Add environment-specific configurations
|
||||
|
||||
#### 3.3 Update build-ios.sh
|
||||
|
||||
- [ ] Add mode-based environment support
|
||||
- [ ] Update environment detection
|
||||
- [ ] Add environment-specific configurations
|
||||
|
||||
### Phase 4: Documentation Updates (Day 2)
|
||||
|
||||
#### 4.1 Update BUILDING.md
|
||||
|
||||
- [ ] Document new Vite mode-based pattern
|
||||
- [ ] Update build instructions
|
||||
- [ ] Add environment-specific examples
|
||||
- [ ] Update troubleshooting section
|
||||
|
||||
#### 4.2 Update scripts/README.md
|
||||
|
||||
- [ ] Document new Vite mode-based build patterns
|
||||
- [ ] Update usage examples
|
||||
- [ ] Add environment configuration guide
|
||||
|
||||
#### 4.3 Update CI/CD Documentation
|
||||
|
||||
- [ ] Update GitHub Actions workflows
|
||||
- [ ] Update Docker build instructions
|
||||
- [ ] Update deployment guides
|
||||
|
||||
### Phase 5: Testing & Validation (Day 3)
|
||||
|
||||
#### 5.1 Environment Testing
|
||||
|
||||
- [ ] Test dev environment builds
|
||||
- [ ] Test test environment builds
|
||||
- [ ] Test prod environment builds
|
||||
- [ ] Validate environment variables
|
||||
|
||||
#### 5.2 Platform Testing
|
||||
|
||||
- [ ] Test web builds across environments
|
||||
- [ ] Test capacitor builds across environments
|
||||
- [ ] Test capacitor android sync across environments
|
||||
- [ ] Test capacitor ios sync across environments
|
||||
- [ ] Test electron builds across environments
|
||||
- [ ] Test electron windows builds across environments
|
||||
- [ ] Test electron mac builds across environments
|
||||
- [ ] Test electron linux builds across environments
|
||||
- [ ] Test electron appimage builds across environments
|
||||
- [ ] Test electron dmg builds across environments
|
||||
- [ ] Test docker builds across environments
|
||||
- [ ] Test docker image creation and tagging
|
||||
- [ ] Test docker environment-specific configurations
|
||||
|
||||
#### 5.3 Integration Testing
|
||||
|
||||
- [ ] Test with existing CI/CD pipelines
|
||||
- [ ] Test with existing deployment scripts
|
||||
- [ ] Test with existing development workflows
|
||||
|
||||
## Environment-Specific Configurations
|
||||
|
||||
### Development Environment (--mode development)
|
||||
|
||||
```typescript
|
||||
{
|
||||
VITE_API_URL: 'http://localhost:3000',
|
||||
VITE_DEBUG: 'true',
|
||||
VITE_LOG_LEVEL: 'debug',
|
||||
VITE_ENABLE_DEV_TOOLS: 'true'
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Environment (--mode test)
|
||||
|
||||
```typescript
|
||||
{
|
||||
VITE_API_URL: 'https://test-api.timesafari.com',
|
||||
VITE_DEBUG: 'false',
|
||||
VITE_LOG_LEVEL: 'info',
|
||||
VITE_ENABLE_DEV_TOOLS: 'false'
|
||||
}
|
||||
```
|
||||
|
||||
### Production Environment (--mode production)
|
||||
|
||||
```typescript
|
||||
{
|
||||
VITE_API_URL: 'https://api.timesafari.com',
|
||||
VITE_DEBUG: 'false',
|
||||
VITE_LOG_LEVEL: 'warn',
|
||||
VITE_ENABLE_DEV_TOOLS: 'false'
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- [ ] Keep existing script names as aliases
|
||||
- [ ] Add deprecation warnings for old scripts
|
||||
- [ ] Maintain existing CI/CD compatibility
|
||||
- [ ] Provide migration guide for users
|
||||
|
||||
### Gradual Rollout
|
||||
|
||||
1. **Week 1**: Implement new scripts alongside existing ones
|
||||
2. **Week 2**: Update CI/CD to use new pattern
|
||||
3. **Week 3**: Update documentation and guides
|
||||
4. **Week 4**: Deprecate old scripts with warnings
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Technical Metrics
|
||||
|
||||
- [ ] All builds work with Vite mode-based pattern
|
||||
- [ ] Environment variables properly loaded
|
||||
- [ ] Build artifacts correctly generated
|
||||
- [ ] No regression in existing functionality
|
||||
|
||||
### Process Metrics
|
||||
|
||||
- [ ] Reduced build script complexity
|
||||
- [ ] Improved environment management
|
||||
- [ ] Better developer experience
|
||||
- [ ] Consistent build patterns
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
### Low Risk
|
||||
|
||||
- [ ] Environment variable changes
|
||||
- [ ] Package.json script updates
|
||||
- [ ] Documentation updates
|
||||
|
||||
### Medium Risk
|
||||
|
||||
- [ ] Vite configuration changes (mode-based)
|
||||
- [ ] Shell script modifications
|
||||
- [ ] CI/CD pipeline updates
|
||||
|
||||
### High Risk
|
||||
|
||||
- [ ] Breaking existing build processes
|
||||
- [ ] Environment-specific bugs
|
||||
- [ ] Deployment failures
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
### Immediate Rollback
|
||||
|
||||
- [ ] Revert package.json changes
|
||||
- [ ] Restore original vite configs
|
||||
- [ ] Restore original shell scripts
|
||||
|
||||
### Gradual Rollback
|
||||
|
||||
- [ ] Keep old scripts as primary
|
||||
- [ ] Use new scripts as experimental
|
||||
- [ ] Gather feedback before full migration
|
||||
|
||||
## Timeline
|
||||
|
||||
### Day 1: Foundation
|
||||
|
||||
- [ ] Environment configuration setup
|
||||
- [ ] Package.json script updates
|
||||
- [ ] Basic testing
|
||||
|
||||
### Day 2: Integration
|
||||
|
||||
- [ ] Shell script updates
|
||||
- [ ] Documentation updates
|
||||
- [ ] Integration testing
|
||||
|
||||
### Day 3: Validation
|
||||
|
||||
- [ ] Comprehensive testing
|
||||
- [ ] Performance validation
|
||||
- [ ] Documentation review
|
||||
|
||||
### Day 4: Deployment
|
||||
|
||||
- [ ] CI/CD updates
|
||||
- [ ] Production validation
|
||||
- [ ] User communication
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Review and approve plan**
|
||||
2. **Set up development environment**
|
||||
3. **Begin Phase 1 implementation**
|
||||
4. **Create test cases**
|
||||
5. **Start implementation**
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready for implementation
|
||||
**Priority**: Medium
|
||||
**Estimated Effort**: 3-4 days
|
||||
**Dependencies**: None
|
||||
**Stakeholders**: Development team, DevOps team
|
||||