Compare commits
1 Commits
get-get-ha
...
web-serve-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e290ad488 |
@@ -8,3 +8,28 @@ alwaysApply: true
|
||||
✅ 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
|
||||
✅ do not add or commit for the user; let him control that process
|
||||
|
||||
always preview changes and commit message to use and allow me to copy and paste
|
||||
✅ Preferred Commit Message Format
|
||||
|
||||
Short summary in the first line (concise and high-level).
|
||||
Avoid long commit bodies unless truly necessary.
|
||||
|
||||
✅ Valued Content in Commit Messages
|
||||
|
||||
Specific fixes or features.
|
||||
Symptoms or problems that were fixed.
|
||||
Notes about tests passing or TS/linting errors being resolved (briefly).
|
||||
|
||||
❌ Avoid in Commit Messages
|
||||
|
||||
Vague terms: “improved”, “enhanced”, “better” — especially from AI.
|
||||
Minor changes: small doc tweaks, one-liners, cleanup, or lint fixes.
|
||||
Redundant blurbs: repeated across files or too generic.
|
||||
Multiple overlapping purposes in a single commit — prefer narrow, focused commits.
|
||||
Long explanations of what can be deduced from good in-line code comments.
|
||||
|
||||
Guiding Principle
|
||||
|
||||
Let code and inline documentation speak for themselves. Use commits to highlight what isn't obvious from reading the code.
|
||||
|
||||
@@ -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.
|
||||
@@ -312,21 +312,3 @@ Description of current situation or problem.
|
||||
**Last Updated**: 2025-07-09
|
||||
**Version**: 1.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
|
||||
|
||||
### Heading Uniqueness
|
||||
|
||||
- **Rule**: No duplicate heading content at the same level
|
||||
- **Scope**: Within a single document
|
||||
- **Rationale**: Maintains clear document structure and navigation
|
||||
- **Example**:
|
||||
|
||||
```markdown
|
||||
## Features ✅
|
||||
### Authentication
|
||||
### Authorization
|
||||
|
||||
## Features ❌ (Duplicate heading)
|
||||
### Security
|
||||
### Performance
|
||||
```
|
||||
@@ -1,96 +1,70 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
# Time Safari Context
|
||||
|
||||
## Project Overview
|
||||
|
||||
Time Safari is an application designed to foster community building through gifts,
|
||||
gratitude, and collaborative projects. The app should make it extremely easy and
|
||||
intuitive for users of any age and capability to recognize contributions, build
|
||||
trust networks, and organize collective action. It is built on services that
|
||||
preserve privacy and data sovereignty.
|
||||
Time Safari is an application designed to foster community building through gifts, gratitude, and collaborative projects. The app should make it extremely easy and intuitive for users of any age and capability to recognize contributions, build trust networks, and organize collective action. It is built on services that preserve privacy and data sovereignty.
|
||||
|
||||
The ultimate goals of Time Safari are two-fold:
|
||||
|
||||
1. **Connect** Make it easy, rewarding, and non-threatening for people to
|
||||
connect with others who have similar interests, and to initiate activities
|
||||
together. This helps people accomplish and learn from other individuals in
|
||||
less-structured environments; moreover, it helps them discover who they want
|
||||
to continue to support and with whom they want to maintain relationships.
|
||||
1. **Connect** Make it easy, rewarding, and non-threatening for people to connect with others who have similar interests, and to initiate activities together. This helps people accomplish and learn from other individuals in less-structured environments; moreover, it helps them discover who they want to continue to support and with whom they want to maintain relationships.
|
||||
|
||||
2. **Reveal** Widely advertise the great support and rewards that are being
|
||||
given and accepted freely, especially non-monetary ones. Using visuals and text,
|
||||
display the kind of impact that gifts are making in the lives of others. Also
|
||||
show useful and engaging reports of project statistics and personal accomplishments.
|
||||
2. **Reveal** Widely advertise the great support and rewards that are being given and accepted freely, especially non-monetary ones. Using visuals and text, display the kind of impact that gifts are making in the lives of others. Also show useful and engaging reports of project statistics and personal accomplishments.
|
||||
|
||||
|
||||
## Core Approaches
|
||||
|
||||
Time Safari should help everyday users build meaningful connections and organize
|
||||
collective efforts by:
|
||||
Time Safari should help everyday users build meaningful connections and organize collective efforts by:
|
||||
|
||||
1. **Recognizing Contributions**: Creating permanent, verifiable records of gifts
|
||||
and contributions people give to each other and their communities.
|
||||
1. **Recognizing Contributions**: Creating permanent, verifiable records of gifts and contributions people give to each other and their communities.
|
||||
|
||||
2. **Facilitating Collaboration**: Making it ridiculously easy for people to ask
|
||||
for or propose help on projects and interests that matter to them.
|
||||
2. **Facilitating Collaboration**: Making it ridiculously easy for people to ask for or propose help on projects and interests that matter to them.
|
||||
|
||||
3. **Building Trust Networks**: Enabling users to maintain their network and activity
|
||||
visibility. Developing reputation through verified contributions and references,
|
||||
which can be selectively shown to others outside the network.
|
||||
3. **Building Trust Networks**: Enabling users to maintain their network and activity visibility. Developing reputation through verified contributions and references, which can be selectively shown to others outside the network.
|
||||
|
||||
4. **Preserving Privacy**: Ensuring personal identifiers are only shared with
|
||||
explicitly authorized contacts, allowing private individuals including children
|
||||
to participate safely.
|
||||
4. **Preserving Privacy**: Ensuring personal identifiers are only shared with explicitly authorized contacts, allowing private individuals including children to participate safely.
|
||||
|
||||
5. **Engaging Content**: Displaying people's records in compelling stories, and
|
||||
highlighting those projects that are lifting people's lives long-term, both in
|
||||
physical support and in emotional-spiritual-creative thriving.
|
||||
5. **Engaging Content**: Displaying people's records in compelling stories, and highlighting those projects that are lifting people's lives long-term, both in physical support and in emotional-spiritual-creative thriving.
|
||||
|
||||
|
||||
## Technical Foundation
|
||||
|
||||
This application is built on a privacy-preserving claims architecture (via
|
||||
endorser.ch) with these key characteristics:
|
||||
This application is built on a privacy-preserving claims architecture (via endorser.ch) with these key characteristics:
|
||||
|
||||
- **Decentralized Identifiers (DIDs)**: User identities are based on public/private
|
||||
key pairs stored on their devices
|
||||
- **Cryptographic Verification**: All claims and confirmations are
|
||||
cryptographically signed
|
||||
- **User-Controlled Visibility**: Users explicitly control who can see their
|
||||
identifiers and data
|
||||
- **Merkle-Chained Claims**: Claims are cryptographically chained for verification
|
||||
and integrity
|
||||
- **Native and Web App**: Works on Capacitor (iOS, Android), Desktop (Electron
|
||||
and CEFPython), and web browsers
|
||||
- **Decentralized Identifiers (DIDs)**: User identities are based on public/private key pairs stored on their devices
|
||||
- **Cryptographic Verification**: All claims and confirmations are cryptographically signed
|
||||
- **User-Controlled Visibility**: Users explicitly control who can see their identifiers and data
|
||||
- **Merkle-Chained Claims**: Claims are cryptographically chained for verification and integrity
|
||||
- **Native and Web App**: Works on Capacitor (iOS, Android), Desktop (Electron and CEFPython), and web browsers
|
||||
|
||||
## User Journey
|
||||
|
||||
The typical progression of usage follows these stages:
|
||||
|
||||
1. **Gratitude & Recognition**: Users begin by expressing and recording gratitude
|
||||
for gifts received, building a foundation of acknowledgment.
|
||||
1. **Gratitude & Recognition**: Users begin by expressing and recording gratitude for gifts received, building a foundation of acknowledgment.
|
||||
|
||||
2. **Project Proposals**: Users propose projects and ideas, reaching out to connect
|
||||
with others who share similar interests.
|
||||
2. **Project Proposals**: Users propose projects and ideas, reaching out to connect with others who share similar interests.
|
||||
|
||||
3. **Action Triggers**: Offers of help serve as triggers and motivations to execute
|
||||
proposed projects, moving from ideas to action.
|
||||
3. **Action Triggers**: Offers of help serve as triggers and motivations to execute proposed projects, moving from ideas to action.
|
||||
|
||||
## Context for LLM Development
|
||||
|
||||
When developing new functionality for Time Safari, consider these design principles:
|
||||
|
||||
1. **Accessibility First**: Features should be usable by non-technical users with
|
||||
minimal learning curve.
|
||||
1. **Accessibility First**: Features should be usable by non-technical users with minimal learning curve.
|
||||
|
||||
2. **Privacy by Design**: All features must respect user privacy and data sovereignty.
|
||||
|
||||
3. **Progressive Enhancement**: Core functionality should work across all devices,
|
||||
with richer experiences where supported.
|
||||
3. **Progressive Enhancement**: Core functionality should work across all devices, with richer experiences where supported.
|
||||
|
||||
4. **Voluntary Collaboration**: The system should enable but never coerce participation.
|
||||
|
||||
@@ -98,40 +72,31 @@ with richer experiences where supported.
|
||||
|
||||
6. **Network Effects**: Consider how features scale as more users join the platform.
|
||||
|
||||
7. **Low Resource Requirements**: The system should be lightweight enough to run
|
||||
on inexpensive devices users already own.
|
||||
7. **Low Resource Requirements**: The system should be lightweight enough to run on inexpensive devices users already own.
|
||||
|
||||
## Use Cases to Support
|
||||
|
||||
LLM development should focus on enhancing these key use cases:
|
||||
|
||||
1. **Community Building**: Tools that help people find others with shared
|
||||
interests and values.
|
||||
1. **Community Building**: Tools that help people find others with shared interests and values.
|
||||
|
||||
2. **Project Coordination**: Features that make it easy to propose collaborative
|
||||
projects and to submit suggestions and offers to existing ones.
|
||||
2. **Project Coordination**: Features that make it easy to propose collaborative projects and to submit suggestions and offers to existing ones.
|
||||
|
||||
3. **Reputation Building**: Methods for users to showcase their contributions
|
||||
and reliability, in contexts where they explicitly reveal that information.
|
||||
3. **Reputation Building**: Methods for users to showcase their contributions and reliability, in contexts where they explicitly reveal that information.
|
||||
|
||||
4. **Governance Experimentation**: Features that facilitate decision-making and
|
||||
collective governance.
|
||||
4. **Governance Experimentation**: Features that facilitate decision-making and collective governance.
|
||||
|
||||
## Constraints
|
||||
|
||||
When developing new features, be mindful of these constraints:
|
||||
|
||||
1. **Privacy Preservation**: User identifiers must remain private except when
|
||||
explicitly shared.
|
||||
1. **Privacy Preservation**: User identifiers must remain private except when explicitly shared.
|
||||
|
||||
2. **Platform Limitations**: Features must work within the constraints of the target
|
||||
app platforms, while aiming to leverage the best platform technology available.
|
||||
2. **Platform Limitations**: Features must work within the constraints of the target app platforms, while aiming to leverage the best platform technology available.
|
||||
|
||||
3. **Endorser API Limitations**: Backend features are constrained by the endorser.ch
|
||||
API capabilities.
|
||||
3. **Endorser API Limitations**: Backend features are constrained by the endorser.ch API capabilities.
|
||||
|
||||
4. **Performance on Low-End Devices**: The application should remain performant
|
||||
on older/simpler devices.
|
||||
4. **Performance on Low-End Devices**: The application should remain performant on older/simpler devices.
|
||||
|
||||
5. **Offline-First When Possible**: Key functionality should work offline when feasible.
|
||||
|
||||
@@ -151,14 +116,12 @@ on older/simpler devices.
|
||||
|
||||
## Project Architecture
|
||||
|
||||
- The application must work on web browser, PWA (Progressive Web Application),
|
||||
desktop via Electron, and mobile via Capacitor
|
||||
- The application must work on web browser, PWA (Progressive Web Application), desktop via Electron, and mobile via Capacitor
|
||||
- Building for each platform is managed via Vite
|
||||
|
||||
## Core Development Principles
|
||||
|
||||
### DRY development
|
||||
|
||||
- **Code Reuse**
|
||||
- Extract common functionality into utility functions
|
||||
- Create reusable components for UI patterns
|
||||
@@ -214,24 +177,14 @@ on older/simpler devices.
|
||||
- Use shared test configurations
|
||||
- Create reusable test helpers
|
||||
- Implement consistent test patterns
|
||||
- F.I.R.S.T. (for Unit Tests)
|
||||
F – Fast
|
||||
I – Independent
|
||||
R – Repeatable
|
||||
S – Self-validating
|
||||
T – Timely
|
||||
|
||||
|
||||
### SOLID Principles
|
||||
|
||||
- **Single Responsibility**: Each class/component should have only one reason to
|
||||
change
|
||||
- **Single Responsibility**: Each class/component should have only one reason to change
|
||||
- Components should focus on one specific feature (e.g., QR scanning, DID management)
|
||||
- Services should handle one type of functionality (e.g., platform services,
|
||||
crypto services)
|
||||
- Services should handle one type of functionality (e.g., platform services, crypto services)
|
||||
- Utilities should provide focused helper functions
|
||||
|
||||
- **Open/Closed**: Software entities should be open for extension but closed for
|
||||
modification
|
||||
- **Open/Closed**: Software entities should be open for extension but closed for modification
|
||||
- Use interfaces for service definitions
|
||||
- Implement plugin architecture for platform-specific features
|
||||
- Allow component behavior extension through props and events
|
||||
@@ -252,7 +205,6 @@ on older/simpler devices.
|
||||
- Implement factory patterns for component creation
|
||||
|
||||
### Law of Demeter
|
||||
|
||||
- Components should only communicate with immediate dependencies
|
||||
- Avoid chaining method calls (e.g., `this.service.getUser().getProfile().getName()`)
|
||||
- Use mediator patterns for complex component interactions
|
||||
@@ -260,7 +212,6 @@ on older/simpler devices.
|
||||
- Keep component communication through defined events and props
|
||||
|
||||
### Composition over Inheritance
|
||||
|
||||
- Prefer building components through composition
|
||||
- Use mixins for shared functionality
|
||||
- Implement feature toggles through props
|
||||
@@ -268,7 +219,6 @@ on older/simpler devices.
|
||||
- Use service composition for complex features
|
||||
|
||||
### Interface Segregation
|
||||
|
||||
- Define clear interfaces for services
|
||||
- Keep component APIs minimal and focused
|
||||
- Split large interfaces into smaller, specific ones
|
||||
@@ -276,7 +226,6 @@ on older/simpler devices.
|
||||
- Implement role-based interfaces for different use cases
|
||||
|
||||
### Fail Fast
|
||||
|
||||
- Validate inputs early in the process
|
||||
- Use TypeScript strict mode
|
||||
- Implement comprehensive error handling
|
||||
@@ -284,7 +233,6 @@ on older/simpler devices.
|
||||
- Use assertions for development-time validation
|
||||
|
||||
### Principle of Least Astonishment
|
||||
|
||||
- Follow Vue.js conventions consistently
|
||||
- Use familiar naming patterns
|
||||
- Implement predictable component behaviors
|
||||
@@ -292,7 +240,6 @@ on older/simpler devices.
|
||||
- Keep UI interactions intuitive
|
||||
|
||||
### Information Hiding
|
||||
|
||||
- Encapsulate implementation details
|
||||
- Use private class members
|
||||
- Implement proper access modifiers
|
||||
@@ -300,7 +247,6 @@ on older/simpler devices.
|
||||
- Use TypeScript's access modifiers effectively
|
||||
|
||||
### Single Source of Truth
|
||||
|
||||
- Use Pinia for state management
|
||||
- Maintain one source for user data
|
||||
- Centralize configuration management
|
||||
@@ -308,9 +254,23 @@ on older/simpler devices.
|
||||
- Implement proper state synchronization
|
||||
|
||||
### Principle of Least Privilege
|
||||
|
||||
- Implement proper access control
|
||||
- Use minimal required permissions
|
||||
- Follow privacy-by-design principles
|
||||
- Restrict component access to necessary data
|
||||
- Implement proper authentication/authorization
|
||||
|
||||
### Continuous Integration/Continuous Deployment (CI/CD)
|
||||
- Automated testing on every commit
|
||||
- Consistent build process across platforms
|
||||
- Automated deployment pipelines
|
||||
- Quality gates for code merging
|
||||
- Environment-specific configurations
|
||||
|
||||
This expanded documentation provides:
|
||||
1. Clear principles for development
|
||||
2. Practical implementation guidelines
|
||||
3. Real-world examples
|
||||
4. TypeScript integration
|
||||
5. Best practices for Time Safari
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
---
|
||||
# Rules for peaceful co-existence with developers
|
||||
|
||||
do not add or commit for the user; let him control that process
|
||||
|
||||
the content of commit messages should be from the files awaiting staging
|
||||
and those which have been staged. use the differences in those files
|
||||
to inform the content of the commit message
|
||||
|
||||
always preview changes and commit message to use and allow me to copy and paste
|
||||
✅ Preferred Commit Message Format
|
||||
|
||||
Short summary in the first line (concise and high-level).
|
||||
Avoid long commit bodies unless truly necessary.
|
||||
|
||||
✅ Valued Content in Commit Messages
|
||||
|
||||
Specific fixes or features.
|
||||
Symptoms or problems that were fixed.
|
||||
Notes about tests passing or TS/linting errors being resolved (briefly).
|
||||
|
||||
❌ Avoid in Commit Messages
|
||||
|
||||
Vague terms: “improved”, “enhanced”, “better” — especially from AI.
|
||||
Minor changes: small doc tweaks, one-liners, cleanup, or lint fixes.
|
||||
Redundant blurbs: repeated across files or too generic.
|
||||
Multiple overlapping purposes in a single commit — prefer narrow, focused commits.
|
||||
Long explanations of what can be deduced from good in-line code comments.
|
||||
|
||||
Guiding Principle
|
||||
|
||||
Let code and inline documentation speak for themselves. Use commits to highlight what isn't obvious from reading the code.
|
||||
@@ -15,7 +15,7 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build outputs
|
||||
# dist - Allow dist directory for Docker builds (contains pre-built assets)
|
||||
dist
|
||||
dist-*
|
||||
build
|
||||
*.tsbuildinfo
|
||||
|
||||
31
.gitignore
vendored
@@ -55,23 +55,7 @@ build_logs/
|
||||
icons
|
||||
|
||||
*.log
|
||||
|
||||
# Generated Android assets and resources (should be generated during build)
|
||||
android/app/src/main/assets/public/
|
||||
|
||||
# Generated Android resources (icons, splash screens, etc.)
|
||||
android/app/src/main/res/drawable*/
|
||||
android/app/src/main/res/mipmap*/
|
||||
android/app/src/main/res/values/ic_launcher_background.xml
|
||||
|
||||
# Keep these Android configuration files in version control:
|
||||
# - android/app/src/main/assets/capacitor.plugins.json
|
||||
# - android/app/src/main/res/values/strings.xml
|
||||
# - android/app/src/main/res/values/styles.xml
|
||||
# - android/app/src/main/res/layout/activity_main.xml
|
||||
# - android/app/src/main/res/xml/config.xml
|
||||
# - android/app/src/main/res/xml/file_paths.xml
|
||||
|
||||
android/app/src/main/res/
|
||||
sql-wasm.wasm
|
||||
|
||||
# Temporary and generated files
|
||||
@@ -99,7 +83,11 @@ ios/App/App/public/assets/
|
||||
ios/App/App/build/
|
||||
ios/App/build/
|
||||
|
||||
# Capacitor build artifacts (covered by android/app/build/ above)
|
||||
# Capacitor generated configs (keep source configs)
|
||||
android/app/build/intermediates/assets/debug/mergeDebugAssets/capacitor.*.json
|
||||
android/app/build/intermediates/compressed_assets/debug/compressDebugAssets/out/assets/capacitor.*.json.jar
|
||||
android/app/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-capacitor-cordova-android-plugins.jar
|
||||
android/app/build/outputs/aar/capacitor-cordova-android-plugins-debug.aar
|
||||
|
||||
# Keep these Capacitor files in version control:
|
||||
# - capacitor.config.json (root, electron, ios)
|
||||
@@ -123,9 +111,4 @@ electron/out/
|
||||
# - 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
|
||||
# - electron/resources/electron-publisher-custom.js
|
||||
805
BUILDING.md
24
Dockerfile
@@ -36,10 +36,6 @@
|
||||
# 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
|
||||
@@ -66,7 +62,6 @@ RUN addgroup -g 1001 -S nodejs && \
|
||||
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
|
||||
@@ -87,7 +82,6 @@ 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
|
||||
@@ -113,21 +107,23 @@ RUN apk update && \
|
||||
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
|
||||
# Create non-root user for nginx
|
||||
RUN addgroup -g 1001 -S nginx && \
|
||||
adduser -S nginx -u 1001 -G nginx
|
||||
|
||||
# Copy main nginx configuration
|
||||
# Copy appropriate nginx configuration based on build mode
|
||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# Copy production nginx configuration
|
||||
COPY docker/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy staging configuration if needed
|
||||
COPY docker/staging.conf /etc/nginx/conf.d/staging.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 && \
|
||||
RUN mkdir -p /var/cache/nginx /var/log/nginx /var/run && \
|
||||
chown -R nginx:nginx /var/cache/nginx /var/log/nginx /var/run && \
|
||||
chown -R nginx:nginx /usr/share/nginx/html
|
||||
|
||||
# Switch to non-root user
|
||||
@@ -143,6 +139,8 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
# Start nginx with proper signal handling
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TEST STAGE - For test environment testing
|
||||
# =============================================================================
|
||||
|
||||
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
|
||||
|
||||
36
README.md
@@ -97,37 +97,15 @@ rmdir /s /q %APPDATA%\TimeSafari
|
||||
```bash
|
||||
# Create isolated browser profile
|
||||
mkdir ~/timesafari-dev-data
|
||||
|
||||
# Start browser with custom profile
|
||||
google-chrome --user-data-dir=~/timesafari-dev-data
|
||||
|
||||
# Clear when needed
|
||||
rm -rf ~/timesafari-dev-data
|
||||
```
|
||||
|
||||
## Domain Configuration
|
||||
|
||||
TimeSafari uses a centralized domain configuration system to ensure consistent
|
||||
URL generation across all environments. This prevents localhost URLs from
|
||||
appearing in shared links during development.
|
||||
|
||||
### Key Features
|
||||
- ✅ **Production URLs for Sharing**: All copy link buttons use production domain
|
||||
- ✅ **Environment-Specific Internal URLs**: Internal operations use appropriate
|
||||
environment URLs
|
||||
- ✅ **Single Point of Control**: Change domain in one place for entire app
|
||||
- ✅ **Type-Safe Configuration**: Full TypeScript support
|
||||
|
||||
### Quick Reference
|
||||
|
||||
```typescript
|
||||
// For sharing functionality (environment-specific)
|
||||
import { APP_SERVER } from "@/constants/app";
|
||||
const shareLink = `${APP_SERVER}/deep-link/claim/123`;
|
||||
|
||||
// For internal operations (environment-specific)
|
||||
import { APP_SERVER } from "@/constants/app";
|
||||
const apiUrl = `${APP_SERVER}/api/claim/123`;
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
- [Domain Configuration System](docs/domain-configuration.md) - Complete guide
|
||||
- [Constants and Configuration](src/constants/app.ts) - Core constants
|
||||
See the script for complete platform-specific instructions.
|
||||
|
||||
## Tests
|
||||
|
||||
|
||||
7
android/.gitignore
vendored
@@ -84,6 +84,13 @@ freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
|
||||
@@ -64,14 +64,6 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
pickFirsts += ['**/lib/x86_64/libbarhopper_v3.so', '**/lib/x86_64/libimage_processing_util_jni.so', '**/lib/x86_64/libsqlcipher.so']
|
||||
}
|
||||
}
|
||||
|
||||
// Configure for 16 KB page size compatibility
|
||||
|
||||
|
||||
// Enable bundle builds (without which it doesn't work right for bundleDebug vs bundleRelease)
|
||||
bundle {
|
||||
|
||||
@@ -57,14 +57,13 @@
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"allowMixedContent": true,
|
||||
"allowMixedContent": false,
|
||||
"captureInput": true,
|
||||
"webContentsDebuggingEnabled": false,
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch",
|
||||
"10.0.2.2:3000"
|
||||
"api.endorser.ch"
|
||||
]
|
||||
},
|
||||
"electron": {
|
||||
|
||||
0
android/app/src/main/assets/public/cordova.js
vendored
Normal file
0
android/app/src/main/assets/public/cordova_plugins.js
vendored
Normal file
BIN
android/app/src/main/assets/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 463 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 70 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
android/app/src/main/assets/public/img/icons/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 46 KiB |
BIN
android/app/src/main/assets/public/img/icons/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2480 4005 c-25 -7 -58 -20 -75 -29 -16 -9 -40 -16 -52 -16 -17 0
|
||||
-24 -7 -28 -27 -3 -16 -14 -45 -24 -65 -21 -41 -13 -55 18 -38 25 13 67 13 92
|
||||
-1 15 -8 35 -4 87 17 99 39 130 41 197 10 64 -29 77 -31 107 -15 20 11 20 11
|
||||
-3 35 -12 13 -30 24 -38 24 -24 1 -132 38 -148 51 -8 7 -11 20 -7 32 12 37
|
||||
-40 47 -126 22z"/>
|
||||
<path d="M1450 3775 c-7 -8 -18 -15 -24 -15 -7 0 -31 -14 -54 -32 -29 -22 -38
|
||||
-34 -29 -40 17 -11 77 -10 77 1 0 5 16 16 35 25 60 29 220 19 290 -18 17 -9
|
||||
33 -16 37 -16 4 0 31 -15 60 -34 108 -70 224 -215 282 -353 30 -71 53 -190 42
|
||||
-218 -10 -27 -23 -8 -52 75 -30 90 -88 188 -120 202 -13 6 -26 9 -29 6 -3 -2
|
||||
11 -51 30 -108 28 -83 35 -119 35 -179 0 -120 -22 -127 -54 -17 -11 37 -13 21
|
||||
-18 -154 -5 -180 -8 -200 -32 -264 -51 -132 -129 -245 -199 -288 -21 -12 -79
|
||||
-49 -129 -80 -161 -102 -294 -141 -473 -141 -228 0 -384 76 -535 259 -81 99
|
||||
-118 174 -154 312 -31 121 -35 273 -11 437 19 127 19 125 -4 125 -23 0 -51
|
||||
-34 -87 -104 -14 -28 -33 -64 -41 -81 -19 -34 -22 -253 -7 -445 9 -106 12
|
||||
-119 44 -170 19 -30 42 -67 50 -81 64 -113 85 -140 130 -169 28 -18 53 -44 61
|
||||
-62 8 -20 36 -45 83 -76 62 -39 80 -46 151 -54 44 -5 96 -13 115 -18 78 -20
|
||||
238 -31 282 -19 24 6 66 8 95 5 76 -9 169 24 319 114 32 19 80 56 106 82 27
|
||||
26 52 48 58 48 5 0 27 26 50 58 48 66 56 70 132 71 62 1 165 29 238 64 112 55
|
||||
177 121 239 245 37 76 39 113 10 267 -12 61 -23 131 -26 156 -5 46 -5 47 46
|
||||
87 92 73 182 70 263 -8 l51 -49 -6 -61 c-4 -34 -13 -85 -21 -113 -28 -103 -30
|
||||
-161 -4 -228 16 -44 32 -67 55 -83 18 -11 39 -37 47 -58 10 -23 37 -53 73 -81
|
||||
32 -25 69 -57 82 -71 14 -14 34 -26 47 -26 12 0 37 -7 56 -15 20 -8 66 -17
|
||||
104 -20 107 -10 110 -11 150 -71 50 -75 157 -177 197 -187 18 -5 53 -24 78
|
||||
-42 71 -51 176 -82 304 -89 61 -4 127 -12 147 -18 29 -9 45 -8 77 6 23 9 50
|
||||
16 60 16 31 0 163 46 216 76 28 15 75 46 105 69 30 23 69 49 85 58 17 8 46 31
|
||||
64 51 19 20 40 36 47 36 18 0 77 70 100 120 32 66 45 108 55 173 5 32 16 71
|
||||
24 87 43 84 43 376 0 549 -27 105 -43 127 -135 188 -30 21 -65 46 -77 57 -13
|
||||
11 -23 17 -23 14 0 -3 21 -46 47 -94 79 -151 85 -166 115 -263 25 -83 28 -110
|
||||
28 -226 0 -144 -17 -221 -75 -335 -39 -77 -208 -244 -304 -299 -451 -263 -975
|
||||
-67 -1138 426 -23 70 -26 95 -28 254 -1 108 -7 183 -14 196 -6 12 -11 31 -11
|
||||
43 0 32 31 122 52 149 10 13 18 28 18 34 0 5 25 40 56 78 60 73 172 170 219
|
||||
190 30 12 30 13 6 17 -15 2 -29 -2 -37 -12 -6 -9 -16 -16 -22 -16 -6 0 -23
|
||||
-11 -39 -24 -15 -12 -33 -25 -40 -27 -17 -6 -82 -60 -117 -97 -65 -70 -75 -82
|
||||
-107 -133 -23 -34 -35 -46 -37 -35 -3 16 20 87 44 134 6 12 9 34 6 48 -4 22
|
||||
-8 25 -31 19 -14 -3 -38 -15 -53 -26 -34 -24 -34 -21 -6 28 65 112 184 206
|
||||
291 227 15 3 39 9 55 12 l27 6 -24 9 c-90 35 -304 -66 -478 -225 -39 -36 -74
|
||||
-66 -77 -66 -22 0 18 82 72 148 19 23 32 46 28 49 -4 4 -26 13 -49 19 -73 21
|
||||
-161 54 -171 64 -6 6 -20 10 -32 10 -21 0 -21 -1 -8 -40 45 -130 8 -247 -93
|
||||
-299 -25 -13 -31 0 -14 29 15 22 1 33 -22 17 -56 -36 -117 -22 -117 28 0 13
|
||||
-16 47 -35 76 -22 34 -33 60 -29 73 4 16 -3 26 -26 39 -16 10 -30 21 -30 25 1
|
||||
18 54 64 87 76 l38 13 -33 5 c-30 4 -115 -18 -154 -42 -13 -7 -20 -5 -27 8 -9
|
||||
16 -12 16 -53 1 -160 -61 -258 -104 -258 -114 0 -7 10 -20 21 -31 103 -91 217
|
||||
-297 249 -449 28 -135 41 -237 35 -276 -14 -91 -48 -170 -97 -220 -44 -47 -68
|
||||
-60 -68 -40 0 6 4 12 8 15 5 3 24 35 42 72 l33 67 -6 141 c-4 103 -11 158 -26
|
||||
205 -12 35 -21 70 -21 77 0 7 -20 56 -45 108 -82 173 -227 322 -392 401 -67
|
||||
33 -90 39 -163 42 -108 5 -130 10 -130 28 0 20 -63 20 -80 0z"/>
|
||||
<path d="M3710 3765 c0 -20 8 -28 39 -41 22 -8 42 -22 45 -30 5 -14 42 -19 70
|
||||
-8 10 4 -7 21 -58 55 -41 27 -79 49 -85 49 -6 0 -11 -11 -11 -25z"/>
|
||||
<path d="M3173 3734 c-9 -25 10 -36 35 -18 12 8 22 19 22 25 0 16 -50 10 -57
|
||||
-7z"/>
|
||||
<path d="M1982 3728 c6 -16 36 -34 44 -26 3 4 4 14 1 23 -7 17 -51 21 -45 3z"/>
|
||||
<path d="M1540 3620 c0 -5 7 -10 16 -10 8 0 12 5 9 10 -3 6 -10 10 -16 10 -5
|
||||
0 -9 -4 -9 -10z"/>
|
||||
<path d="M4467 3624 c-4 -4 23 -27 60 -50 84 -56 99 -58 67 -9 -28 43 -107 79
|
||||
-127 59z"/>
|
||||
<path d="M655 3552 c-11 -2 -26 -9 -33 -14 -7 -6 -27 -18 -45 -27 -36 -18 -58
|
||||
-64 -39 -83 9 -9 25 1 70 43 53 48 78 78 70 84 -2 1 -12 -1 -23 -3z"/>
|
||||
<path d="M1015 3460 c-112 -24 -247 -98 -303 -165 -53 -65 -118 -214 -136
|
||||
-311 -20 -113 -20 -145 -1 -231 20 -88 49 -153 102 -230 79 -113 186 -182 331
|
||||
-214 108 -24 141 -24 247 1 130 30 202 72 316 181 102 100 153 227 152 384 0
|
||||
142 -58 293 -150 395 -60 67 -180 145 -261 171 -75 23 -232 34 -297 19z m340
|
||||
-214 c91 -43 174 -154 175 -234 0 -18 -9 -51 -21 -73 -19 -37 -19 -42 -5 -64
|
||||
35 -54 12 -121 -48 -142 -22 -7 -47 -19 -55 -27 -9 -8 -41 -27 -71 -42 -50
|
||||
-26 -64 -29 -155 -29 -111 0 -152 14 -206 68 -49 49 -63 85 -64 162 0 59 4 78
|
||||
28 118 31 52 96 105 141 114 23 5 33 17 56 68 46 103 121 130 225 81z"/>
|
||||
<path d="M3985 3464 c-44 -7 -154 -44 -200 -67 -55 -28 -138 -96 -162 -132
|
||||
-10 -16 -39 -75 -64 -130 l-44 -100 0 -160 0 -160 45 -90 c53 -108 152 -214
|
||||
245 -264 59 -31 215 -71 281 -71 53 0 206 40 255 67 98 53 203 161 247 253 53
|
||||
113 74 193 74 280 -1 304 -253 564 -557 575 -49 2 -103 1 -120 -1z m311 -220
|
||||
c129 -68 202 -209 160 -309 -15 -35 -15 -42 -1 -72 26 -55 -3 -118 -59 -129
|
||||
-19 -3 -43 -15 -53 -26 -26 -29 -99 -64 -165 -78 -45 -10 -69 -10 -120 -1 -74
|
||||
15 -113 37 -161 91 -110 120 -50 331 109 385 24 8 44 23 52 39 6 14 18 38 25
|
||||
53 33 72 127 93 213 47z"/>
|
||||
<path d="M487 3394 c-21 -12 -27 -21 -25 -40 2 -14 7 -26 12 -27 14 -3 48 48
|
||||
44 66 -3 14 -6 14 -31 1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 705 KiB |
@@ -0,0 +1,11 @@
|
||||
Model Information:
|
||||
* title: Lupine Plant
|
||||
* source: https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439
|
||||
* author: rufusrockwell (https://sketchfab.com/rufusrockwell)
|
||||
|
||||
Model License:
|
||||
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
* requirements: Author must be credited. Commercial use is allowed.
|
||||
|
||||
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||
This work is based on "Lupine Plant" (https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439) by rufusrockwell (https://sketchfab.com/rufusrockwell) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
BIN
android/app/src/main/assets/public/models/lupine_plant/scene.bin
Normal file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 2,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
41.3074951171875,
|
||||
40.37548828125,
|
||||
87.85917663574219
|
||||
],
|
||||
"min": [
|
||||
-35.245540618896484,
|
||||
-36.895416259765625,
|
||||
-0.9094290137290955
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 33108,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9999382495880127,
|
||||
0.9986748695373535,
|
||||
0.9985831379890442
|
||||
],
|
||||
"min": [
|
||||
-0.9998949766159058,
|
||||
-0.9975876212120056,
|
||||
-0.411094069480896
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 3,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
0.9987699389457703,
|
||||
0.9998998045921326,
|
||||
0.9577858448028564,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-0.9987726807594299,
|
||||
-0.9990445971488953,
|
||||
-0.999801516532898,
|
||||
1.0
|
||||
],
|
||||
"type": "VEC4"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"componentType": 5126,
|
||||
"count": 2759,
|
||||
"max": [
|
||||
1.0061479806900024,
|
||||
0.9993550181388855
|
||||
],
|
||||
"min": [
|
||||
0.00279300007969141,
|
||||
0.0011620000004768372
|
||||
],
|
||||
"type": "VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView": 0,
|
||||
"componentType": 5125,
|
||||
"count": 6378,
|
||||
"type": "SCALAR"
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"extras": {
|
||||
"author": "rufusrockwell (https://sketchfab.com/rufusrockwell)",
|
||||
"license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
|
||||
"source": "https://sketchfab.com/3d-models/lupine-plant-bf30f1110c174d4baedda0ed63778439",
|
||||
"title": "Lupine Plant"
|
||||
},
|
||||
"generator": "Sketchfab-12.68.0",
|
||||
"version": "2.0"
|
||||
},
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 25512,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 22072,
|
||||
"byteOffset": 25512,
|
||||
"byteStride": 8,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 66216,
|
||||
"byteOffset": 47584,
|
||||
"byteStride": 12,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteLength": 44144,
|
||||
"byteOffset": 113800,
|
||||
"byteStride": 16,
|
||||
"name": "floatBufferViews",
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 157944,
|
||||
"uri": "scene.bin"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "textures/lambert2SG_baseColor.png"
|
||||
},
|
||||
{
|
||||
"uri": "textures/lambert2SG_normal.png"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"alphaCutoff": 0.2,
|
||||
"alphaMode": "MASK",
|
||||
"doubleSided": true,
|
||||
"name": "lambert2SG",
|
||||
"normalTexture": {
|
||||
"index": 1
|
||||
},
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"name": "Object_0",
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 0,
|
||||
"TANGENT": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 4,
|
||||
"material": 0,
|
||||
"mode": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
2.220446049250313e-16,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
2.220446049250313e-16,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"name": "Sketchfab_model"
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
2
|
||||
],
|
||||
"name": "LupineSF.obj.cleaner.materialmerger.gles"
|
||||
},
|
||||
{
|
||||
"mesh": 0,
|
||||
"name": "Object_2"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9987,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"name": "Sketchfab_Scene",
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
},
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 4.7 MiB |
2
android/app/src/main/assets/public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
||||
170
android/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background>
|
||||
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
|
||||
</background>
|
||||
<foreground>
|
||||
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.12.0'
|
||||
classpath 'com.android.tools.build:gradle:8.11.0'
|
||||
classpath 'com.google.gms:google-services:4.4.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -20,4 +20,4 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.suppressUnsupportedCompileSdk=36
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ext {
|
||||
minSdkVersion = 22
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 36
|
||||
compileSdkVersion = 34
|
||||
targetSdkVersion = 34
|
||||
androidxActivityVersion = '1.8.0'
|
||||
androidxAppCompatVersion = '1.6.1'
|
||||
androidxCoordinatorLayoutVersion = '1.2.0'
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"icon": {
|
||||
"ios": {
|
||||
"source": "resources/ios/icon/icon.png",
|
||||
"target": "ios/App/App/Assets.xcassets/AppIcon.appiconset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/icon/icon.png",
|
||||
"target": "android/app/src/main/res"
|
||||
},
|
||||
"web": {
|
||||
"source": "resources/web/icon/icon.png",
|
||||
"target": "public/img/icons"
|
||||
}
|
||||
},
|
||||
"splash": {
|
||||
"ios": {
|
||||
"source": "resources/ios/splash/splash.png",
|
||||
"target": "ios/App/App/Assets.xcassets/Splash.imageset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/splash/splash.png",
|
||||
"target": "android/app/src/main/res"
|
||||
}
|
||||
},
|
||||
"splashDark": {
|
||||
"ios": {
|
||||
"source": "resources/ios/splash/splash_dark.png",
|
||||
"target": "ios/App/App/Assets.xcassets/SplashDark.imageset"
|
||||
},
|
||||
"android": {
|
||||
"source": "resources/android/splash/splash_dark.png",
|
||||
"target": "android/app/src/main/res"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,14 +57,13 @@
|
||||
]
|
||||
},
|
||||
"android": {
|
||||
"allowMixedContent": true,
|
||||
"allowMixedContent": false,
|
||||
"captureInput": true,
|
||||
"webContentsDebuggingEnabled": false,
|
||||
"allowNavigation": [
|
||||
"*.timesafari.app",
|
||||
"*.jsdelivr.net",
|
||||
"api.endorser.ch",
|
||||
"10.0.2.2:3000"
|
||||
"api.endorser.ch"
|
||||
]
|
||||
},
|
||||
"electron": {
|
||||
|
||||
@@ -54,16 +54,14 @@ server {
|
||||
}
|
||||
|
||||
# Handle API requests (if needed)
|
||||
# Note: Backend API is not currently deployed
|
||||
# Uncomment and configure when backend service is available
|
||||
# location /api/ {
|
||||
# limit_req zone=api burst=20 nodelay;
|
||||
# proxy_pass http://backend:3000;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://backend:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Handle health check
|
||||
location /health {
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
# - Static file caching optimization
|
||||
# - Security hardening
|
||||
|
||||
# user nginx; # Commented out - nginx runs as non-root user in container
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /tmp/nginx.pid; # Use /tmp for PID file to avoid permission issues
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
|
||||
@@ -54,16 +54,14 @@ server {
|
||||
}
|
||||
|
||||
# Handle API requests (if needed)
|
||||
# Note: Backend API is not currently deployed
|
||||
# Uncomment and configure when backend service is available
|
||||
# location /api/ {
|
||||
# limit_req zone=api burst=20 nodelay;
|
||||
# proxy_pass http://backend:3000;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# }
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
proxy_pass http://backend:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Handle health check
|
||||
location /health {
|
||||
|
||||
115
docs/README.md
@@ -1,115 +0,0 @@
|
||||
# TimeSafari Documentation
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-01-27
|
||||
**Status**: 🎯 **COMPLETE** - Documentation organized and structured
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
This documentation is organized into logical categories to ensure easy navigation and maintenance. Each folder contains no more than 7 items to maintain clarity and usability.
|
||||
|
||||
### 📚 User Guides (`user-guides/`)
|
||||
Documentation for end users and potential users of TimeSafari:
|
||||
- User Guide - Comprehensive explanation of TimeSafari's purpose and features
|
||||
- Quick Start Guide - Immediate actionable steps for new users
|
||||
- Real-World Examples - Concrete stories of community transformation
|
||||
|
||||
### 🔧 Build System (`build-system/`)
|
||||
Documentation for building and deploying TimeSafari across platforms:
|
||||
- Build Systems Overview - Complete architecture of build processes
|
||||
- Build Troubleshooting - Common issues and solutions
|
||||
- Platform-specific build scripts and configurations
|
||||
- Auto-run and automation guides
|
||||
|
||||
### 🔄 Migration (`migration/`)
|
||||
Documentation for the database migration from Dexie to SQLite:
|
||||
- Migration progress tracking and assessments
|
||||
- Migration templates and best practices
|
||||
- Component migration testing and validation
|
||||
- Migration tools and utilities
|
||||
|
||||
### 💻 Development (`development/`)
|
||||
Documentation for developers working on TimeSafari:
|
||||
- Domain configuration and setup
|
||||
- Development tools and utilities
|
||||
- Code standards and templates
|
||||
- Testing frameworks and practices
|
||||
|
||||
### 🏗️ Architecture (`architecture/`)
|
||||
High-level system design and architectural decisions:
|
||||
- System architecture overview
|
||||
- Design patterns and principles
|
||||
- Integration guides
|
||||
- Performance considerations
|
||||
|
||||
### 🧪 Testing (`testing/`)
|
||||
Testing documentation and procedures:
|
||||
- Test frameworks and tools
|
||||
- Testing strategies and methodologies
|
||||
- Quality assurance processes
|
||||
- Performance testing guidelines
|
||||
|
||||
### 📖 Examples (`examples/`)
|
||||
Code examples and implementation patterns:
|
||||
- Implementation examples
|
||||
- Best practice demonstrations
|
||||
- Integration examples
|
||||
- Troubleshooting examples
|
||||
|
||||
## Documentation Standards
|
||||
|
||||
### File Organization
|
||||
- **Maximum 7 items per folder**: Ensures easy navigation and maintenance
|
||||
- **Logical grouping**: Related documents are grouped together
|
||||
- **Clear naming**: File names clearly indicate content and purpose
|
||||
- **Version control**: All changes are tracked in git with proper commit messages
|
||||
|
||||
### Documentation Quality
|
||||
- **Rich documentation**: Comprehensive coverage at file, class, and method levels
|
||||
- **Consistent formatting**: Follows established markdown standards
|
||||
- **Regular updates**: Documentation is updated as code changes
|
||||
- **User-focused**: Content is written for the intended audience
|
||||
|
||||
### Maintenance
|
||||
- **Regular reviews**: Documentation is reviewed and updated regularly
|
||||
- **Feedback integration**: User feedback is incorporated into documentation
|
||||
- **Cross-references**: Related documents are properly linked
|
||||
- **Searchability**: Content is organized for easy discovery
|
||||
|
||||
## Getting Started
|
||||
|
||||
### For Users
|
||||
1. Start with the [Quick Start Guide](user-guides/quick-start-guide.md)
|
||||
2. Read the [User Guide](user-guides/user-guide.md) for comprehensive understanding
|
||||
3. Explore [Real-World Examples](user-guides/real-world-examples.md) for inspiration
|
||||
|
||||
### For Developers
|
||||
1. Review the [Build System Overview](build-system/build-systems-overview.md)
|
||||
2. Check [Development Setup](development/) for environment configuration
|
||||
3. Understand the [Migration Process](migration/) if working on database changes
|
||||
|
||||
### For Contributors
|
||||
1. Read the [Development Guidelines](development/)
|
||||
2. Review [Testing Procedures](testing/)
|
||||
3. Check [Architecture Decisions](architecture/)
|
||||
|
||||
## Contributing to Documentation
|
||||
|
||||
When adding or updating documentation:
|
||||
|
||||
1. **Choose the right folder**: Place documents in the most appropriate category
|
||||
2. **Follow naming conventions**: Use clear, descriptive file names
|
||||
3. **Maintain folder limits**: Create sub-folders if a folder exceeds 7 items
|
||||
4. **Update this README**: Add new categories or reorganize as needed
|
||||
5. **Version in git**: Commit documentation changes with clear messages
|
||||
|
||||
## Documentation Tools
|
||||
|
||||
- **Markdown**: All documentation uses markdown format
|
||||
- **Git**: Version control for all documentation changes
|
||||
- **Linting**: Markdown linting ensures consistent formatting
|
||||
- **Validation**: Regular checks ensure documentation accuracy
|
||||
|
||||
---
|
||||
|
||||
*This documentation structure is designed to scale with the project while maintaining clarity and usability.*
|
||||
@@ -1,338 +0,0 @@
|
||||
# Environment Variable Precedence and API Configuration
|
||||
|
||||
**Date:** August 4, 2025
|
||||
**Author:** Matthew Raymer
|
||||
|
||||
## Overview
|
||||
|
||||
This document explains the order of precedence for environment variables in the
|
||||
TimeSafari project, how `.env` files are used, and the API configuration scheme
|
||||
for different environments.
|
||||
|
||||
## Order of Precedence (Highest to Lowest)
|
||||
|
||||
### 1. Shell Script Overrides (Highest Priority)
|
||||
|
||||
Shell scripts can override environment variables for platform-specific needs:
|
||||
|
||||
```bash
|
||||
# scripts/common.sh - setup_build_env()
|
||||
if [ "$BUILD_MODE" = "development" ]; then
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://localhost:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://localhost:3000"
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Platform-Specific Overrides (High Priority)
|
||||
|
||||
Platform-specific build scripts can override for mobile development:
|
||||
|
||||
```bash
|
||||
# scripts/build-android.sh
|
||||
if [ "$BUILD_MODE" = "development" ]; then
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://10.0.2.2:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://10.0.2.2:3000"
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Environment-Specific .env Files (Medium Priority)
|
||||
|
||||
Environment-specific `.env` files provide environment-specific defaults:
|
||||
|
||||
```bash
|
||||
# .env.development, .env.test, .env.production
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000
|
||||
```
|
||||
|
||||
### 4. Fallback .env File (Low Priority)
|
||||
|
||||
General `.env` file provides project-wide defaults:
|
||||
|
||||
```bash
|
||||
# .env (if exists)
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
|
||||
```
|
||||
|
||||
### 5. app.ts Constants (Lowest Priority - Fallback)
|
||||
|
||||
Hardcoded constants in `src/constants/app.ts` provide safety nets:
|
||||
|
||||
```typescript
|
||||
export const DEFAULT_ENDORSER_API_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_ENDORSER_API_SERVER ||
|
||||
AppString.PROD_ENDORSER_API_SERVER;
|
||||
```
|
||||
|
||||
## Build Process Flow
|
||||
|
||||
### 1. Shell Scripts Set Base Values
|
||||
|
||||
```bash
|
||||
# scripts/common.sh
|
||||
setup_build_env() {
|
||||
if [ "$BUILD_MODE" = "development" ]; then
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://localhost:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://localhost:3000"
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Platform-Specific Overrides
|
||||
|
||||
```bash
|
||||
# scripts/build-android.sh
|
||||
if [ "$BUILD_MODE" = "development" ]; then
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://10.0.2.2:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://10.0.2.2:3000"
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Load .env Files
|
||||
|
||||
```bash
|
||||
# scripts/build-web.sh
|
||||
local env_file=".env.$BUILD_MODE" # .env.development, .env.test, .env.production
|
||||
if [ -f "$env_file" ]; then
|
||||
load_env_file "$env_file"
|
||||
fi
|
||||
|
||||
# Fallback to .env
|
||||
if [ -f ".env" ]; then
|
||||
load_env_file ".env"
|
||||
fi
|
||||
```
|
||||
|
||||
### 4. Vite Processes Environment
|
||||
|
||||
```typescript
|
||||
// vite.config.common.mts
|
||||
dotenv.config(); // Loads .env files
|
||||
```
|
||||
|
||||
### 5. Application Uses Values
|
||||
|
||||
```typescript
|
||||
// src/constants/app.ts
|
||||
export const DEFAULT_ENDORSER_API_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_ENDORSER_API_SERVER ||
|
||||
AppString.PROD_ENDORSER_API_SERVER;
|
||||
```
|
||||
|
||||
## API Configuration Scheme
|
||||
|
||||
### Environment Configuration Summary
|
||||
|
||||
| Environment | Endorser API (Claims) | Partner API | Image API |
|
||||
|-------------|----------------------|-------------|-----------|
|
||||
| **Development** | `http://localhost:3000` | `http://localhost:3000` | `https://image-api.timesafari.app` |
|
||||
| **Test** | `https://test-api.endorser.ch` | `https://test-partner-api.endorser.ch` | `https://image-api.timesafari.app` |
|
||||
| **Production** | `https://api.endorser.ch` | `https://partner-api.endorser.ch` | `https://image-api.timesafari.app` |
|
||||
|
||||
### Mobile Development Overrides
|
||||
|
||||
#### Android Development
|
||||
|
||||
- **Emulator**: `http://10.0.2.2:3000` (Android emulator default)
|
||||
- **Physical Device**: `http://{CUSTOM_IP}:3000` (Custom IP for physical device)
|
||||
|
||||
#### iOS Development
|
||||
|
||||
- **Simulator**: `http://localhost:3000` (iOS simulator default)
|
||||
- **Physical Device**: `http://{CUSTOM_IP}:3000` (Custom IP for physical device)
|
||||
|
||||
## .env File Structure
|
||||
|
||||
### .env.development
|
||||
```bash
|
||||
# ==========================================
|
||||
# DEVELOPMENT ENVIRONMENT CONFIGURATION
|
||||
# ==========================================
|
||||
# API Server Configuration:
|
||||
# - Endorser API (Claims): Local development server
|
||||
# - Partner API: Local development server (aligned with claims)
|
||||
# - Image API: Test server (shared for development)
|
||||
# ==========================================
|
||||
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# iOS doesn't like spaces in the app title.
|
||||
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 production).
|
||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
|
||||
|
||||
# API Servers (Development - Local)
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=http://localhost:3000
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=http://localhost:3000
|
||||
|
||||
# Image API (Test server for development)
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
|
||||
|
||||
# Push Server (disabled for localhost)
|
||||
#VITE_DEFAULT_PUSH_SERVER... can't be set up with localhost domain
|
||||
|
||||
# Feature Flags
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
```
|
||||
|
||||
### .env.test
|
||||
```bash
|
||||
# ==========================================
|
||||
# TEST ENVIRONMENT CONFIGURATION
|
||||
# ==========================================
|
||||
# API Server Configuration:
|
||||
# - Endorser API (Claims): Test server
|
||||
# - Partner API: Test server (aligned with claims)
|
||||
# - Image API: Test server
|
||||
# ==========================================
|
||||
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# iOS doesn't like spaces in the app title.
|
||||
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).
|
||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HWE8FWHQ1YGP7GFZYYPS272F
|
||||
|
||||
# API Servers (Test Environment)
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=https://test-partner-api.endorser.ch
|
||||
|
||||
# Image API (Test server)
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app
|
||||
|
||||
# Push Server (Test)
|
||||
VITE_DEFAULT_PUSH_SERVER=https://test.timesafari.app
|
||||
|
||||
# Feature Flags
|
||||
VITE_PASSKEYS_ENABLED=true
|
||||
```
|
||||
|
||||
### .env.production
|
||||
```bash
|
||||
# ==========================================
|
||||
# PRODUCTION ENVIRONMENT CONFIGURATION
|
||||
# ==========================================
|
||||
# API Server Configuration:
|
||||
# - Endorser API (Claims): Production server
|
||||
# - Partner API: Production server (aligned with claims)
|
||||
# - Image API: Production server
|
||||
# ==========================================
|
||||
|
||||
# Only the variables that start with VITE_ are seen in the application import.meta.env in Vue.
|
||||
|
||||
# App Server
|
||||
VITE_APP_SERVER=https://timesafari.app
|
||||
|
||||
# This is the claim ID for actions in the BVC project.
|
||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H
|
||||
|
||||
# API Servers (Production Environment)
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
|
||||
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
|
||||
|
||||
# Image API (Production server)
|
||||
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
|
||||
|
||||
# Push Server (Production)
|
||||
VITE_DEFAULT_PUSH_SERVER=https://timesafari.app
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
### 1. API Alignment
|
||||
- **Partner API** values follow the same pattern as **Claim API** (Endorser API)
|
||||
- Both APIs use the same environment-specific endpoints
|
||||
- This ensures consistency across the application
|
||||
|
||||
### 2. Platform Flexibility
|
||||
- Shell scripts can override for platform-specific needs
|
||||
- Android emulator uses `10.0.2.2:3000`
|
||||
- iOS simulator uses `localhost:3000`
|
||||
- Physical devices use custom IP addresses
|
||||
|
||||
### 3. Environment Isolation
|
||||
- Each environment has its own `.env` file
|
||||
- Test environment uses test APIs
|
||||
- Development environment uses local APIs
|
||||
- Production environment uses production APIs
|
||||
|
||||
### 4. Safety Nets
|
||||
- Hardcoded constants in `app.ts` provide fallbacks
|
||||
- Multiple layers of configuration prevent failures
|
||||
- Clear precedence order ensures predictable behavior
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Development Build
|
||||
```bash
|
||||
# Uses .env.development + shell script overrides
|
||||
npm run build:web -- --mode development
|
||||
```
|
||||
|
||||
### Test Build
|
||||
```bash
|
||||
# Uses .env.test + shell script overrides
|
||||
npm run build:web -- --mode test
|
||||
```
|
||||
|
||||
### Production Build
|
||||
```bash
|
||||
# Uses .env.production + shell script overrides
|
||||
npm run build:web -- --mode production
|
||||
```
|
||||
|
||||
### Android Development
|
||||
```bash
|
||||
# Uses .env.development + Android-specific overrides
|
||||
./scripts/build-android.sh --dev
|
||||
```
|
||||
|
||||
### iOS Development
|
||||
```bash
|
||||
# Uses .env.development + iOS-specific overrides
|
||||
./scripts/build-ios.sh --dev
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Environment Variable Debugging
|
||||
```bash
|
||||
# Show current environment variables
|
||||
./scripts/build-web.sh --env
|
||||
|
||||
# Check specific variable
|
||||
echo $VITE_DEFAULT_ENDORSER_API_SERVER
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Wrong API Server**: Check if shell script overrides are correct
|
||||
2. **Missing .env File**: Ensure environment-specific .env file exists
|
||||
3. **Platform-Specific Issues**: Verify platform overrides in build scripts
|
||||
4. **Vite Not Loading**: Check if `dotenv.config()` is called
|
||||
|
||||
### Validation
|
||||
```bash
|
||||
# Validate environment configuration
|
||||
npm run test-env
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use environment-specific .env files** for different environments
|
||||
2. **Keep shell script overrides minimal** and platform-specific
|
||||
3. **Document API alignment** in .env file headers
|
||||
4. **Use hardcoded fallbacks** in `app.ts` for safety
|
||||
5. **Test all environments** before deployment
|
||||
6. **Validate configuration** with test scripts
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Build System Overview](../build-system/README.md)
|
||||
- [Android Custom API IP](../platforms/android-custom-api-ip.md)
|
||||
- [API Configuration](../api-configuration.md)
|
||||
- [Environment Setup](../environment-setup.md)
|
||||
@@ -1,322 +0,0 @@
|
||||
# Mobile Custom API IP Configuration
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-01-27
|
||||
**Status**: ✅ **COMPLETE** - Custom API IP support for physical device development
|
||||
|
||||
## Overview
|
||||
|
||||
When deploying TimeSafari to physical Android devices during development, you may need to specify a custom IP address for the claim API server. This is necessary because physical devices cannot access `localhost` or `10.0.2.2` (Android emulator IP) to reach your local development server.
|
||||
|
||||
## Problem
|
||||
|
||||
During mobile development:
|
||||
- **Android Emulator**: Uses `10.0.2.2:3000` to access host machine's localhost (Android emulator default)
|
||||
- **iOS Simulator**: Uses `localhost:3000` to access host machine's localhost (iOS simulator default)
|
||||
- **Physical Devices**: Cannot access `localhost` or `10.0.2.2` - needs actual IP address for network access
|
||||
|
||||
## Solution
|
||||
|
||||
The mobile build system uses platform-appropriate defaults and supports specifying a custom IP address for the claim API server when building for physical devices:
|
||||
- **Android**: Defaults to `10.0.2.2:3000` for emulator development
|
||||
- **iOS**: Uses Capacitor default (`localhost:3000`) for simulator development
|
||||
|
||||
## Usage
|
||||
|
||||
### Command Line Usage
|
||||
|
||||
```bash
|
||||
# Android - Default behavior (uses 10.0.2.2 for emulator)
|
||||
./scripts/build-android.sh --dev
|
||||
|
||||
# Android - Custom IP for physical device
|
||||
./scripts/build-android.sh --dev --api-ip 192.168.1.100
|
||||
|
||||
# iOS - Default behavior (uses localhost for simulator)
|
||||
./scripts/build-ios.sh --dev
|
||||
|
||||
# iOS - Custom IP for physical device
|
||||
./scripts/build-ios.sh --dev --api-ip 192.168.1.100
|
||||
|
||||
# Test environment with custom IP
|
||||
./scripts/build-android.sh --test --api-ip 192.168.1.100
|
||||
./scripts/build-ios.sh --test --api-ip 192.168.1.100
|
||||
|
||||
# Build and auto-run with custom IP
|
||||
./scripts/build-android.sh --dev --api-ip 192.168.1.100 --auto-run
|
||||
./scripts/build-ios.sh --dev --api-ip 192.168.1.100 --auto-run
|
||||
```
|
||||
|
||||
### NPM Scripts
|
||||
|
||||
```bash
|
||||
# Android - Default development build (uses 10.0.2.2 for emulator)
|
||||
npm run build:android:dev
|
||||
|
||||
# Android - Development build with custom IP (requires IP parameter)
|
||||
npm run build:android:dev:custom 192.168.1.100
|
||||
|
||||
# iOS - Default development build (uses localhost for simulator)
|
||||
npm run build:ios:dev
|
||||
|
||||
# iOS - Development build with custom IP (requires IP parameter)
|
||||
npm run build:ios:dev:custom 192.168.1.100
|
||||
|
||||
# Test builds with custom IP (requires IP parameter)
|
||||
npm run build:android:test:custom 192.168.1.100
|
||||
npm run build:ios:test:custom 192.168.1.100
|
||||
|
||||
# Development build + auto-run with custom IP
|
||||
npm run build:android:dev:run:custom 192.168.1.100
|
||||
npm run build:ios:dev:run:custom 192.168.1.100
|
||||
|
||||
# Test build + auto-run with custom IP
|
||||
npm run build:android:test:run:custom 192.168.1.100
|
||||
npm run build:ios:test:run:custom 192.168.1.100
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Scenario 1: Development on Simulator/Emulator (Default)
|
||||
|
||||
```bash
|
||||
# Android - Default behavior - uses 10.0.2.2 for emulator
|
||||
npm run build:android:dev
|
||||
|
||||
# iOS - Default behavior - uses localhost for simulator
|
||||
npm run build:ios:dev
|
||||
|
||||
# Build and immediately run on simulator/emulator
|
||||
npm run build:android:dev:run
|
||||
npm run build:ios:dev:run
|
||||
```
|
||||
|
||||
### Scenario 2: Development on Physical Device
|
||||
|
||||
```bash
|
||||
# Your development server is running on 192.168.1.50:3000
|
||||
npm run build:android:dev:custom 192.168.1.50
|
||||
npm run build:ios:dev:custom 192.168.1.50
|
||||
|
||||
# Build and immediately run on device
|
||||
npm run build:android:dev:run:custom 192.168.1.50
|
||||
npm run build:ios:dev:run:custom 192.168.1.50
|
||||
```
|
||||
|
||||
### Scenario 3: Testing on Physical Device
|
||||
|
||||
```bash
|
||||
# Your test server is running on 192.168.1.75:3000
|
||||
npm run build:android:test:custom 192.168.1.75
|
||||
npm run build:ios:test:custom 192.168.1.75
|
||||
|
||||
# Build and immediately run on device
|
||||
npm run build:android:test:run:custom 192.168.1.75
|
||||
npm run build:ios:test:run:custom 192.168.1.75
|
||||
```
|
||||
|
||||
### Scenario 4: Direct Script Usage
|
||||
|
||||
```bash
|
||||
# Default behavior (uses platform-appropriate defaults)
|
||||
./scripts/build-android.sh --dev --studio
|
||||
./scripts/build-ios.sh --dev --studio
|
||||
|
||||
# Custom IP for physical device
|
||||
./scripts/build-android.sh --dev --api-ip 192.168.1.100 --studio
|
||||
./scripts/build-ios.sh --dev --api-ip 192.168.1.100 --studio
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### Environment Variable Override
|
||||
|
||||
The build system handles API server configuration as follows:
|
||||
|
||||
1. **Android default**: Uses Android emulator default (`http://10.0.2.2:3000`)
|
||||
2. **iOS default**: Uses Capacitor default (`http://localhost:3000`)
|
||||
3. **Custom IP specified**: Overrides with `http://<custom-ip>:3000` for physical device development
|
||||
4. **Maintains other APIs**: Image and Partner APIs remain at production URLs
|
||||
5. **Logs the configuration**: Shows which IP is being used in build logs
|
||||
|
||||
### Build Process
|
||||
|
||||
```bash
|
||||
# Development mode with Android emulator default (10.0.2.2)
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://10.0.2.2:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://10.0.2.2:3000"
|
||||
npm run build:capacitor -- --mode development
|
||||
|
||||
# Development mode with iOS simulator default (localhost)
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://localhost:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://localhost:3000"
|
||||
npm run build:capacitor -- --mode development
|
||||
|
||||
# Development mode with custom IP
|
||||
export VITE_DEFAULT_ENDORSER_API_SERVER="http://192.168.1.100:3000"
|
||||
export VITE_DEFAULT_PARTNER_API_SERVER="http://192.168.1.100:3000"
|
||||
npm run build:capacitor -- --mode development
|
||||
```
|
||||
|
||||
### Default Behavior
|
||||
|
||||
- **Android (no `--api-ip`)**: Uses Android emulator default (`10.0.2.2:3000`)
|
||||
- **iOS (no `--api-ip`)**: Uses Capacitor default (`localhost:3000`)
|
||||
- **Custom IP specified**: Uses provided IP address for physical device development
|
||||
- **Invalid IP format**: Build will fail with clear error message
|
||||
- **Network unreachable**: App will show connection errors at runtime
|
||||
|
||||
## Finding Your IP Address
|
||||
|
||||
### On Linux/macOS
|
||||
|
||||
```bash
|
||||
# Find your local IP address
|
||||
ifconfig | grep "inet " | grep -v 127.0.0.1
|
||||
# or
|
||||
ip addr show | grep "inet " | grep -v 127.0.0.1
|
||||
```
|
||||
|
||||
### On Windows
|
||||
|
||||
```bash
|
||||
# Find your local IP address
|
||||
ipconfig | findstr "IPv4"
|
||||
```
|
||||
|
||||
### Common Network Patterns
|
||||
|
||||
- **Home WiFi**: Usually `192.168.1.x` or `192.168.0.x`
|
||||
- **Office Network**: May be `10.x.x.x` or `172.16.x.x`
|
||||
- **Mobile Hotspot**: Often `192.168.43.x`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Device Cannot Connect to API
|
||||
|
||||
```bash
|
||||
# Check if your IP is accessible
|
||||
ping 192.168.1.100
|
||||
|
||||
# Check if port 3000 is open
|
||||
telnet 192.168.1.100 3000
|
||||
```
|
||||
|
||||
#### 2. Build Fails with Invalid IP
|
||||
|
||||
```bash
|
||||
# Ensure IP format is correct
|
||||
./scripts/build-android.sh --dev --api-ip 192.168.1.100 # ✅ Correct
|
||||
./scripts/build-android.sh --dev --api-ip localhost # ❌ Wrong
|
||||
```
|
||||
|
||||
#### 3. Firewall Blocking Connection
|
||||
|
||||
```bash
|
||||
# Check firewall settings
|
||||
sudo ufw status # Ubuntu/Debian
|
||||
sudo firewall-cmd --list-all # CentOS/RHEL
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```bash
|
||||
# Enable verbose logging
|
||||
./scripts/build-android.sh --dev --api-ip 192.168.1.100 --verbose
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use Consistent IP Addresses
|
||||
|
||||
```bash
|
||||
# Create aliases for common development scenarios
|
||||
alias build-dev="npm run build:android:dev:custom 192.168.1.100"
|
||||
alias build-test="npm run build:android:test:custom 192.168.1.100"
|
||||
```
|
||||
|
||||
### 2. Document Your Setup
|
||||
|
||||
```bash
|
||||
# Create a development setup file
|
||||
echo "DEV_API_IP=192.168.1.100" > .env.development
|
||||
echo "TEST_API_IP=192.168.1.100" >> .env.development
|
||||
```
|
||||
|
||||
### 3. Network Security
|
||||
|
||||
- Ensure your development server is only accessible on your local network
|
||||
- Use HTTPS in production environments
|
||||
- Consider VPN for remote development scenarios
|
||||
|
||||
### 4. Team Development
|
||||
|
||||
```bash
|
||||
# Share IP configuration with team
|
||||
# Add to .env.example
|
||||
DEV_API_IP=192.168.1.100
|
||||
TEST_API_IP=192.168.1.100
|
||||
```
|
||||
|
||||
## Integration with CI/CD
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```yaml
|
||||
# Example CI/CD configuration
|
||||
variables:
|
||||
DEV_API_IP: "192.168.1.100"
|
||||
TEST_API_IP: "192.168.1.100"
|
||||
|
||||
build:
|
||||
script:
|
||||
- npm run build:android:dev:custom $DEV_API_IP
|
||||
```
|
||||
|
||||
### Automated Testing
|
||||
|
||||
```bash
|
||||
# Test with different IP configurations
|
||||
npm run build:android:test:custom 192.168.1.100
|
||||
npm run build:android:test:custom 10.0.0.100
|
||||
```
|
||||
|
||||
## Migration from Legacy
|
||||
|
||||
### Previous Workarounds
|
||||
|
||||
Before this feature, developers had to:
|
||||
1. Manually edit environment files
|
||||
2. Use different build configurations
|
||||
3. Modify source code for IP addresses
|
||||
|
||||
### New Approach
|
||||
|
||||
```bash
|
||||
# Simple one-liner
|
||||
npm run build:android:dev:custom 192.168.1.100
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
|
||||
1. **IP Validation**: Automatic IP format validation
|
||||
2. **Network Discovery**: Auto-detect available IP addresses
|
||||
3. **Port Configuration**: Support for custom ports
|
||||
4. **Multiple APIs**: Support for custom IPs for all API endpoints
|
||||
|
||||
### Integration Opportunities
|
||||
|
||||
1. **Docker Integration**: Automatic IP detection in containerized environments
|
||||
2. **Network Profiles**: Save and reuse common network configurations
|
||||
3. **Hot Reload**: Automatic rebuild when IP changes
|
||||
|
||||
---
|
||||
|
||||
**Status**: Complete and ready for production use
|
||||
**Last Updated**: 2025-01-27
|
||||
**Version**: 1.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
@@ -1,84 +0,0 @@
|
||||
# Contact Sharing - URL Solution
|
||||
|
||||
## Overview
|
||||
|
||||
Simple implementation to switch ContactQRScanShowView from copying QR value (CSV) to copying a URL for better user experience.
|
||||
|
||||
## Problem
|
||||
|
||||
The ContactQRScanShowView was copying QR value (CSV content) to clipboard instead of a URL, making contact sharing less user-friendly.
|
||||
|
||||
## Solution
|
||||
|
||||
Updated the `onCopyUrlToClipboard()` method in ContactQRScanShowView.vue to generate and copy a URL instead of the QR value.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### ContactQRScanShowView.vue
|
||||
|
||||
**Added Imports:**
|
||||
```typescript
|
||||
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
```
|
||||
|
||||
**Updated Method:**
|
||||
```typescript
|
||||
async onCopyUrlToClipboard() {
|
||||
try {
|
||||
// Generate URL for sharing
|
||||
const account = (await libsUtil.retrieveFullyDecryptedAccount(
|
||||
this.activeDid,
|
||||
)) as Account;
|
||||
const jwtUrl = await generateEndorserJwtUrlForAccount(
|
||||
account,
|
||||
this.isRegistered,
|
||||
this.givenName,
|
||||
this.profileImageUrl,
|
||||
true,
|
||||
);
|
||||
|
||||
// Copy the URL to clipboard
|
||||
useClipboard()
|
||||
.copy(jwtUrl)
|
||||
.then(() => {
|
||||
this.notify.toast(
|
||||
"Copied",
|
||||
NOTIFY_QR_URL_COPIED.message,
|
||||
QR_TIMEOUT_MEDIUM,
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Failed to generate contact URL:", error);
|
||||
this.notify.error("Failed to generate contact URL. Please try again.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Better UX**: Recipients can click the URL to add contact directly
|
||||
2. **Consistency**: Both ContactQRScanShowView and ContactQRScanFullView now use URL format
|
||||
3. **Error Handling**: Graceful fallback if URL generation fails
|
||||
4. **Simple**: Minimal changes, no new components needed
|
||||
|
||||
## User Experience
|
||||
|
||||
**Before:**
|
||||
- Click QR code → Copy CSV data to clipboard
|
||||
- Recipient must paste CSV into input field
|
||||
|
||||
**After:**
|
||||
- Click QR code → Copy URL to clipboard
|
||||
- Recipient clicks URL → Contact added automatically
|
||||
|
||||
## Testing
|
||||
|
||||
- ✅ Linting passes
|
||||
- ✅ Error handling implemented
|
||||
- ✅ Consistent with ContactQRScanFullView behavior
|
||||
- ✅ Maintains existing notification system
|
||||
|
||||
## Deployment
|
||||
|
||||
Ready for deployment. No breaking changes, maintains backward compatibility.
|
||||
@@ -1,221 +0,0 @@
|
||||
# Domain Configuration System
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-01-27
|
||||
**Status**: ✅ **UPDATED** - Simplified to use APP_SERVER for all functionality
|
||||
|
||||
## Overview
|
||||
|
||||
TimeSafari uses a centralized domain configuration system to ensure consistent
|
||||
URL generation across all environments. This system provides a single point of
|
||||
control for domain changes and uses environment-specific configuration for all
|
||||
functionality including sharing.
|
||||
|
||||
## Problem Solved
|
||||
|
||||
### Issue: Inconsistent Domain Usage
|
||||
|
||||
Previously, the system used separate constants for different types of URLs:
|
||||
|
||||
- **Internal Operations**: Used `APP_SERVER` (environment-specific)
|
||||
- **Sharing**: Used separate constants (removed)
|
||||
|
||||
This created complexity and confusion about when to use which constant.
|
||||
|
||||
### Solution: Unified Domain Configuration
|
||||
|
||||
All functionality now uses the `APP_SERVER` constant, which provides
|
||||
environment-specific URLs that can be configured per environment.
|
||||
|
||||
## Implementation
|
||||
|
||||
### Core Configuration
|
||||
|
||||
The domain configuration is centralized in `src/constants/app.ts`:
|
||||
|
||||
```typescript
|
||||
export enum AppString {
|
||||
// ... other constants ...
|
||||
PROD_PUSH_SERVER = "https://timesafari.app",
|
||||
// ... other constants ...
|
||||
}
|
||||
|
||||
// Environment-specific server URL for all functionality
|
||||
export const APP_SERVER =
|
||||
import.meta.env.VITE_APP_SERVER || "https://timesafari.app";
|
||||
```
|
||||
|
||||
### Usage Pattern
|
||||
|
||||
All components that generate URLs follow this pattern:
|
||||
|
||||
```typescript
|
||||
import { APP_SERVER } from "@/constants/app";
|
||||
|
||||
// In component class
|
||||
APP_SERVER = APP_SERVER;
|
||||
|
||||
// In methods
|
||||
const deepLink = `${APP_SERVER}/deep-link/claim/${claimId}`;
|
||||
```
|
||||
|
||||
### Components Updated
|
||||
|
||||
The following components and services use `APP_SERVER`:
|
||||
|
||||
#### Views
|
||||
- `ClaimView.vue` - Claim and certificate links
|
||||
- `ProjectViewView.vue` - Project copy links
|
||||
- `ConfirmGiftView.vue` - Confirm gift deep links
|
||||
- `UserProfileView.vue` - Profile copy links
|
||||
- `InviteOneView.vue` - Invite link generation
|
||||
- `ContactsView.vue` - Contact import links
|
||||
- `OnboardMeetingSetupView.vue` - Meeting members links
|
||||
|
||||
#### Components
|
||||
- `HiddenDidDialog.vue` - Hidden DID dialog links
|
||||
|
||||
#### Services
|
||||
- `endorserServer.ts` - Contact import confirm links
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Environment-Specific Configuration
|
||||
|
||||
The system uses environment variables to configure domains:
|
||||
|
||||
```bash
|
||||
# Development
|
||||
VITE_APP_SERVER=http://localhost:8080
|
||||
|
||||
# Test
|
||||
VITE_APP_SERVER=https://test.timesafari.app
|
||||
|
||||
# Production
|
||||
VITE_APP_SERVER=https://timesafari.app
|
||||
```
|
||||
|
||||
### Changing the Domain
|
||||
|
||||
To change the domain for all functionality:
|
||||
|
||||
1. **Update environment variables** for the target environment:
|
||||
```bash
|
||||
VITE_APP_SERVER=https://your-new-domain.com
|
||||
```
|
||||
|
||||
2. **Rebuild the application** for all platforms:
|
||||
```bash
|
||||
npm run build:web
|
||||
npm run build:capacitor
|
||||
npm run build:electron
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
### ✅ Simplified Configuration
|
||||
|
||||
- Single constant for all URL generation
|
||||
- No confusion about which constant to use
|
||||
- Consistent behavior across all functionality
|
||||
|
||||
### ✅ Environment Flexibility
|
||||
|
||||
- Easy to configure different domains per environment
|
||||
- Support for development, test, and production environments
|
||||
- Environment-specific sharing URLs when needed
|
||||
|
||||
### ✅ Maintainability
|
||||
|
||||
- Single source of truth for domain configuration
|
||||
- Easy to change domain across entire application
|
||||
- Clear pattern for implementing new URL functionality
|
||||
|
||||
### ✅ Developer Experience
|
||||
|
||||
- Simple, consistent pattern for URL generation
|
||||
- Clear documentation and examples
|
||||
- Type-safe configuration with TypeScript
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing
|
||||
|
||||
1. **Development Environment**:
|
||||
```bash
|
||||
npm run dev
|
||||
# Navigate to any page with copy link buttons
|
||||
# Verify links use configured domain
|
||||
```
|
||||
|
||||
2. **Production Build**:
|
||||
```bash
|
||||
npm run build:web
|
||||
# Deploy and test sharing functionality
|
||||
# Verify all links work correctly
|
||||
```
|
||||
|
||||
### Automated Testing
|
||||
|
||||
The implementation includes comprehensive linting to ensure:
|
||||
|
||||
- All components properly import `APP_SERVER`
|
||||
- No hardcoded URLs in functionality
|
||||
- Consistent usage patterns across the codebase
|
||||
|
||||
## Implementation Pattern
|
||||
|
||||
### Current Approach
|
||||
|
||||
```typescript
|
||||
// ✅ Single constant for all functionality
|
||||
import { APP_SERVER } from "@/constants/app";
|
||||
const shareLink = `${APP_SERVER}/deep-link/claim/123`;
|
||||
const apiUrl = `${APP_SERVER}/api/claim/123`;
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Potential Improvements
|
||||
|
||||
1. **Environment-Specific Sharing Domains**:
|
||||
```typescript
|
||||
export const getShareDomain = () => {
|
||||
if (import.meta.env.PROD) {
|
||||
return AppString.PROD_PUSH_SERVER;
|
||||
}
|
||||
return AppString.TEST1_PUSH_SERVER; // Use test domain for dev sharing
|
||||
};
|
||||
```
|
||||
|
||||
2. **Dynamic Domain Detection**:
|
||||
```typescript
|
||||
export const SHARE_DOMAIN =
|
||||
import.meta.env.VITE_SHARE_DOMAIN || AppString.PROD_PUSH_SERVER;
|
||||
```
|
||||
|
||||
3. **Platform-Specific Domains**:
|
||||
|
||||
```typescript
|
||||
export const getPlatformShareDomain = () => {
|
||||
const platform = process.env.VITE_PLATFORM;
|
||||
switch (platform) {
|
||||
case 'web': return AppString.PROD_PUSH_SERVER;
|
||||
case 'capacitor': return AppString.PROD_PUSH_SERVER;
|
||||
case 'electron': return AppString.PROD_PUSH_SERVER;
|
||||
default: return AppString.PROD_PUSH_SERVER;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Build Systems Overview](build-systems-overview.md) - Environment configuration
|
||||
- [Constants and Configuration](src/constants/app.ts) - Core constants
|
||||
- [Migration Guide](doc/migration-to-wa-sqlite.md) - Database migration context
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-01-27
|
||||
**Version**: 2.0
|
||||
**Maintainer**: Matthew Raymer
|
||||
@@ -1,113 +0,0 @@
|
||||
# $updateSettings to $saveSettings Consolidation Plan
|
||||
|
||||
## Overview
|
||||
Consolidate `$updateSettings` method into `$saveSettings` to eliminate code duplication and improve maintainability. The `$updateSettings` method is currently just a thin wrapper around `$saveSettings` and `$saveUserSettings`, providing no additional functionality.
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Current Implementation
|
||||
```typescript
|
||||
// Current $updateSettings - just a wrapper
|
||||
async $updateSettings(changes: Partial<Settings>, did?: string): Promise<boolean> {
|
||||
try {
|
||||
if (did) {
|
||||
return await this.$saveUserSettings(did, changes);
|
||||
} else {
|
||||
return await this.$saveSettings(changes);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("[PlatformServiceMixin] Error updating settings:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Usage Statistics
|
||||
- **$updateSettings**: 42 references across codebase
|
||||
- **$saveSettings**: 38 references across codebase
|
||||
- **$saveUserSettings**: 12 references across codebase
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Documentation and Planning ✅
|
||||
- [x] Document current usage patterns
|
||||
- [x] Identify all call sites
|
||||
- [x] Create migration plan
|
||||
|
||||
### Phase 2: Implementation
|
||||
- [ ] Update `$saveSettings` to accept optional `did` parameter
|
||||
- [ ] Add error handling to `$saveSettings` (currently missing)
|
||||
- [ ] Deprecate `$updateSettings` with migration notice
|
||||
- [ ] Update all call sites to use `$saveSettings` directly
|
||||
|
||||
### Phase 3: Cleanup
|
||||
- [ ] Remove `$updateSettings` method
|
||||
- [ ] Update documentation
|
||||
- [ ] Update tests
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Enhanced $saveSettings Method
|
||||
```typescript
|
||||
async $saveSettings(changes: Partial<Settings>, did?: string): Promise<boolean> {
|
||||
try {
|
||||
// Convert settings for database storage
|
||||
const convertedChanges = this._convertSettingsForStorage(changes);
|
||||
|
||||
if (did) {
|
||||
// User-specific settings
|
||||
return await this.$saveUserSettings(did, convertedChanges);
|
||||
} else {
|
||||
// Default settings
|
||||
return await this.$saveSettings(convertedChanges);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("[PlatformServiceMixin] Error saving settings:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migration Benefits
|
||||
1. **Reduced Code Duplication**: Single method handles both use cases
|
||||
2. **Improved Maintainability**: One place to fix issues
|
||||
3. **Consistent Error Handling**: Unified error handling approach
|
||||
4. **Better Type Safety**: Single method signature to maintain
|
||||
|
||||
### Risk Assessment
|
||||
- **Low Risk**: `$updateSettings` is just a wrapper, no complex logic
|
||||
- **Backward Compatible**: Can maintain both methods during transition
|
||||
- **Testable**: Existing tests can be updated incrementally
|
||||
|
||||
## Call Site Migration Examples
|
||||
|
||||
### Before (using $updateSettings)
|
||||
```typescript
|
||||
await this.$updateSettings({ searchBoxes: [newSearchBox] });
|
||||
await this.$updateSettings({ filterFeedByNearby: false }, userDid);
|
||||
```
|
||||
|
||||
### After (using $saveSettings)
|
||||
```typescript
|
||||
await this.$saveSettings({ searchBoxes: [newSearchBox] });
|
||||
await this.$saveSettings({ filterFeedByNearby: false }, userDid);
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
1. **Unit Tests**: Update existing tests to use `$saveSettings`
|
||||
2. **Integration Tests**: Verify both default and user-specific settings work
|
||||
3. **Migration Tests**: Ensure searchBoxes conversion still works
|
||||
4. **Performance Tests**: Verify no performance regression
|
||||
|
||||
## Timeline
|
||||
- **Phase 1**: ✅ Complete
|
||||
- **Phase 2**: 1-2 days
|
||||
- **Phase 3**: 1 day
|
||||
- **Total**: 2-3 days
|
||||
|
||||
## Success Criteria
|
||||
- [ ] All existing functionality preserved
|
||||
- [ ] No performance regression
|
||||
- [ ] All tests passing
|
||||
- [ ] Reduced code duplication
|
||||
- [ ] Improved maintainability
|
||||