Compare commits
1 Commits
fix-deep-l
...
app_id_fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd32c37cfb |
@@ -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
|
||||
@@ -1,65 +0,0 @@
|
||||
# ADR Template
|
||||
|
||||
## ADR-XXXX-YY-ZZ: [Short Title]
|
||||
|
||||
**Date:** YYYY-MM-DD
|
||||
**Status:** [PROPOSED | ACCEPTED | REJECTED | DEPRECATED | SUPERSEDED]
|
||||
**Deciders:** [List of decision makers]
|
||||
**Technical Story:** [Link to issue/PR if applicable]
|
||||
|
||||
## Context
|
||||
|
||||
[Describe the forces at play, including technological, political, social, and
|
||||
project local. These forces are probably in tension, and should be called out as
|
||||
such. The language in this section is value-neutral. It is simply describing facts.]
|
||||
|
||||
## Decision
|
||||
|
||||
[Describe our response to these forces. We will use the past tense ("We will...").]
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- [List positive consequences]
|
||||
|
||||
### Negative
|
||||
- [List negative consequences or trade-offs]
|
||||
|
||||
### Neutral
|
||||
- [List neutral consequences or notes]
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- **Alternative 1:** [Description] - [Why rejected]
|
||||
- **Alternative 2:** [Description] - [Why rejected]
|
||||
- **Alternative 3:** [Description] - [Why rejected]
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
[Any specific implementation details, migration steps, or technical considerations]
|
||||
|
||||
## References
|
||||
|
||||
- [Link to relevant documentation]
|
||||
- [Link to related ADRs]
|
||||
- [Link to external resources]
|
||||
|
||||
## Related Decisions
|
||||
|
||||
- [List related ADRs or decisions]
|
||||
|
||||
---
|
||||
|
||||
## Usage Guidelines
|
||||
|
||||
1. **Copy this template** for new ADRs
|
||||
2. **Number sequentially** (ADR-001, ADR-002, etc.)
|
||||
3. **Use descriptive titles** that clearly indicate the decision
|
||||
4. **Include all stakeholders** in the deciders list
|
||||
5. **Link to related issues** and documentation
|
||||
6. **Update status** as decisions evolve
|
||||
7. **Store in** `doc/architecture-decisions/` directory
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
@@ -1,352 +0,0 @@
|
||||
---
|
||||
description: when you need to understand the system architecture or make changes that impact the system architecture
|
||||
alwaysApply: false
|
||||
---
|
||||
# TimeSafari Cross-Platform Architecture Guide
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Architecture guidelines
|
||||
|
||||
## 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 |
|
||||
|
||||
## 2. Project Structure
|
||||
|
||||
### Core Directories
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/ # Vue components
|
||||
├── services/ # Platform services and business logic
|
||||
├── views/ # Page components
|
||||
├── router/ # Vue router configuration
|
||||
├── types/ # TypeScript type definitions
|
||||
├── utils/ # Utility functions
|
||||
├── lib/ # Core libraries
|
||||
├── platforms/ # Platform-specific implementations
|
||||
├── electron/ # Electron-specific code
|
||||
├── constants/ # Application constants
|
||||
├── db/ # Database related code
|
||||
├── interfaces/ # TypeScript interfaces
|
||||
└── assets/ # Static assets
|
||||
```
|
||||
|
||||
### Entry Points
|
||||
|
||||
- `main.ts` → Base entry
|
||||
- `main.common.ts` → Shared init
|
||||
- `main.capacitor.ts` → Mobile entry
|
||||
- `main.electron.ts` → Electron entry
|
||||
- `main.web.ts` → Web entry
|
||||
|
||||
## 3. Service Architecture
|
||||
|
||||
### Service Organization
|
||||
|
||||
```tree
|
||||
services/
|
||||
├── QRScanner/
|
||||
│ ├── WebInlineQRScanner.ts
|
||||
│ └── interfaces.ts
|
||||
├── platforms/
|
||||
│ ├── WebPlatformService.ts
|
||||
│ ├── CapacitorPlatformService.ts
|
||||
│ └── ElectronPlatformService.ts
|
||||
└── factory/
|
||||
└── PlatformServiceFactory.ts
|
||||
```
|
||||
|
||||
### Factory Pattern
|
||||
|
||||
Use a **singleton factory** to select platform services via
|
||||
`process.env.VITE_PLATFORM`.
|
||||
|
||||
## 4. Feature Guidelines
|
||||
|
||||
### QR Code Scanning
|
||||
|
||||
- Define `QRScannerService` interface.
|
||||
- Implement platform-specific classes (`WebInlineQRScanner`, Capacitor,
|
||||
etc).
|
||||
- Provide `addListener` and `onStream` hooks for composability.
|
||||
|
||||
### Deep Linking
|
||||
|
||||
- URL format: `timesafari://<route>[/<param>][?query=value]`
|
||||
- Web: `router.beforeEach` → parse query
|
||||
- Capacitor: `App.addListener("appUrlOpen", …)`
|
||||
|
||||
## 5. Build Process
|
||||
|
||||
- `vite.config.common.mts` → shared config
|
||||
- Platform configs: `vite.config.web.mts`, `.capacitor.mts`,
|
||||
`.electron.mts`
|
||||
- Use `process.env.VITE_PLATFORM` for conditional loading.
|
||||
|
||||
```bash
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
npm run build:electron
|
||||
```
|
||||
|
||||
## 6. Testing Strategy
|
||||
|
||||
- **Unit tests** for services.
|
||||
- **Playwright** for Web + Capacitor:
|
||||
- `playwright.config-local.ts` includes web + Pixel 5.
|
||||
- **Electron tests**: add `spectron` or Playwright-Electron.
|
||||
- Mark tests with platform tags:
|
||||
|
||||
```ts
|
||||
test.skip(!process.env.MOBILE_TEST, "Mobile-only test");
|
||||
```
|
||||
|
||||
> 🔗 **Human Hook:** Before merging new tests, hold a short sync (≤15
|
||||
> min) with QA to align on coverage and flaky test risks.
|
||||
|
||||
## 7. Error Handling
|
||||
|
||||
- Global Vue error handler → logs with component name.
|
||||
- Platform-specific wrappers log API errors with platform prefix
|
||||
(`[Capacitor API Error]`, etc).
|
||||
- Use structured logging (not `console.log`).
|
||||
|
||||
## 8. Best Practices
|
||||
|
||||
- Keep platform code **isolated** in `platforms/`.
|
||||
- Always define a **shared interface** first.
|
||||
- Use feature detection, not platform detection, when possible.
|
||||
- Dependency injection for services → improves testability.
|
||||
- Maintain **Competence Hooks** in PRs (2–3 prompts for dev
|
||||
discussion).
|
||||
|
||||
## 9. Dependency Management
|
||||
|
||||
- Key deps: `@capacitor/core`, `electron`, `vue`.
|
||||
- Use conditional `import()` for platform-specific libs.
|
||||
|
||||
## 10. Security Considerations
|
||||
|
||||
- **Permissions**: Always check + request gracefully.
|
||||
- **Storage**: Secure storage for sensitive data; encrypt when possible.
|
||||
- **Audits**: Schedule quarterly security reviews.
|
||||
|
||||
## 11. ADR Process
|
||||
|
||||
- All major architecture choices → log in `doc/adr/`.
|
||||
- Use ADR template with Context, Decision, Consequences, Status.
|
||||
- Link related ADRs in PR descriptions.
|
||||
|
||||
> 🔗 **Human Hook:** When proposing a new ADR, schedule a 30-min
|
||||
> design sync for discussion, not just async review.
|
||||
|
||||
## 12. Collaboration Hooks
|
||||
|
||||
- **QR features**: Sync with Security before merging → permissions &
|
||||
privacy.
|
||||
- **New platform builds**: Demo in team meeting → confirm UX
|
||||
differences.
|
||||
- **Critical ADRs**: Present in guild or architecture review.
|
||||
|
||||
## Self-Check
|
||||
|
||||
- [ ] Does this feature implement a shared interface?
|
||||
- [ ] Are fallbacks + errors handled gracefully?
|
||||
- [ ] Have relevant ADRs been updated/linked?
|
||||
- [ ] Did I add competence hooks or prompts for the team?
|
||||
- [ ] Was human interaction (sync/review/demo) scheduled?
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active architecture guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: Vue 3, Capacitor, Electron, Vite
|
||||
**Stakeholders**: Development team, Architecture team
|
||||
|
||||
- [ ] Are fallbacks + errors handled gracefully?
|
||||
- [ ] Have relevant ADRs been updated/linked?
|
||||
- [ ] Did I add competence hooks or prompts for the team?
|
||||
- [ ] Was human interaction (sync/review/demo) scheduled?
|
||||
# TimeSafari Cross-Platform Architecture Guide
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Architecture guidelines
|
||||
|
||||
## 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 |
|
||||
|
||||
## 2. Project Structure
|
||||
|
||||
### Core Directories
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/ # Vue components
|
||||
├── services/ # Platform services and business logic
|
||||
├── views/ # Page components
|
||||
├── router/ # Vue router configuration
|
||||
├── types/ # TypeScript type definitions
|
||||
├── utils/ # Utility functions
|
||||
├── lib/ # Core libraries
|
||||
├── platforms/ # Platform-specific implementations
|
||||
├── electron/ # Electron-specific code
|
||||
├── constants/ # Application constants
|
||||
├── db/ # Database related code
|
||||
├── interfaces/ # TypeScript interfaces
|
||||
└── assets/ # Static assets
|
||||
```
|
||||
|
||||
### Entry Points
|
||||
|
||||
- `main.ts` → Base entry
|
||||
- `main.common.ts` → Shared init
|
||||
- `main.capacitor.ts` → Mobile entry
|
||||
- `main.electron.ts` → Electron entry
|
||||
- `main.web.ts` → Web entry
|
||||
|
||||
## 3. Service Architecture
|
||||
|
||||
### Service Organization
|
||||
|
||||
```tree
|
||||
services/
|
||||
├── QRScanner/
|
||||
│ ├── WebInlineQRScanner.ts
|
||||
│ └── interfaces.ts
|
||||
├── platforms/
|
||||
│ ├── WebPlatformService.ts
|
||||
│ ├── CapacitorPlatformService.ts
|
||||
│ └── ElectronPlatformService.ts
|
||||
└── factory/
|
||||
└── PlatformServiceFactory.ts
|
||||
```
|
||||
|
||||
### Factory Pattern
|
||||
|
||||
Use a **singleton factory** to select platform services via
|
||||
`process.env.VITE_PLATFORM`.
|
||||
|
||||
## 4. Feature Guidelines
|
||||
|
||||
### QR Code Scanning
|
||||
|
||||
- Define `QRScannerService` interface.
|
||||
- Implement platform-specific classes (`WebInlineQRScanner`, Capacitor,
|
||||
etc).
|
||||
- Provide `addListener` and `onStream` hooks for composability.
|
||||
|
||||
### Deep Linking
|
||||
|
||||
- URL format: `timesafari://<route>[/<param>][?query=value]`
|
||||
- Web: `router.beforeEach` → parse query
|
||||
- Capacitor: `App.addListener("appUrlOpen", …)`
|
||||
|
||||
## 5. Build Process
|
||||
|
||||
- `vite.config.common.mts` → shared config
|
||||
- Platform configs: `vite.config.web.mts`, `.capacitor.mts`,
|
||||
`.electron.mts`
|
||||
- Use `process.env.VITE_PLATFORM` for conditional loading.
|
||||
|
||||
```bash
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
npm run build:electron
|
||||
```
|
||||
|
||||
## 6. Testing Strategy
|
||||
|
||||
- **Unit tests** for services.
|
||||
- **Playwright** for Web + Capacitor:
|
||||
- `playwright.config-local.ts` includes web + Pixel 5.
|
||||
- **Electron tests**: add `spectron` or Playwright-Electron.
|
||||
- Mark tests with platform tags:
|
||||
|
||||
```ts
|
||||
test.skip(!process.env.MOBILE_TEST, "Mobile-only test");
|
||||
```
|
||||
|
||||
> 🔗 **Human Hook:** Before merging new tests, hold a short sync (≤15
|
||||
> min) with QA to align on coverage and flaky test risks.
|
||||
|
||||
## 7. Error Handling
|
||||
|
||||
- Global Vue error handler → logs with component name.
|
||||
- Platform-specific wrappers log API errors with platform prefix
|
||||
(`[Capacitor API Error]`, etc).
|
||||
- Use structured logging (not `console.log`).
|
||||
|
||||
## 8. Best Practices
|
||||
|
||||
- Keep platform code **isolated** in `platforms/`.
|
||||
- Always define a **shared interface** first.
|
||||
- Use feature detection, not platform detection, when possible.
|
||||
- Dependency injection for services → improves testability.
|
||||
- Maintain **Competence Hooks** in PRs (2–3 prompts for dev
|
||||
discussion).
|
||||
|
||||
## 9. Dependency Management
|
||||
|
||||
- Key deps: `@capacitor/core`, `electron`, `vue`.
|
||||
- Use conditional `import()` for platform-specific libs.
|
||||
|
||||
## 10. Security Considerations
|
||||
|
||||
- **Permissions**: Always check + request gracefully.
|
||||
- **Storage**: Secure storage for sensitive data; encrypt when possible.
|
||||
- **Audits**: Schedule quarterly security reviews.
|
||||
|
||||
## 11. ADR Process
|
||||
|
||||
- All major architecture choices → log in `doc/adr/`.
|
||||
- Use ADR template with Context, Decision, Consequences, Status.
|
||||
- Link related ADRs in PR descriptions.
|
||||
|
||||
> 🔗 **Human Hook:** When proposing a new ADR, schedule a 30-min
|
||||
> design sync for discussion, not just async review.
|
||||
|
||||
## 12. Collaboration Hooks
|
||||
|
||||
- **QR features**: Sync with Security before merging → permissions &
|
||||
privacy.
|
||||
- **New platform builds**: Demo in team meeting → confirm UX
|
||||
differences.
|
||||
- **Critical ADRs**: Present in guild or architecture review.
|
||||
|
||||
## Self-Check
|
||||
|
||||
- [ ] Does this feature implement a shared interface?
|
||||
- [ ] Are fallbacks + errors handled gracefully?
|
||||
- [ ] Have relevant ADRs been updated/linked?
|
||||
- [ ] Did I add competence hooks or prompts for the team?
|
||||
- [ ] Was human interaction (sync/review/demo) scheduled?
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active architecture guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: Vue 3, Capacitor, Electron, Vite
|
||||
**Stakeholders**: Development team, Architecture team
|
||||
|
||||
- [ ] Are fallbacks + errors handled gracefully?
|
||||
- [ ] Have relevant ADRs been updated/linked?
|
||||
- [ ] Did I add competence hooks or prompts for the team?
|
||||
- [ ] Was human interaction (sync/review/demo) scheduled?
|
||||
@@ -1,181 +0,0 @@
|
||||
# Time Safari Context
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Core application context
|
||||
|
||||
## Project Overview
|
||||
|
||||
Time Safari is an application designed to foster community building through
|
||||
gifts, gratitude, and collaborative projects. The app makes it 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.
|
||||
|
||||
## Core Goals
|
||||
|
||||
1. **Connect**: Make it easy, rewarding, and non-threatening for people to
|
||||
connect with others who have similar interests, and to initiate activities
|
||||
together.
|
||||
|
||||
2. **Reveal**: Widely advertise the great support and rewards that are being
|
||||
given and accepted freely, especially non-monetary ones, showing the impact
|
||||
gifts make in people's lives.
|
||||
|
||||
## Technical Foundation
|
||||
|
||||
### Architecture
|
||||
|
||||
- **Privacy-preserving claims architecture** via endorser.ch
|
||||
- **Decentralized Identifiers (DIDs)**: User identities based on
|
||||
public/private key pairs stored on devices
|
||||
- **Cryptographic Verification**: All claims and confirmations are
|
||||
cryptographically signed
|
||||
- **User-Controlled Visibility**: Users explicitly control who can see their
|
||||
identifiers and data
|
||||
- **Cross-Platform**: Web (PWA), Mobile (Capacitor), Desktop (Electron)
|
||||
|
||||
### Current Database State
|
||||
|
||||
- **Database**: SQLite via Absurd SQL (browser) and native SQLite
|
||||
(mobile/desktop)
|
||||
- **Legacy Support**: IndexedDB (Dexie) for backward compatibility
|
||||
- **Status**: Modern database architecture fully implemented
|
||||
|
||||
### Core Technologies
|
||||
|
||||
- **Frontend**: Vue 3 + TypeScript + vue-facing-decorator
|
||||
- **Styling**: TailwindCSS
|
||||
- **Build**: Vite with platform-specific configs
|
||||
- **Testing**: Playwright E2E, Jest unit tests
|
||||
- **Database**: SQLite (Absurd SQL in browser), IndexedDB (legacy)
|
||||
- **State**: Pinia stores
|
||||
- **Platform Services**: Abstracted behind interfaces with factory pattern
|
||||
|
||||
## Development Principles
|
||||
|
||||
### Code Organization
|
||||
|
||||
- **Platform Services**: Abstract platform-specific code behind interfaces
|
||||
- **Service Factory**: Use `PlatformServiceFactory` for platform selection
|
||||
- **Type Safety**: Strict TypeScript, no `any` types, use type guards
|
||||
- **Modern Architecture**: Use current platform service patterns
|
||||
|
||||
### Architecture Patterns
|
||||
|
||||
- **Dependency Injection**: Services injected via mixins and factory pattern
|
||||
- **Interface Segregation**: Small, focused interfaces over large ones
|
||||
- **Composition over Inheritance**: Prefer mixins and composition
|
||||
- **Single Responsibility**: Each component/service has one clear purpose
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
- **E2E**: Playwright for critical user journeys
|
||||
- **Unit**: Jest with F.I.R.S.T. principles
|
||||
- **Platform Coverage**: Web + Capacitor (Pixel 5) in CI
|
||||
- **Quality Assurance**: Comprehensive testing and validation
|
||||
|
||||
## Current Development Focus
|
||||
|
||||
### Active Development
|
||||
|
||||
- **Feature Development**: Build new functionality using modern platform
|
||||
services
|
||||
- **Performance Optimization**: Improve app performance and user experience
|
||||
- **Platform Enhancement**: Leverage platform-specific capabilities
|
||||
- **Code Quality**: Maintain high standards and best practices
|
||||
|
||||
### Development Metrics
|
||||
|
||||
- **Code Quality**: High standards maintained across all platforms
|
||||
- **Performance**: Optimized for all target devices
|
||||
- **Testing**: Comprehensive coverage maintained
|
||||
- **User Experience**: Focus on intuitive, accessible interfaces
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### Web (PWA)
|
||||
|
||||
- **QR Scanning**: WebInlineQRScanner
|
||||
- **Deep Linking**: URL parameters
|
||||
- **File System**: Limited browser APIs
|
||||
- **Build**: `npm run build:web` (development build)
|
||||
|
||||
### Mobile (Capacitor)
|
||||
|
||||
- **QR Scanning**: @capacitor-mlkit/barcode-scanning
|
||||
- **Deep Linking**: App URL open events
|
||||
- **File System**: Capacitor Filesystem
|
||||
- **Build**: `npm run build:capacitor`
|
||||
|
||||
### Desktop (Electron)
|
||||
|
||||
- **File System**: Node.js fs
|
||||
- **Build**: `npm run build:electron`
|
||||
- **Distribution**: AppImage, DEB, DMG packages
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Build Commands
|
||||
|
||||
```bash
|
||||
# Web (development)
|
||||
npm run build:web
|
||||
|
||||
# Mobile
|
||||
npm run build:capacitor
|
||||
npm run build:native
|
||||
|
||||
# Desktop
|
||||
npm run build:electron
|
||||
npm run build:electron:appimage
|
||||
npm run build:electron:deb
|
||||
npm run build:electron:dmg
|
||||
```
|
||||
|
||||
### Testing Commands
|
||||
|
||||
```bash
|
||||
# Web E2E
|
||||
npm run test:web
|
||||
|
||||
# Mobile
|
||||
npm run test:mobile
|
||||
npm run test:android
|
||||
npm run test:ios
|
||||
|
||||
# Type checking
|
||||
npm run type-check
|
||||
npm run lint-fix
|
||||
```
|
||||
|
||||
## Key Constraints
|
||||
|
||||
1. **Privacy First**: User identifiers remain private except when explicitly
|
||||
shared
|
||||
2. **Platform Compatibility**: Features must work across all target platforms
|
||||
3. **Performance**: Must remain performant on older/simpler devices
|
||||
4. **Modern Architecture**: New features should use current platform services
|
||||
5. **Offline Capability**: Key functionality should work offline when feasible
|
||||
|
||||
## Use Cases to Support
|
||||
|
||||
1. **Community Building**: Tools for finding others with shared interests
|
||||
2. **Project Coordination**: Easy proposal and collaboration on projects
|
||||
3. **Reputation Building**: Showcasing contributions and reliability
|
||||
4. **Governance**: Facilitating decision-making and collective governance
|
||||
|
||||
## Resources
|
||||
|
||||
- **Testing**: `docs/migration-testing/`
|
||||
- **Architecture**: `docs/architecture-decisions.md`
|
||||
- **Build Context**: `docs/build-modernization-context.md`
|
||||
|
||||
---
|
||||
|
||||
## Status: Active application context
|
||||
|
||||
- **Priority**: Critical
|
||||
- **Estimated Effort**: Ongoing reference
|
||||
- **Dependencies**: Vue 3, TypeScript, SQLite, Capacitor, Electron
|
||||
- **Stakeholders**: Development team, Product team
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
description: when doing anything with capacitor assets
|
||||
alwaysApply: false
|
||||
---
|
||||
# Asset Configuration Directive
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Asset management guidelines
|
||||
|
||||
*Scope: Assets Only (icons, splashes, image pipelines) — not overall build
|
||||
orchestration*
|
||||
|
||||
## Intent
|
||||
|
||||
- Version **asset configuration files** (optionally dev-time generated).
|
||||
- **Do not** version platform asset outputs (Android/iOS/Electron); generate
|
||||
them **at build-time** with standard tools.
|
||||
- Keep existing per-platform build scripts unchanged.
|
||||
|
||||
## Source of Truth
|
||||
|
||||
- **Preferred (Capacitor default):** `resources/` as the single master source.
|
||||
- **Alternative:** `assets/` is acceptable **only** if `capacitor-assets` is
|
||||
explicitly configured to read from it.
|
||||
- **Never** maintain both `resources/` and `assets/` as parallel sources.
|
||||
Migrate and delete the redundant folder.
|
||||
|
||||
## Config Files
|
||||
|
||||
- Live under: `config/assets/` (committed).
|
||||
- Examples:
|
||||
- `config/assets/capacitor-assets.config.json` (or the path the tool
|
||||
expects)
|
||||
- `config/assets/android.assets.json`
|
||||
- `config/assets/ios.assets.json`
|
||||
- `config/assets/common.assets.yaml` (optional shared layer)
|
||||
- **Dev-time generation allowed** for these configs; **build-time
|
||||
generation is forbidden**.
|
||||
|
||||
## Build-Time Behavior
|
||||
|
||||
- Build generates platform assets (not configs) using the standard chain:
|
||||
|
||||
```bash
|
||||
npm run build:capacitor # web build via Vite (.mts)
|
||||
npx cap sync
|
||||
npx capacitor-assets generate # produces platform assets; not committed
|
||||
# then platform-specific build steps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active asset management directive
|
||||
**Priority**: Medium
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: capacitor-assets toolchain
|
||||
**Stakeholders**: Development team, Build team
|
||||
|
||||
npx capacitor-assets generate # produces platform assets; not committed
|
||||
# then platform-specific build steps
|
||||
@@ -1,154 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
```json
|
||||
{
|
||||
"coaching_level": "standard",
|
||||
"socratic_max_questions": 7,
|
||||
"verbosity": "normal",
|
||||
"timebox_minutes": null,
|
||||
"format_enforcement": "strict"
|
||||
}
|
||||
```
|
||||
|
||||
# Base Context — Human Competence First
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Core interaction guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
All interactions must *increase the human's competence over time* while
|
||||
completing the task efficiently. The model may handle menial work and memory
|
||||
extension, but must also promote learning, autonomy, and healthy work habits.
|
||||
The model should also **encourage human interaction and collaboration** rather
|
||||
than replacing it — outputs should be designed to **facilitate human discussion,
|
||||
decision-making, and creativity**, not to atomize tasks into isolated, purely
|
||||
machine-driven steps.
|
||||
|
||||
## Principles
|
||||
|
||||
1. Competence over convenience: finish the task *and* leave the human more
|
||||
capable next time.
|
||||
2. Mentorship, not lectures: be concise, concrete, and immediately applicable.
|
||||
3. Transparency: show assumptions, limits, and uncertainty; cite when
|
||||
non-obvious.
|
||||
4. Optional scaffolding: include small, skimmable learning hooks that do not
|
||||
bloat output.
|
||||
5. Time respect: default to **lean output**; offer opt-in depth via toggles.
|
||||
6. Psychological safety: encourage, never condescend; no medical/clinical
|
||||
advice. No censorship!
|
||||
7. Reusability: structure outputs so they can be saved, searched, reused, and
|
||||
repurposed.
|
||||
8. **Collaborative Bias**: Favor solutions that invite human review,
|
||||
discussion, and iteration. When in doubt, ask "Who should this be shown
|
||||
to?" or "Which human input would improve this?"
|
||||
|
||||
## Toggle Definitions
|
||||
|
||||
### coaching_level
|
||||
|
||||
Determines the depth of learning support: `light` (short hooks),
|
||||
`standard` (balanced), `deep` (detailed).
|
||||
|
||||
### socratic_max_questions
|
||||
|
||||
The number of clarifying questions the model may ask before proceeding.
|
||||
If >0, questions should be targeted, minimal, and followed by reasonable
|
||||
assumptions if unanswered.
|
||||
|
||||
### verbosity
|
||||
|
||||
'terse' (just a sentence), `concise` (minimum commentary), `normal`
|
||||
(balanced explanation), or other project-defined levels.
|
||||
|
||||
### timebox_minutes
|
||||
|
||||
*integer or null* — When set to a positive integer (e.g., `5`), this acts
|
||||
as a **time budget** guiding the model to prioritize delivering the most
|
||||
essential parts of the task within that constraint.
|
||||
|
||||
Behavior when set:
|
||||
|
||||
1. **Prioritize Core Output** — Deliver the minimum viable solution or
|
||||
result first.
|
||||
2. **Limit Commentary** — Competence Hooks and Collaboration Hooks must be
|
||||
shorter than normal.
|
||||
3. **Signal Skipped Depth** — Omitted details should be listed under
|
||||
*Deferred for depth*.
|
||||
4. **Order by Value** — Start with blocking or high-value items, then
|
||||
proceed to nice-to-haves if budget allows.
|
||||
|
||||
If `null`, there is no timebox — the model can produce full-depth
|
||||
responses.
|
||||
|
||||
### format_enforcement
|
||||
|
||||
`strict` (reject outputs with format drift) or `relaxed` (minor deviations
|
||||
acceptable).
|
||||
|
||||
## Modes (select or combine)
|
||||
|
||||
- **Doer**: produce the artifact fast, minimal commentary.
|
||||
- **Mentor**: add short "why/how" notes + next-step pointers.
|
||||
- **Socratic**: ask up to N targeted questions when requirements are
|
||||
ambiguous.
|
||||
- **Pair-Programmer/Pair-Writer**: explain tradeoffs as you implement.
|
||||
- **Facilitator**: structure output to be reviewable, commentable, and
|
||||
ready for group discussion.
|
||||
|
||||
Default: Doer + short Mentor notes.
|
||||
|
||||
## Competence & Collaboration Levers (keep lightweight)
|
||||
|
||||
- "Why this works" (≤3 bullets)
|
||||
- "Common pitfalls" (≤3 bullets)
|
||||
- "Next skill unlock" (1 tiny action or reading)
|
||||
- "Teach-back" (1 sentence prompt the human can answer to self-check)
|
||||
- "Discussion prompts" (≤2 short questions for peers/stakeholders)
|
||||
|
||||
## Output Contract (apply to every deliverable)
|
||||
|
||||
- Clear **Objective** (1 line)
|
||||
- **Result** (artifact/code/answer)
|
||||
- **Use/Run** (how to apply/test)
|
||||
- **Competence Hooks** (the 4 learning levers above, kept terse)
|
||||
- **Collaboration Hooks** (discussion prompts or group review steps)
|
||||
- **Assumptions & Limits**
|
||||
- **References** (if used; links or titles)
|
||||
|
||||
## Do-Not
|
||||
|
||||
- No filler, hedging, or moralizing.
|
||||
- No medical/mental-health advice; keep "healthy habits" to general work
|
||||
practices.
|
||||
- No invented facts; mark uncertainty plainly.
|
||||
- No censorship.
|
||||
- Avoid outputs that bypass human review when such review is valuable.
|
||||
|
||||
## Related Rulesets
|
||||
|
||||
- **software_development.mdc**: For software-specific development practices
|
||||
- **research_diagnostic.mdc**: For investigation and research workflows
|
||||
|
||||
## Self-Check (model, before responding)
|
||||
|
||||
- [ ] Task done *and* at least one competence lever included (≤120 words
|
||||
total).
|
||||
- [ ] At least one collaboration/discussion hook present.
|
||||
- [ ] Output follows the **Output Contract** sections.
|
||||
- [ ] Toggles respected; verbosity remains concise.
|
||||
- [ ] Uncertainties/assumptions surfaced.
|
||||
- [ ] No disallowed content.
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active core guidelines
|
||||
**Priority**: Critical
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: None (base ruleset)
|
||||
**Stakeholders**: All AI interactions
|
||||
|
||||
- [ ] Uncertainties/assumptions surfaced.
|
||||
- [ ] No disallowed content.
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
globs: **/db/databaseUtil.ts, **/interfaces/absurd-sql.d.ts, **/src/registerSQLWorker.js, **/
|
||||
services/AbsurdSqlDatabaseService.ts
|
||||
alwaysApply: false
|
||||
---
|
||||
# Absurd SQL - Cursor Development Guide
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Database development guidelines
|
||||
|
||||
## Project Overview
|
||||
|
||||
Absurd SQL is a backend implementation for sql.js that enables persistent
|
||||
SQLite databases in the browser by using IndexedDB as a block storage system.
|
||||
This guide provides rules and best practices for developing with this project
|
||||
in Cursor.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
absurd-sql/
|
||||
├── src/ # Source code
|
||||
├── dist/ # Built files
|
||||
├── package.json # Dependencies and scripts
|
||||
├── rollup.config.js # Build configuration
|
||||
└── jest.config.js # Test configuration
|
||||
```
|
||||
|
||||
## Development Rules
|
||||
|
||||
### 1. Worker Thread Requirements
|
||||
|
||||
- All SQL operations MUST be performed in a worker thread
|
||||
- Main thread should only handle worker initialization and communication
|
||||
- Never block the main thread with database operations
|
||||
|
||||
### 2. Code Organization
|
||||
|
||||
- Keep worker code in separate files (e.g., `*.worker.js`)
|
||||
- Use ES modules for imports/exports
|
||||
- Follow the project's existing module structure
|
||||
|
||||
### 3. Required Headers
|
||||
|
||||
When developing locally or deploying, ensure these headers are set:
|
||||
|
||||
```
|
||||
Cross-Origin-Opener-Policy: same-origin
|
||||
Cross-Origin-Embedder-Policy: require-corp
|
||||
```
|
||||
|
||||
### 4. Browser Compatibility
|
||||
|
||||
- Primary target: Modern browsers with SharedArrayBuffer support
|
||||
- Fallback mode: Safari (with limitations)
|
||||
- Always test in both modes
|
||||
|
||||
### 5. Database Configuration
|
||||
|
||||
Recommended database settings:
|
||||
|
||||
```sql
|
||||
PRAGMA journal_mode=MEMORY;
|
||||
PRAGMA page_size=8192; -- Optional, but recommended
|
||||
```
|
||||
|
||||
### 6. Development Workflow
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
yarn add @jlongster/sql.js absurd-sql
|
||||
```
|
||||
|
||||
2. Development commands:
|
||||
- `yarn build` - Build the project
|
||||
- `yarn jest` - Run tests
|
||||
- `yarn serve` - Start development server
|
||||
|
||||
### 7. Testing Guidelines
|
||||
|
||||
- Write tests for both SharedArrayBuffer and fallback modes
|
||||
- Use Jest for testing
|
||||
- Include performance benchmarks for critical operations
|
||||
|
||||
### 8. Performance Considerations
|
||||
|
||||
- Use bulk operations when possible
|
||||
- Monitor read/write performance
|
||||
- Consider using transactions for multiple operations
|
||||
- Avoid unnecessary database connections
|
||||
|
||||
### 9. Error Handling
|
||||
|
||||
- Implement proper error handling for:
|
||||
- Worker initialization failures
|
||||
- Database connection issues
|
||||
- Concurrent access conflicts (in fallback mode)
|
||||
- Storage quota exceeded scenarios
|
||||
|
||||
### 10. Security Best Practices
|
||||
|
||||
- Never expose database operations directly to the client
|
||||
- Validate all SQL queries
|
||||
- Implement proper access controls
|
||||
- Handle sensitive data appropriately
|
||||
|
||||
### 11. Code Style
|
||||
|
||||
- Follow ESLint configuration
|
||||
- Use async/await for asynchronous operations
|
||||
- Document complex database operations
|
||||
- Include comments for non-obvious optimizations
|
||||
|
||||
### 12. Debugging
|
||||
|
||||
- Use `jest-debug` for debugging tests
|
||||
- Monitor IndexedDB usage in browser dev tools
|
||||
- Check worker communication in console
|
||||
- Use performance monitoring tools
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Worker Initialization
|
||||
|
||||
```javascript
|
||||
// Main thread
|
||||
import { initBackend } from 'absurd-sql/dist/indexeddb-main-thread';
|
||||
|
||||
function init() {
|
||||
let worker = new Worker(new URL('./index.worker.js', import.meta.url));
|
||||
initBackend(worker);
|
||||
}
|
||||
```
|
||||
|
||||
### Database Setup
|
||||
|
||||
```javascript
|
||||
// Worker thread
|
||||
import initSqlJs from '@jlongster/sql.js';
|
||||
import { SQLiteFS } from 'absurd-sql';
|
||||
import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend';
|
||||
|
||||
async function setupDatabase() {
|
||||
let SQL = await initSqlJs({ locateFile: file => file });
|
||||
let sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend());
|
||||
SQL.register_for_idb(sqlFS);
|
||||
|
||||
SQL.FS.mkdir('/sql');
|
||||
SQL.FS.mount(sqlFS, {}, '/sql');
|
||||
|
||||
return new SQL.Database('/sql/db.sqlite', { filename: true });
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. SharedArrayBuffer not available
|
||||
- Check COOP/COEP headers
|
||||
- Verify browser support
|
||||
- Test fallback mode
|
||||
|
||||
2. Worker initialization failures
|
||||
- Check file paths
|
||||
- Verify module imports
|
||||
- Check browser console for errors
|
||||
|
||||
3. Performance issues
|
||||
- Monitor IndexedDB usage
|
||||
- Check for unnecessary operations
|
||||
- Verify transaction usage
|
||||
|
||||
## Resources
|
||||
|
||||
- [Project Demo](https://priceless-keller-d097e5.netlify.app/)
|
||||
- [Example Project](https://github.com/jlongster/absurd-example-project)
|
||||
- [Blog Post](https://jlongster.com/future-sql-web)
|
||||
- [SQL.js Documentation](https://github.com/sql-js/sql.js/)
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active database development guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: Absurd SQL, SQL.js, IndexedDB
|
||||
**Stakeholders**: Development team, Database team
|
||||
- [Project Demo](https://priceless-keller-d097e5.netlify.app/)
|
||||
- [Example Project](https://github.com/jlongster/absurd-example-project)
|
||||
- [Blog Post](https://jlongster.com/future-sql-web)
|
||||
- [SQL.js Documentation](https://github.com/sql-js/sql.js/)
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
globs: **/databaseUtil.ts,**/AccountViewView.vue,**/ContactsView.vue,**/DatabaseMigration.vue,**/NewIdentifierView.vue
|
||||
alwaysApply: false
|
||||
---
|
||||
# What to do with Dexie
|
||||
|
||||
All references in the codebase to Dexie apply only to migration from IndexedDb to
|
||||
Sqlite and will be deprecated in future versions.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
globs: **/src/**/*
|
||||
alwaysApply: false
|
||||
---
|
||||
✅ 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,139 +0,0 @@
|
||||
---
|
||||
description: when dealing with types and Typesript
|
||||
alwaysApply: false
|
||||
---
|
||||
```json
|
||||
{
|
||||
"coaching_level": "light",
|
||||
"socratic_max_questions": 7,
|
||||
"verbosity": "concise",
|
||||
"timebox_minutes": null,
|
||||
"format_enforcement": "strict"
|
||||
}
|
||||
```
|
||||
|
||||
# TypeScript Type Safety Guidelines
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Type safety enforcement
|
||||
|
||||
## Overview
|
||||
|
||||
Practical rules to keep TypeScript strict and predictable. Minimize exceptions.
|
||||
|
||||
## Core Rules
|
||||
|
||||
1. **No `any`**
|
||||
- Use explicit types. If unknown, use `unknown` and **narrow** via guards.
|
||||
|
||||
2. **Error handling uses guards**
|
||||
- Reuse guards from `src/interfaces/**` (e.g., `isDatabaseError`,
|
||||
`isApiError`).
|
||||
- Catch with `unknown`; never cast to `any`.
|
||||
|
||||
3. **Dynamic property access is type‑safe**
|
||||
- Use `keyof` + `in` checks:
|
||||
|
||||
```ts
|
||||
obj[k as keyof typeof obj]
|
||||
```
|
||||
|
||||
- Avoid `(obj as any)[k]`.
|
||||
|
||||
## Type Safety Enforcement
|
||||
|
||||
### Core Type Safety Rules
|
||||
|
||||
- **No `any` Types**: Use explicit types or `unknown` with proper type guards
|
||||
- **Error Handling Uses Guards**: Implement and reuse type guards from `src/interfaces/**`
|
||||
- **Dynamic Property Access**: Use `keyof` + `in` checks for type-safe property access
|
||||
|
||||
### Type Guard Patterns
|
||||
- **API Errors**: Use `isApiError(error)` guards for API error handling
|
||||
- **Database Errors**: Use `isDatabaseError(error)` guards for database operations
|
||||
- **Axios Errors**: Implement `isAxiosError(error)` guards for HTTP error handling
|
||||
|
||||
### Implementation Guidelines
|
||||
- **Avoid Type Assertions**: Replace `as any` with proper type guards and interfaces
|
||||
- **Narrow Types Properly**: Use type guards to narrow `unknown` types safely
|
||||
- **Document Type Decisions**: Explain complex type structures and their purpose
|
||||
|
||||
## Minimal Special Cases (document in PR when used)
|
||||
|
||||
- **Vue refs / instances**: Use `ComponentPublicInstance` or specific
|
||||
component types for dynamic refs.
|
||||
- **3rd‑party libs without types**: Narrow immediately to a **known
|
||||
interface**; do not leave `any` hanging.
|
||||
|
||||
## Patterns (short)
|
||||
|
||||
### Database errors
|
||||
|
||||
```ts
|
||||
try { await this.$addContact(contact); }
|
||||
catch (e: unknown) {
|
||||
if (isDatabaseError(e) && e.message.includes("Key already exists")) {
|
||||
/* handle duplicate */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API errors
|
||||
|
||||
```ts
|
||||
try { await apiCall(); }
|
||||
catch (e: unknown) {
|
||||
if (isApiError(e)) {
|
||||
const msg = e.response?.data?.error?.message;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic keys
|
||||
|
||||
```ts
|
||||
const keys = Object.keys(newSettings).filter(
|
||||
k => k in newSettings && newSettings[k as keyof typeof newSettings] !== undefined
|
||||
);
|
||||
```
|
||||
|
||||
## Checklists
|
||||
|
||||
**Before commit**
|
||||
|
||||
- [ ] No `any` (except documented, justified cases)
|
||||
- [ ] Errors handled via guards
|
||||
- [ ] Dynamic access uses `keyof`/`in`
|
||||
- [ ] Imports point to correct interfaces/types
|
||||
|
||||
**Code review**
|
||||
|
||||
- [ ] Hunt hidden `as any`
|
||||
- [ ] Guard‑based error paths verified
|
||||
- [ ] Dynamic ops are type‑safe
|
||||
- [ ] Prefer existing types over re‑inventing
|
||||
|
||||
## Tools
|
||||
|
||||
- `npm run lint-fix` — lint & auto‑fix
|
||||
- `npm run type-check` — strict type compilation (CI + pre‑release)
|
||||
- IDE: enable strict TS, ESLint/TS ESLint, Volar (Vue 3)
|
||||
|
||||
## References
|
||||
|
||||
- TS Handbook — https://www.typescriptlang.org/docs/
|
||||
- TS‑ESLint — https://typescript-eslint.io/rules/
|
||||
- Vue 3 + TS — https://vuejs.org/guide/typescript/
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active type safety guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: TypeScript, ESLint, Vue 3
|
||||
**Stakeholders**: Development team
|
||||
|
||||
- TS Handbook — https://www.typescriptlang.org/docs/
|
||||
- TS‑ESLint — https://typescript-eslint.io/rules/
|
||||
- Vue 3 + TS — https://vuejs.org/guide/typescript/
|
||||
@@ -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,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,222 +0,0 @@
|
||||
---
|
||||
description: when dealing with cameras in the application
|
||||
alwaysApply: false
|
||||
---
|
||||
# Camera Implementation Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how camera functionality is implemented across the
|
||||
TimeSafari application. The application uses cameras for two main purposes:
|
||||
|
||||
1. QR Code scanning
|
||||
2. Photo capture
|
||||
|
||||
## Components
|
||||
|
||||
### QRScannerDialog.vue
|
||||
|
||||
Primary component for QR code scanning in web browsers.
|
||||
|
||||
**Key Features:**
|
||||
|
||||
- Uses `qrcode-stream` for web-based QR scanning
|
||||
- Supports both front and back cameras
|
||||
- Provides real-time camera status feedback
|
||||
- Implements error handling with user-friendly messages
|
||||
- Includes camera switching functionality
|
||||
|
||||
**Camera Access Flow:**
|
||||
|
||||
1. Checks for camera API availability
|
||||
2. Enumerates available video devices
|
||||
3. Requests camera permissions
|
||||
4. Initializes camera stream with preferred settings
|
||||
5. Handles various error conditions with specific messages
|
||||
|
||||
### PhotoDialog.vue
|
||||
|
||||
Component for photo capture and selection.
|
||||
|
||||
**Key Features:**
|
||||
|
||||
- Cross-platform photo capture interface
|
||||
- Image cropping capabilities
|
||||
- File selection fallback
|
||||
- Unified interface for different platforms
|
||||
|
||||
## Services
|
||||
|
||||
### QRScanner Services
|
||||
|
||||
#### WebDialogQRScanner
|
||||
|
||||
Web-based implementation of QR scanning.
|
||||
|
||||
**Key Methods:**
|
||||
|
||||
- `checkPermissions()`: Verifies camera permission status
|
||||
- `requestPermissions()`: Requests camera access
|
||||
- `isSupported()`: Checks for camera API support
|
||||
- Handles various error conditions with specific messages
|
||||
|
||||
#### CapacitorQRScanner
|
||||
|
||||
Native implementation using Capacitor's MLKit.
|
||||
|
||||
**Key Features:**
|
||||
|
||||
- Uses `@capacitor-mlkit/barcode-scanning`
|
||||
- Supports both front and back cameras
|
||||
- Implements permission management
|
||||
- Provides continuous scanning capability
|
||||
|
||||
### Platform Services
|
||||
|
||||
#### WebPlatformService
|
||||
|
||||
Web-specific implementation of platform features.
|
||||
|
||||
**Camera Capabilities:**
|
||||
|
||||
- Uses HTML5 file input with capture attribute
|
||||
- Falls back to file selection if camera unavailable
|
||||
- Processes captured images for consistent format
|
||||
|
||||
#### CapacitorPlatformService
|
||||
|
||||
Native implementation using Capacitor.
|
||||
|
||||
**Camera Features:**
|
||||
|
||||
- Uses `Camera.getPhoto()` for native camera access
|
||||
- Supports image editing
|
||||
- Configures high-quality image capture
|
||||
- Handles base64 image processing
|
||||
|
||||
#### ElectronPlatformService
|
||||
|
||||
Desktop implementation (currently unimplemented).
|
||||
|
||||
**Status:**
|
||||
|
||||
- Camera functionality not yet implemented
|
||||
- Planned to use Electron's media APIs
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### iOS
|
||||
|
||||
- Requires `NSCameraUsageDescription` in Info.plist
|
||||
- Supports both front and back cameras
|
||||
- Implements proper permission handling
|
||||
|
||||
### Android
|
||||
|
||||
- Requires camera permissions in manifest
|
||||
- Supports both front and back cameras
|
||||
- Handles permission requests through Capacitor
|
||||
|
||||
### Web
|
||||
|
||||
- Requires HTTPS for camera access
|
||||
- Implements fallback mechanisms
|
||||
- Handles browser compatibility issues
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Error Scenarios
|
||||
|
||||
1. No camera found
|
||||
2. Permission denied
|
||||
3. Camera in use by another application
|
||||
4. HTTPS required
|
||||
5. Browser compatibility issues
|
||||
|
||||
### Error Response
|
||||
|
||||
- User-friendly error messages
|
||||
- Troubleshooting tips
|
||||
- Clear instructions for resolution
|
||||
- Platform-specific guidance
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Permission Management
|
||||
|
||||
- Explicit permission requests
|
||||
- Permission state tracking
|
||||
- Graceful handling of denied permissions
|
||||
|
||||
### Data Handling
|
||||
|
||||
- Secure image processing
|
||||
- Proper cleanup of camera resources
|
||||
- No persistent storage of camera data
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Camera Access
|
||||
|
||||
1. Always check for camera availability
|
||||
2. Request permissions explicitly
|
||||
3. Handle all error conditions
|
||||
4. Provide clear user feedback
|
||||
5. Implement proper cleanup
|
||||
|
||||
### Performance
|
||||
|
||||
1. Optimize camera resolution
|
||||
2. Implement proper resource cleanup
|
||||
3. Handle camera switching efficiently
|
||||
4. Manage memory usage
|
||||
|
||||
### User Experience
|
||||
|
||||
1. Clear status indicators
|
||||
2. Intuitive camera controls
|
||||
3. Helpful error messages
|
||||
4. Smooth camera switching
|
||||
5. Responsive UI feedback
|
||||
|
||||
## Future Improvements
|
||||
|
||||
### Planned Enhancements
|
||||
|
||||
1. Implement Electron camera support
|
||||
2. Add advanced camera features
|
||||
3. Improve error handling
|
||||
4. Enhance user feedback
|
||||
5. Optimize performance
|
||||
|
||||
### Known Issues
|
||||
|
||||
1. Electron camera implementation pending
|
||||
2. Some browser compatibility limitations
|
||||
3. Platform-specific quirks to address
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Key Packages
|
||||
|
||||
- `@capacitor-mlkit/barcode-scanning`
|
||||
- `qrcode-stream`
|
||||
- `vue-picture-cropper`
|
||||
- Platform-specific camera APIs
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
1. Permission handling
|
||||
2. Camera switching
|
||||
3. Error conditions
|
||||
4. Platform compatibility
|
||||
5. Performance metrics
|
||||
|
||||
### Test Environment
|
||||
|
||||
- Multiple browsers
|
||||
- iOS and Android devices
|
||||
- Desktop platforms
|
||||
- Various network conditions
|
||||
@@ -1,117 +0,0 @@
|
||||
# Investigation Report Example
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Investigation methodology example
|
||||
|
||||
## Investigation — Registration Dialog Test Flakiness
|
||||
|
||||
## Objective
|
||||
|
||||
Identify root cause of flaky tests related to registration dialogs in contact
|
||||
import scenarios.
|
||||
|
||||
## System Map
|
||||
|
||||
- User action → ContactInputForm → ContactsView.addContact() →
|
||||
handleRegistrationPrompt()
|
||||
- setTimeout(1000ms) → Modal dialog → User response → Registration API call
|
||||
- Test execution → Wait for dialog → Assert dialog content → Click response
|
||||
button
|
||||
|
||||
## Findings (Evidence)
|
||||
|
||||
- **1-second timeout causes flakiness** — evidence:
|
||||
`src/views/ContactsView.vue:971-1000`; setTimeout(..., 1000) in
|
||||
handleRegistrationPrompt()
|
||||
- **Import flow bypasses dialogs** — evidence:
|
||||
`src/views/ContactImportView.vue:500-520`; importContacts() calls
|
||||
$insertContact() directly, no handleRegistrationPrompt()
|
||||
- **Dialog only appears in direct add flow** — evidence:
|
||||
`src/views/ContactsView.vue:774-800`; addContact() calls
|
||||
handleRegistrationPrompt() after database insert
|
||||
|
||||
## Hypotheses & Failure Modes
|
||||
|
||||
- H1: 1-second timeout makes dialog appearance unpredictable; would fail when
|
||||
tests run faster than 1000ms
|
||||
- H2: Test environment timing differs from development; watch for CI vs local
|
||||
test differences
|
||||
|
||||
## Corrections
|
||||
|
||||
- Updated: "Multiple dialogs interfere with imports" → "Import flow never
|
||||
triggers dialogs - they only appear in direct contact addition"
|
||||
- Updated: "Complex batch registration needed" → "Simple timeout removal and
|
||||
test mode flag sufficient"
|
||||
|
||||
## Diagnostics (Next Checks)
|
||||
|
||||
- [ ] Repro on CI environment vs local
|
||||
- [ ] Measure actual dialog appearance timing
|
||||
- [ ] Test with setTimeout removed
|
||||
- [ ] Verify import flow doesn't call handleRegistrationPrompt
|
||||
|
||||
## Risks & Scope
|
||||
|
||||
- Impacted: Contact addition tests, registration workflow tests; Data: None;
|
||||
Users: Test suite reliability
|
||||
|
||||
## Decision / Next Steps
|
||||
|
||||
- Owner: Development Team; By: 2025-01-28
|
||||
- Action: Remove 1-second timeout + add test mode flag; Exit criteria: Tests
|
||||
pass consistently
|
||||
|
||||
## References
|
||||
|
||||
- `src/views/ContactsView.vue:971-1000`
|
||||
- `src/views/ContactImportView.vue:500-520`
|
||||
- `src/views/ContactsView.vue:774-800`
|
||||
|
||||
## Competence Hooks
|
||||
|
||||
- Why this works: Code path tracing revealed separate execution flows,
|
||||
evidence disproved initial assumptions
|
||||
- Common pitfalls: Assuming related functionality without tracing execution
|
||||
paths, over-engineering solutions to imaginary problems
|
||||
- Next skill: Learn to trace code execution before proposing architectural
|
||||
changes
|
||||
- Teach-back: "What evidence shows that contact imports bypass registration
|
||||
dialogs?"
|
||||
|
||||
## Key Learning Points
|
||||
|
||||
### Evidence-First Approach
|
||||
|
||||
This investigation demonstrates the importance of:
|
||||
|
||||
1. **Tracing actual code execution** rather than making assumptions
|
||||
2. **Citing specific evidence** with file:line references
|
||||
3. **Validating problem scope** before proposing solutions
|
||||
4. **Considering simpler alternatives** before complex architectural changes
|
||||
|
||||
### Code Path Tracing Value
|
||||
|
||||
By tracing the execution paths, we discovered:
|
||||
|
||||
- Import flow and direct add flow are completely separate
|
||||
- The "multiple dialog interference" problem didn't exist
|
||||
- A simple timeout removal would solve the actual issue
|
||||
|
||||
### Prevention of Over-Engineering
|
||||
|
||||
The investigation prevented:
|
||||
|
||||
- Unnecessary database schema changes
|
||||
- Complex batch registration systems
|
||||
- Migration scripts for non-existent problems
|
||||
- Architectural changes based on assumptions
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active investigation methodology
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: software_development.mdc
|
||||
**Stakeholders**: Development team, QA team
|
||||
@@ -1,222 +0,0 @@
|
||||
# Agent Contract — TimeSafari Logging (Unified, MANDATORY)
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Mandatory logging standards
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines unified logging standards for the TimeSafari project,
|
||||
ensuring consistent, rest-parameter logging style using the project logger.
|
||||
No `console.*` methods are allowed in production code.
|
||||
|
||||
## Scope and Goals
|
||||
|
||||
**Scope**: Applies to all diffs and generated code in this workspace unless
|
||||
explicitly exempted below.
|
||||
|
||||
**Goal**: One consistent, rest-parameter logging style using the project
|
||||
logger; no `console.*` in production code.
|
||||
|
||||
## Non‑Negotiables (DO THIS)
|
||||
|
||||
- You **MUST** use the project logger; **DO NOT** use any `console.*`
|
||||
methods.
|
||||
- Import exactly as:
|
||||
- `import { logger } from '@/utils/logger'`
|
||||
- If `@` alias is unavailable, compute the correct relative path (do not
|
||||
fail).
|
||||
- Call signatures use **rest parameters**: `logger.info(message, ...args)`
|
||||
- Prefer primitives/IDs and small objects in `...args`; **never build a
|
||||
throwaway object** just to "wrap context".
|
||||
- Production defaults: Web = `warn+`, Electron = `error`, Dev/Capacitor =
|
||||
`info+` (override via `VITE_LOG_LEVEL`).
|
||||
- **Database persistence**: `info|warn|error` are persisted; `debug` is not.
|
||||
Use `logger.toDb(msg, level?)` for DB-only.
|
||||
|
||||
## Available Logger API (Authoritative)
|
||||
|
||||
- `logger.debug(message, ...args)` — verbose internals, timings, input/output
|
||||
shapes
|
||||
- `logger.log(message, ...args)` — synonym of `info` for general info
|
||||
- `logger.info(message, ...args)` — lifecycle, state changes, success paths
|
||||
- `logger.warn(message, ...args)` — recoverable issues, retries, degraded mode
|
||||
- `logger.error(message, ...args)` — failures, thrown exceptions, aborts
|
||||
- `logger.toDb(message, level?)` — DB-only entry (default level = `info`)
|
||||
- `logger.toConsoleAndDb(message, isError)` — console + DB (use sparingly)
|
||||
- `logger.withContext(componentName)` — returns a scoped logger
|
||||
|
||||
## Level Guidelines (Use These Heuristics)
|
||||
|
||||
### DEBUG
|
||||
|
||||
Use for method entry/exit, computed values, filters, loops, retries, and
|
||||
external call payload sizes.
|
||||
|
||||
```typescript
|
||||
logger.debug('[HomeView] reloadFeedOnChange() called');
|
||||
logger.debug('[HomeView] Current filter settings',
|
||||
settings.filterFeedByVisible,
|
||||
settings.filterFeedByNearby,
|
||||
settings.searchBoxes?.length ?? 0);
|
||||
logger.debug('[FeedFilters] Toggling nearby filter',
|
||||
this.isNearby, this.settingChanged, this.activeDid);
|
||||
```
|
||||
|
||||
**Avoid**: Vague messages (`'Processing data'`).
|
||||
|
||||
### INFO
|
||||
|
||||
Use for user-visible lifecycle and completed operations.
|
||||
|
||||
```typescript
|
||||
logger.info('[StartView] Component mounted', process.env.VITE_PLATFORM);
|
||||
logger.info('[StartView] User selected new seed generation');
|
||||
logger.info('[SearchAreaView] Search box stored',
|
||||
searchBox.name, searchBox.bbox);
|
||||
logger.info('[ContactQRScanShowView] Contact registration OK',
|
||||
contact.did);
|
||||
```
|
||||
|
||||
**Avoid**: Diagnostic details that belong in `debug`.
|
||||
|
||||
### WARN
|
||||
|
||||
Use for recoverable issues, fallbacks, unexpected-but-handled conditions.
|
||||
|
||||
```typescript
|
||||
logger.warn('[ContactQRScanShowView] Invalid scan result – no value',
|
||||
resultType);
|
||||
logger.warn('[ContactQRScanShowView] Invalid QR format – no JWT in URL');
|
||||
logger.warn('[ContactQRScanShowView] JWT missing "own" field');
|
||||
```
|
||||
|
||||
**Avoid**: Hard failures (those are `error`).
|
||||
|
||||
### ERROR
|
||||
|
||||
Use for unrecoverable failures, data integrity issues, and thrown
|
||||
exceptions.
|
||||
|
||||
```typescript
|
||||
logger.error('[HomeView Settings] initializeIdentity() failed', err);
|
||||
logger.error('[StartView] Failed to load initialization data', error);
|
||||
logger.error('[ContactQRScanShowView] Error processing contact QR',
|
||||
error, rawValue);
|
||||
```
|
||||
|
||||
**Avoid**: Expected user cancels (use `info`/`debug`).
|
||||
|
||||
## Context Hygiene (Consistent, Minimal, Helpful)
|
||||
|
||||
- **Component context**: Prefer scoped logger.
|
||||
|
||||
```typescript
|
||||
const log = logger.withContext('UserService');
|
||||
log.info('User created', userId);
|
||||
log.error('Failed to create user', error);
|
||||
```
|
||||
|
||||
If not using `withContext`, prefix message with `[ComponentName]`.
|
||||
|
||||
- **Emojis**: Optional and minimal for visual scanning. Recommended set:
|
||||
- Start/finish: 🚀 / ✅
|
||||
- Retry/loop: 🔄
|
||||
- External call: 📡
|
||||
- Data/metrics: 📊
|
||||
- Inspection: 🔍
|
||||
|
||||
- **Sensitive data**: Never log secrets (tokens, keys, passwords) or
|
||||
payloads >10KB. Prefer IDs over objects; redact/hash when needed.
|
||||
|
||||
## Migration — Auto‑Rewrites (Apply Every Time)
|
||||
|
||||
- Exact transforms:
|
||||
- `console.debug(...)` → `logger.debug(...)`
|
||||
- `console.log(...)` → `logger.log(...)` (or `logger.info(...)` when
|
||||
clearly stateful)
|
||||
- `console.info(...)` → `logger.info(...)`
|
||||
- `console.warn(...)` → `logger.warn(...)`
|
||||
- `console.error(...)` → `logger.error(...)`
|
||||
|
||||
- Multi-arg handling:
|
||||
- First arg becomes `message` (stringify safely if non-string).
|
||||
- Remaining args map 1:1 to `...args`:
|
||||
`console.info(msg, a, b)` → `logger.info(String(msg), a, b)`
|
||||
|
||||
- Sole `Error`:
|
||||
- `console.error(err)` → `logger.error(err.message, err)`
|
||||
|
||||
- **Object-wrapping cleanup**: Replace `{{ userId, meta }}` wrappers with
|
||||
separate args:
|
||||
`logger.info('User signed in', userId, meta)`
|
||||
|
||||
## DB Logging Rules
|
||||
|
||||
- `debug` **never** persists automatically.
|
||||
- `info|warn|error` persist automatically.
|
||||
- For DB-only events (no console), call `logger.toDb('Message',
|
||||
'info'|'warn'|'error')`.
|
||||
|
||||
## Exceptions (Tightly Scoped)
|
||||
|
||||
Allowed paths (still prefer logger):
|
||||
|
||||
- `**/*.test.*`, `**/*.spec.*`
|
||||
- `scripts/dev/**`, `scripts/migrate/**`
|
||||
|
||||
To intentionally keep `console.*`, add a pragma on the previous line:
|
||||
|
||||
```typescript
|
||||
// cursor:allow-console reason="short justification"
|
||||
console.log('temporary output');
|
||||
```
|
||||
|
||||
Without the pragma, rewrite to `logger.*`.
|
||||
|
||||
## CI & Diff Enforcement
|
||||
|
||||
- Do not introduce `console.*` anywhere outside allowed, pragma'd spots.
|
||||
- If an import is missing, insert it and resolve alias/relative path
|
||||
correctly.
|
||||
- Enforce rest-parameter call shape in reviews; replace object-wrapped
|
||||
context.
|
||||
- Ensure environment log level rules remain intact (`VITE_LOG_LEVEL`
|
||||
respected).
|
||||
|
||||
## Quick Before/After
|
||||
|
||||
### **Before**
|
||||
|
||||
```typescript
|
||||
console.log('User signed in', user.id, meta);
|
||||
console.error('Failed to update profile', err);
|
||||
console.info('Filter toggled', this.hasVisibleDid);
|
||||
```
|
||||
|
||||
### **After**
|
||||
|
||||
```typescript
|
||||
import { logger } from '@/utils/logger';
|
||||
|
||||
logger.info('User signed in', user.id, meta);
|
||||
logger.error('Failed to update profile', err);
|
||||
logger.debug('[FeedFilters] Filter toggled', this.hasVisibleDid);
|
||||
```
|
||||
|
||||
## Checklist (for every PR)
|
||||
|
||||
- [ ] No `console.*` (or properly pragma'd in the allowed locations)
|
||||
- [ ] Correct import path for `logger`
|
||||
- [ ] Rest-parameter call shape (`message, ...args`)
|
||||
- [ ] Right level chosen (debug/info/warn/error)
|
||||
- [ ] No secrets / oversized payloads / throwaway context objects
|
||||
- [ ] Component context provided (scoped logger or `[Component]` prefix)
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active and enforced
|
||||
**Priority**: Critical
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: TimeSafari logger utility
|
||||
**Stakeholders**: Development team, Code review team
|
||||
@@ -1,174 +0,0 @@
|
||||
---
|
||||
description: Use this workflow when doing **pre-implementation research, defect investigations with uncertain repros, or clarifying system architecture and behaviors**.
|
||||
alwaysApply: false
|
||||
---
|
||||
```json
|
||||
{
|
||||
"coaching_level": "light",
|
||||
"socratic_max_questions": 2,
|
||||
"verbosity": "concise",
|
||||
"timebox_minutes": null,
|
||||
"format_enforcement": "strict"
|
||||
}
|
||||
```
|
||||
|
||||
# Research & Diagnostic Workflow (R&D)
|
||||
|
||||
## Purpose
|
||||
|
||||
Provide a **repeatable, evidence-first** workflow to investigate features and
|
||||
defects **before coding**. Outputs are concise reports, hypotheses, and next
|
||||
steps—**not** code changes.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Pre-implementation research for new features
|
||||
- Defect investigations (repros uncertain, user-specific failures)
|
||||
- Architecture/behavior clarifications (e.g., auth flows, merges, migrations)
|
||||
|
||||
---
|
||||
|
||||
## Enhanced with Software Development Ruleset
|
||||
|
||||
When investigating software issues, also apply:
|
||||
|
||||
- **Code Path Tracing**: Required for technical investigations
|
||||
- **Evidence Validation**: Ensure claims are code-backed
|
||||
- **Solution Complexity Assessment**: Justify architectural changes
|
||||
|
||||
---
|
||||
|
||||
## Output Contract (strict)
|
||||
|
||||
1) **Objective** — 1–2 lines
|
||||
2) **System Map (if helpful)** — short diagram or bullet flow (≤8 bullets)
|
||||
3) **Findings (Evidence-linked)** — bullets; each with file/function refs
|
||||
4) **Hypotheses & Failure Modes** — short list, each testable
|
||||
5) **Corrections** — explicit deltas from earlier assumptions (if any)
|
||||
6) **Diagnostics** — what to check next (logs, DB, env, repro steps)
|
||||
7) **Risks & Scope** — what could break; affected components
|
||||
8) **Decision/Next Steps** — what we'll do, who's involved, by when
|
||||
9) **References** — code paths, ADRs, docs
|
||||
10) **Competence & Collaboration Hooks** — brief, skimmable
|
||||
|
||||
> Keep total length lean. Prefer links and bullets over prose.
|
||||
|
||||
---
|
||||
|
||||
## Quickstart Template
|
||||
|
||||
Copy/paste and fill:
|
||||
|
||||
```md
|
||||
# Investigation — <short title>
|
||||
|
||||
## Objective
|
||||
<one or two lines>
|
||||
|
||||
## System Map
|
||||
- <module> → <function> → <downstream>
|
||||
- <data path> → <db table> → <api>
|
||||
|
||||
## Findings (Evidence)
|
||||
- <claim> — evidence: `src/path/file.ts:function` (lines X–Y); log snippet/trace id
|
||||
- <claim> — evidence: `...`
|
||||
|
||||
## Hypotheses & Failure Modes
|
||||
- H1: <hypothesis>; would fail when <condition>
|
||||
- H2: <hypothesis>; watch for <signal>
|
||||
|
||||
## Corrections
|
||||
- Updated: <old statement> → <new statement with evidence>
|
||||
|
||||
## Diagnostics (Next Checks)
|
||||
- [ ] Repro on <platform/version>
|
||||
- [ ] Inspect <table/store> for <record>
|
||||
- [ ] Capture <log/trace>
|
||||
|
||||
## Risks & Scope
|
||||
- Impacted: <areas/components>; Data: <tables/keys>; Users: <segments>
|
||||
|
||||
## Decision / Next Steps
|
||||
- Owner: <name>; By: <date> (YYYY-MM-DD)
|
||||
- Action: <spike/bugfix/ADR>; Exit criteria: <binary checks>
|
||||
|
||||
## References
|
||||
- `src/...`
|
||||
- ADR: `docs/adr/xxxx-yy-zz-something.md`
|
||||
- Design: `docs/...`
|
||||
|
||||
## Competence Hooks
|
||||
- Why this works: <≤3 bullets>
|
||||
- Common pitfalls: <≤3 bullets>
|
||||
- Next skill: <≤1 item>
|
||||
- Teach-back: "<one question>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Evidence Quality Bar
|
||||
|
||||
- **Cite the source** (file:func, line range if possible).
|
||||
- **Prefer primary evidence** (code, logs) over inference.
|
||||
- **Disambiguate platform** (Web/Capacitor/Electron) and **state** (migration, auth).
|
||||
- **Note uncertainty** explicitly.
|
||||
|
||||
---
|
||||
|
||||
## Code Path Tracing (Required for Software Investigations)
|
||||
|
||||
Before proposing solutions, trace the actual execution path:
|
||||
|
||||
- [ ] **Entry Points**: Identify where the flow begins (user action, API call, etc.)
|
||||
- [ ] **Component Flow**: Map which components/methods are involved
|
||||
- [ ] **Data Path**: Track how data moves through the system
|
||||
- [ ] **Exit Points**: Confirm where the flow ends and what results
|
||||
- [ ] **Evidence Collection**: Gather specific code citations for each step
|
||||
|
||||
---
|
||||
|
||||
## Collaboration Hooks
|
||||
|
||||
- **Syncs:** 10–15m with QA/Security/Platform owners for high-risk areas.
|
||||
- **ADR:** Record major decisions; link here.
|
||||
- **Review:** Share repro + diagnostics checklist in PR/issue.
|
||||
|
||||
---
|
||||
|
||||
## Integration with Other Rulesets
|
||||
|
||||
### With software_development.mdc
|
||||
|
||||
- **Enhanced Evidence Validation**: Use code path tracing for technical investigations
|
||||
- **Architecture Assessment**: Apply complexity justification to proposed solutions
|
||||
- **Impact Analysis**: Assess effects on existing systems before recommendations
|
||||
|
||||
### With base_context.mdc
|
||||
|
||||
- **Competence Building**: Focus on technical investigation skills
|
||||
- **Collaboration**: Structure outputs for team review and discussion
|
||||
|
||||
---
|
||||
|
||||
## Self-Check (model, before responding)
|
||||
|
||||
- [ ] Output matches the **Output Contract** sections.
|
||||
- [ ] Each claim has **evidence** or **uncertainty** is flagged.
|
||||
- [ ] Hypotheses are testable; diagnostics are actionable.
|
||||
- [ ] Competence + collaboration hooks present (≤120 words total).
|
||||
- [ ] Respect toggles; keep it concise.
|
||||
- [ ] **Code path traced** (for software investigations).
|
||||
- [ ] **Evidence validated** against actual code execution.
|
||||
|
||||
---
|
||||
|
||||
## Optional Globs (examples)
|
||||
|
||||
> Uncomment `globs` in the header if you want auto-attach behavior.
|
||||
|
||||
- `src/platforms/**`, `src/services/**` — attach during service/feature investigations
|
||||
- `docs/adr/**` — attach when editing ADRs
|
||||
|
||||
## Referenced Files
|
||||
|
||||
- Consider including templates as context: `@adr_template.mdc`, `@investigation_report_example.mdc`
|
||||
@@ -1,225 +0,0 @@
|
||||
|
||||
# Software Development Ruleset
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Core development guidelines
|
||||
|
||||
## Purpose
|
||||
|
||||
Specialized guidelines for software development tasks including code review,
|
||||
debugging, architecture decisions, and testing.
|
||||
|
||||
## Core Principles
|
||||
|
||||
### 1. Evidence-First Development
|
||||
|
||||
- **Code Citations Required**: Always cite specific file:line references when
|
||||
making claims
|
||||
- **Execution Path Tracing**: Trace actual code execution before proposing
|
||||
architectural changes
|
||||
- **Assumption Validation**: Flag assumptions as "assumed" vs "evidence-based"
|
||||
|
||||
### 2. Code Review Standards
|
||||
|
||||
- **Trace Before Proposing**: Always trace execution paths before suggesting
|
||||
changes
|
||||
- **Evidence Over Inference**: Prefer code citations over logical deductions
|
||||
- **Scope Validation**: Confirm the actual scope of problems before proposing
|
||||
solutions
|
||||
|
||||
### 3. Problem-Solution Validation
|
||||
|
||||
- **Problem Scope**: Does the solution address the actual problem?
|
||||
- **Evidence Alignment**: Does the solution match the evidence?
|
||||
- **Complexity Justification**: Is added complexity justified by real needs?
|
||||
- **Alternative Analysis**: What simpler solutions were considered?
|
||||
|
||||
### 4. Dependency Management & Environment Validation
|
||||
|
||||
- **Pre-build Validation**: Always validate critical dependencies before executing
|
||||
build scripts
|
||||
- **Environment Consistency**: Ensure team members have identical development
|
||||
environments
|
||||
- **Dependency Verification**: Check that required packages are installed and
|
||||
accessible
|
||||
- **Path Resolution**: Use `npx` for local dependencies to avoid PATH issues
|
||||
|
||||
## Required Workflows
|
||||
|
||||
### Before Proposing Changes
|
||||
|
||||
- [ ] **Code Path Tracing**: Map execution flow from entry to exit
|
||||
- [ ] **Evidence Collection**: Gather specific code citations and logs
|
||||
- [ ] **Assumption Surfacing**: Identify what's proven vs. inferred
|
||||
- [ ] **Scope Validation**: Confirm the actual extent of the problem
|
||||
- [ ] **Dependency Validation**: Verify all required dependencies are available
|
||||
and accessible
|
||||
|
||||
### During Solution Design
|
||||
|
||||
- [ ] **Evidence Alignment**: Ensure solution addresses proven problems
|
||||
- [ ] **Complexity Assessment**: Justify any added complexity
|
||||
- [ ] **Alternative Evaluation**: Consider simpler approaches first
|
||||
- [ ] **Impact Analysis**: Assess effects on existing systems
|
||||
- [ ] **Environment Impact**: Assess how changes affect team member setups
|
||||
|
||||
## Software-Specific Competence Hooks
|
||||
|
||||
### Evidence Validation
|
||||
|
||||
- **"What code path proves this claim?"**
|
||||
- **"How does data actually flow through the system?"**
|
||||
- **"What am I assuming vs. what can I prove?"**
|
||||
|
||||
### Code Tracing
|
||||
|
||||
- **"What's the execution path from user action to system response?"**
|
||||
- **"Which components actually interact in this scenario?"**
|
||||
- **"Where does the data originate and where does it end up?"**
|
||||
|
||||
### Architecture Decisions
|
||||
|
||||
- **"What evidence shows this change is necessary?"**
|
||||
- **"What simpler solution could achieve the same goal?"**
|
||||
- **"How does this change affect the existing system architecture?"**
|
||||
|
||||
### Dependency & Environment Management
|
||||
|
||||
- **"What dependencies does this feature require and are they properly
|
||||
declared?"**
|
||||
- **"How will this change affect team member development environments?"**
|
||||
- **"What validation can we add to catch dependency issues early?"**
|
||||
|
||||
## Dependency Management Best Practices
|
||||
|
||||
### Pre-build Validation
|
||||
|
||||
- **Check Critical Dependencies**: Validate essential tools before executing build
|
||||
scripts
|
||||
- **Use npx for Local Dependencies**: Prefer `npx tsx` over direct `tsx` to
|
||||
avoid PATH issues
|
||||
- **Environment Consistency**: Ensure all team members have identical dependency
|
||||
versions
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
- **Missing npm install**: Team members cloning without running `npm install`
|
||||
- **PATH Issues**: Direct command execution vs. npm script execution differences
|
||||
- **Version Mismatches**: Different Node.js/npm versions across team members
|
||||
|
||||
### Validation Strategies
|
||||
|
||||
- **Dependency Check Scripts**: Implement pre-build validation for critical
|
||||
dependencies
|
||||
- **Environment Requirements**: Document and enforce minimum Node.js/npm versions
|
||||
- **Onboarding Checklist**: Standardize team member setup procedures
|
||||
|
||||
### Error Messages and Guidance
|
||||
|
||||
- **Specific Error Context**: Provide clear guidance when dependency issues occur
|
||||
- **Actionable Solutions**: Direct users to specific commands (`npm install`,
|
||||
`npm run check:dependencies`)
|
||||
- **Environment Diagnostics**: Implement comprehensive environment validation
|
||||
tools
|
||||
|
||||
### Build Script Enhancements
|
||||
|
||||
- **Early Validation**: Check dependencies before starting build processes
|
||||
- **Graceful Degradation**: Continue builds when possible but warn about issues
|
||||
- **Helpful Tips**: Remind users about dependency management best practices
|
||||
|
||||
## Integration with Other Rulesets
|
||||
|
||||
### With base_context.mdc
|
||||
|
||||
- Inherits generic competence principles
|
||||
- Adds software-specific evidence requirements
|
||||
- Maintains collaboration and learning focus
|
||||
|
||||
### With research_diagnostic.mdc
|
||||
|
||||
- Enhances investigation with code path tracing
|
||||
- Adds evidence validation to diagnostic workflow
|
||||
- Strengthens problem identification accuracy
|
||||
|
||||
## Usage Guidelines
|
||||
|
||||
### When to Use This Ruleset
|
||||
|
||||
- Code reviews and architectural decisions
|
||||
- Bug investigation and debugging
|
||||
- Performance optimization
|
||||
- Feature implementation planning
|
||||
- Testing strategy development
|
||||
|
||||
### When to Combine with Others
|
||||
|
||||
- **base_context + software_development**: General development tasks
|
||||
- **research_diagnostic + software_development**: Technical investigations
|
||||
- **All three**: Complex architectural decisions or major refactoring
|
||||
|
||||
## Self-Check (model, before responding)
|
||||
|
||||
- [ ] Code path traced and documented
|
||||
- [ ] Evidence cited with specific file:line references
|
||||
- [ ] Assumptions clearly flagged as proven vs. inferred
|
||||
- [ ] Solution complexity justified by evidence
|
||||
- [ ] Simpler alternatives considered and documented
|
||||
- [ ] Impact on existing systems assessed
|
||||
- [ ] Dependencies validated and accessible
|
||||
- [ ] Environment impact assessed for team members
|
||||
- [ ] Pre-build validation implemented where appropriate
|
||||
|
||||
## Additional Core Principles
|
||||
|
||||
### 4. Dependency Management & Environment Validation
|
||||
- **Pre-build Validation**: Always validate critical dependencies before executing build scripts
|
||||
- **Environment Consistency**: Ensure team members have identical development environments
|
||||
- **Dependency Verification**: Check that required packages are installed and accessible
|
||||
- **Path Resolution**: Use `npx` for local dependencies to avoid PATH issues
|
||||
|
||||
## Additional Required Workflows
|
||||
|
||||
### Dependency Validation (Before Proposing Changes)
|
||||
- [ ] **Dependency Validation**: Verify all required dependencies are available and accessible
|
||||
|
||||
### Environment Impact Assessment (During Solution Design)
|
||||
- [ ] **Environment Impact**: Assess how changes affect team member setups
|
||||
|
||||
## Additional Competence Hooks
|
||||
|
||||
### Dependency & Environment Management
|
||||
- **"What dependencies does this feature require and are they properly declared?"**
|
||||
- **"How will this change affect team member development environments?"**
|
||||
- **"What validation can we add to catch dependency issues early?"**
|
||||
|
||||
## Dependency Management Best Practices
|
||||
|
||||
### Pre-build Validation
|
||||
- **Check Critical Dependencies**: Validate essential tools before executing build scripts
|
||||
- **Use npx for Local Dependencies**: Prefer `npx tsx` over direct `tsx` to avoid PATH issues
|
||||
- **Environment Consistency**: Ensure all team members have identical dependency versions
|
||||
|
||||
### Common Pitfalls
|
||||
- **Missing npm install**: Team members cloning without running `npm install`
|
||||
- **PATH Issues**: Direct command execution vs. npm script execution differences
|
||||
- **Version Mismatches**: Different Node.js/npm versions across team members
|
||||
|
||||
### Validation Strategies
|
||||
- **Dependency Check Scripts**: Implement pre-build validation for critical dependencies
|
||||
- **Environment Requirements**: Document and enforce minimum Node.js/npm versions
|
||||
- **Onboarding Checklist**: Standardize team member setup procedures
|
||||
|
||||
### Error Messages and Guidance
|
||||
- **Specific Error Context**: Provide clear guidance when dependency issues occur
|
||||
- **Actionable Solutions**: Direct users to specific commands (`npm install`, `npm run check:dependencies`)
|
||||
- **Environment Diagnostics**: Implement comprehensive environment validation tools
|
||||
|
||||
### Build Script Enhancements
|
||||
- **Early Validation**: Check dependencies before starting build processes
|
||||
- **Graceful Degradation**: Continue builds when possible but warn about issues
|
||||
- **Helpful Tips**: Remind users about dependency management best practices
|
||||
|
||||
- **Narrow Types Properly**: Use type guards to narrow `unknown` types safely
|
||||
- **Document Type Decisions**: Explain complex type structures and their purpose
|
||||
@@ -1,329 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
# Time Handling in Development Workflow
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-17
|
||||
**Status**: 🎯 **ACTIVE** - Production Ready
|
||||
|
||||
## Overview
|
||||
|
||||
This guide establishes **how time should be referenced and used** across the
|
||||
development workflow. It is not tied to any one project, but applies to **all
|
||||
feature development, issue investigations, ADRs, and documentation**.
|
||||
|
||||
## General Principles
|
||||
|
||||
- **Explicit over relative**: Always prefer absolute dates (`2025-08-17`) over
|
||||
relative references like "last week."
|
||||
- **ISO 8601 Standard**: Use `YYYY-MM-DD` format for all date references in
|
||||
docs, issues, ADRs, and commits.
|
||||
- **Time zones**: Default to **UTC** unless explicitly tied to user-facing
|
||||
behavior.
|
||||
- **Precision**: Only specify as much precision as needed (date vs. datetime vs.
|
||||
timestamp).
|
||||
- **Consistency**: Align time references across ADRs, commits, and investigation
|
||||
reports.
|
||||
|
||||
## In Documentation & ADRs
|
||||
|
||||
- Record decision dates using **absolute ISO dates**.
|
||||
- For ongoing timelines, state start and end explicitly (e.g., `2025-08-01` →
|
||||
`2025-08-17`).
|
||||
- Avoid ambiguous terms like *recently*, *last month*, or *soon*.
|
||||
- For time-based experiments (e.g., A/B tests), always include:
|
||||
|
||||
- Start date
|
||||
- Expected duration
|
||||
- Review date checkpoint
|
||||
|
||||
## In Code & Commits
|
||||
|
||||
- Use **UTC timestamps** in logs, DB migrations, and serialized formats.
|
||||
- In commits, link changes to **date-bound ADRs or investigation docs**.
|
||||
- For migrations, include both **applied date** and **intended version window**.
|
||||
- Use constants for known fixed dates; avoid hardcoding arbitrary strings.
|
||||
|
||||
## In Investigations & Research
|
||||
|
||||
- Capture **when** an issue occurred (absolute time or version tag).
|
||||
- When describing failures: note whether they are **time-sensitive** (e.g., after
|
||||
migrations, cache expirations).
|
||||
- Record diagnostic timelines in ISO format (not relative).
|
||||
- For performance regressions, annotate both **baseline timeframe** and
|
||||
**measurement timeframe**.
|
||||
|
||||
## Collaboration Hooks
|
||||
|
||||
- During reviews, verify **time references are clear, absolute, and
|
||||
standardized**.
|
||||
- In syncs, reframe relative terms ("this week") into shared absolute
|
||||
references.
|
||||
- Tag ADRs with both **date created** and **review by** checkpoints.
|
||||
|
||||
## Self-Check Before Submitting
|
||||
|
||||
- [ ] Did I check the time using the **developer's actual system time and
|
||||
timezone**?
|
||||
- [ ] Am I using absolute ISO dates?
|
||||
- [ ] Is UTC assumed unless specified otherwise?
|
||||
- [ ] Did I avoid ambiguous relative terms?
|
||||
- [ ] If duration matters, did I specify both start and end?
|
||||
- [ ] For future work, did I include a review/revisit date?
|
||||
|
||||
## Real-Time Context in Developer Interactions
|
||||
|
||||
- The model must always resolve **"current time"** using the **developer's
|
||||
actual system time and timezone**.
|
||||
- When generating timestamps (e.g., in investigation logs, ADRs, or examples),
|
||||
the model should:
|
||||
|
||||
- Use the **developer's current local time** by default.
|
||||
- Indicate the timezone explicitly (e.g., `2025-08-17T10:32-05:00`).
|
||||
- Optionally provide UTC alongside if context requires cross-team clarity.
|
||||
|
||||
- When interpreting relative terms like *now*, *today*, *last week*:
|
||||
|
||||
- Resolve them against the **developer's current time**.
|
||||
- Convert them into **absolute ISO-8601 values** in the output.
|
||||
|
||||
## LLM Time Checking Instructions
|
||||
|
||||
**CRITICAL**: The LLM must actively query the system for current time rather
|
||||
than assuming or inventing times.
|
||||
|
||||
### How to Check Current Time
|
||||
|
||||
#### 1. **Query System Time (Required)**
|
||||
|
||||
- **Always start** by querying the current system time using available tools
|
||||
- **Never assume** what the current time is
|
||||
- **Never use** placeholder values like "current time" or "now"
|
||||
|
||||
#### 2. **Available Time Query Methods**
|
||||
|
||||
- **System Clock**: Use `date` command or equivalent system time function
|
||||
- **Programming Language**: Use language-specific time functions (e.g.,
|
||||
`Date.now()`, `datetime.now()`)
|
||||
- **Environment Variables**: Check for time-related environment variables
|
||||
- **API Calls**: Use time service APIs if available
|
||||
|
||||
#### 3. **Required Time Information**
|
||||
|
||||
When querying time, always obtain:
|
||||
|
||||
- **Current Date**: YYYY-MM-DD format
|
||||
- **Current Time**: HH:MM:SS format (24-hour)
|
||||
- **Timezone**: Current system timezone or UTC offset
|
||||
- **UTC Equivalent**: Convert local time to UTC for cross-team clarity
|
||||
|
||||
#### 4. **Time Query Examples**
|
||||
|
||||
```bash
|
||||
# Example: Query system time
|
||||
$ date
|
||||
# Expected output: Mon Aug 17 10:32:45 EDT 2025
|
||||
|
||||
# Example: Query UTC time
|
||||
$ date -u
|
||||
# Expected output: Mon Aug 17 14:32:45 UTC 2025
|
||||
```
|
||||
|
||||
```python
|
||||
# Example: Python time query
|
||||
import datetime
|
||||
current_time = datetime.datetime.now()
|
||||
utc_time = datetime.datetime.utcnow()
|
||||
print(f"Local: {current_time}")
|
||||
print(f"UTC: {utc_time}")
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Example: JavaScript time query
|
||||
const now = new Date();
|
||||
const utc = new Date().toISOString();
|
||||
console.log(`Local: ${now}`);
|
||||
console.log(`UTC: ${utc}`);
|
||||
```
|
||||
|
||||
#### 5. **LLM Time Checking Workflow**
|
||||
|
||||
1. **Query**: Actively query system for current time
|
||||
2. **Validate**: Confirm time data is reasonable and current
|
||||
3. **Format**: Convert to ISO 8601 format
|
||||
4. **Context**: Provide both local and UTC times when helpful
|
||||
5. **Document**: Show the source of time information
|
||||
|
||||
#### 6. **Error Handling for Time Queries**
|
||||
|
||||
- **If time query fails**: Ask user for current time or use "unknown time"
|
||||
with explanation
|
||||
- **If timezone unclear**: Default to UTC and ask for clarification
|
||||
- **If time seems wrong**: Verify with user before proceeding
|
||||
- **Always log**: Record when and how time was obtained
|
||||
|
||||
#### 7. **Time Query Verification**
|
||||
|
||||
Before using queried time, verify:
|
||||
|
||||
- [ ] Time is recent (within last few minutes)
|
||||
- [ ] Timezone information is available
|
||||
- [ ] UTC conversion is accurate
|
||||
- [ ] Format follows ISO 8601 standard
|
||||
|
||||
## Model Behavior Rules
|
||||
|
||||
- **Never invent a "fake now"**: All "current time" references must come from
|
||||
the real system clock available at runtime.
|
||||
- **Check developer time zone**: If ambiguous, ask for clarification (e.g.,
|
||||
"Should I use UTC or your local timezone?").
|
||||
- **Format for clarity**:
|
||||
|
||||
- Local time: `YYYY-MM-DDTHH:mm±hh:mm`
|
||||
- UTC equivalent (if needed): `YYYY-MM-DDTHH:mmZ`
|
||||
|
||||
## Examples
|
||||
|
||||
### Good
|
||||
|
||||
- "Feature flag rollout started on `2025-08-01` and will be reviewed on
|
||||
`2025-08-21`."
|
||||
- "Migration applied on `2025-07-15T14:00Z`."
|
||||
- "Issue reproduced on `2025-08-17T09:00-05:00 (local)` /
|
||||
`2025-08-17T14:00Z (UTC)`."
|
||||
|
||||
### Bad
|
||||
|
||||
- "Feature flag rolled out last week."
|
||||
- "Migration applied recently."
|
||||
- "Now is August, so we assume this was last month."
|
||||
|
||||
### More Examples
|
||||
|
||||
#### Issue Reports
|
||||
|
||||
- ✅ **Good**: "User reported login failure at `2025-08-17T14:30:00Z`. Issue
|
||||
persisted until `2025-08-17T15:45:00Z`."
|
||||
- ❌ **Bad**: "User reported login failure earlier today. Issue lasted for a
|
||||
while."
|
||||
|
||||
#### Release Planning
|
||||
|
||||
- ✅ **Good**: "Feature X scheduled for release on `2025-08-25`. Testing
|
||||
window: `2025-08-20` to `2025-08-24`."
|
||||
- ❌ **Bad**: "Feature X will be released next week after testing."
|
||||
|
||||
#### Performance Monitoring
|
||||
|
||||
- ✅ **Good**: "Baseline performance measured on `2025-08-10T09:00:00Z`.
|
||||
Regression detected on `2025-08-15T14:00:00Z`."
|
||||
- ❌ **Bad**: "Performance was good last week but got worse this week."
|
||||
|
||||
## Technical Implementation Notes
|
||||
|
||||
### UTC Storage Principle
|
||||
|
||||
- **Store all timestamps in UTC** in databases, logs, and serialized formats
|
||||
- **Convert to local time only for user display**
|
||||
- **Use ISO 8601 format** for all storage: `YYYY-MM-DDTHH:mm:ss.sssZ`
|
||||
|
||||
### Common Implementation Patterns
|
||||
|
||||
#### Database Storage
|
||||
|
||||
```sql
|
||||
-- ✅ Good: Store in UTC
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
|
||||
-- ❌ Bad: Store in local time
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
```
|
||||
|
||||
#### API Responses
|
||||
|
||||
```json
|
||||
// ✅ Good: Include both UTC and local time
|
||||
{
|
||||
"eventTime": "2025-08-17T14:00:00Z",
|
||||
"localTime": "2025-08-17T10:00:00-04:00",
|
||||
"timezone": "America/New_York"
|
||||
}
|
||||
|
||||
// ❌ Bad: Only local time
|
||||
{
|
||||
"eventTime": "2025-08-17T10:00:00-04:00"
|
||||
}
|
||||
```
|
||||
|
||||
#### Logging
|
||||
|
||||
```python
|
||||
# ✅ Good: Log in UTC with timezone info
|
||||
logger.info(f"User action at {datetime.utcnow().isoformat()}Z (UTC)")
|
||||
|
||||
# ❌ Bad: Log in local time
|
||||
logger.info(f"User action at {datetime.now()}")
|
||||
```
|
||||
|
||||
### Timezone Handling Best Practices
|
||||
|
||||
#### 1. Always Store Timezone Information
|
||||
|
||||
- Include IANA timezone identifier (e.g., `America/New_York`)
|
||||
- Store UTC offset at time of creation
|
||||
- Handle daylight saving time transitions automatically
|
||||
|
||||
#### 2. User Display Considerations
|
||||
|
||||
- Convert UTC to user's preferred timezone
|
||||
- Show timezone abbreviation when helpful
|
||||
- Use relative time for recent events ("2 hours ago")
|
||||
|
||||
#### 3. Edge Case Handling
|
||||
|
||||
- **Daylight Saving Time**: Use timezone-aware libraries
|
||||
- **Leap Seconds**: Handle gracefully (rare but important)
|
||||
- **Invalid Times**: Validate before processing
|
||||
|
||||
### Common Mistakes to Avoid
|
||||
|
||||
#### 1. Timezone Confusion
|
||||
|
||||
- ❌ **Don't**: Assume server timezone is user timezone
|
||||
- ✅ **Do**: Always convert UTC to user's local time for display
|
||||
|
||||
#### 2. Format Inconsistency
|
||||
|
||||
- ❌ **Don't**: Mix different time formats in the same system
|
||||
- ✅ **Do**: Standardize on ISO 8601 for all storage
|
||||
|
||||
#### 3. Relative Time References
|
||||
|
||||
- ❌ **Don't**: Use relative terms in persistent storage
|
||||
- ✅ **Do**: Convert relative terms to absolute timestamps immediately
|
||||
|
||||
## References
|
||||
|
||||
- [ISO 8601 Date and Time Standard](https://en.wikipedia.org/wiki/ISO_8601)
|
||||
- [IANA Timezone Database](https://www.iana.org/time-zones)
|
||||
- [ADR Template](./adr_template.md)
|
||||
- [Research & Diagnostic Workflow](./research_diagnostic.mdc)
|
||||
|
||||
---
|
||||
|
||||
**Rule of Thumb**: Every time reference in development artifacts should be
|
||||
**clear in 6 months without context**, and aligned to the **developer's actual
|
||||
current time**.
|
||||
|
||||
**Technical Rule of Thumb**: **Store in UTC, display in local time, always
|
||||
include timezone context.**
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active
|
||||
**Version**: 1.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
**Next Review**: 2025-09-17
|
||||
@@ -1,335 +0,0 @@
|
||||
---
|
||||
description: interacting with git
|
||||
alwaysApply: false
|
||||
---
|
||||
# Directive: Peaceful Co-Existence with Developers
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-08-19
|
||||
**Status**: 🎯 **ACTIVE** - Version control guidelines
|
||||
|
||||
## 1) Version-Control Ownership
|
||||
|
||||
- **MUST NOT** run `git add`, `git commit`, or any write action.
|
||||
- **MUST** leave staging/committing to the developer.
|
||||
|
||||
## 2) Source of Truth for Commit Text
|
||||
|
||||
- **MUST** derive messages **only** from:
|
||||
- files **staged** for commit (primary), and
|
||||
- files **awaiting staging** (context).
|
||||
- **MUST** use the **diffs** to inform content.
|
||||
- **MUST NOT** invent changes or imply work not present in diffs.
|
||||
|
||||
## 3) Mandatory Preview Flow
|
||||
|
||||
- **ALWAYS** present, before any real commit:
|
||||
- file list + brief per-file notes,
|
||||
- a **draft commit message** (copy-paste ready),
|
||||
- nothing auto-applied.
|
||||
|
||||
## 4) Version Synchronization Requirements
|
||||
|
||||
- **MUST** check for version changes in `package.json` before committing
|
||||
- **MUST** ensure `CHANGELOG.md` is updated when `package.json` version
|
||||
changes
|
||||
- **MUST** validate version format consistency between both files
|
||||
- **MUST** include version bump commits in changelog with proper semantic
|
||||
versioning
|
||||
|
||||
### Version Sync Checklist (Before Commit)
|
||||
|
||||
- [ ] `package.json` version matches latest `CHANGELOG.md` entry
|
||||
- [ ] New version follows semantic versioning
|
||||
(MAJOR.MINOR.PATCH[-PRERELEASE])
|
||||
- [ ] Changelog entry includes all significant changes since last version
|
||||
- [ ] Version bump commit message follows `build(version): bump to X.Y.Z`
|
||||
format
|
||||
- [ ] Breaking changes properly documented with migration notes
|
||||
- [ ] Alert developer in chat message that version has been updated
|
||||
|
||||
### Version Change Detection
|
||||
|
||||
- **Check for version changes** in staged/unstaged `package.json`
|
||||
- **Alert developer** if version changed but changelog not updated
|
||||
- **Suggest changelog update** with proper format and content
|
||||
- **Validate semantic versioning** compliance
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- **Version Detection**: Compare `package.json` version field with latest
|
||||
changelog entry
|
||||
- **Semantic Validation**: Ensure version follows `X.Y.Z[-PRERELEASE]`
|
||||
format
|
||||
- **Changelog Format**: Follow [Keep a Changelog](https://keepachangelog.com/)
|
||||
standards
|
||||
- **Breaking Changes**: Use `!` in commit message and `BREAKING CHANGE:`
|
||||
in changelog
|
||||
- **Pre-release Versions**: Include beta/alpha/rc suffixes in both files
|
||||
consistently
|
||||
|
||||
## Commit Message Format (Normative)
|
||||
|
||||
### A. Subject Line (required)
|
||||
|
||||
```
|
||||
<type>(<scope>)<!>: <summary>
|
||||
```
|
||||
|
||||
- **type** (lowercase, Conventional Commits):
|
||||
`feat|fix|refactor|perf|docs|test|build|chore|ci|revert`
|
||||
- **scope**: optional module/package/area (e.g., `api`, `ui/login`, `db`)
|
||||
- **!**: include when a breaking change is introduced
|
||||
- **summary**: imperative mood, ≤ 72 chars, no trailing period
|
||||
|
||||
**Examples**
|
||||
|
||||
- `fix(api): handle null token in refresh path`
|
||||
- `feat(ui/login)!: require OTP after 3 failed attempts`
|
||||
|
||||
### B. Body (optional, when it adds non-obvious value)
|
||||
|
||||
- One blank line after subject.
|
||||
- Wrap at ~72 chars.
|
||||
- Explain **what** and **why**, not line-by-line "how".
|
||||
- Include brief notes like tests passing or TS/lint issues resolved
|
||||
**only if material**.
|
||||
|
||||
**Body checklist**
|
||||
|
||||
- [ ] Problem/symptom being addressed
|
||||
- [ ] High-level approach or rationale
|
||||
- [ ] Risks, tradeoffs, or follow-ups (if any)
|
||||
|
||||
### C. Footer (optional)
|
||||
|
||||
- Issue refs: `Closes #123`, `Refs #456`
|
||||
- Breaking change (alternative to `!`):
|
||||
`BREAKING CHANGE: <impact + migration note>`
|
||||
- Authors: `Co-authored-by: Name <email>`
|
||||
- Security: `CVE-XXXX-YYYY: <short note>` (if applicable)
|
||||
|
||||
## Content Guidance
|
||||
|
||||
### Include (when relevant)
|
||||
|
||||
- Specific fixes/features delivered
|
||||
- Symptoms/problems fixed
|
||||
- Brief note that tests passed or TS/lint errors resolved
|
||||
|
||||
### Avoid
|
||||
|
||||
- Vague: *improved, enhanced, better*
|
||||
- Trivialities: tiny docs, one-liners, pure lint cleanups (separate,
|
||||
focused commits if needed)
|
||||
- Redundancy: generic blurbs repeated across files
|
||||
- Multi-purpose dumps: keep commits **narrow and focused**
|
||||
- Long explanations that good inline code comments already cover
|
||||
|
||||
**Guiding Principle:** Let code and inline docs speak. Use commits to
|
||||
highlight what isn't obvious.
|
||||
|
||||
## Copy-Paste Templates
|
||||
|
||||
### Minimal (no body)
|
||||
|
||||
```text
|
||||
<type>(<scope>): <summary>
|
||||
```
|
||||
|
||||
### Standard (with body & footer)
|
||||
|
||||
```text
|
||||
<type>(<scope>)<!>: <summary>
|
||||
|
||||
<why-this-change?>
|
||||
<what-it-does?>
|
||||
<risks-or-follow-ups?>
|
||||
|
||||
Closes #<id>
|
||||
BREAKING CHANGE: <impact + migration>
|
||||
Co-authored-by: <Name> <email>
|
||||
```
|
||||
|
||||
## Assistant Output Checklist (before showing the draft)
|
||||
|
||||
- [ ] List changed files + 1–2 line notes per file
|
||||
- [ ] Provide **one** focused draft message (subject/body/footer)
|
||||
- [ ] Subject ≤ 72 chars, imperative mood, correct `type(scope)!` syntax
|
||||
- [ ] Body only if it adds non-obvious value
|
||||
- [ ] No invented changes; aligns strictly with diffs
|
||||
- [ ] Render as a single copy-paste block for the developer
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active version control guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: git, package.json, CHANGELOG.md
|
||||
**Stakeholders**: Development team, AI assistants
|
||||
|
||||
- [ ] No invented changes; aligns strictly with diffs
|
||||
- [ ] Render as a single copy-paste block for the developer
|
||||
|
||||
## 1) Version-Control Ownership
|
||||
|
||||
- **MUST NOT** run `git add`, `git commit`, or any write action.
|
||||
- **MUST** leave staging/committing to the developer.
|
||||
|
||||
## 2) Source of Truth for Commit Text
|
||||
|
||||
- **MUST** derive messages **only** from:
|
||||
- files **staged** for commit (primary), and
|
||||
- files **awaiting staging** (context).
|
||||
- **MUST** use the **diffs** to inform content.
|
||||
- **MUST NOT** invent changes or imply work not present in diffs.
|
||||
|
||||
## 3) Mandatory Preview Flow
|
||||
|
||||
- **ALWAYS** present, before any real commit:
|
||||
- file list + brief per-file notes,
|
||||
- a **draft commit message** (copy-paste ready),
|
||||
- nothing auto-applied.
|
||||
|
||||
## 4) Version Synchronization Requirements
|
||||
|
||||
- **MUST** check for version changes in `package.json` before committing
|
||||
- **MUST** ensure `CHANGELOG.md` is updated when `package.json` version
|
||||
changes
|
||||
- **MUST** validate version format consistency between both files
|
||||
- **MUST** include version bump commits in changelog with proper semantic
|
||||
versioning
|
||||
|
||||
### Version Sync Checklist (Before Commit)
|
||||
|
||||
- [ ] `package.json` version matches latest `CHANGELOG.md` entry
|
||||
- [ ] New version follows semantic versioning
|
||||
(MAJOR.MINOR.PATCH[-PRERELEASE])
|
||||
- [ ] Changelog entry includes all significant changes since last version
|
||||
- [ ] Version bump commit message follows `build(version): bump to X.Y.Z`
|
||||
format
|
||||
- [ ] Breaking changes properly documented with migration notes
|
||||
- [ ] Alert developer in chat message that version has been updated
|
||||
|
||||
### Version Change Detection
|
||||
|
||||
- **Check for version changes** in staged/unstaged `package.json`
|
||||
- **Alert developer** if version changed but changelog not updated
|
||||
- **Suggest changelog update** with proper format and content
|
||||
- **Validate semantic versioning** compliance
|
||||
|
||||
### Implementation Notes
|
||||
|
||||
- **Version Detection**: Compare `package.json` version field with latest
|
||||
changelog entry
|
||||
- **Semantic Validation**: Ensure version follows `X.Y.Z[-PRERELEASE]`
|
||||
format
|
||||
- **Changelog Format**: Follow [Keep a Changelog](https://keepachangelog.com/)
|
||||
standards
|
||||
- **Breaking Changes**: Use `!` in commit message and `BREAKING CHANGE:`
|
||||
in changelog
|
||||
- **Pre-release Versions**: Include beta/alpha/rc suffixes in both files
|
||||
consistently
|
||||
|
||||
## Commit Message Format (Normative)
|
||||
|
||||
### A. Subject Line (required)
|
||||
|
||||
```
|
||||
<type>(<scope>)<!>: <summary>
|
||||
```
|
||||
|
||||
- **type** (lowercase, Conventional Commits):
|
||||
`feat|fix|refactor|perf|docs|test|build|chore|ci|revert`
|
||||
- **scope**: optional module/package/area (e.g., `api`, `ui/login`, `db`)
|
||||
- **!**: include when a breaking change is introduced
|
||||
- **summary**: imperative mood, ≤ 72 chars, no trailing period
|
||||
|
||||
**Examples**
|
||||
|
||||
- `fix(api): handle null token in refresh path`
|
||||
- `feat(ui/login)!: require OTP after 3 failed attempts`
|
||||
|
||||
### B. Body (optional, when it adds non-obvious value)
|
||||
|
||||
- One blank line after subject.
|
||||
- Wrap at ~72 chars.
|
||||
- Explain **what** and **why**, not line-by-line "how".
|
||||
- Include brief notes like tests passing or TS/lint issues resolved
|
||||
**only if material**.
|
||||
|
||||
**Body checklist**
|
||||
|
||||
- [ ] Problem/symptom being addressed
|
||||
- [ ] High-level approach or rationale
|
||||
- [ ] Risks, tradeoffs, or follow-ups (if any)
|
||||
|
||||
### C. Footer (optional)
|
||||
|
||||
- Issue refs: `Closes #123`, `Refs #456`
|
||||
- Breaking change (alternative to `!`):
|
||||
`BREAKING CHANGE: <impact + migration note>`
|
||||
- Authors: `Co-authored-by: Name <email>`
|
||||
- Security: `CVE-XXXX-YYYY: <short note>` (if applicable)
|
||||
|
||||
## Content Guidance
|
||||
|
||||
### Include (when relevant)
|
||||
|
||||
- Specific fixes/features delivered
|
||||
- Symptoms/problems fixed
|
||||
- Brief note that tests passed or TS/lint errors resolved
|
||||
|
||||
### Avoid
|
||||
|
||||
- Vague: *improved, enhanced, better*
|
||||
- Trivialities: tiny docs, one-liners, pure lint cleanups (separate,
|
||||
focused commits if needed)
|
||||
- Redundancy: generic blurbs repeated across files
|
||||
- Multi-purpose dumps: keep commits **narrow and focused**
|
||||
- Long explanations that good inline code comments already cover
|
||||
|
||||
**Guiding Principle:** Let code and inline docs speak. Use commits to
|
||||
highlight what isn't obvious.
|
||||
|
||||
## Copy-Paste Templates
|
||||
|
||||
### Minimal (no body)
|
||||
|
||||
```text
|
||||
<type>(<scope>): <summary>
|
||||
```
|
||||
|
||||
### Standard (with body & footer)
|
||||
|
||||
```text
|
||||
<type>(<scope>)<!>: <summary>
|
||||
|
||||
<why-this-change?>
|
||||
<what-it-does?>
|
||||
<risks-or-follow-ups?>
|
||||
|
||||
Closes #<id>
|
||||
BREAKING CHANGE: <impact + migration>
|
||||
Co-authored-by: <Name> <email>
|
||||
```
|
||||
|
||||
## Assistant Output Checklist (before showing the draft)
|
||||
|
||||
- [ ] List changed files + 1–2 line notes per file
|
||||
- [ ] Provide **one** focused draft message (subject/body/footer)
|
||||
- [ ] Subject ≤ 72 chars, imperative mood, correct `type(scope)!` syntax
|
||||
- [ ] Body only if it adds non-obvious value
|
||||
- [ ] No invented changes; aligns strictly with diffs
|
||||
- [ ] Render as a single copy-paste block for the developer
|
||||
|
||||
---
|
||||
|
||||
**Status**: Active version control guidelines
|
||||
**Priority**: High
|
||||
**Estimated Effort**: Ongoing reference
|
||||
**Dependencies**: git, package.json, CHANGELOG.md
|
||||
**Stakeholders**: Development team, AI assistants
|
||||
|
||||
* [ ] No invented changes; aligns strictly with diffs
|
||||
* [ ] Render as a single copy-paste block for the developer
|
||||
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,18 +1,12 @@
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# Logging Configuration - Development environment gets maximum visibility
|
||||
VITE_LOG_LEVEL=debug
|
||||
|
||||
# iOS doesn't like spaces in the app title.
|
||||
TIME_SAFARI_APP_TITLE="TimeSafari_Dev"
|
||||
VITE_APP_SERVER=http://localhost:8080
|
||||
# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not
|
||||
|
||||
|
||||
VITE_APP_SERVER=http://localhost:3000
|
||||
# This is the claim ID for actions in the BVC project, with the JWT ID on this environment (not production).
|
||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
|
||||
# Using shared server by default to ease setup, which works for shared test users.
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000
|
||||
#VITE_DEFAULT_PUSH_SERVER... can't be set up with localhost domain
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
|
||||
6
.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# Admin DID credentials
|
||||
ADMIN_DID=did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F
|
||||
ADMIN_PRIVATE_KEY=2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b
|
||||
|
||||
# API Configuration
|
||||
ENDORSER_API_URL=https://test-api.endorser.ch/api/v2/claim
|
||||
@@ -1,7 +1,6 @@
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# Logging Configuration - Production environment gets minimal logging for performance
|
||||
VITE_LOG_LEVEL=warn
|
||||
|
||||
|
||||
VITE_APP_SERVER=https://timesafari.app
|
||||
# This is the claim ID for actions in the BVC project.
|
||||
@@ -10,4 +9,3 @@ 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
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# Logging Configuration - Test environment gets balanced logging for debugging
|
||||
VITE_LOG_LEVEL=info
|
||||
|
||||
# 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, with the JWT ID on this environment (not production).
|
||||
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
|
||||
11
.eslintrc.js
@@ -4,12 +4,6 @@ module.exports = {
|
||||
node: true,
|
||||
es2022: true,
|
||||
},
|
||||
ignorePatterns: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'dist-electron/',
|
||||
'*.d.ts'
|
||||
],
|
||||
extends: [
|
||||
"plugin:vue/vue3-recommended",
|
||||
"eslint:recommended",
|
||||
@@ -30,9 +24,8 @@ module.exports = {
|
||||
}],
|
||||
"no-console": process.env.NODE_ENV === "production" ? "error" : "warn",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "warn",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "off"
|
||||
},
|
||||
};
|
||||
|
||||
142
.github/workflows/asset-validation.yml
vendored
@@ -1,142 +0,0 @@
|
||||
name: Asset Validation & CI Safeguards
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'resources/**'
|
||||
- 'config/assets/**'
|
||||
- 'capacitor-assets.config.json'
|
||||
- 'capacitor.config.ts'
|
||||
- 'capacitor.config.json'
|
||||
push:
|
||||
branches: [main, develop]
|
||||
paths:
|
||||
- 'resources/**'
|
||||
- 'config/assets/**'
|
||||
- 'capacitor-assets.config.json'
|
||||
- 'capacitor.config.ts'
|
||||
- 'capacitor.config.json'
|
||||
|
||||
jobs:
|
||||
asset-validation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Validate asset configuration
|
||||
run: npm run assets:validate
|
||||
|
||||
- name: Check for committed platform assets (Android)
|
||||
run: |
|
||||
if git ls-files -z android/app/src/main/res | grep -E '(AppIcon.*\.png|Splash.*\.png|mipmap-.*/ic_launcher.*\.png)' > /dev/null; then
|
||||
echo "❌ Android platform assets found in VCS - these should be generated at build-time"
|
||||
git ls-files -z android/app/src/main/res | grep -E '(AppIcon.*\.png|Splash.*\.png|mipmap-.*/ic_launcher.*\.png)'
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ No Android platform assets committed"
|
||||
|
||||
- name: Check for committed platform assets (iOS)
|
||||
run: |
|
||||
if git ls-files -z ios/App/App/Assets.xcassets | grep -E '(AppIcon.*\.png|Splash.*\.png)' > /dev/null; then
|
||||
echo "❌ iOS platform assets found in VCS - these should be generated at build-time"
|
||||
git ls-files -z ios/App/App/Assets.xcassets | grep -E '(AppIcon.*\.png|Splash.*\.png)'
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ No iOS platform assets committed"
|
||||
|
||||
- name: Test asset generation
|
||||
run: |
|
||||
echo "🧪 Testing asset generation workflow..."
|
||||
npm run build:capacitor
|
||||
npx cap sync
|
||||
npx capacitor-assets generate --dry-run || npx capacitor-assets generate
|
||||
echo "✅ Asset generation test completed"
|
||||
|
||||
- name: Verify clean tree after build
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "❌ Dirty tree after build - asset configs were modified"
|
||||
git status
|
||||
git diff
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Build completed with clean tree"
|
||||
|
||||
schema-validation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Validate schema compliance
|
||||
run: |
|
||||
echo "🔍 Validating schema compliance..."
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const config = JSON.parse(fs.readFileSync('capacitor-assets.config.json', 'utf8'));
|
||||
const schema = JSON.parse(fs.readFileSync('config/assets/schema.json', 'utf8'));
|
||||
|
||||
// Basic schema validation
|
||||
if (!config.icon || !config.splash) {
|
||||
throw new Error('Missing required sections: icon and splash');
|
||||
}
|
||||
|
||||
if (!config.icon.source || !config.splash.source) {
|
||||
throw new Error('Missing required source fields');
|
||||
}
|
||||
|
||||
if (!/^resources\/.*\.(png|svg)$/.test(config.icon.source)) {
|
||||
throw new Error('Icon source must be in resources/ directory');
|
||||
}
|
||||
|
||||
if (!/^resources\/.*\.(png|svg)$/.test(config.splash.source)) {
|
||||
throw new Error('Splash source must be in resources/ directory');
|
||||
}
|
||||
|
||||
console.log('✅ Schema validation passed');
|
||||
"
|
||||
|
||||
- name: Check source file existence
|
||||
run: |
|
||||
echo "📁 Checking source file existence..."
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const config = JSON.parse(fs.readFileSync('capacitor-assets.config.json', 'utf8'));
|
||||
|
||||
const requiredFiles = [
|
||||
config.icon.source,
|
||||
config.splash.source
|
||||
];
|
||||
|
||||
if (config.splash.darkSource) {
|
||||
requiredFiles.push(config.splash.darkSource);
|
||||
}
|
||||
|
||||
const missingFiles = requiredFiles.filter(file => !fs.existsSync(file));
|
||||
|
||||
if (missingFiles.length > 0) {
|
||||
console.error('❌ Missing source files:', missingFiles);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✅ All source files exist');
|
||||
"
|
||||
104
.gitignore
vendored
@@ -38,106 +38,30 @@ pnpm-debug.log*
|
||||
/dist-capacitor/
|
||||
/test-playwright-results/
|
||||
playwright-tests
|
||||
test-playwright
|
||||
dist-electron-packages
|
||||
ios
|
||||
.ruby-version
|
||||
+.env
|
||||
|
||||
# Test files generated by scripts test-ios.js & test-android.js
|
||||
# Generated test files
|
||||
.generated/
|
||||
|
||||
# Fastlane
|
||||
ios/fastlane/report.xml
|
||||
ios/fastlane/Preview.html
|
||||
ios/fastlane/screenshots
|
||||
ios/fastlane/test_output
|
||||
android/fastlane/report.xml
|
||||
android/fastlane/Preview.html
|
||||
android/fastlane/screenshots
|
||||
android/fastlane/test_output
|
||||
.env.default
|
||||
vendor/
|
||||
|
||||
# Build logs
|
||||
build_logs/
|
||||
|
||||
# PWA icon files generated by capacitor-assets
|
||||
icons
|
||||
# Android generated assets
|
||||
android/app/src/main/assets/public/assets/
|
||||
|
||||
*.log
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
|
||||
# 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
|
||||
|
||||
# Android generated assets (deny-listed in CI)
|
||||
android/app/src/main/res/mipmap-*/ic_launcher*.png
|
||||
android/app/src/main/res/drawable*/splash*.png
|
||||
|
||||
# iOS generated assets (deny-listed in CI)
|
||||
ios/App/App/Assets.xcassets/**/AppIcon*.png
|
||||
ios/App/App/Assets.xcassets/**/Splash*.png
|
||||
|
||||
# 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
|
||||
@@ -1 +0,0 @@
|
||||
{"MD013": {"code_blocks": false}}
|
||||
@@ -1 +0,0 @@
|
||||
18.19.0
|
||||
2553
BUILDING.md
56
CHANGELOG.md
@@ -5,62 +5,6 @@ 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.7] - 2025.08.18
|
||||
### Fixed
|
||||
- Deep link for onboard-meeting-members
|
||||
|
||||
|
||||
## [1.0.6] - 2025.08.09
|
||||
### Fixed
|
||||
- Deep link errors where none would validate
|
||||
|
||||
|
||||
## [1.0.5] - 2025.07.24
|
||||
### Fixed
|
||||
- Export & import of contacts corrupted contact methods
|
||||
|
||||
|
||||
## [1.0.4] - 2025.07.20 - 002f2407208d56cc59c0aa7c880535ae4cbace8b
|
||||
### Fixed
|
||||
- Deep link for invite-one-accept
|
||||
|
||||
|
||||
## [1.0.3] - 2025.07.12 - a9a8ba217cd6015321911e98e6843e988dc2c4ae
|
||||
### Changed
|
||||
- Photo is pinned to profile mode
|
||||
### Fixed
|
||||
- Deep link URLs (and other prod settings)
|
||||
- Error in BVC begin view
|
||||
|
||||
|
||||
## [1.0.2] - 2025.06.20 - 276e0a741bc327de3380c4e508cccb7fee58c06d
|
||||
### Added
|
||||
- Version on feed title
|
||||
|
||||
|
||||
## [1.0.1] - 2025.06.20
|
||||
### Added
|
||||
- Allow a user to block someone else's content from view
|
||||
|
||||
|
||||
## [1.0.0] - 2025.06.20 - 5aa693de6337e5dbb278bfddc6bd39094bc14f73
|
||||
### Added
|
||||
- Web-oriented migration from IndexedDB to SQLite
|
||||
|
||||
|
||||
## [0.5.8]
|
||||
### Added
|
||||
- /deep-link/ path for URLs that are shared with people
|
||||
### Changed
|
||||
- External links now go to /deep-link/...
|
||||
- Feed visuals now have arrow imagery from giver to receiver
|
||||
|
||||
|
||||
## [0.4.7]
|
||||
### Fixed
|
||||
- Cameras everywhere
|
||||
### Changed
|
||||
- IndexedDB -> SQLite
|
||||
|
||||
|
||||
## [0.4.5] - 2025.02.23
|
||||
|
||||
170
Dockerfile
@@ -1,170 +0,0 @@
|
||||
# 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)
|
||||
|
||||
# =============================================================================
|
||||
# BASE STAGE - Common dependencies and setup
|
||||
# =============================================================================
|
||||
FROM node:22-alpine3.20 AS base
|
||||
|
||||
# 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
|
||||
|
||||
# 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*.json ./
|
||||
|
||||
# Install dependencies with security audit
|
||||
RUN npm ci --only=production --audit --fund=false && \
|
||||
npm audit fix --audit-level=moderate || true
|
||||
|
||||
# =============================================================================
|
||||
# BUILDER STAGE - Copy pre-built assets
|
||||
# =============================================================================
|
||||
FROM base AS builder
|
||||
|
||||
# Define build arguments with defaults
|
||||
ARG BUILD_MODE=production
|
||||
ARG NODE_ENV=production
|
||||
|
||||
# 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
|
||||
|
||||
# Copy built assets from builder stage
|
||||
COPY --from=builder --chown=nginx:nginx /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
|
||||
|
||||
# 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
|
||||
|
||||
235
README.md
@@ -5,208 +5,86 @@ and expand to crowd-fund with time & money, then record and see the impact of co
|
||||
|
||||
## Roadmap
|
||||
|
||||
See [ClickUp](https://sharing.clickup.com/9014278710/l/h/8cmnyhp-174/10573fec74e2ba0) for current priorities.
|
||||
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.)
|
||||
|
||||
## 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.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build:web:serve -- --test
|
||||
npm run dev
|
||||
```
|
||||
|
||||
To be able to make submissions: go to "profile" (bottom left), go to the bottom and expand "Show Advanced Settings", go to the bottom and to the "Test Page", and finally "Become User 0" to see all the functionality.
|
||||
See [BUILDING.md](BUILDING.md) for more details.
|
||||
|
||||
See [BUILDING.md](BUILDING.md) for comprehensive build instructions for all platforms (Web, Electron, iOS, Android, Docker).
|
||||
See the test locations for "IMAGE_API_SERVER" or "PARTNER_API_SERVER" below, or use http://localhost:3000 for local endorser.ch
|
||||
|
||||
## Development Database Clearing
|
||||
|
||||
TimeSafari provides a simple script-based approach to clear the local database (not the claim server) for development purposes.
|
||||
### Run all UI tests
|
||||
|
||||
## Logging Configuration
|
||||
Look at [BUILDING.md](BUILDING.md) for the "test-all" instructions and [TESTING.md](test-playwright/TESTING.md) for more details.
|
||||
|
||||
TimeSafari supports configurable logging levels via the `VITE_LOG_LEVEL` environment variable. This allows developers to control console output verbosity without modifying code.
|
||||
|
||||
### Quick Usage
|
||||
### 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`.
|
||||
|
||||
* 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 later).
|
||||
|
||||
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 0.3.55 && git push origin 0.3.55`.
|
||||
|
||||
* For test, build the app (because test server is not yet set up to build):
|
||||
|
||||
```bash
|
||||
# Show only errors
|
||||
VITE_LOG_LEVEL=error npm run dev
|
||||
|
||||
# Show warnings and errors
|
||||
VITE_LOG_LEVEL=warn npm run dev
|
||||
|
||||
# Show info, warnings, and errors (default)
|
||||
VITE_LOG_LEVEL=info npm run dev
|
||||
|
||||
# Show all log levels including debug
|
||||
VITE_LOG_LEVEL=debug npm run dev
|
||||
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_PASSKEYS_ENABLED=true npm run build
|
||||
```
|
||||
|
||||
### Available Levels
|
||||
... and transfer to the test server:
|
||||
|
||||
- **`error`**: Critical errors only
|
||||
- **`warn`**: Warnings and errors (default for production web)
|
||||
- **`info`**: Info, warnings, and errors (default for development/capacitor)
|
||||
- **`debug`**: All log levels including verbose debugging
|
||||
```bash
|
||||
rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari
|
||||
```
|
||||
|
||||
See [Logging Configuration Guide](doc/logging-configuration.md) for complete details.
|
||||
(Let's replace that with a .env.development or .env.staging file.)
|
||||
|
||||
### Quick Usage
|
||||
```bash
|
||||
# Run the database clearing script
|
||||
./scripts/clear-database.sh
|
||||
(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.)
|
||||
|
||||
# Then restart your development server
|
||||
npm run build:electron:dev # For Electron
|
||||
npm run build:web:dev # For Web
|
||||
```
|
||||
* For prod, get on the server and run the correct build:
|
||||
|
||||
### What It Does
|
||||
... and log onto the server:
|
||||
|
||||
#### **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
|
||||
* `pkgx +npm sh`
|
||||
|
||||
#### **Web Browser**
|
||||
- Provides instructions for using custom browser data directories
|
||||
- Shows manual clearing via browser DevTools
|
||||
- Ensures reliable database clearing without browser complications
|
||||
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 0.3.55 && npm install && npm run build && cd -`
|
||||
|
||||
### 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
|
||||
(The plain `npm run build` uses the .env.production file.)
|
||||
|
||||
### Manual Commands (if needed)
|
||||
* Back up the time-safari/dist folder & deploy: `mv time-safari/dist time-safari-dist-prev.0 && mv crowd-funder-for-time-pwa/dist time-safari/`
|
||||
|
||||
#### **Electron Database Location**
|
||||
```bash
|
||||
# Linux
|
||||
rm -rf ~/.config/TimeSafari/*
|
||||
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production.
|
||||
|
||||
# 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
|
||||
|
||||
- [Constants and Configuration](src/constants/app.ts) - Core constants
|
||||
|
||||
## Tests
|
||||
|
||||
See [TESTING.md](test-playwright/TESTING.md) for detailed test instructions.
|
||||
|
||||
## Asset Management
|
||||
|
||||
TimeSafari uses a standardized asset configuration system for consistent
|
||||
icon and splash screen generation across all platforms.
|
||||
|
||||
### Asset Sources
|
||||
|
||||
- **Single source of truth**: `resources/` directory (Capacitor default)
|
||||
- **Source files**: `icon.png`, `splash.png`, `splash_dark.png`
|
||||
- **Format**: PNG or SVG files for optimal quality
|
||||
## Icons
|
||||
|
||||
### Asset Generation
|
||||
|
||||
- **Configuration**: `config/assets/capacitor-assets.config.json`
|
||||
- **Schema validation**: `config/assets/schema.json`
|
||||
- **Build-time generation**: Platform assets generated via `capacitor-assets`
|
||||
- **No VCS commits**: Generated assets are never committed to version control
|
||||
|
||||
### Development Commands
|
||||
|
||||
```bash
|
||||
# Generate/update asset configurations
|
||||
npm run assets:config
|
||||
|
||||
# Validate asset configurations
|
||||
npm run assets:validate
|
||||
|
||||
# Clean generated platform assets (local dev only)
|
||||
npm run assets:clean
|
||||
|
||||
# Build with asset generation
|
||||
npm run build:native
|
||||
```
|
||||
|
||||
### Environment Setup & Dependencies
|
||||
|
||||
Before building the application, ensure your development environment is properly
|
||||
configured:
|
||||
|
||||
```bash
|
||||
# Install all dependencies (required first time and after updates)
|
||||
npm install
|
||||
|
||||
# Validate your development environment
|
||||
npm run check:dependencies
|
||||
|
||||
# Check prerequisites for testing
|
||||
npm run test:prerequisites
|
||||
```
|
||||
|
||||
**Common Issues & Solutions**:
|
||||
|
||||
- **"tsx: command not found"**: Run `npm install` to install devDependencies
|
||||
- **"capacitor-assets: command not found"**: Ensure `@capacitor/assets` is installed
|
||||
- **Build failures**: Run `npm run check:dependencies` to diagnose environment issues
|
||||
|
||||
**Required Versions**:
|
||||
- Node.js: 18+ (LTS recommended)
|
||||
- npm: 8+ (comes with Node.js)
|
||||
- Platform-specific tools: Android Studio, Xcode (for mobile builds)
|
||||
|
||||
### Platform Support
|
||||
|
||||
- **Android**: Adaptive icons with foreground/background, monochrome support
|
||||
- **iOS**: LaunchScreen storyboard preferred, splash assets when needed
|
||||
- **Web**: PWA icons generated during build to `dist/` (not committed)
|
||||
|
||||
### Font Awesome Icons
|
||||
|
||||
To add a Font Awesome icon, add to `fontawesome.ts` and reference with
|
||||
`font-awesome` element and `icon` attribute with the hyphenated name.
|
||||
To add an icon, add to main.ts and reference with `fa` element and `icon` attribute with the hyphenated name.
|
||||
|
||||
## Other
|
||||
|
||||
@@ -219,43 +97,6 @@ To add a Font Awesome icon, add to `fontawesome.ts` and reference with
|
||||
|
||||
* If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",`
|
||||
|
||||
### Code Organization
|
||||
|
||||
The project uses a centralized approach to type definitions and interfaces:
|
||||
|
||||
* `src/interfaces/` - Contains all TypeScript interfaces and type definitions
|
||||
* `deepLinks.ts` - Deep linking type system and Zod validation schemas
|
||||
* `give.ts` - Give-related interfaces and type definitions
|
||||
* `claims.ts` - Claim-related interfaces and verifiable credentials
|
||||
* `common.ts` - Shared interfaces and utility types
|
||||
* Other domain-specific interface files
|
||||
|
||||
Key principles:
|
||||
- All interfaces and types are defined in the interfaces folder
|
||||
- Zod schemas are used for runtime validation and type generation
|
||||
- Domain-specific interfaces are separated into their own files
|
||||
- Common interfaces are shared through `common.ts`
|
||||
- Type definitions are generated from Zod schemas where possible
|
||||
|
||||
### Database Architecture
|
||||
|
||||
The application uses a platform-agnostic database layer with Vue mixins for service access:
|
||||
|
||||
* `src/services/PlatformService.ts` - Database interface 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.
|
||||
|
||||
### Kudos
|
||||
|
||||
Gifts make the world go 'round!
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
|
||||
# What to do about storage for native apps?
|
||||
|
||||
|
||||
## Problem
|
||||
|
||||
We can't trust iOS IndexedDB to persist. I want to start delivering an app to people now, in preparation for presentations mid-June: Rotary on June 12 and Porcfest on June 17.
|
||||
|
||||
* Apple WebKit puts a [7-day cap on IndexedDB](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/).
|
||||
|
||||
* The web standards expose a `persist` method to mark memory as persistent, and [supposedly WebView supports it](https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persisted), but too many other things indicate it's not reliable. I've talked with [ChatGPT](https://chatgpt.com/share/68322f40-84c8-8007-b213-855f7962989a) & Venice & Claude (in Cursor); [this answer from Perplexity](https://www.perplexity.ai/search/which-platforms-prompt-the-use-HUQLqy4qQD2cRbkmO4CgHg) says that most platforms don't prompt and Safari doesn't support it; I don't know if that means WebKit as well.
|
||||
|
||||
* Capacitor says [not to trust it on iOS](https://capacitorjs.com/docs/v6/guides/storage).
|
||||
|
||||
Also, with sensitive data, the accounts info should be encrypted.
|
||||
|
||||
|
||||
# Options
|
||||
|
||||
* There is a community [SQLite plugin for Capacitor](https://github.com/capacitor-community/sqlite) with encryption by [SQLCipher](https://github.com/sqlcipher/sqlcipher).
|
||||
|
||||
* [This tutorial](https://jepiqueau.github.io/2023/09/05/Ionic7Vue-SQLite-CRUD-App.html#part-1---web---table-of-contents) shows how that plugin works for web as well as native.
|
||||
|
||||
* Capacitor abstracts [user preferences in an API](https://capacitorjs.com/docs/apis/preferences), which uses different underlying libraries on iOS & Android. Unfortunately, it won't do any filtering or searching, and is only meant for small amounts of data. (It could be used for settings and for identifiers, but contacts will grow and image blobs won't work.)
|
||||
|
||||
* There are hints that Capacitor offers another custom storage API but all I could find was that Preferences API.
|
||||
|
||||
* [Ionic Storage](https://ionic.io/docs/secure-storage) is an enterprise solution, which also supports encryption.
|
||||
|
||||
* Not an option yet: Dexie may support SQLite in [a future version](https://dexie.org/roadmap/dexie5.0).
|
||||
|
||||
|
||||
|
||||
# Current Plan
|
||||
|
||||
* Implement SQLite for Capacitor & web, with encryption. That will allow us to test quickly and keep the same interface for native & web, but we don't deal with migrations for current web users.
|
||||
|
||||
* After that is delivered, write a migration for current web users from IndexedDB to SQLite.
|
||||
|
||||
|
||||
|
||||
# Current method calls
|
||||
|
||||
... which is not 100% complete because the AI that generated thus claimed no usage of 'temp' DB.
|
||||
|
||||
### Secret Database (secretDB) - Used for storing the encryption key
|
||||
|
||||
secretDB.open() - Opens the database
|
||||
secretDB.secret.get(MASTER_SECRET_KEY) - Retrieves the secret key
|
||||
secretDB.secret.add({ id: MASTER_SECRET_KEY, secret }) - Adds a new secret key
|
||||
|
||||
### Accounts Database (accountsDB) - Used for storing sensitive account information
|
||||
|
||||
accountsDB.open() - Opens the database
|
||||
accountsDB.accounts.count() - Counts number of accounts
|
||||
accountsDB.accounts.toArray() - Gets all accounts
|
||||
accountsDB.accounts.where("did").equals(did).first() - Gets a specific account by DID
|
||||
accountsDB.accounts.add(account) - Adds a new account
|
||||
|
||||
### Non-sensitive Database (db) - Used for settings, contacts, logs, and temp data
|
||||
|
||||
Settings operations:
|
||||
export all settings (Dexie format)
|
||||
db.settings.get(MASTER_SETTINGS_KEY) - Gets default settings
|
||||
db.settings.where("accountDid").equals(did).first() - Gets account-specific settings
|
||||
db.settings.where("accountDid").equals(did).modify(settingsChanges) - Updates account settings
|
||||
db.settings.add(settingsChanges) - Adds new settings
|
||||
db.settings.count() - Counts number of settings
|
||||
db.settings.update(key, changes) - Updates settings
|
||||
|
||||
Contacts operations:
|
||||
export all contacts (Dexie format)
|
||||
db.contacts.toArray() - Gets all contacts
|
||||
db.contacts.add(contact) - Adds a new contact
|
||||
db.contacts.update(did, contactData) - Updates a contact
|
||||
db.contacts.delete(did) - Deletes a contact
|
||||
db.contacts.where("did").equals(did).first() - Gets a specific contact by DID
|
||||
|
||||
Logs operations:
|
||||
db.logs.get(todayKey) - Gets logs for a specific day
|
||||
db.logs.update(todayKey, { message: fullMessage }) - Updates logs
|
||||
db.logs.clear() - Clears all logs
|
||||
|
||||
|
||||
30
android/.gitignore
vendored
@@ -1,20 +1,5 @@
|
||||
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
|
||||
|
||||
app/build/*
|
||||
!app/build/.npmkeep
|
||||
|
||||
# Copied web assets
|
||||
app/src/main/assets/public
|
||||
|
||||
# Generated Config files
|
||||
app/src/main/assets/capacitor.config.json
|
||||
app/src/main/assets/capacitor.plugins.json
|
||||
app/src/main/res/xml/config.xml
|
||||
|
||||
# secrets
|
||||
app/gradle.properties.secrets
|
||||
app/time-safari-upload-key-pkcs12.jks
|
||||
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
@@ -84,6 +69,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
|
||||
|
||||
@@ -99,3 +91,11 @@ lint/tmp/
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-android-plugins
|
||||
|
||||
# Copied web assets
|
||||
app/src/main/assets/public
|
||||
|
||||
# Generated Config files
|
||||
app/src/main/assets/capacitor.config.json
|
||||
app/src/main/assets/capacitor.plugins.json
|
||||
app/src/main/res/xml/config.xml
|
||||
|
||||
BIN
android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
2
android/.gradle/buildOutputCleanup/cache.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
#Fri Mar 21 07:27:50 UTC 2025
|
||||
gradle.version=8.2.1
|
||||
BIN
android/.gradle/file-system.probe
Normal file
2
android/app/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build/*
|
||||
!/build/.npmkeep
|
||||
@@ -1,38 +1,14 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
// These are sample values to set in gradle.properties.secrets
|
||||
// MY_KEYSTORE_FILE=time-safari-upload-key-pkcs12.jks
|
||||
// MY_KEYSTORE_PASSWORD=...
|
||||
// MY_KEY_ALIAS=time-safari-key-alias
|
||||
// MY_KEY_PASSWORD=...
|
||||
|
||||
// Try to load from environment variables first
|
||||
project.ext.MY_KEYSTORE_FILE = System.getenv('ANDROID_KEYSTORE_FILE') ?: ""
|
||||
project.ext.MY_KEYSTORE_PASSWORD = System.getenv('ANDROID_KEYSTORE_PASSWORD') ?: ""
|
||||
project.ext.MY_KEY_ALIAS = System.getenv('ANDROID_KEY_ALIAS') ?: ""
|
||||
project.ext.MY_KEY_PASSWORD = System.getenv('ANDROID_KEY_PASSWORD') ?: ""
|
||||
|
||||
// If no environment variables, try to load from secrets file
|
||||
if (!project.ext.MY_KEYSTORE_FILE) {
|
||||
def secretsPropertiesFile = rootProject.file("app/gradle.properties.secrets")
|
||||
if (secretsPropertiesFile.exists()) {
|
||||
Properties secretsProperties = new Properties()
|
||||
secretsProperties.load(new FileInputStream(secretsPropertiesFile))
|
||||
secretsProperties.each { name, value ->
|
||||
project.ext[name] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'app.timesafari'
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "app.timesafari.app"
|
||||
applicationId "app.timesafari"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 40
|
||||
versionName "1.0.7"
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
@@ -40,49 +16,10 @@ android {
|
||||
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
if (project.ext.MY_KEYSTORE_FILE &&
|
||||
project.ext.MY_KEYSTORE_PASSWORD &&
|
||||
project.ext.MY_KEY_ALIAS &&
|
||||
project.ext.MY_KEY_PASSWORD) {
|
||||
|
||||
storeFile file(project.ext.MY_KEYSTORE_FILE)
|
||||
storePassword project.ext.MY_KEYSTORE_PASSWORD
|
||||
keyAlias project.ext.MY_KEY_ALIAS
|
||||
keyPassword project.ext.MY_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
// Only sign if we have the signing config
|
||||
if (signingConfigs.release.storeFile != null) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
language {
|
||||
enableSplit = true
|
||||
}
|
||||
density {
|
||||
enableSplit = true
|
||||
}
|
||||
abi {
|
||||
enableSplit = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,8 +36,6 @@ dependencies {
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
||||
implementation project(':capacitor-android')
|
||||
implementation project(':capacitor-community-sqlite')
|
||||
implementation "androidx.biometric:biometric:1.2.0-alpha05"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
|
||||
@@ -9,13 +9,7 @@ android {
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-community-sqlite')
|
||||
implementation project(':capacitor-mlkit-barcode-scanning')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-camera')
|
||||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-share')
|
||||
implementation project(':capawesome-capacitor-file-picker')
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "123456789000",
|
||||
"project_id": "timesafari-app",
|
||||
"storage_bucket": "timesafari-app.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:123456789000:android:1234567890abcdef",
|
||||
"android_client_info": {
|
||||
"package_name": "app.timesafari.app"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDummyKeyForBuildPurposesOnly12345"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -21,6 +21,6 @@ public class ExampleInstrumentedTest {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("app.timesafari.app", appContext.getPackageName());
|
||||
assertEquals("app.timesafari", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@@ -7,14 +8,15 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_main"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.NoActionBarLaunch">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -26,6 +28,7 @@
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="timesafari" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
@@ -33,15 +36,13 @@
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="true" />
|
||||
</manifest>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"appId": "app.timesafari",
|
||||
"appName": "TimeSafari",
|
||||
"webDir": "dist",
|
||||
"bundledWebRuntime": false,
|
||||
"server": {
|
||||
"cleartext": true
|
||||
},
|
||||
@@ -15,107 +16,6 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"SplashScreen": {
|
||||
"launchShowDuration": 3000,
|
||||
"launchAutoHide": true,
|
||||
"backgroundColor": "#ffffff",
|
||||
"androidSplashResourceName": "splash",
|
||||
"androidScaleType": "CENTER_CROP",
|
||||
"showSpinner": false,
|
||||
"androidSpinnerStyle": "large",
|
||||
"iosSpinnerStyle": "small",
|
||||
"spinnerColor": "#999999",
|
||||
"splashFullScreen": true,
|
||||
"splashImmersive": true
|
||||
},
|
||||
"CapSQLite": {
|
||||
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
||||
"iosIsEncryption": false,
|
||||
"iosBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"androidIsEncryption": false,
|
||||
"androidBiometric": {
|
||||
"biometricAuth": false,
|
||||
"biometricTitle": "Biometric login for TimeSafari"
|
||||
},
|
||||
"electronIsEncryption": false
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
"contentInset": "never",
|
||||
"allowsLinkPreview": true,
|
||||
"scrollEnabled": true,
|
||||
"limitsNavigationsToAppBoundDomains": true,
|
||||
"backgroundColor": "#ffffff",
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch"
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"allowMixedContent": true,
|
||||
"captureInput": true,
|
||||
"webContentsDebuggingEnabled": false,
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch",
|
||||
"10.0.2.2:3000"
|
||||
]
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,6 @@
|
||||
[
|
||||
{
|
||||
"pkg": "@capacitor-community/sqlite",
|
||||
"classpath": "com.getcapacitor.community.database.sqlite.CapacitorSQLitePlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor-mlkit/barcode-scanning",
|
||||
"classpath": "io.capawesome.capacitorjs.plugins.mlkit.barcodescanning.BarcodeScannerPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/app",
|
||||
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/camera",
|
||||
"classpath": "com.capacitorjs.plugins.camera.CameraPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/filesystem",
|
||||
"classpath": "com.capacitorjs.plugins.filesystem.FilesystemPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/share",
|
||||
"classpath": "com.capacitorjs.plugins.share.SharePlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capawesome/capacitor-file-picker",
|
||||
"classpath": "io.capawesome.capacitorjs.plugins.filepicker.FilePickerPlugin"
|
||||
}
|
||||
]
|
||||
|
||||
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 |
17
android/app/src/main/assets/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>TimeSafari</title>
|
||||
<script type="module" crossorigin src="/assets/index-DHTxVcAY.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but TimeSafari doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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:
|
||||
@@ -1,15 +1,7 @@
|
||||
package app.timesafari;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
//import com.getcapacitor.community.sqlite.SQLite;
|
||||
|
||||
public class MainActivity extends BridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Initialize SQLite
|
||||
//registerPlugin(SQLite.class);
|
||||
}
|
||||
// ... existing code ...
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package timesafari.app;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public class MainActivity extends BridgeActivity {}
|
||||
BIN
android/app/src/main/res/drawable-land-hdpi/splash.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
android/app/src/main/res/drawable-land-mdpi/splash.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
android/app/src/main/res/drawable-land-xhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
android/app/src/main/res/drawable-land-xxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
android/app/src/main/res/drawable-land-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
android/app/src/main/res/drawable-port-hdpi/splash.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
android/app/src/main/res/drawable-port-mdpi/splash.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
android/app/src/main/res/drawable-port-xhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
android/app/src/main/res/drawable-port-xxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
android/app/src/main/res/drawable-port-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -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>
|
||||
BIN
android/app/src/main/res/drawable/splash.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |