docs: reconcile documentation with reality (P3)
Make the project's documentation match the code and remove the sprawl. The docs
claimed Phase 2.8 (drug interactions) was 'planning/0%' and the backend '~91%
complete' — both wrong: 2.8 is implemented and live, plus the P0/P1 security
and test work is done. Five root CI/CD docs described a 'docker-build' CI job
that was removed; ~18 backend/ status snapshots and ~24 docs/implementation
duplicates cluttered the tree.
Deletions (85 files):
- Root: 4 stale CI/CD reports (CI-CD-{COMPLETION-REPORT,IMPLEMENTATION-SUMMARY,
STATUS-REPORT,FINAL-STATUS}.md) — all describe the removed docker-build job.
- backend/: 18 phase/build/fix snapshots and code-dump .txt files.
- docs/: the 3 one-time reorg reports; ~17 docs/implementation duplicates and
process artifacts; 4 stale docs/development CI docs + git snapshots;
redundant deployment/testing files.
- thoughts/: STATUS.md (said Phase 2.4 in-progress), superseded phase notes and
duplicative research inputs. tmp/ (928KB of CI debug logs, gitignored).
Moves (18 files):
- 9 genuine decision records -> docs/adr/ (Architecture Decision Records),
date-prefixes stripped, with an index README.
- 8 historical-but-valuable phase plans/specs + the old CI-CD-FINAL-SOLUTION ->
docs/archive/ (now-populated, with a README explaining it's superseded
material). thoughts/ tree removed.
Rewrites (13 files) to match reality:
- Drop the fake '% complete' figures everywhere in favor of Implemented /
In-Progress / Planned with concrete endpoint/feature lists.
- Phase 2.8 -> Implemented; add /api/interactions/* and /api/auth/{refresh,
logout} to the endpoint lists; fix 'Rust 1.93' -> edition 2021.
- Add a Security section (token_version validation, hashed refresh-token
persistence, fail-fast config, real-IP audit) and correct the test-coverage
and deployment claims to reality.
- New canonical docs/development/CI-CD.md (4 jobs: format/clippy/build/test,
mongo service, no docker-build + why).
- README, docs/README, product/{STATUS,ROADMAP,PROGRESS,README,introduction},
implementation/README, development/README, testing/README, AI_AGENT_GUIDE,
.cursorrules, .gooserules all updated.
Verified: greps for 'Phase 2.8 (Planning)', 'PLANNING (0%)', 'Rust 1.93',
'91%/10%/85% complete', and 'docker-build' return nothing outside docs/archive;
all internal doc links resolve; backend/src untouched (cargo build clean).
This commit is contained in:
parent
bd1b7c2925
commit
17efc4f656
119 changed files with 469 additions and 17801 deletions
24
docs/adr/README.md
Normal file
24
docs/adr/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Architecture Decision Records
|
||||
|
||||
This directory holds the project's decision records — the "why" behind the
|
||||
major technical choices. These were originally written during Phase 1 research
|
||||
(dated Jan–Feb 2026) and moved here from the old `thoughts/research/` tree during
|
||||
the documentation reconciliation. They are historical context, not current specs.
|
||||
|
||||
## Decisions
|
||||
|
||||
| Record | Topic |
|
||||
|--------|-------|
|
||||
| [tech-stack-decision.md](./tech-stack-decision.md) | Master stack choice: Rust/Axum backend, React frontend, MongoDB, JWT |
|
||||
| [mongodb-schema-decision.md](./mongodb-schema-decision.md) | Document model + at-rest encryption approach |
|
||||
| [jwt-authentication-decision.md](./jwt-authentication-decision.md) | JWT access/refresh tokens, recovery phrases |
|
||||
| [frontend-decision-summary.md](./frontend-decision-summary.md) | React (web) + React Native (mobile, future) split |
|
||||
| [state-management-decision.md](./state-management-decision.md) | Client state — *superseded*: decision was Redux Toolkit, **actual code uses Zustand** |
|
||||
| [monorepo-structure.md](./monorepo-structure.md) | Repository layout (`backend/`, `web/`, `mobile/`, `docs/`) |
|
||||
| [backend-deployment-constraints.md](./backend-deployment-constraints.md) | Deployment requirements (Solaria, Docker) |
|
||||
| [mobile-health-frameworks-data.md](./mobile-health-frameworks-data.md) | HealthKit / Health Connect data-type reference (for future mobile work) |
|
||||
| [android-health-connect-data-types.md](./android-health-connect-data-types.md) | Android Health Connect data types |
|
||||
|
||||
> **Note**: Where a decision diverges from the implemented code (e.g. state
|
||||
> management), the code is the source of truth and the ADR is kept only as
|
||||
> historical record of the reasoning at the time.
|
||||
431
docs/adr/android-health-connect-data-types.md
Normal file
431
docs/adr/android-health-connect-data-types.md
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
# Android Health Connect - Available Data Types Research
|
||||
|
||||
**Date**: 2026-01-12
|
||||
**Platform**: Android Health Connect API
|
||||
**Source**: https://developer.android.com/health-and-fitness/guides/health-connect/plan/data-types
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Android Health Connect is a unified API that allows apps to read and write health and fitness data from a central on-device store. It's compatible with Android SDK 28 (Pie) and higher.
|
||||
|
||||
**Key Points**:
|
||||
- Requires explicit user permissions for each data type
|
||||
- All data is stored locally on the device
|
||||
- Apps can read/write data with user consent
|
||||
- Supports medical records and health data
|
||||
- Privacy-focused design
|
||||
|
||||
---
|
||||
|
||||
## Complete Data Types Catalog (41 Types)
|
||||
|
||||
### 🏃 Physical Activity & Movement
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **StepsRecord** | Step count over time | Daily activity tracking |
|
||||
| **DistanceRecord** | Distance traveled | Walking/running/cycling distances |
|
||||
| **FloorsClimbedRecord** | Number of floors climbed | Stair climbing activity |
|
||||
| **ElevationGainedRecord** | Elevation gained | Hiking/mountain activities |
|
||||
| **SpeedRecord** | Speed measurement | Running/cycling pace |
|
||||
| **StepsCadenceRecord** | Steps per minute | Running/cycling cadence |
|
||||
| **CyclingPedalingCadenceRecord** | Pedal cadence | Cycling performance |
|
||||
| **WheelchairPushesRecord** | Wheelchair pushes | Accessibility tracking |
|
||||
| **ExerciseSessionRecord** | Complete workout sessions | Gym/fitness activities |
|
||||
| **PlannedExerciseSessionRecord** | Scheduled workouts | Workout planning |
|
||||
| **ActivityIntensityRecord** | Activity intensity levels | Exercise intensity zones |
|
||||
|
||||
---
|
||||
|
||||
### 💪 Body Composition & Measurements
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **WeightRecord** | Body weight | Weight tracking |
|
||||
| **HeightRecord** | Height | BMI calculations |
|
||||
| **BodyFatRecord** | Body fat percentage | Body composition |
|
||||
| **BodyWaterMassRecord** | Body water mass | Hydration tracking |
|
||||
| **BoneMassRecord** | Bone mass | Bone health |
|
||||
| **LeanBodyMassRecord** | Lean muscle mass | Fitness progress |
|
||||
|
||||
---
|
||||
|
||||
### ❤️ Heart & Cardiovascular
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **HeartRateRecord** | Real-time heart rate | Heart rate monitoring |
|
||||
| **RestingHeartRateRecord** | Resting heart rate | Cardiovascular health |
|
||||
| **HeartRateVariabilityRmssdRecord** | HRV (RMSSD) | Stress/recovery tracking |
|
||||
| **BloodPressureRecord** | Systolic/diastolic pressure | Hypertension monitoring |
|
||||
| **RespiratoryRateRecord** | Breaths per minute | Respiratory health |
|
||||
| **Vo2MaxRecord** | Maximum oxygen uptake | Cardiovascular fitness |
|
||||
| **OxygenSaturationRecord** | Blood oxygen levels (SpO2) | Oxygen monitoring |
|
||||
|
||||
---
|
||||
|
||||
### 🌡️ Temperature & Metabolism
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **BodyTemperatureRecord** | Body temperature | Fever/health monitoring |
|
||||
| **BasalBodyTemperatureRecord** | Basal body temperature | Fertility tracking |
|
||||
| **SkinTemperatureRecord** | Skin temperature | Sleep/stress monitoring |
|
||||
| **BasalMetabolicRateRecord** | BMR | Metabolism tracking |
|
||||
|
||||
---
|
||||
|
||||
### 🔥 Calories & Energy
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **ActiveCaloriesBurnedRecord** | Calories from activity | Exercise calorie burn |
|
||||
| **TotalCaloriesBurnedRecord** | Total daily calories | Complete energy expenditure |
|
||||
|
||||
---
|
||||
|
||||
### 💧 Hydration & Nutrition
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **HydrationRecord** | Water intake | Hydration tracking |
|
||||
| **NutritionRecord** | Detailed nutrition data | Diet/macronutrient tracking |
|
||||
|
||||
---
|
||||
|
||||
### 💤 Sleep & Mindfulness
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **SleepSessionRecord** | Complete sleep sessions | Sleep analysis |
|
||||
| **MindfulnessSessionRecord** | Meditation/mindfulness | Mental wellness |
|
||||
|
||||
---
|
||||
|
||||
### 🩸 Women's Health
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **MenstruationPeriodRecord** | Menstrual cycle | Period tracking |
|
||||
| **MenstruationFlowRecord** | Flow intensity | Cycle details |
|
||||
| **IntermenstrualBleedingRecord** | Spotting between periods | Cycle health |
|
||||
| **CervicalMucusRecord** | Cervical mucus | Fertility tracking |
|
||||
| **OvulationTestRecord** | Ovulation test results | Fertility planning |
|
||||
| **SexualActivityRecord** | Sexual activity logs | Health tracking |
|
||||
|
||||
---
|
||||
|
||||
### 🩺 Blood & Medical
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **BloodGlucoseRecord** | Blood glucose levels | Diabetes management |
|
||||
|
||||
---
|
||||
|
||||
### ⚡ Power & Performance
|
||||
|
||||
| Data Type | Description | Use Case |
|
||||
|-----------|-------------|----------|
|
||||
| **PowerRecord** | Power output | Cycling/rowing performance |
|
||||
| **ForceRecord** | Force measurement | Strength training |
|
||||
|
||||
---
|
||||
|
||||
## Permissions Model
|
||||
|
||||
Each data type requires specific health permissions:
|
||||
|
||||
### Examples of Permission Strings
|
||||
- `android.permission.health.READ_STEPS`
|
||||
- `android.permission.health.WRITE_STEPS`
|
||||
- `android.permission.health.READ_HEART_RATE`
|
||||
- `android.permission.health.WRITE_HEART_RATE`
|
||||
- `android.permission.health.READ_BLOOD_PRESSURE`
|
||||
- `android.permission.health.WRITE_BLOOD_PRESSURE`
|
||||
|
||||
**Important**: Users must grant each permission individually through the Health Connect interface.
|
||||
|
||||
---
|
||||
|
||||
## Data Structure Format
|
||||
|
||||
Most records follow this structure:
|
||||
```kotlin
|
||||
Record(
|
||||
startTime: Instant,
|
||||
startZoneOffset: ZoneOffset,
|
||||
endTime: Instant,
|
||||
endZoneOffset: ZoneOffset,
|
||||
metadata: Metadata {
|
||||
id: String,
|
||||
dataOrigin: DataOrigin,
|
||||
lastModifiedTime: Instant,
|
||||
clientRecordId: String?,
|
||||
device: Device?,
|
||||
recordingMethod: RecordingMethod?
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Example: **BloodPressureRecord**
|
||||
```kotlin
|
||||
BloodPressureRecord(
|
||||
systolic = Pressure.millimetersOfMercury(120.0),
|
||||
diastolic = Pressure.millimetersOfMercury(80.0),
|
||||
time = Instant.now(),
|
||||
zoneOffset = ZoneOffset.UTC,
|
||||
metadata = Metadata(...)
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Medical Records (New Feature)
|
||||
|
||||
Health Connect now supports medical records:
|
||||
- **Medical resource format**: FHIR-based structure
|
||||
- **Reading medical data**: Requires additional permissions
|
||||
- **Writing medical data**: Vaccination records, lab results, etc.
|
||||
- **Data format**: Structured medical records with standardized fields
|
||||
|
||||
### Medical Record Types
|
||||
- Immunizations
|
||||
- Lab results
|
||||
- Vital signs
|
||||
- Medications
|
||||
- Allergies
|
||||
- Conditions
|
||||
- Procedures
|
||||
|
||||
---
|
||||
|
||||
## Integration Approaches for Normogen
|
||||
|
||||
### 1. Direct Health Connect Integration (Recommended)
|
||||
**Pros**:
|
||||
- Native Android integration
|
||||
- No third-party dependencies
|
||||
- Unified API for all data types
|
||||
- Privacy-preserving (local storage)
|
||||
|
||||
**Cons**:
|
||||
- Android-only
|
||||
- Requires Android 9+ (API 28+)
|
||||
- Need to handle user permissions
|
||||
- Not available on older Android versions
|
||||
|
||||
**Implementation**:
|
||||
```kotlin
|
||||
// Dependency
|
||||
implementation("androidx.health:health-connect-client:1.1.0-alpha07")
|
||||
|
||||
// Check availability
|
||||
val healthConnectManager = HealthConnectManager.getOrCreate(context)
|
||||
if (healthConnectManager.isAvailable) {
|
||||
// Use Health Connect
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Cross-Platform Wrapper Libraries
|
||||
|
||||
**Example**: Flutter Health Package (`health` package on pub.dev)
|
||||
|
||||
**Supported Data Types** (limited subset):
|
||||
- Steps
|
||||
- Heart rate
|
||||
- Sleep
|
||||
- Blood oxygen
|
||||
- Blood pressure
|
||||
- Weight
|
||||
- Height
|
||||
- Active energy burned
|
||||
- Total energy burned
|
||||
- Distance
|
||||
- Water intake
|
||||
- Nutrition
|
||||
|
||||
**Pros**:
|
||||
- Cross-platform (iOS & Android)
|
||||
- Simple API
|
||||
- Active community
|
||||
|
||||
**Cons**:
|
||||
- Limited data types
|
||||
- May not support all Health Connect features
|
||||
- Dependency on third-party maintenance
|
||||
|
||||
### 3. Hybrid Approach (Recommended for Normogen)
|
||||
|
||||
**Android**: Use native Health Connect API
|
||||
- Access all 41 data types
|
||||
- Full permission control
|
||||
- Medical records support
|
||||
|
||||
**iOS**: Use HealthKit
|
||||
- Equivalent data types
|
||||
- Similar permission model
|
||||
|
||||
**Web/PWA**: Web Bluetooth API (limited)
|
||||
- Connect to BLE devices directly
|
||||
- Very limited device support
|
||||
|
||||
---
|
||||
|
||||
## Data Type Mapping to Normogen Features
|
||||
|
||||
| Normogen Feature | Health Connect Data Types |
|
||||
|-----------------|---------------------------|
|
||||
| **General Health Stats** | WeightRecord, HeightRecord, BodyFatRecord |
|
||||
| **Physical Activity** | StepsRecord, DistanceRecord, ExerciseSessionRecord |
|
||||
| **Heart Monitoring** | HeartRateRecord, RestingHeartRateRecord, HeartRateVariabilityRmssdRecord |
|
||||
| **Blood Pressure** | BloodPressureRecord |
|
||||
| **Sleep Tracking** | SleepSessionRecord |
|
||||
| **Temperature** | BodyTemperatureRecord, BasalBodyTemperatureRecord, SkinTemperatureRecord |
|
||||
| **Respiration** | RespiratoryRateRecord, OxygenSaturationRecord |
|
||||
| **Period Tracking** | MenstruationPeriodRecord, MenstruationFlowRecord, CervicalMucusRecord, OvulationTestRecord |
|
||||
| **Hydration** | HydrationRecord |
|
||||
| **Nutrition** | NutritionRecord |
|
||||
| **Blood Glucose** | BloodGlucoseRecord (diabetes) |
|
||||
| **Lab Results** | Medical records API |
|
||||
| **Medication** | Medical records API |
|
||||
|
||||
---
|
||||
|
||||
## Limitations & Considerations
|
||||
|
||||
### ⚠️ Missing Data Types
|
||||
- **Pill identification**: No API for identifying pills by shape/appearance
|
||||
- **Medication reminders**: Not built into Health Connect (app-level feature)
|
||||
- **Dental information**: Not covered
|
||||
- **Medical appointments**: Not covered (calendar events)
|
||||
|
||||
### 🔒 Privacy Requirements
|
||||
- User must grant each permission explicitly
|
||||
- Cannot force permissions
|
||||
- Some data types require additional health permissions
|
||||
- Medical records require special handling
|
||||
|
||||
### 📱 Device Compatibility
|
||||
- **Minimum**: Android 9 (API 28)
|
||||
- **Optimal**: Android 14 (API 34) for full feature set
|
||||
- **Health Connect module**: Must be installed from Play Store (on Android 13) or pre-installed (Android 14+)
|
||||
|
||||
### 📊 Data Granularity
|
||||
- **Real-time**: Available (heart rate, steps during exercise)
|
||||
- **Daily summaries**: Available (most data types)
|
||||
- **Historical queries**: Supported with time ranges
|
||||
|
||||
---
|
||||
|
||||
## Implementation Example
|
||||
|
||||
### Reading Steps Data
|
||||
|
||||
```kotlin
|
||||
suspend fun readSteps(
|
||||
healthConnectManager: HealthConnectManager,
|
||||
startTime: Instant,
|
||||
endTime: Instant
|
||||
): List<StepsRecord> {
|
||||
val response = healthConnectManager.readRecords(
|
||||
ReadRecordsRequest(
|
||||
recordType = StepsRecord::class,
|
||||
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
|
||||
)
|
||||
)
|
||||
return response.records
|
||||
}
|
||||
```
|
||||
|
||||
### Writing Blood Pressure Data
|
||||
|
||||
```kotlin
|
||||
suspend fun writeBloodPressure(
|
||||
healthConnectManager: HealthConnectManager,
|
||||
systolic: Double,
|
||||
diastolic: Double,
|
||||
timestamp: Instant
|
||||
) {
|
||||
val record = BloodPressureRecord(
|
||||
systolic = Pressure.millimetersOfMercury(systolic),
|
||||
diastolic = Pressure.millimetersOfMercury(diastolic),
|
||||
time = timestamp,
|
||||
zoneOffset = ZoneOffset.systemDefault(),
|
||||
metadata = Metadata(
|
||||
dataOrigin = DataOrigin("com.normogen.app"),
|
||||
lastModifiedTime = Instant.now()
|
||||
)
|
||||
)
|
||||
|
||||
healthConnectManager.insertRecords(listOf(record))
|
||||
}
|
||||
```
|
||||
|
||||
### Reading Sleep Sessions
|
||||
|
||||
```kotlin
|
||||
suspend fun readSleepSessions(
|
||||
healthConnectManager: HealthConnectManager,
|
||||
startTime: Instant,
|
||||
endTime: Instant
|
||||
): List<SleepSessionRecord> {
|
||||
val response = healthConnectManager.readRecords(
|
||||
ReadRecordsRequest(
|
||||
recordType = SleepSessionRecord::class,
|
||||
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
|
||||
)
|
||||
)
|
||||
return response.records
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommendations for Normogen
|
||||
|
||||
### ✅ Use Health Connect For:
|
||||
1. **All sensor data collection** (steps, heart rate, sleep, etc.)
|
||||
2. **Physical activity tracking** (exercise sessions, distance, calories)
|
||||
3. **Women's health features** (period tracking, ovulation, etc.)
|
||||
4. **Vital signs** (blood pressure, blood glucose, temperature)
|
||||
5. **Body measurements** (weight, height, body composition)
|
||||
|
||||
### ❌ Don't Use Health Connect For:
|
||||
1. **Medication reminders** - Use app-level scheduling
|
||||
2. **Pill identification** - Not available in API
|
||||
3. **Medical appointments** - Use calendar integration
|
||||
4. **Lab results storage** - Store encrypted on server (as planned)
|
||||
5. **Dental records** - Custom data model needed
|
||||
|
||||
### 🎯 Integration Strategy:
|
||||
1. **Primary data source**: Health Connect for automatic sensor data
|
||||
2. **Manual entry**: Allow users to manually input data not available via sensors
|
||||
3. **Background sync**: Periodic sync with Health Connect to update records
|
||||
4. **Privacy**: All data synced to server should be encrypted client-side (zero-knowledge)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ **Research complete** - All 41 data types documented
|
||||
2. ⏳ **Create data mapping** - Map Normogen features to Health Connect types
|
||||
3. ⏳ **Design integration** - Plan permission flow and UI
|
||||
4. ⏳ **Implement PoC** - Build prototype with key data types
|
||||
5. ⏳ **iOS equivalent** - Research HealthKit for comparison
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Official Documentation](https://developer.android.com/health-and-fitness/guides/health-connect/plan/data-types)
|
||||
- [GitHub Samples](https://github.com/android/health-samples)
|
||||
- [Health Connect on Play Store](https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata)
|
||||
- [Privacy Policy](https://developer.android.com/health-and-fitness/health-connect/privacy)
|
||||
|
||||
---
|
||||
|
||||
**Generated by**: goose AI assistant
|
||||
**Last Updated**: 2026-01-12
|
||||
786
docs/adr/backend-deployment-constraints.md
Normal file
786
docs/adr/backend-deployment-constraints.md
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
### /home/asoliver/desarrollo/normogen/thoughts/research/2026-02-14-backend-deployment-constraints.md
|
||||
```markdown
|
||||
1: # Backend Deployment Constraints
|
||||
2:
|
||||
3: ## Deployment Requirements
|
||||
4:
|
||||
5: ### Docker + Docker Compose
|
||||
6: - Backend must be containerized using Docker
|
||||
7: - Use Docker Compose for local development and homelab deployment
|
||||
8: - Multi-stage builds for optimal image size
|
||||
9: - Non-root user for security
|
||||
10:
|
||||
11: ### Kubernetes Compatibility
|
||||
12: - Design for future Kubernetes deployment
|
||||
13: - Use environment-based configuration (env vars)
|
||||
14: - Health check endpoints (`/health`, `/ready`)
|
||||
15: - Graceful shutdown handling
|
||||
16: - Stateless application design
|
||||
17: - ConfigMap and Secret ready
|
||||
18:
|
||||
19: ### One-Command Deployment
|
||||
20: ```bash
|
||||
21: # Clone repository
|
||||
22: git clone https://github.com/yourusername/normogen.git
|
||||
23: cd normogen
|
||||
24:
|
||||
25: # Setup configuration
|
||||
26: cp config/example.env config/.env
|
||||
27: # Edit config/.env with your settings
|
||||
28:
|
||||
29: # Build and run
|
||||
30: docker compose build
|
||||
31: docker compose up -d
|
||||
32: ```
|
||||
33:
|
||||
34: ## Homelab Deployment (Phase 1)
|
||||
35:
|
||||
36: ### Port Configuration
|
||||
37: - **MongoDB**: Standard ports
|
||||
38: - Primary: `27017` (default MongoDB port)
|
||||
39: - This allows connecting with existing MongoDB tools/admin UIs
|
||||
40:
|
||||
41: - **Backend API**: `6000` (homelab range)
|
||||
42: - External: `6000` (host port)
|
||||
43: - Internal: `8000` (container port)
|
||||
44: - Mapped in docker-compose.yml
|
||||
45:
|
||||
46: - **Future Services**: Port range `6000-6999`
|
||||
47: - `6000`: Backend API (current)
|
||||
48: - `6001`: Web UI (future)
|
||||
49: - `6002`: Admin dashboard (future)
|
||||
50: - `6003`: Metrics/monitoring (future)
|
||||
51:
|
||||
52: ### Network Configuration
|
||||
53: - Docker network: `normogen-network`
|
||||
54: - Must communicate with existing Docker services on homelab server
|
||||
55: - MongoDB accessible to host for backup/admin tools
|
||||
56:
|
||||
57: ### Environment Configuration
|
||||
58: ```bash
|
||||
59: # config/.env (gitignored)
|
||||
60: # Server Configuration
|
||||
61: RUST_LOG=info
|
||||
62: SERVER_HOST=0.0.0.0
|
||||
63: SERVER_PORT=8000
|
||||
64: ALLOWED_ORIGINS=http://localhost:3000,http://localhost:6001
|
||||
65:
|
||||
66: # Database Configuration
|
||||
67: MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
68: MONGODB_DATABASE=normogen
|
||||
69:
|
||||
70: # JWT Configuration
|
||||
71: JWT_SECRET=your-super-secret-jwt-key-here
|
||||
72: JWT_ACCESS_TOKEN_EXPIRY_MINUTES=15
|
||||
73: JWT_REFRESH_TOKEN_EXPIRY_DAYS=30
|
||||
74:
|
||||
75: # Encryption Configuration (for validation only)
|
||||
76: # Actual encryption happens client-side
|
||||
77: ENCRYPTION_ALGORITHM=aes-256-gcm
|
||||
78:
|
||||
79: # Rate Limiting
|
||||
80: RATE_LIMIT_REQUESTS=100
|
||||
81: RATE_LIMIT_DURATION_SECONDS=60
|
||||
82: ```
|
||||
83:
|
||||
84: ### Docker Compose Structure
|
||||
85: ```yaml
|
||||
86: # docker-compose.yml
|
||||
87: version: '3.8'
|
||||
88:
|
||||
89: services:
|
||||
90: backend:
|
||||
91: build:
|
||||
92: context: .
|
||||
93: dockerfile: docker/Dockerfile
|
||||
94: container_name: normogen-backend
|
||||
95: ports:
|
||||
96: - "6000:8000" # Homelab port range
|
||||
97: environment:
|
||||
98: - RUST_LOG=${RUST_LOG:-info}
|
||||
99: - SERVER_PORT=8000
|
||||
100: - MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
101: - MONGODB_DATABASE=${MONGODB_DATABASE:-normogen}
|
||||
102: - JWT_SECRET=${JWT_SECRET}
|
||||
103: - JWT_ACCESS_TOKEN_EXPIRY_MINUTES=${JWT_ACCESS_TOKEN_EXPIRY_MINUTES:-15}
|
||||
104: - JWT_REFRESH_TOKEN_EXPIRY_DAYS=${JWT_REFRESH_TOKEN_EXPIRY_DAYS:-30}
|
||||
105: env_file:
|
||||
106: - config/.env
|
||||
107: depends_on:
|
||||
108: mongodb:
|
||||
109: condition: service_healthy
|
||||
110: networks:
|
||||
111: - normogen-network
|
||||
112: restart: unless-stopped
|
||||
113: healthcheck:
|
||||
114: test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
115: interval: 30s
|
||||
116: timeout: 10s
|
||||
117: retries: 3
|
||||
118: start_period: 40s
|
||||
119:
|
||||
120: mongodb:
|
||||
121: image: mongo:6.0
|
||||
122: container_name: normogen-mongodb
|
||||
123: ports:
|
||||
124: - "27017:27017" # Standard MongoDB port
|
||||
125: environment:
|
||||
126: - MONGO_INITDB_DATABASE=${MONGO_DATABASE:-normogen}
|
||||
127: volumes:
|
||||
128: - mongodb_data:/data/db
|
||||
129: - mongodb_config:/data/configdb
|
||||
130: networks:
|
||||
131: - normogen-network
|
||||
132: restart: unless-stopped
|
||||
133: healthcheck:
|
||||
134: test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
135: interval: 10s
|
||||
136: timeout: 5s
|
||||
137: retries: 5
|
||||
138: start_period: 10s
|
||||
139:
|
||||
140: volumes:
|
||||
141: mongodb_data:
|
||||
142: driver: local
|
||||
143: mongodb_config:
|
||||
144: driver: local
|
||||
145:
|
||||
146: networks:
|
||||
147: normogen-network:
|
||||
148: driver: bridge
|
||||
149: ```
|
||||
150:
|
||||
151: ## Kubernetes Deployment (Phase 2 - Future)
|
||||
152:
|
||||
153: ### Manifests Structure
|
||||
154: ```
|
||||
155: k8s/
|
||||
156: ├── base/
|
||||
157: │ ├── deployment.yaml
|
||||
158: │ ├── service.yaml
|
||||
159: │ ├── configmap.yaml
|
||||
160: │ ├── secrets.yaml
|
||||
161: │ └── ingress.yaml
|
||||
162: └── overlays/
|
||||
163: ├── homelab/
|
||||
164: │ ├── kustomization.yaml
|
||||
165: │ └── patches/
|
||||
166: └── production/
|
||||
167: ├── kustomization.yaml
|
||||
168: └── patches/
|
||||
169: ```
|
||||
170:
|
||||
171: ### Deployment Configuration
|
||||
172: - **Replicas**: 2-3 for high availability
|
||||
173: - **Liveness Probe**: `/health` (10s interval, 5s timeout)
|
||||
174: - **Readiness Probe**: `/ready` (5s interval, 3s timeout)
|
||||
175: - **Resource Limits**:
|
||||
176: - CPU: 500m-1000m
|
||||
177: - Memory: 256Mi-512Mi
|
||||
178: - **Helm Chart**: Optional for easier deployment
|
||||
179:
|
||||
180: ### Configuration Management
|
||||
181: - **ConfigMap**: Non-sensitive config (log levels, ports)
|
||||
182: - **Secrets**: Sensitive config (JWT secret, DB URI)
|
||||
183: - **Environment Variables**: All configuration via env vars
|
||||
184:
|
||||
185: ## Dockerfile Design
|
||||
186:
|
||||
187: ### Multi-Stage Build
|
||||
188: ```dockerfile
|
||||
189: # docker/Dockerfile
|
||||
190:
|
||||
191: # Build stage
|
||||
192: FROM rust:1.75-alpine AS builder
|
||||
193: WORKDIR /app
|
||||
194:
|
||||
195: # Install build dependencies
|
||||
196: RUN apk add --no-cache musl-dev pkgconf openssl-dev
|
||||
197:
|
||||
198: # Copy manifests
|
||||
199: COPY Cargo.toml Cargo.lock ./
|
||||
200:
|
||||
201: # Create dummy main.rs to build dependencies
|
||||
202: RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||
203: RUN cargo build --release && rm -rf src
|
||||
204:
|
||||
205: # Copy source code
|
||||
206: COPY src ./src
|
||||
207:
|
||||
208: # Build application
|
||||
209: RUN touch src/main.rs && cargo build --release
|
||||
210:
|
||||
211: # Runtime stage
|
||||
212: FROM alpine:3.18
|
||||
213: WORKDIR /app
|
||||
214:
|
||||
215: # Install runtime dependencies
|
||||
216: RUN apk add --no-cache ca-certificates openssl
|
||||
217:
|
||||
218: # Copy binary from builder
|
||||
219: COPY --from=builder /app/target/release/normogen-backend /app/normogen-backend
|
||||
220:
|
||||
221: # Create non-root user
|
||||
222: RUN addgroup -g 1000 normogen && \
|
||||
223: adduser -D -u 1000 -G normogen normogen && \
|
||||
224: chown -R normogen:normogen /app
|
||||
225:
|
||||
226: USER normogen
|
||||
227:
|
||||
228: # Expose port
|
||||
229: EXPOSE 8000
|
||||
230:
|
||||
231: # Check
|
||||
232: HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
233: CMD wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1
|
||||
234:
|
||||
235: # Run application
|
||||
236: CMD ["./normogen-backend"]
|
||||
237: ```
|
||||
238:
|
||||
239: ## Configuration Management
|
||||
240:
|
||||
241: ### Environment Variables
|
||||
242: All configuration via environment variables (12-factor app):
|
||||
243: - Database connections
|
||||
244: - JWT secrets
|
||||
245: - API credentials
|
||||
246: - Feature flags
|
||||
247: - Log levels
|
||||
248:
|
||||
249: ### Configuration Files
|
||||
250: ```
|
||||
251: config/
|
||||
252: ├── .env # Gitignored, local dev
|
||||
253: ├── .env.example # Git committed, template
|
||||
254: └── defaults.env # Git committed, defaults
|
||||
255: ```
|
||||
256:
|
||||
257: ### Configuration Validation
|
||||
258: - Validate required env vars on startup
|
||||
259: - Fail fast if misconfigured
|
||||
260: - Log configuration (sanitize secrets)
|
||||
261:
|
||||
262: ## Endpoints
|
||||
263:
|
||||
264: ### Check Endpoints
|
||||
265: ```rust
|
||||
266: // GET /health - Liveness probe
|
||||
267: // Returns: {"status": "ok"}
|
||||
268: // Used by: K8s liveness probe, Docker check
|
||||
269: // Purpose: Is the app running?
|
||||
270:
|
||||
271: // GET /ready - Readiness probe
|
||||
272: // Returns: {"status": "ready", "database": "connected"}
|
||||
273: // Used by: K8s readiness probe
|
||||
274: // Purpose: Is the app ready to serve traffic?
|
||||
275: ```
|
||||
276:
|
||||
277: ## Logging & Observability
|
||||
278:
|
||||
279: ### Structured Logging
|
||||
280: - JSON format for production
|
||||
281: - Log levels: ERROR, WARN, INFO, DEBUG, TRACE
|
||||
282: - Request ID tracing
|
||||
283: - Sensitive data sanitization
|
||||
284:
|
||||
285: ### Metrics (Future)
|
||||
286: - Prometheus endpoint: `/metrics`
|
||||
287: - Request rate, error rate, latency
|
||||
288: - Database connection pool status
|
||||
289:
|
||||
290: ## Security Considerations
|
||||
291:
|
||||
292: ### Container Security
|
||||
293: - Non-root user (UID 1000)
|
||||
294: - Read-only filesystem (except /tmp)
|
||||
295: - Minimal base image (Alpine)
|
||||
296: - No shell in runtime image
|
||||
297: - Security scanning (Trivy, Snyk)
|
||||
298:
|
||||
299: ### Secrets Management
|
||||
300: - Never commit secrets to git
|
||||
301: - Use environment variables
|
||||
302: - K8s: Use secrets, not configmaps
|
||||
303: - Docker: Use env_file or Docker secrets
|
||||
304: - Gitignore: `config/.env`
|
||||
305:
|
||||
306: ## Deployment Checklist
|
||||
307:
|
||||
308: ### Initial Setup
|
||||
309: - [ ] Clone repository
|
||||
310: - [ ] Copy `config/.env.example` to `config/.env`
|
||||
311: - [ ] Configure environment variables
|
||||
312: - [ ] Create Docker network: `docker network create normogen-network`
|
||||
313: - [ ] Generate JWT secret: `openssl rand -base64 32`
|
||||
314:
|
||||
315: ### Build & Run
|
||||
316: - [ ] Build: `docker compose build`
|
||||
317: - [ ] Run: `docker compose up -d`
|
||||
318: - [ ] Check logs: `docker compose logs -f backend`
|
||||
319: - [ ] Check status: `curl http://localhost:6000/health`
|
||||
320: - [ ] Check ready: `curl http://localhost:6000/ready`
|
||||
321:
|
||||
322: ### Verification
|
||||
323: - [ ] Backend responds on port 6000
|
||||
324: - [ ] MongoDB accessible on port 27017
|
||||
325: - [ ] Checks passing
|
||||
326: - [ ] Database connection working
|
||||
327: - [ ] JWT authentication working
|
||||
328:
|
||||
329: ## Questions for Clarification
|
||||
330:
|
||||
331: ### Environment
|
||||
332: 1. **Reverse Proxy**: Will you use a reverse proxy (Nginx, Traefik, Caddy)?
|
||||
333: - If yes, should TLS be handled at proxy or backend?
|
||||
334: - What domain/path for the API?
|
||||
335:
|
||||
336: 2. **MongoDB Deployment**:
|
||||
337: - Is MongoDB already running in your homelab?
|
||||
338: - Or should docker-compose spin up a dedicated MongoDB instance for Normogen?
|
||||
339: - If existing: What's the connection string?
|
||||
340:
|
||||
341: 3. **Resource Limits**:
|
||||
342: - Any CPU/memory constraints for the homelab?
|
||||
343: - Suggested limits: 500m CPU, 512Mi RAM?
|
||||
344:
|
||||
345: 4. **Backup Strategy**:
|
||||
346: - MongoDB backups? (Volume mount, scheduled dump)
|
||||
347: - Configuration backups?
|
||||
348:
|
||||
349: 5. **Monitoring**:
|
||||
350: - Log aggregation? (ELK, Loki, Splunk)
|
||||
351: - Metrics collection? (Prometheus, Grafana)
|
||||
352: - APM? (Datadog, New Relic)
|
||||
353:
|
||||
354: 6. **CI/CD**:
|
||||
355: - Will you use GitHub Actions, GitLab CI, or Jenkins?
|
||||
356: - Auto-deploy on commit to main branch?
|
||||
357: - Automated testing before deploy?
|
||||
358:
|
||||
359: ### Development Workflow
|
||||
360: 7. **Hot Reload**: Development mode with hot reload?
|
||||
361: - Use `cargo-watch` for auto-rebuild on file changes?
|
||||
362:
|
||||
363: 8. **Database Migrations**:
|
||||
364: - Run migrations on startup?
|
||||
365: - Separate migration tool?
|
||||
366:
|
||||
367: 9. **Seed Data**:
|
||||
368: - Seed development database with sample data?
|
||||
369:
|
||||
370: ### Production Readiness
|
||||
371: 10. **Rate Limiting**:
|
||||
372: - Per-IP rate limiting?
|
||||
373: - Per-user rate limiting (after auth)?
|
||||
374:
|
||||
375: 11. **CORS Configuration**:
|
||||
376: - Allowed origins for local dev?
|
||||
377: - Allowed origins for production?
|
||||
378:
|
||||
379: 12. **TLS/HTTPS**:
|
||||
380: - Local dev: HTTP or HTTPS?
|
||||
381: - Production: TLS termination at proxy?
|
||||
382:
|
||||
383: ## Next Steps
|
||||
384:
|
||||
385: Once the above questions are answered, we can proceed with:
|
||||
386:
|
||||
387: 1. **Phase 2.1**: Docker Compose Setup
|
||||
388: - Create Dockerfile (multi-stage build)
|
||||
389: - Create docker-compose.yml
|
||||
390: - Create configuration templates
|
||||
391: - Test local deployment
|
||||
392:
|
||||
393: 2. **Phase 2.2**: Axum Server Setup
|
||||
394: - Initialize Rust project
|
||||
395: - Setup Axum dependencies
|
||||
396: - Create check endpoints
|
||||
397: - Test containerized build
|
||||
398:
|
||||
399: 3. **Phase 2.3**: MongoDB Integration
|
||||
400: - MongoDB connection pooling
|
||||
401: - Readiness check with database
|
||||
402: - Test database connectivity
|
||||
403:
|
||||
404: 4. **Phase 2.4**: Configuration Management
|
||||
405: - Environment variable validation
|
||||
406: - Configuration struct
|
||||
407: - Secret loading
|
||||
408:
|
||||
409: 5. **Phase 2.5**: Deployment Testing
|
||||
410: - Test on homelab server
|
||||
411: - Verify checks
|
||||
412: - Verify database connection
|
||||
413: - Test restart behavior
|
||||
```
|
||||
|
||||
## Deployment Decisions (User Confirmed)
|
||||
|
||||
### 1. MongoDB Deployment
|
||||
✅ **New MongoDB instance in docker-compose**
|
||||
- MongoDB will be spun up as part of docker-compose.yml
|
||||
- Volume mounts for data persistence
|
||||
- Standard port 27017 for admin tool access
|
||||
|
||||
### 2. Reverse Proxy
|
||||
✅ **Using reverse proxy for TLS termination**
|
||||
- Backend handles HTTP only
|
||||
- TLS/HTTPS handled by reverse proxy (Nginx/Traefik/Caddy)
|
||||
- CORS configuration needed for allowed origins
|
||||
|
||||
### 3. Development Workflow
|
||||
✅ **Hot reload for local development**
|
||||
- Use `cargo-watch` for auto-rebuild on file changes
|
||||
- Separate docker-compose.dev.yml for development
|
||||
- Production build without hot reload
|
||||
|
||||
### 4. Resource Limits
|
||||
✅ **Homelab resource constraints**
|
||||
- CPU: 1000m (1 CPU core limit)
|
||||
- Memory: 1000Mi (1GB RAM limit)
|
||||
- Configure in docker-compose.yml
|
||||
- Configure in Kubernetes Deployment for future
|
||||
|
||||
### 5. Repository & CI/CD
|
||||
✅ **Forgejo repository**
|
||||
- Git hosting: Forgejo (self-hosted GitHub-compatible)
|
||||
- CI/CD: Forgejo Actions (GitHub Actions compatible)
|
||||
- Single repository for backend, mobile, web
|
||||
|
||||
## Updated Monorepo Structure
|
||||
|
||||
```
|
||||
normogen/ # Root repository
|
||||
├── backend/ # Rust backend
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── main.rs
|
||||
│ │ ├── auth/
|
||||
│ │ ├── api/
|
||||
│ │ ├── db/
|
||||
│ │ └── config/
|
||||
│ ├── docker/
|
||||
│ │ └── Dockerfile # Multi-stage build
|
||||
│ ├── Cargo.toml
|
||||
│ ├── Cargo.lock
|
||||
│ ├── docker-compose.yml # Homelab deployment
|
||||
│ ├── docker-compose.dev.yml # Development with hot reload
|
||||
│ ├── config/
|
||||
│ │ ├── .env.example
|
||||
│ │ └── defaults.env
|
||||
│ └── k8s/ # Future Kubernetes manifests
|
||||
│ ├── base/
|
||||
│ └── overlays/
|
||||
│
|
||||
├── mobile/ # React Native (iOS + Android)
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/
|
||||
│ │ ├── screens/
|
||||
│ │ ├── navigation/
|
||||
│ │ ├── store/
|
||||
│ │ ├── services/
|
||||
│ │ └── utils/
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── App.tsx
|
||||
│ └── android/
|
||||
│ └── ios/
|
||||
│
|
||||
├── web/ # React web app
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/
|
||||
│ │ ├── pages/
|
||||
│ │ ├── store/
|
||||
│ │ ├── services/
|
||||
│ │ └── utils/
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ └── index.html
|
||||
│
|
||||
├── shared/ # Shared TypeScript code
|
||||
│ ├── src/
|
||||
│ │ ├── types/ # Shared types
|
||||
│ │ ├── validation/ # Zod schemas
|
||||
│ │ ├── encryption/ # Encryption utilities
|
||||
│ │ └── api/ # API client
|
||||
│ └── package.json
|
||||
│
|
||||
├── thoughts/ # Research & design docs
|
||||
│ └── research/
|
||||
│
|
||||
├── .gitignore # Root gitignore
|
||||
├── README.md # Root README
|
||||
└── docker-compose.root.yml # Optional: Run all services
|
||||
```
|
||||
|
||||
### Updated Docker Compose with Resource Limits
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml (production)
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: normogen-backend
|
||||
ports:
|
||||
- "6000:8000"
|
||||
environment:
|
||||
- RUST_LOG=${RUST_LOG:-info}
|
||||
- SERVER_PORT=8000
|
||||
- MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
- MONGODB_DATABASE=${MONGODB_DATABASE:-normogen}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- JWT_ACCESS_TOKEN_EXPIRY_MINUTES=${JWT_ACCESS_TOKEN_EXPIRY_MINUTES:-15}
|
||||
- JWT_REFRESH_TOKEN_EXPIRY_DAYS=${JWT_REFRESH_TOKEN_EXPIRY_DAYS:-30}
|
||||
env_file:
|
||||
- config/.env
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0' # 1 CPU core
|
||||
memory: 1000M # 1GB RAM
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
check:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
container_name: normogen-mongodb
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=${MONGO_DATABASE:-normogen}
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
- mongodb_config:/data/configdb
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
check:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
mongodb_data:
|
||||
driver: local
|
||||
mongodb_config:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
normogen-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Development Docker Compose (Hot Reload)
|
||||
|
||||
```yaml
|
||||
# docker-compose.dev.yml (development)
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.dev
|
||||
container_name: normogen-backend-dev
|
||||
ports:
|
||||
- "6000:8000"
|
||||
volumes:
|
||||
- ./src:/app/src # Hot reload: Mount source code
|
||||
- ./Cargo.toml:/app/Cargo.toml
|
||||
environment:
|
||||
- RUST_LOG=debug
|
||||
- SERVER_PORT=8000
|
||||
- MONGODB_URI=mongodb://mongodb:27017/normogen
|
||||
- MONGODB_DATABASE=normogen_dev
|
||||
- JWT_SECRET=dev-secret-do-not-use-in-production
|
||||
- CARGO_WATCH=1 # Enable hot reload
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- normogen-network
|
||||
restart: unless-stopped
|
||||
|
||||
mongodb:
|
||||
image: mongo:6.0
|
||||
container_name: normogen-mongodb-dev
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_DATABASE=normogen_dev
|
||||
volumes:
|
||||
- mongodb_dev_data:/data/db
|
||||
networks:
|
||||
- normogen-network
|
||||
check:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
mongodb_dev_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
normogen-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Development Dockerfile (with cargo-watch)
|
||||
|
||||
```dockerfile
|
||||
# docker/Dockerfile.dev
|
||||
|
||||
FROM rust:1.75-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime and build dependencies
|
||||
RUN apk add --no-cache \
|
||||
musl-dev \
|
||||
pkgconf \
|
||||
openssl-dev \
|
||||
curl \
|
||||
wget \
|
||||
git
|
||||
|
||||
# Install cargo-watch for hot reload
|
||||
RUN cargo install cargo-watch
|
||||
|
||||
# Copy manifests
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
|
||||
# Create dummy main.rs to build dependencies
|
||||
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||
RUN cargo build && rm -rf src
|
||||
|
||||
# Copy source code (will be mounted as volume in dev)
|
||||
COPY src ./src
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run with hot reload
|
||||
CMD ["cargo-watch", "-x", "run"]
|
||||
```
|
||||
|
||||
### Forgejo CI/CD (Example)
|
||||
|
||||
```yaml
|
||||
# .forgejo/workflows/backend-build.yml
|
||||
name: Build and Test Backend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Build backend
|
||||
working-directory: ./backend
|
||||
run: cargo build --verbose
|
||||
|
||||
- name: Run tests
|
||||
working-directory: ./backend
|
||||
run: cargo test --verbose
|
||||
|
||||
- name: Build Docker image
|
||||
working-directory: ./backend
|
||||
run: docker build -f docker/Dockerfile -t normogen-backend:${{ github.sha }} .
|
||||
|
||||
deploy-homelab:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- name: Deploy to homelab
|
||||
run: |
|
||||
echo "Deploy to homelab server"
|
||||
# Add deployment script here
|
||||
```
|
||||
|
||||
### CORS Configuration (for Reverse Proxy)
|
||||
|
||||
```rust
|
||||
// src/config/cors.rs
|
||||
use tower_http::cors::{CorsLayer, Any};
|
||||
use axum::http::{HeaderValue, Method};
|
||||
|
||||
pub fn create_cors_layer(allowed_origins: &str) -> CorsLayer {
|
||||
let origins: Vec<&str> = allowed_origins.split(',').map(|s| s.trim()).collect();
|
||||
|
||||
CorsLayer::new()
|
||||
.allow_origin(origins.into_iter().map(|s| {
|
||||
s.parse::<HeaderValue>().unwrap()
|
||||
}).collect::<Vec<_>>())
|
||||
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::PATCH, Method::DELETE, Method::OPTIONS])
|
||||
.allow_headers(Any)
|
||||
.allow_credentials(true)
|
||||
.max_age(3600)
|
||||
}
|
||||
```
|
||||
|
||||
## Updated Deployment Checklist
|
||||
|
||||
### Initial Setup
|
||||
- [ ] Clone repository from Forgejo
|
||||
- [ ] Copy `backend/config/.env.example` to `backend/config/.env`
|
||||
- [ ] Configure environment variables
|
||||
- [ ] Generate JWT secret: `openssl rand -base64 32`
|
||||
- [ ] Set resource limits in docker-compose.yml
|
||||
|
||||
### Development Setup
|
||||
- [ ] Run development: `docker compose -f docker-compose.dev.yml up -d`
|
||||
- [ ] Check logs: `docker compose -f docker-compose.dev.yml logs -f backend`
|
||||
- [ ] Test hot reload: Make changes to src/, verify auto-rebuild
|
||||
|
||||
### Production Deployment
|
||||
- [ ] Run production: `docker compose up -d`
|
||||
- [ ] Check logs: `docker compose logs -f backend`
|
||||
- [ ] Verify resource limits: `docker stats`
|
||||
- [ ] Configure reverse proxy (Nginx/Traefik/Caddy)
|
||||
- [ ] Configure reverse proxy CORS headers
|
||||
- [ ] Test API through reverse proxy
|
||||
|
||||
147
docs/adr/frontend-decision-summary.md
Normal file
147
docs/adr/frontend-decision-summary.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# Frontend Framework Decision Summary
|
||||
|
||||
**Date**: 2026-02-14
|
||||
**Decision**: **React Native + React**
|
||||
|
||||
---
|
||||
|
||||
## Platform Strategy
|
||||
|
||||
### Primary: Mobile Apps (iOS + Android)
|
||||
- Daily health tracking and data entry
|
||||
- Health sensor integration (HealthKit, Health Connect)
|
||||
- QR code scanning (lab results)
|
||||
- Push notifications (reminders)
|
||||
- Background sync
|
||||
|
||||
### Secondary: Web Browser
|
||||
- Complex data visualization and charts
|
||||
- Historical trend analysis
|
||||
- Profile and family management
|
||||
- Extensive reporting
|
||||
|
||||
---
|
||||
|
||||
## Framework Decision: React Native + React
|
||||
|
||||
| Criteria | React Native + React | Flutter | Native |
|
||||
|----------|---------------------|----------|--------|
|
||||
| Code Sharing | 70-80% | 0% | 0% |
|
||||
| Development Cost | Low | Medium | High |
|
||||
| Time to Market | Fast | Medium | Slow |
|
||||
| Health Sensors | ✅ Excellent | ✅ Excellent | ✅ Excellent |
|
||||
| QR Scanning | ✅ Excellent | ✅ Excellent | ✅ Excellent |
|
||||
| Performance | Good | Excellent | Excellent |
|
||||
| Team Skills | JS/TS only | Dart + JS | Swift + Kotlin + JS |
|
||||
| Ecosystem | Largest | Large | Native |
|
||||
|
||||
---
|
||||
|
||||
## Key Advantages
|
||||
|
||||
### 1. Code Sharing (70-80%)
|
||||
- Business logic: State, API, encryption
|
||||
- Data validation: Zod schemas
|
||||
- Date handling: date-fns
|
||||
- Utilities: Monorepo shared package
|
||||
|
||||
### 2. Health Sensors
|
||||
- iOS: react-native-health (HealthKit)
|
||||
- Android: react-native-google-fit (Health Connect)
|
||||
- Background sensor data collection
|
||||
|
||||
### 3. Encryption
|
||||
- react-native-quick-crypto
|
||||
- AES-256-GCM, PBKDF2
|
||||
- Secure key storage (Keychain/Keystore)
|
||||
- Web Crypto API compatible
|
||||
|
||||
### 4. QR Scanning
|
||||
- react-native-camera
|
||||
- Fast, accurate scanning
|
||||
|
||||
### 5. Web Charts
|
||||
- Recharts (React)
|
||||
- Beautiful, interactive visualizations
|
||||
- Perfect for health data
|
||||
|
||||
### 6. Team & Cost
|
||||
- Single language: JavaScript/TypeScript
|
||||
- Single ecosystem: npm
|
||||
- Lower development cost
|
||||
- Faster time to market
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Mobile (React Native)
|
||||
- Framework: React Native 0.73+
|
||||
- Language: TypeScript
|
||||
- Health: react-native-health, react-native-google-fit
|
||||
- Camera: react-native-camera
|
||||
- Encryption: react-native-quick-crypto
|
||||
- HTTP: Axios
|
||||
|
||||
### Web (React)
|
||||
- Framework: React 18+
|
||||
- Language: TypeScript
|
||||
- Charts: Recharts
|
||||
- HTTP: Axios
|
||||
- UI: Tailwind CSS / Chakra UI
|
||||
|
||||
### Shared (Monorepo)
|
||||
- Language: TypeScript
|
||||
- State: Redux/Zustand (TBD)
|
||||
- API: Axios
|
||||
- Encryption: AES-256-GCM, PBKDF2
|
||||
- Validation: Zod
|
||||
- Date: date-fns
|
||||
|
||||
---
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
### Phase 1: Mobile MVP (8-12 weeks)
|
||||
- Setup React Native project
|
||||
- Integrate HealthKit and Health Connect
|
||||
- Implement encryption
|
||||
- Build core UI
|
||||
- Test QR scanning
|
||||
- Background sync
|
||||
|
||||
### Phase 2: Web Companion (4-6 weeks)
|
||||
- Setup React project
|
||||
- Share business logic
|
||||
- Build charts
|
||||
- Profile management UI
|
||||
|
||||
### Phase 3: Polish & Launch (4-6 weeks)
|
||||
- Performance optimization
|
||||
- Security audit
|
||||
- App store submission
|
||||
- Beta launch
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Mobile Framework: React Native
|
||||
2. ⏭️ State Management: Redux vs Zustand
|
||||
3. ⏭️ Database Schema Design
|
||||
4. ⏭️ Create Health Sensor POC
|
||||
5. ⏭️ Implement Authentication
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**React Native + React** is optimal for Normogen:
|
||||
|
||||
- 70-80% code sharing reduces development cost
|
||||
- Excellent health sensor integration
|
||||
- Single language (JavaScript/TypeScript)
|
||||
- Great chart visualization for web
|
||||
- Faster time to market
|
||||
|
||||
**Decision**: Use **React Native** for mobile (iOS + Android) and **React** for web companion app.
|
||||
174
docs/adr/jwt-authentication-decision.md
Normal file
174
docs/adr/jwt-authentication-decision.md
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# JWT Authentication Decision Summary
|
||||
|
||||
**Date**: 2026-02-14
|
||||
**Decision**: **JWT with Refresh Tokens + Recovery Phrases**
|
||||
|
||||
---
|
||||
|
||||
## Authentication Strategy
|
||||
|
||||
### Primary: JWT (JSON Web Tokens)
|
||||
|
||||
**Why JWT?**
|
||||
- Stateless design scales to 1000+ concurrent connections
|
||||
- Works perfectly with mobile apps (AsyncStorage)
|
||||
- No server-side session storage needed
|
||||
- Easy to scale Axum horizontally
|
||||
|
||||
### Token Types
|
||||
|
||||
**Access Token** (15 minutes)
|
||||
- Used for API requests
|
||||
- Short-lived for security
|
||||
- Contains: user_id, email, family_id, permissions
|
||||
|
||||
**Refresh Token** (30 days)
|
||||
- Used to get new access tokens
|
||||
- Long-lived for convenience
|
||||
- Stored in MongoDB for revocation
|
||||
- Rotated on every refresh
|
||||
|
||||
---
|
||||
|
||||
## Token Revocation Strategies
|
||||
|
||||
### 1. Refresh Token Blacklist (Recommended) ⭐
|
||||
- Store refresh tokens in MongoDB
|
||||
- Mark as revoked on logout
|
||||
- Check on every refresh
|
||||
|
||||
### 2. Token Versioning
|
||||
- Include version in JWT claims
|
||||
- Increment on password change
|
||||
- Invalidate all tokens when version changes
|
||||
|
||||
### 3. Access Token Blacklist (Optional)
|
||||
- Store revoked access tokens in Redis
|
||||
- For immediate revocation
|
||||
- Auto-expires with TTL
|
||||
|
||||
---
|
||||
|
||||
## Refresh Token Pattern
|
||||
|
||||
### Token Rotation (Security Best Practice) ⭐
|
||||
|
||||
**Flow**:
|
||||
1. Client sends refresh_token
|
||||
2. Server verifies refresh_token (not revoked, not expired)
|
||||
3. Server generates new access_token
|
||||
4. Server generates new refresh_token
|
||||
5. Server revokes old refresh_token
|
||||
6. Server returns new tokens
|
||||
|
||||
**Why?** Prevents reuse of stolen refresh tokens
|
||||
|
||||
---
|
||||
|
||||
## Zero-Knowledge Password Recovery
|
||||
|
||||
### Recovery Phrases (from encryption.md)
|
||||
|
||||
**Registration**:
|
||||
1. Client generates recovery phrase (random 32 bytes)
|
||||
2. Client encrypts recovery phrase with password
|
||||
3. Client sends: email, password hash, encrypted recovery phrase
|
||||
4. Server stores: email, password hash, encrypted recovery phrase
|
||||
|
||||
**Password Recovery**:
|
||||
1. User requests recovery (enters email)
|
||||
2. Server returns: encrypted recovery phrase
|
||||
3. Client decrypts with recovery key (user enters manually)
|
||||
4. User enters new password
|
||||
5. Client re-encrypts recovery phrase with new password
|
||||
6. Client sends: new password hash, re-encrypted recovery phrase
|
||||
7. Server updates: password hash, encrypted recovery phrase, token_version + 1
|
||||
8. All existing tokens invalidated (version mismatch)
|
||||
|
||||
---
|
||||
|
||||
## Family Member Access Control
|
||||
|
||||
### Permissions in JWT
|
||||
|
||||
```typescript
|
||||
// JWT permissions based on family role
|
||||
{
|
||||
"parent": [
|
||||
"read:own_data",
|
||||
"write:own_data",
|
||||
"read:family_data",
|
||||
"write:family_data",
|
||||
"manage:family_members",
|
||||
"delete:data"
|
||||
],
|
||||
"child": [
|
||||
"read:own_data",
|
||||
"write:own_data"
|
||||
],
|
||||
"elderly": [
|
||||
"read:own_data",
|
||||
"write:own_data",
|
||||
"read:family_data"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Middleware
|
||||
|
||||
- Check permissions on protected routes
|
||||
- Return 403 Forbidden if insufficient permissions
|
||||
- Works with JWT claims
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend (Axum)
|
||||
- jsonwebtoken 9.x (JWT crate)
|
||||
- bcrypt 0.15 (password hashing)
|
||||
- mongodb 3.0 (refresh token storage)
|
||||
- redis (optional, for access token blacklist)
|
||||
|
||||
### Client (React Native + React)
|
||||
- AsyncStorage (token storage)
|
||||
- axios (API client with JWT interceptor)
|
||||
- PBKDF2 (password derivation)
|
||||
- AES-256-GCM (data encryption)
|
||||
|
||||
---
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
- **Week 1**: Basic JWT (login, register, middleware)
|
||||
- **Week 1-2**: Refresh tokens (storage, rotation)
|
||||
- **Week 2**: Token revocation (blacklist, versioning)
|
||||
- **Week 2-3**: Password recovery (recovery phrases)
|
||||
- **Week 3**: Family access control (permissions)
|
||||
- **Week 3-4**: Security hardening (rate limiting, HTTPS)
|
||||
|
||||
**Total**: 3-4 weeks
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Implement basic JWT service in Axum
|
||||
2. Create MongoDB schema for users and refresh tokens
|
||||
3. Implement login/register/refresh/logout handlers
|
||||
4. Create JWT middleware for protected routes
|
||||
5. Implement token revocation (blacklist + versioning)
|
||||
6. Integrate password recovery (from encryption.md)
|
||||
7. Implement family access control (permissions)
|
||||
8. Test entire authentication flow
|
||||
9. Create client-side authentication (React Native + React)
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [Comprehensive JWT Research](./2026-02-14-jwt-authentication-research.md)
|
||||
- [Normogen Encryption Guide](../encryption.md)
|
||||
- [JWT RFC 7519](https://tools.ietf.org/html/rfc7519)
|
||||
- [Axum JWT Guide](https://docs.rs/axum/latest/axum/)
|
||||
- [OWASP JWT Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html)
|
||||
635
docs/adr/mobile-health-frameworks-data.md
Normal file
635
docs/adr/mobile-health-frameworks-data.md
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
---
|
||||
date: 2026-01-05T20:27:17-03:00
|
||||
git_commit: N/A (not a git repository)
|
||||
branch: N/A
|
||||
repository: normogen
|
||||
topic: "Mobile Health Frameworks - Available Data Types"
|
||||
tags: [research, healthkit, health-connect, mobile-integration, data-types]
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Research: Mobile Health Frameworks Data Availability
|
||||
|
||||
## Research Question
|
||||
What health data can be accessed from mobile phone health frameworks (Apple HealthKit and Google Health Connect) with proper application permissions?
|
||||
|
||||
## Summary
|
||||
|
||||
**Key Finding:** Both iOS and Android provide comprehensive access to health data through their respective frameworks (HealthKit and Health Connect). With proper permissions, applications can access **50+ different health data types** including body measurements, vitals, activity, sleep, nutrition, and reproductive health.
|
||||
|
||||
**Platform Coverage:**
|
||||
- **Apple HealthKit (iOS):** 9 major categories, 50+ data types
|
||||
- **Google Health Connect (Android):** 8 major categories, 45+ data types
|
||||
- **Common to Both:** ~15 core data types with overlap
|
||||
|
||||
**User Control:** Both platforms require explicit user permission for each data category, with granular controls and easy revocation.
|
||||
|
||||
---
|
||||
|
||||
## Apple HealthKit (iOS)
|
||||
|
||||
### Data Categories Available
|
||||
|
||||
#### 1. Body Measurements
|
||||
With basic permissions:
|
||||
- **Weight** - kg, lbs
|
||||
- **Height** - cm, in, ft
|
||||
- **Body Mass Index (BMI)** - calculated
|
||||
- **Body Fat Percentage** - %age
|
||||
- **Lean Body Mass** - kg, lbs
|
||||
|
||||
#### 2. Vitals (Requires Special Permissions)
|
||||
- **Heart Rate** - beats per minute (BPM)
|
||||
- **Resting Heart Rate** - BPM
|
||||
- **Blood Pressure** - systolic/diastolic (mmHg)
|
||||
- **Body Temperature** - °C, °F
|
||||
- **Respiratory Rate** - breaths per minute
|
||||
- **Oxygen Saturation (SpO2)** - percentage
|
||||
- **Blood Glucose** - mg/dL, mmol/L
|
||||
|
||||
#### 3. Fitness & Activity
|
||||
- **Step Count** - daily/total steps
|
||||
- **Distance Walking/Running** - km, mi
|
||||
- **Flights Climbed** - count
|
||||
- **Active Energy Burned** - kcal
|
||||
- **Basal Energy Burned** - kcal/day
|
||||
- **Exercise Duration** - minutes/hours
|
||||
- **Workouts** - type, duration, calories, route
|
||||
|
||||
#### 4. Sleep Analysis
|
||||
- **Sleep Duration** - total time asleep
|
||||
- **Time in Bed** - total time in bed
|
||||
- **Sleep Stages** - in bed, asleep, awake
|
||||
- **Sleep Quality** - REM, light, deep sleep
|
||||
|
||||
#### 5. Mobility
|
||||
- **Walking Speed** - m/s
|
||||
- **Walking Asymmetry** - percentage
|
||||
- **Walking Steadiness** - score
|
||||
- **Step Length** - cm, in
|
||||
|
||||
#### 6. Nutrition
|
||||
- **Dietary Energy** - calories
|
||||
- **Macronutrients** - carbs, protein, fat (total, saturated, unsaturated)
|
||||
- **Fiber** - grams
|
||||
- **Sugar** - grams
|
||||
- **Sodium** - milligrams
|
||||
- **Water Intake** - liters, cups, ounces
|
||||
- **Vitamins & Minerals** - various (A, C, D, iron, calcium, etc.)
|
||||
|
||||
#### 7. Reproductive Health
|
||||
- **Menstrual Flow** - light, medium, heavy
|
||||
- **Basal Body Temperature** - °C, °F
|
||||
- **Cervical Mucus Quality** - type and amount
|
||||
- **Ovulation Test Result** - positive/negative
|
||||
- **Sexual Activity** - protected/unprotected
|
||||
- **Spotting** - yes/no
|
||||
|
||||
#### 8. Medical Records & Labs (Clinical Data)
|
||||
- **Allergy Records** - allergen, severity, reaction
|
||||
- **Condition Records** - diagnosis, status
|
||||
- **Immunization Records** - vaccine, date
|
||||
- **Lab Result Records** - test name, result, unit, reference range
|
||||
- **Medication Records** - name, dosage, frequency
|
||||
- **Procedure Records** - procedure, date, outcome
|
||||
- **Vital Signs Records** - clinical measurements
|
||||
|
||||
#### 9. Apple Watch Specific Data
|
||||
- **ECG Results** - ECG readings and classifications
|
||||
- **AFib Detection** - atrial fibrillation notifications
|
||||
- **Fall Detection** - fall events
|
||||
- **Noise Levels** - environmental sound exposure
|
||||
- **Headphone Audio Levels** - audio exposure
|
||||
|
||||
### Permission Requirements
|
||||
|
||||
**Info.plist Required Entries:**
|
||||
```xml
|
||||
<key>NSHealthShareUsageDescription</key>
|
||||
<string>We need access to your health data to track and analyze your wellness metrics.</string>
|
||||
|
||||
<key>NSHealthUpdateUsageDescription</key>
|
||||
<string>We need permission to save health data to your Health app.</string>
|
||||
```
|
||||
|
||||
**Entitlements Required:**
|
||||
- HealthKit capability in Xcode project settings
|
||||
- Special entitlements for clinical data access
|
||||
|
||||
**User Permissions:**
|
||||
- User must explicitly grant permission for each data category
|
||||
- Prompts shown at first access to each category
|
||||
- User can revoke permissions in Settings > Health > Data Access & Devices
|
||||
- Clinical data requires additional user consent
|
||||
|
||||
**Metadata Available:**
|
||||
- **Timestamp:** Start and end time (millisecond precision)
|
||||
- **Device:** Source device (iPhone, Apple Watch, third-party app)
|
||||
- **Units:** Always included with proper conversions
|
||||
- **Provenance:** Which app/device provided the data
|
||||
- **Accuracy:** For sensor-based measurements
|
||||
- **User Notes:** Optional user-created annotations
|
||||
|
||||
---
|
||||
|
||||
## Google Health Connect (Android)
|
||||
|
||||
### Data Types Available
|
||||
|
||||
#### 1. Activity & Exercise
|
||||
- **Steps** - count
|
||||
- **Distance** - meters, kilometers, miles
|
||||
- **Floors** - count
|
||||
- **Elevation** - meters, feet
|
||||
- **Exercise Sessions** - type (running, walking, cycling, etc.), duration, calories
|
||||
- **Swimming** - strokes, laps, distance
|
||||
- **Wheelchair Pushes** - count
|
||||
- **Golf Swings** - count (for supported apps)
|
||||
|
||||
#### 2. Body Measurements
|
||||
- **Weight** - kg, lbs
|
||||
- **Height** - meters, centimeters, feet, inches
|
||||
- **Body Fat** - percentage
|
||||
- **Basal Metabolic Rate** - kcal/day
|
||||
- **Body Water Mass** - kg
|
||||
- **Bone Mass** - kg
|
||||
- **Lean Body Mass** - kg
|
||||
|
||||
#### 3. Vitals
|
||||
- **Heart Rate** - BPM
|
||||
- **Resting Heart Rate** - BPM
|
||||
- **Heart Rate Variability** - milliseconds
|
||||
- **Blood Pressure** - systolic/diastolic in mmHg
|
||||
- **Oxygen Saturation (SpO2)** - percentage
|
||||
- **Body Temperature** - °C, °F
|
||||
- **Respiratory Rate** - breaths/minute
|
||||
|
||||
#### 4. Sleep
|
||||
- **Sleep Sessions** - start time, end time, total duration
|
||||
- **Sleep Stages** - awake, REM, light, deep sleep with durations
|
||||
- **Sleep Latency** - time to fall asleep
|
||||
|
||||
#### 5. Nutrition
|
||||
- **Hydration** - volume in mL, oz, cups
|
||||
- **Nutrition** - calories, macronutrients, micronutrients
|
||||
- **Meal Information** - meal type (breakfast, lunch, dinner, snack)
|
||||
|
||||
#### 6. Cycle Tracking
|
||||
- **Menstruation Flow** - flow amount and type
|
||||
- **Menstruation Period** - start and end dates
|
||||
- **Ovulation** - positive, negative, test result
|
||||
- **Cervical Mucus** - type and quantity
|
||||
- **Sexual Activity** - protection status
|
||||
- **Spotting** - yes/no
|
||||
|
||||
#### 7. Clinical Data
|
||||
- **Blood Glucose** - mg/dL, mmol/L
|
||||
- **Lab Test Results** - similar to Apple HealthKit
|
||||
|
||||
#### 8. Physical Activity Details
|
||||
- **Exercise Type** - running, walking, cycling, swimming, etc.
|
||||
- **Exercise Duration** - time in minutes/hours
|
||||
- **Exercise Calories** - kcal burned
|
||||
- **Exercise Route** - GPS data path (if available)
|
||||
|
||||
### Permission Requirements
|
||||
|
||||
**AndroidManifest.xml:**
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA" />
|
||||
<uses-permission android:name="android.permission.health.WRITE_HEALTH_DATA" />
|
||||
```
|
||||
|
||||
**Runtime Permissions:**
|
||||
- Granular permission requests per data type
|
||||
- User approves each category individually
|
||||
- Health Connect app must be installed on device
|
||||
- User can manage permissions in Health Connect app
|
||||
|
||||
**Requirements:**
|
||||
- Android API level 34+ (Android 14) recommended
|
||||
- Health Connect Jetpack library
|
||||
- Google Play Services (on Play Store devices)
|
||||
- User consent for each data type read
|
||||
|
||||
**Metadata Available:**
|
||||
- **Timestamps:** Start and end time (millisecond precision)
|
||||
- **Device/Source:** Which app or device provided data
|
||||
- **Accuracy:** Measurement precision
|
||||
- **Units:** Always included
|
||||
- **Entry Method:** Manual vs automatic/sensor
|
||||
|
||||
---
|
||||
|
||||
## Cross-Platform Comparison
|
||||
|
||||
### Common Data Types (Both Platforms)
|
||||
These data types are available on both iOS and Android with consistent structure:
|
||||
|
||||
| Data Type | Apple HealthKit | Google Health Connect | Notes |
|
||||
|-----------|----------------|----------------------|-------|
|
||||
| **Weight** | ✓ | ✓ | Both support kg/lbs |
|
||||
| **Height** | ✓ | ✓ | Both support metric/imperial |
|
||||
| **Steps** | ✓ | ✓ | Daily count and historical |
|
||||
| **Distance** | ✓ | ✓ | Walking/running distance |
|
||||
| **Heart Rate** | ✓ | ✓ | BPM, resting HR, HRV |
|
||||
| **Blood Pressure** | ✓ | ✓ | Systolic/diastolic |
|
||||
| **Sleep** | ✓ | ✓ | Duration, stages |
|
||||
| **Active Energy** | ✓ | ✓ | Calories burned |
|
||||
| **Body Temperature** | ✓ | ✓ | °C/°F |
|
||||
| **Blood Glucose** | ✓ | ✓ | mg/dL, mmol/L |
|
||||
| **Respiratory Rate** | ✓ | ✓ | Breaths per minute |
|
||||
| **SpO2** | ✓ | ✓ | Oxygen saturation |
|
||||
| **Nutrition** | ✓ | ✓ | Calories, macros, hydration |
|
||||
| **Exercise** | ✓ | ✓ | Type, duration, calories |
|
||||
| **Body Fat %** | ✓ | ✓ | Percentage |
|
||||
|
||||
### Platform-Specific Features
|
||||
|
||||
**Apple-Only:**
|
||||
- ECG measurements (Apple Watch)
|
||||
- Atrial fibrillation detection
|
||||
- Walking steadiness/asymmetry metrics
|
||||
- Environmental sound levels
|
||||
- More detailed mobility analysis
|
||||
- Integration with Apple ecosystem (Watch, iPad, Mac)
|
||||
|
||||
**Android-Only:**
|
||||
- More granular exercise types
|
||||
- Broader device ecosystem (Samsung, Fitbit, Garmin, etc.)
|
||||
- More flexible third-party app integrations
|
||||
- Earlier API access for some features
|
||||
|
||||
### Unit Conversions
|
||||
Both platforms handle units automatically:
|
||||
|
||||
| Measurement | iOS Units | Android Units | Notes |
|
||||
|------------|-----------|---------------|-------|
|
||||
| Weight | kg, lbs | kg, lbs | 1 kg = 2.20462 lbs |
|
||||
| Height | cm, in | cm, in, ft+in | 1 in = 2.54 cm |
|
||||
| Temperature | °C, °F | °C, °F | °F = (°C × 9/5) + 32 |
|
||||
| Glucose | mg/dL, mmol/L | mg/dL, mmol/L | mg/dL = mmol/L × 18.02 |
|
||||
| Distance | km, mi | km, mi | 1 mi = 1.60934 km |
|
||||
|
||||
### Time Precision
|
||||
- **Apple:** Millisecond precision (Unix timestamp)
|
||||
- **Android:** Millisecond precision (Unix timestamp)
|
||||
- **Both:** Support historical queries with date ranges
|
||||
- **Best Practice:** Store all timestamps in UTC on server
|
||||
|
||||
---
|
||||
|
||||
## Integration Complexity Assessment
|
||||
|
||||
### Apple HealthKit
|
||||
|
||||
**Complexity:** ⭐⭐⭐ (Medium - 3/5)
|
||||
|
||||
**Advantages:**
|
||||
- Mature, stable framework (since iOS 8)
|
||||
- Excellent documentation (with Apple Developer account)
|
||||
- Strong type safety with Swift
|
||||
- Consistent API across iOS versions
|
||||
- Good debugging tools in Xcode
|
||||
- Deep integration with Apple Watch
|
||||
|
||||
**Challenges:**
|
||||
- Requires Mac for development
|
||||
- Requires Xcode
|
||||
- Simulator has limited HealthKit support
|
||||
- Testing on physical device required
|
||||
- Some features require Apple Developer Program ($99/year)
|
||||
|
||||
**Development Requirements:**
|
||||
- macOS with Xcode
|
||||
- iOS deployment target: iOS 13+ (for full features)
|
||||
- Swift or Objective-C
|
||||
- HealthKit framework entitlement
|
||||
|
||||
### Google Health Connect
|
||||
|
||||
**Complexity:** ⭐⭐⭐⭐ (Medium-High - 4/5)
|
||||
|
||||
**Advantages:**
|
||||
- Modern, actively developed framework
|
||||
- Centralizes data from all health apps
|
||||
- Cross-app data sharing
|
||||
- User privacy controls
|
||||
- Works on wide range of devices
|
||||
|
||||
**Challenges:**
|
||||
- Newer framework (introduced 2023, replacing Google Fit)
|
||||
- Documentation still evolving
|
||||
- Android version compatibility (API 34+ recommended)
|
||||
- Device fragmentation (different OEM implementations)
|
||||
- Health Connect app must be installed separately
|
||||
- More complex testing matrix (device/OS combinations)
|
||||
|
||||
**Development Requirements:**
|
||||
- Android Studio
|
||||
- Minimum SDK: API 26 (Android 8) with compatibility layer
|
||||
- Recommended SDK: API 34 (Android 14) for full features
|
||||
- Kotlin or Java
|
||||
- Health Connect Jetpack library
|
||||
- Google Play Services (optional but recommended)
|
||||
|
||||
---
|
||||
|
||||
## Recommended MVP Integration Strategy
|
||||
|
||||
### Phase 1: Manual Entry (Current MVP Scope)
|
||||
**Timeline:** Week 1-4
|
||||
**Features:**
|
||||
- Manual entry of weight, height
|
||||
- Manual entry of basic vitals (heart rate, blood pressure, temperature)
|
||||
- Web-based interface only
|
||||
- No mobile integration yet
|
||||
|
||||
### Phase 2: Mobile Foundation
|
||||
**Timeline:** Week 5-8
|
||||
**Features:**
|
||||
- Build basic iOS and Android apps
|
||||
- Implement authentication
|
||||
- Manual data entry on mobile
|
||||
- Sync with server
|
||||
|
||||
### Phase 3: Health Framework Integration
|
||||
**Timeline:** Week 9-12
|
||||
**Features:**
|
||||
- Implement HealthKit on iOS
|
||||
- Implement Health Connect on Android
|
||||
- Support top 5 most important data types:
|
||||
1. Weight
|
||||
2. Heart Rate
|
||||
3. Blood Pressure
|
||||
4. Sleep (duration)
|
||||
5. Steps (count)
|
||||
- Background sync every 15-30 minutes
|
||||
- Historical data import (last 30 days)
|
||||
|
||||
### Phase 4: Expanded Data Types
|
||||
**Timeline:** Week 13-16
|
||||
**Features:**
|
||||
- Add all common data types
|
||||
- Support for exercise tracking
|
||||
- Nutrition tracking
|
||||
- Advanced sleep analysis
|
||||
- Menstrual cycle tracking
|
||||
|
||||
---
|
||||
|
||||
## Data Model Recommendations
|
||||
|
||||
### Enhanced health_metrics Table
|
||||
|
||||
```sql
|
||||
ALTER TABLE health_metrics ADD COLUMN metric_source VARCHAR(50)
|
||||
CHECK (metric_source IN ('manual', 'healthkit', 'healthconnect', 'third_party_device', 'unknown'));
|
||||
|
||||
ALTER TABLE health_metrics ADD COLUMN source_device_id VARCHAR(255);
|
||||
-- Stores identifier for source device/app (e.g., "com.apple.health.Health", "com.fitbit.FitbitMobile")
|
||||
|
||||
ALTER TABLE health_metrics ADD COLUMN accuracy DECIMAL(5,2);
|
||||
-- Sensor accuracy for automatic measurements (0.0-1.0, where 1.0 = perfect)
|
||||
|
||||
ALTER TABLE health_metrics ADD COLUMN metadata JSONB;
|
||||
-- Flexible storage for platform-specific data:
|
||||
-- iOS: {"HKDevice": "iPhone14,2", "HKSource": "com.apple.Health"}
|
||||
-- Android: {"device": "Samsung Galaxy S21", "package": "com.sec.android.app.health"}
|
||||
```
|
||||
|
||||
### New Table: health_metric_sources
|
||||
```sql
|
||||
CREATE TABLE health_metric_sources (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
platform VARCHAR(20) NOT NULL, -- 'ios' or 'android'
|
||||
device_name VARCHAR(255),
|
||||
source_bundle_id VARCHAR(255), -- App/package ID
|
||||
first_sync TIMESTAMP DEFAULT NOW(),
|
||||
last_sync TIMESTAMP DEFAULT NOW(),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
|
||||
UNIQUE(user_id, platform, source_bundle_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_metric_sources_user ON health_metric_sources(user_id);
|
||||
```
|
||||
|
||||
### New Table: sync_history
|
||||
```sql
|
||||
CREATE TABLE sync_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
platform VARCHAR(20) NOT NULL,
|
||||
sync_type VARCHAR(50) NOT NULL, -- 'initial', 'incremental', 'manual'
|
||||
records_imported INTEGER DEFAULT 0,
|
||||
records_failed INTEGER DEFAULT 0,
|
||||
sync_duration_seconds INTEGER,
|
||||
error_message TEXT,
|
||||
synced_from TIMESTAMP,
|
||||
synced_to TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sync_history_user ON sync_history(user_id, created_at DESC);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sync Strategy
|
||||
|
||||
### Initial Sync (First Connection)
|
||||
When user first connects health framework:
|
||||
1. Request last 30 days of data (common window)
|
||||
2. Import in batches to avoid overwhelming server
|
||||
3. Show progress to user
|
||||
4. Handle errors gracefully
|
||||
5. Store sync timestamp for incremental updates
|
||||
|
||||
### Incremental Sync (Background)
|
||||
Every 15-30 minutes:
|
||||
1. Query for new data since last sync
|
||||
2. Send new records to server
|
||||
3. Handle conflicts (same metric, multiple sources)
|
||||
4. Update last sync timestamp
|
||||
|
||||
### Conflict Resolution Strategy
|
||||
When same metric type exists from multiple sources:
|
||||
1. **Automatic Entry** (sensor/device) > **Manual Entry**
|
||||
2. **More Recent** > **Older** (for time-series data)
|
||||
3. **More Accurate** > **Less Accurate** (based on metadata)
|
||||
4. **User Preference** (if user sets preferred source)
|
||||
|
||||
### Battery Optimization
|
||||
- Limit sync frequency when battery < 20%
|
||||
- Use WorkManager (Android) and Background Tasks (iOS)
|
||||
- Batch requests to minimize wake-ups
|
||||
- Sync only when on Wi-Fi (user preference)
|
||||
- Respect battery saver mode
|
||||
|
||||
---
|
||||
|
||||
## Security & Privacy Considerations
|
||||
|
||||
### Data Transmission
|
||||
- **Always use HTTPS** (TLS 1.3)
|
||||
- **Encrypt sensitive data** at REST on server
|
||||
- **Never store credentials** on device (use tokens)
|
||||
- **Certificate pinning** for API calls
|
||||
|
||||
### Data Storage
|
||||
- **Encrypt at rest** using database encryption
|
||||
- **Separate encryption keys** per user
|
||||
- **No plaintext passwords** (bcrypt/scrypt/Argon2)
|
||||
- **Secure key derivation** for data access
|
||||
|
||||
### User Privacy
|
||||
- **Clear permission requests** explaining why data is needed
|
||||
- **Granular controls** - user chooses what to share
|
||||
- **Easy data deletion** - "nuke option" from intro.md
|
||||
- **No data sharing** with third parties without explicit consent
|
||||
- **Transparent data usage** - show user what's stored
|
||||
|
||||
### Compliance
|
||||
- **GDPR** (Europe)
|
||||
- **HIPAA** (if handling protected health information in US)
|
||||
- **CCPA** (California)
|
||||
- **App Store Review Guidelines** (Apple)
|
||||
- **Google Play Policy** (Android)
|
||||
|
||||
---
|
||||
|
||||
## Open Questions & Further Research
|
||||
|
||||
### Priority 1 (MVP Blocking)
|
||||
1. **Conflict Resolution Algorithm**
|
||||
- What if user manually enters weight but scale also sent data?
|
||||
- Need comprehensive conflict resolution policy
|
||||
|
||||
2. **Background Sync Optimization**
|
||||
- Optimal sync interval for battery vs data freshness
|
||||
- How to handle offline scenarios
|
||||
|
||||
3. **Data Retention Policy**
|
||||
- How long to keep historical data?
|
||||
- Should old data be archived or deleted?
|
||||
|
||||
### Priority 2 (Post-MVP)
|
||||
4. **Third-Party Device Integration**
|
||||
- Fitbit, Garmin, Oura Ring, Whoop, etc.
|
||||
- Each requires separate API integration
|
||||
|
||||
5. **Data Export Format**
|
||||
- What format for user downloads?
|
||||
- JSON, CSV, FHIR (HL7), or custom?
|
||||
|
||||
6. **Advanced Analytics**
|
||||
- Trends, correlations, predictions
|
||||
- Privacy-preserving computations?
|
||||
|
||||
7. **Cross-Platform Sync**
|
||||
- What if user has both iOS and Android devices?
|
||||
- How to merge data from both?
|
||||
|
||||
### Priority 3 (Future)
|
||||
8. **Real-Time Monitoring**
|
||||
- Live heart rate, blood glucose alerts?
|
||||
- Push notification strategy
|
||||
|
||||
9. **Data Visualization**
|
||||
- Charts, graphs, heatmaps
|
||||
- What library to use?
|
||||
|
||||
10. **International Units**
|
||||
- Automatic unit conversion based on user location?
|
||||
- Support for medical vs customary units?
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
### Pre-Development
|
||||
- [ ] Finalize data model with source tracking
|
||||
- [ ] Design conflict resolution algorithm
|
||||
- [ ] Create API endpoints for bulk data import
|
||||
- [ ] Set up database encryption
|
||||
|
||||
### iOS Development
|
||||
- [ ] Add HealthKit capability in Xcode
|
||||
- [ ] Write permission request code
|
||||
- [ ] Implement HealthKit queries for top 5 data types
|
||||
- [ ] Implement background sync with BGTaskScheduler
|
||||
- [ ] Test on physical device (simulator has limited support)
|
||||
|
||||
### Android Development
|
||||
- [ ] Add Health Connect dependencies
|
||||
- [ ] Add permissions to AndroidManifest
|
||||
- [ ] Write permission request code
|
||||
- [ ] Implement Health Connect queries for top 5 data types
|
||||
- [ ] Implement background sync with WorkManager
|
||||
- [ ] Test on multiple Android versions/devices
|
||||
|
||||
### Backend Development
|
||||
- [ ] Create bulk import API endpoints
|
||||
- [ ] Implement conflict resolution logic
|
||||
- [ ] Add sync history tracking
|
||||
- [ ] Optimize database indexes for time-series queries
|
||||
- [ ] Implement data deletion endpoint ("nuke")
|
||||
|
||||
### Testing
|
||||
- [ ] Unit tests for data parsing
|
||||
- [ ] Integration tests for sync logic
|
||||
- [ ] Manual testing on physical devices
|
||||
- [ ] Battery usage profiling
|
||||
- [ ] Security audit
|
||||
- [ ] Load testing with thousands of records
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Feasibility:** ✅ **Highly Feasible**
|
||||
|
||||
Both mobile platforms provide robust, well-documented frameworks for health data access. The integration is straightforward for common data types (weight, height, heart rate, blood pressure, sleep, steps).
|
||||
|
||||
**Recommendation for MVP:**
|
||||
- Start with **Phase 1** (manual entry) to validate core architecture
|
||||
- Move to **Phase 2** (mobile apps) for basic platform functionality
|
||||
- Implement **Phase 3** (health frameworks) with top 5 data types
|
||||
- Expand in **Phase 4** based on user feedback
|
||||
|
||||
**Timeline Estimate:**
|
||||
- Phase 1: 4 weeks (manual entry web app)
|
||||
- Phase 2: 4 weeks (mobile app foundation)
|
||||
- Phase 3: 4 weeks (health framework integration)
|
||||
- Phase 4: 4 weeks (expanded data types)
|
||||
|
||||
**Total to Full Mobile Integration:** ~16 weeks (4 months)
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
### Official Documentation
|
||||
- [Apple HealthKit Documentation](https://developer.apple.com/documentation/healthkit)
|
||||
- [Google Health Connect Documentation](https://developer.android.com/health-connect)
|
||||
- [Apple Human Interface Guidelines - Health](https://developer.apple.com/design/human-interface-guidelines/health)
|
||||
- [Google Play - Health Apps Policy](https://play.google.com/console/about/health/)
|
||||
|
||||
### Data Type References
|
||||
- [HealthKit HKObjectType Constants](https://developer.apple.com/documentation/healthkit/hkobjecttype)
|
||||
- [Health Connect Data Types](https://developer.android.com/reference/kotlin/androidx/health/data/class)
|
||||
- [Common Data Elements - FHIR](https://hl7.org/fhir/observation.html)
|
||||
|
||||
### Code Examples
|
||||
- Apple Sample Code: HKWorkoutSession, HKHealthStore
|
||||
- Android Sample Code: Health Connect Samples on GitHub
|
||||
|
||||
---
|
||||
|
||||
**Next Steps:**
|
||||
1. Review this research with stakeholders
|
||||
2. Prioritize which data types for MVP
|
||||
3. Choose mobile development framework (React Native vs native)
|
||||
4. Begin implementation with Phase 1 (manual entry)
|
||||
183
docs/adr/mongodb-schema-decision.md
Normal file
183
docs/adr/mongodb-schema-decision.md
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# MongoDB Schema Design Decision Summary
|
||||
|
||||
**Date**: 2026-02-14
|
||||
**Decision**: **Zero-Knowledge Encryption for All Sensitive Data + Metadata**
|
||||
|
||||
---
|
||||
|
||||
## Core Principle
|
||||
|
||||
**ALL sensitive data AND metadata must be encrypted client-side before reaching MongoDB.**
|
||||
|
||||
### Example: Blood Pressure Reading
|
||||
|
||||
**Before encryption** (client-side):
|
||||
```javascript
|
||||
{
|
||||
value: "120/80",
|
||||
type: "blood_pressure",
|
||||
unit: "mmHg",
|
||||
date: "2026-02-14T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**After encryption** (stored in MongoDB):
|
||||
```javascript
|
||||
{
|
||||
healthDataId: "health-123",
|
||||
userId: "user-456",
|
||||
profileId: "profile-789",
|
||||
familyId: "family-012",
|
||||
|
||||
// Encrypted (value + metadata)
|
||||
healthData: [
|
||||
{
|
||||
encrypted: true,
|
||||
data: "a1b2c3d4...",
|
||||
iv: "e5f6g7h8...",
|
||||
authTag: "i9j0k1l2..."
|
||||
}
|
||||
],
|
||||
|
||||
// Metadata (plaintext)
|
||||
createdAt: ISODate("2026-02-14T10:30:00Z"),
|
||||
updatedAt: ISODate("2026-02-14T10:30:00Z"),
|
||||
dataSource: "healthKit"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Collections Summary
|
||||
|
||||
| Collection | Purpose | Encrypted Fields | Plaintext Fields |
|
||||
|-----------|---------|------------------|-----------------|
|
||||
| **users** | Authentication | encryptedRecoveryPhrase | userId, email, passwordHash, tokenVersion, familyId, familyRole, permissions |
|
||||
| **families** | Family structure | familyName, familyMetadata | familyId, members[*].userId, members[*].profileId, members[*].role |
|
||||
| **profiles** | Person profiles | profileName, profileMetadata | profileId, userId, familyId, profileType |
|
||||
| **health_data** | Health records | healthData[*] (value + metadata) | healthDataId, userId, profileId, familyId, createdAt, updatedAt, dataSource |
|
||||
| **lab_results** | Lab tests | labData (value + metadata), labMetadata | labResultId, userId, profileId, familyId, createdAt, updatedAt, dataSource |
|
||||
| **medications** | Medication tracking | medicationData (value + metadata), reminderSchedule | medicationId, userId, profileId, familyId, active, createdAt, updatedAt |
|
||||
| **appointments** | Medical appointments | appointmentData (value + metadata), reminderSettings | appointmentId, userId, profileId, familyId, createdAt, updatedAt |
|
||||
| **shares** | Shared data | encryptedData (share-specific password) | shareId, userId, documentId, collectionName, createdAt, expiresAt, accessCount, isRevoked |
|
||||
| **refresh_tokens** | JWT tokens | None | jti, userId, createdAt, expiresAt, revoked |
|
||||
|
||||
---
|
||||
|
||||
## Encryption Strategy
|
||||
|
||||
### Client-Side Encryption
|
||||
|
||||
**Encryption Flow**:
|
||||
1. User enters health data
|
||||
2. Client derives encryption key from password (PBKDF2)
|
||||
3. Client encrypts health data (AES-256-GCM)
|
||||
4. Client sends encrypted data to server
|
||||
5. Server stores encrypted data in MongoDB
|
||||
6. Server NEVER decrypts data
|
||||
|
||||
### What Must Be Encrypted
|
||||
- ✅ **Health data values** (e.g., "120/80")
|
||||
- ✅ **Health data metadata** (e.g., "blood_pressure", "mmHg")
|
||||
- ✅ **Lab test results** (e.g., "cholesterol", "200", "LabCorp")
|
||||
- ✅ **Medication data** (e.g., "Aspirin", "100mg", "daily")
|
||||
- ✅ **Appointment data** (e.g., "checkup", "Dr. Smith")
|
||||
- ✅ **Profile data** (e.g., "John Doe", "1990-01-01")
|
||||
- ✅ **Family data** (e.g., "Smith Family", "123 Main St")
|
||||
### What Can Be Plaintext
|
||||
- ✅ **User IDs** (userId, profileId, familyId) - for queries
|
||||
- ✅ **Email addresses** - for authentication
|
||||
- ✅ **Dates** (createdAt, updatedAt) - for sorting
|
||||
- ✅ **Data sources** (healthKit, googleFit) - for analytics
|
||||
- ✅ **Tags** (cardio, daily) - for client-side search
|
||||
|
||||
---
|
||||
|
||||
## Privacy-Preserving Queries
|
||||
|
||||
### 1. Plaintext Queries (Recommended)
|
||||
|
||||
**Query by plaintext fields only**:
|
||||
```javascript
|
||||
const healthData = await db.health_data.find({
|
||||
userId: 'user-123', // Plaintext ✅
|
||||
profileId: 'profile-456', // Plaintext ✅
|
||||
familyId: 'family-789' // Plaintext ✅
|
||||
}).toArray();
|
||||
|
||||
// Client decrypts healthData[i].healthData[j]
|
||||
```
|
||||
|
||||
### 2. Tagging System (Encrypted Search)
|
||||
|
||||
**Client adds searchable tags to encrypted data**:
|
||||
```javascript
|
||||
const healthData = await db.health_data.find({
|
||||
userId: 'user-123',
|
||||
tags: { $in: ['cardio', 'daily'] } // Plaintext tags ✅
|
||||
}).toArray();
|
||||
|
||||
// Client decrypts healthData[i].healthData[j]
|
||||
```
|
||||
|
||||
### 3. Date Range Queries (Plaintext Dates)
|
||||
|
||||
**Store dates as plaintext** (for range queries):
|
||||
```javascript
|
||||
const healthData = await db.health_data.find({
|
||||
userId: 'user-123',
|
||||
date: {
|
||||
$gte: ISODate("2026-02-01"),
|
||||
$lte: ISODate("2026-02-28")
|
||||
}
|
||||
}).toArray();
|
||||
|
||||
// Client decrypts healthData[i].healthData[j]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Backend (Axum + MongoDB)
|
||||
- **Axum 0.7.x**: Web framework
|
||||
- **MongoDB 6.0+**: Database
|
||||
- **Rust**: Server language
|
||||
### Client (React Native + React)
|
||||
- **AES-256-GCM**: Encryption algorithm
|
||||
- **PBKDF2**: Key derivation function
|
||||
- **Crypto API**: Node.js crypto / react-native-quick-crypto
|
||||
|
||||
---
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
- **Week 1**: Create MongoDB indexes
|
||||
- **Week 1-2**: Implement client-side encryption (React Native + React)
|
||||
- **Week 2-3**: Implement server-side API (Axum + MongoDB)
|
||||
- **Week 3**: Test encryption flow
|
||||
- **Week 3-4**: Test data migration (key rotation)
|
||||
- **Week 4**: Test privacy-preserving queries
|
||||
- **Week 4-5**: Performance testing
|
||||
**Total**: 4-5 weeks
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Create MongoDB indexes for all collections
|
||||
2. Implement client-side encryption (React Native + React)
|
||||
3. Implement server-side API (Axum + MongoDB)
|
||||
4. Test encryption flow (end-to-end)
|
||||
5. Test data migration (key rotation)
|
||||
6. Test privacy-preserving queries
|
||||
7. Performance testing
|
||||
8. Create API documentation
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [Comprehensive MongoDB Schema Research](./2026-02-14-mongodb-schema-design-research.md)
|
||||
- [Normogen Encryption Guide](../encryption.md)
|
||||
- [JWT Authentication Research](./2026-02-14-jwt-authentication-research.md)
|
||||
- [Technology Stack Decisions](./2026-02-14-tech-stack-decision.md)
|
||||
312
docs/adr/monorepo-structure.md
Normal file
312
docs/adr/monorepo-structure.md
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# Monorepo Structure
|
||||
|
||||
## Repository Layout
|
||||
|
||||
```
|
||||
normogen/ # Root Forgejo repository
|
||||
├── backend/ # Rust backend (Axum + MongoDB)
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── main.rs # Entry point
|
||||
│ │ ├── auth/ # Authentication
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── jwt_service.rs
|
||||
│ │ │ ├── claims.rs
|
||||
│ │ │ └── middleware.rs
|
||||
│ │ ├── api/ # API endpoints
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── users.rs
|
||||
│ │ │ ├── families.rs
|
||||
│ │ │ ├── profiles.rs
|
||||
│ │ │ ├── health_data.rs
|
||||
│ │ │ ├── lab_results.rs
|
||||
│ │ │ ├── medications.rs
|
||||
│ │ │ ├── appointments.rs
|
||||
│ │ │ └── shares.rs
|
||||
│ │ ├── db/ # Database
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── mongo.rs
|
||||
│ │ │ ├── models.rs
|
||||
│ │ │ └── repositories.rs
|
||||
│ │ ├── config/ # Configuration
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── app.rs
|
||||
│ │ │ ├── jwt.rs
|
||||
│ │ │ ├── mongo.rs
|
||||
│ │ │ └── cors.rs
|
||||
│ │ ├── middleware/ # Middleware
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── auth.rs
|
||||
│ │ │ ├── logging.rs
|
||||
│ │ │ └── rate_limit.rs
|
||||
│ │ ├── utils/ # Utilities
|
||||
│ │ │ ├── mod.rs
|
||||
│ │ │ ├── crypto.rs
|
||||
│ │ │ └── validation.rs
|
||||
│ │ └── error.rs # Error types
|
||||
│ ├── docker/
|
||||
│ │ ├── Dockerfile # Production build
|
||||
│ │ └── Dockerfile.dev # Development build
|
||||
│ ├── config/
|
||||
│ │ ├── .env.example # Environment template
|
||||
│ │ └── defaults.env # Default values
|
||||
│ ├── k8s/ # Kubernetes manifests (future)
|
||||
│ │ ├── base/
|
||||
│ │ └── overlays/
|
||||
│ ├── Cargo.toml # Dependencies
|
||||
│ ├── Cargo.lock # Lock file
|
||||
│ ├── docker-compose.yml # Production deployment
|
||||
│ ├── docker-compose.dev.yml # Development deployment
|
||||
│ └── README.md # Backend README
|
||||
│
|
||||
├── mobile/ # React Native (iOS + Android)
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/ # Reusable components
|
||||
│ │ │ ├── common/
|
||||
│ │ │ ├── health/
|
||||
│ │ │ ├── lab/
|
||||
│ │ │ └── medication/
|
||||
│ │ ├── screens/ # Screen components
|
||||
│ │ │ ├── auth/
|
||||
│ │ │ ├── home/
|
||||
│ │ │ ├── family/
|
||||
│ │ │ ├── profile/
|
||||
│ │ │ ├── health/
|
||||
│ │ │ ├── lab/
|
||||
│ │ │ └── settings/
|
||||
│ │ ├── navigation/ # Navigation config
|
||||
│ │ │ ├── AppNavigator.tsx
|
||||
│ │ │ ├── AuthNavigator.tsx
|
||||
│ │ │ └── LinkingConfiguration.tsx
|
||||
│ │ ├── store/ # Redux store
|
||||
│ │ │ ├── slices/
|
||||
│ │ │ │ ├── authSlice.ts
|
||||
│ │ │ │ ├── userSlice.ts
|
||||
│ │ │ │ ├── familySlice.ts
|
||||
│ │ │ │ ├── profileSlice.ts
|
||||
│ │ │ │ └── healthDataSlice.ts
|
||||
│ │ │ └── store.ts
|
||||
│ │ ├── services/ # API services
|
||||
│ │ │ ├── api.ts # Axios client
|
||||
│ │ │ ├── authService.ts
|
||||
│ │ │ ├── userService.ts
|
||||
│ │ │ └── healthDataService.ts
|
||||
│ │ ├── utils/ # Utilities
|
||||
│ │ │ ├── encryption.ts # Client-side encryption
|
||||
│ │ │ ├── validation.ts
|
||||
│ │ │ └── constants.ts
|
||||
│ │ ├── hooks/ # Custom hooks
|
||||
│ │ │ ├── useAuth.ts
|
||||
│ │ │ └── useEncryptedStorage.ts
|
||||
│ │ ├── types/ # TypeScript types
|
||||
│ │ │ └── index.ts
|
||||
│ │ └── assets/ # Images, fonts
|
||||
│ ├── android/ # Android native code
|
||||
│ │ ├── app/
|
||||
│ │ └── build.gradle
|
||||
│ ├── ios/ # iOS native code
|
||||
│ │ ├── Normogen
|
||||
│ │ └── Podfile
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── App.tsx # Entry component
|
||||
│ ├── README.md
|
||||
│ └── .env.example
|
||||
│
|
||||
├── web/ # React web app
|
||||
│ ├── src/ # Source code
|
||||
│ │ ├── components/ # Reusable components
|
||||
│ │ │ ├── common/
|
||||
│ │ │ ├── health/
|
||||
│ │ │ ├── lab/
|
||||
│ │ │ └── charts/
|
||||
│ │ ├── pages/ # Page components
|
||||
│ │ │ ├── auth/
|
||||
│ │ │ ├── home/
|
||||
│ │ │ ├── family/
|
||||
│ │ │ ├── profile/
|
||||
│ │ │ ├── health/
|
||||
│ │ │ ├── lab/
|
||||
│ │ │ └── settings/
|
||||
│ │ ├── store/ # Redux store (shared with mobile)
|
||||
│ │ │ ├── slices/
|
||||
│ │ │ └── store.ts
|
||||
│ │ ├── services/ # API services (shared with mobile)
|
||||
│ │ │ ├── api.ts
|
||||
│ │ │ └── ...
|
||||
│ │ ├── utils/ # Utilities (shared with mobile)
|
||||
│ │ │ ├── encryption.ts
|
||||
│ │ │ └── ...
|
||||
│ │ ├── hooks/ # Custom hooks
|
||||
│ │ │ └── ...
|
||||
│ │ ├── types/ # TypeScript types (shared)
|
||||
│ │ │ └── index.ts
|
||||
│ │ ├── styles/ # CSS/global styles
|
||||
│ │ │ └── global.css
|
||||
│ │ └── App.tsx
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── index.html
|
||||
│ ├── vite.config.ts # Vite config
|
||||
│ └── README.md
|
||||
│
|
||||
├── shared/ # Shared TypeScript code
|
||||
│ ├── src/
|
||||
│ │ ├── types/ # Shared type definitions
|
||||
│ │ │ ├── user.ts
|
||||
│ │ │ ├── family.ts
|
||||
│ │ │ ├── profile.ts
|
||||
│ │ │ ├── healthData.ts
|
||||
│ │ │ ├── labResults.ts
|
||||
│ │ │ ├── medications.ts
|
||||
│ │ │ ├── appointments.ts
|
||||
│ │ │ ├── shares.ts
|
||||
│ │ │ └── api.ts
|
||||
│ │ ├── validation/ # Zod schemas
|
||||
│ │ │ ├── user.ts
|
||||
│ │ │ ├── family.ts
|
||||
│ │ │ └── healthData.ts
|
||||
│ │ ├── encryption/ # Encryption utilities
|
||||
│ │ │ ├── crypto.ts
|
||||
│ │ │ └── keyDerivation.ts
|
||||
│ │ ├── api/ # Shared API client
|
||||
│ │ │ ├── client.ts
|
||||
│ │ │ └── endpoints.ts
|
||||
│ │ └── constants/ # Shared constants
|
||||
│ │ ├── routes.ts
|
||||
│ │ └── config.ts
|
||||
│ ├── package.json
|
||||
│ ├── tsconfig.json
|
||||
│ └── README.md
|
||||
│
|
||||
├── thoughts/ # Research & design docs
|
||||
│ ├── research/
|
||||
│ │ ├── 2026-02-14-rust-framework-comparison.md
|
||||
│ │ ├── 2026-02-14-rust-framework-performance-research.md
|
||||
│ │ ├── 2026-02-14-performance-findings.md
|
||||
│ │ ├── 2026-02-14-research-summary.md
|
||||
│ │ ├── 2026-02-14-frontend-mobile-research.md
|
||||
│ │ ├── 2026-02-14-frontend-decision-summary.md
|
||||
│ │ ├── 2026-02-14-state-management-research.md
|
||||
│ │ ├── 2026-02-14-state-management-decision.md
|
||||
│ │ ├── 2026-02-14-jwt-authentication-research.md
|
||||
│ │ ├── 2026-02-14-jwt-authentication-decision.md
|
||||
│ │ ├── 2026-02-14-mongodb-schema-design-research.md
|
||||
│ │ ├── 2026-02-14-mongodb-schema-decision.md
|
||||
│ │ ├── 2026-02-14-backend-deployment-constraints.md
|
||||
│ │ └── 2026-02-14-monorepo-structure.md
|
||||
│ └── research/
|
||||
│
|
||||
├── .gitignore # Root gitignore
|
||||
├── README.md # Root README
|
||||
├── docker-compose.root.yml # Run all services (optional)
|
||||
└── .forgejo/ # Forgejo CI/CD workflows
|
||||
└── workflows/
|
||||
├── backend-build.yml
|
||||
├── mobile-build.yml
|
||||
└── web-build.yml
|
||||
```
|
||||
|
||||
## Directory Creation Commands
|
||||
|
||||
```bash
|
||||
# Create root directories
|
||||
mkdir -p backend/{src/{auth,api,db,config,middleware,utils},docker,config,k8s/base,k8s/overlays/homelab,k8s/overlays/production}
|
||||
mkdir -p mobile/{src/{components/{common,health,lab,medication},screens/{auth,home,family,profile,health,lab,settings},navigation,store/slices,services,utils,hooks,types,assets},android,ios}
|
||||
mkdir -p web/{src/{components/{common,health,lab,charts},pages/{auth,home,family,profile,health,lab,settings},store/slices,services,utils,hooks,types,styles}}
|
||||
mkdir -p shared/src/{types,validation,encryption,api,constants}
|
||||
mkdir -p thoughts/research
|
||||
mkdir -p .forgejo/workflows
|
||||
|
||||
# Create placeholder files
|
||||
touch backend/src/{main.rs,auth/mod.rs,api/mod.rs,db/mod.rs,config/mod.rs,middleware/mod.rs,utils/mod.rs,error.rs}
|
||||
touch mobile/src/{App.tsx,navigation/AppNavigator.tsx,store/store.ts,services/api.ts,utils/encryption.ts}
|
||||
touch web/src/{App.tsx,store/store.ts,services/api.ts,utils/encryption.ts}
|
||||
touch shared/src/{types/index.ts,validation/index.ts,encryption/crypto.ts,api/client.ts}
|
||||
```
|
||||
|
||||
## Git Strategy
|
||||
|
||||
### Branch Strategy
|
||||
- `main`: Production releases
|
||||
- `develop`: Development integration
|
||||
- `feature/backend-*`: Backend features
|
||||
- `feature/mobile-*`: Mobile features
|
||||
- `feature/web-*`: Web features
|
||||
- `feature/shared-*`: Shared code features
|
||||
|
||||
### Commit Message Format
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
Types: feat, fix, docs, style, refactor, test, chore
|
||||
|
||||
Scopes: backend, mobile, web, shared, ci/cd
|
||||
|
||||
Examples:
|
||||
- `feat(backend): Implement JWT authentication with refresh tokens`
|
||||
- `fix(mobile): Resolve encryption key storage issue`
|
||||
- `docs(shared): Update API type definitions`
|
||||
- `chore(ci/cd): Add Forgejo workflow for backend builds`
|
||||
|
||||
## Shared Code Management
|
||||
|
||||
### TypeScript Package
|
||||
The `shared/` directory contains TypeScript code shared between mobile and web:
|
||||
- Type definitions (API models)
|
||||
- Validation schemas (Zod)
|
||||
- Encryption utilities
|
||||
- API client
|
||||
- Constants
|
||||
|
||||
### Usage in Mobile/Web
|
||||
```json
|
||||
// mobile/package.json and web/package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"shared": "file:../shared"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Watch Mode for Development
|
||||
```bash
|
||||
# In shared/ directory
|
||||
npm run watch # Watch and rebuild on changes
|
||||
|
||||
# In mobile/ and web/ directories
|
||||
# Changes to shared/ are automatically picked up
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Initialize Monorepo Structure**
|
||||
- Create all directories
|
||||
- Create placeholder files
|
||||
- Update root .gitignore
|
||||
|
||||
2. **Backend Initialization**
|
||||
- Initialize Rust project (backend/)
|
||||
- Setup Cargo.toml
|
||||
- Create docker-compose files
|
||||
- Create Dockerfiles
|
||||
|
||||
3. **Shared Code Setup**
|
||||
- Initialize TypeScript project (shared/)
|
||||
- Setup type definitions
|
||||
- Setup Zod validation schemas
|
||||
- Setup encryption utilities
|
||||
|
||||
4. **Mobile Setup** (Phase 3)
|
||||
- Initialize React Native project
|
||||
- Setup Redux Toolkit
|
||||
- Setup navigation
|
||||
|
||||
5. **Web Setup** (Phase 3)
|
||||
- Initialize React project
|
||||
- Setup Redux Toolkit
|
||||
- Setup routing
|
||||
106
docs/adr/state-management-decision.md
Normal file
106
docs/adr/state-management-decision.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# State Management Decision Summary
|
||||
|
||||
**Date**: 2026-02-14
|
||||
**Decision**: **Redux Toolkit 2.x**
|
||||
|
||||
---
|
||||
|
||||
## Scorecard
|
||||
|
||||
| Criterion | Redux Toolkit | Zustand | Jotai | Weight |
|
||||
|-----------|---------------|----------|--------|--------|
|
||||
| Code Sharing | 10 | 10 | 10 | Critical |
|
||||
| Bundle Size | 7 | 10 | 10 | Critical |
|
||||
| TypeScript | 10 | 10 | 10 | Critical |
|
||||
| Complex State | 10 | 7 | 5 | Critical |
|
||||
| Offline Sync | 10 | 7 | 5 | Critical |
|
||||
| **Weighted Score** | **9.2** | 8.6 | 7.6 | - |
|
||||
|
||||
---
|
||||
|
||||
## Decision: Redux Toolkit 2.x
|
||||
|
||||
**Score**: 9.2/10
|
||||
|
||||
### Key Advantages
|
||||
|
||||
1. **Best for Complex State**
|
||||
- Family structure, multi-person profiles, permissions
|
||||
- Built-in normalization (createEntityAdapter)
|
||||
- Predictable state updates
|
||||
- Time-travel debugging
|
||||
|
||||
2. **Best for Offline Sync**
|
||||
- RTK Query for server state management
|
||||
- Optimistic updates
|
||||
- Background sync support
|
||||
- Battle-tested offline patterns
|
||||
|
||||
3. **Best Ecosystem**
|
||||
- Largest ecosystem
|
||||
- Most resources, tutorials, examples
|
||||
- Most production deployments
|
||||
- Easiest to hire developers
|
||||
|
||||
4. **Best Developer Experience**
|
||||
- Time-travel debugging
|
||||
- Predictable state updates
|
||||
- Easy to debug
|
||||
|
||||
### Trade-offs
|
||||
|
||||
- More boilerplate: More code, but clearer structure
|
||||
- Steeper learning curve: More concepts, but better patterns
|
||||
- Larger bundle: 60KB vs 3KB (negligible impact on 50-100MB app)
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Shared (Monorepo)
|
||||
- **State Management**: Redux Toolkit 2.x
|
||||
- **Data Fetching**: RTK Query 2.x
|
||||
- **Async Thunks**: createAsyncThunk
|
||||
- **Persistence**: Redux Persist 6.x
|
||||
- **Selectors**: Reselect 5.x
|
||||
- **DevTools**: Redux DevTools
|
||||
|
||||
---
|
||||
|
||||
## Alternative Considered: Zustand
|
||||
|
||||
**Score**: 8.6/10
|
||||
|
||||
**Why Redux Toolkit wins**:
|
||||
- Better for complex state (family structure)
|
||||
- Better for offline sync (RTK Query)
|
||||
- Larger ecosystem (more resources)
|
||||
|
||||
**When to use Zustand instead**:
|
||||
- If team has no Redux experience
|
||||
- If state is simpler (no family structure)
|
||||
- If development speed is more important
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Implement Redux Toolkit POC
|
||||
2. Create family structure state slice
|
||||
3. Implement RTK Query for server state
|
||||
4. Test offline synchronization
|
||||
5. Test encrypted data caching
|
||||
6. Make final decision
|
||||
|
||||
---
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
- Setup Redux Toolkit: 1 day
|
||||
- Create state slices: 2-3 days
|
||||
- Implement RTK Query: 2-3 days
|
||||
- Implement offline sync: 3-5 days
|
||||
- Test encrypted caching: 2-3 days
|
||||
- Evaluate DX: 1-2 days
|
||||
|
||||
**Total**: 11-17 days (2-3 weeks)
|
||||
316
docs/adr/tech-stack-decision.md
Normal file
316
docs/adr/tech-stack-decision.md
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
# Technology Stack Decisions
|
||||
|
||||
**Last Updated**: 2026-02-14
|
||||
|
||||
---
|
||||
|
||||
## Decisions Made
|
||||
|
||||
### 1. Rust Web Framework: Axum
|
||||
**Decision**: Axum 0.7.x
|
||||
|
||||
**Rationale**:
|
||||
- Superior I/O performance for encrypted data transfer
|
||||
- Better streaming support for large encrypted responses
|
||||
- Lower memory usage for concurrent connections
|
||||
- Tower middleware ecosystem
|
||||
- Excellent async patterns for lazy loading
|
||||
|
||||
**Reference**: [2026-02-14-performance-findings.md](./2026-02-14-performance-findings.md)
|
||||
|
||||
---
|
||||
|
||||
### 2. Mobile Framework: React Native
|
||||
**Decision**: React Native 0.73+ for iOS + Android
|
||||
|
||||
**Platform Strategy**:
|
||||
- **Primary**: Mobile apps (iOS + Android) - Daily health tracking, sensor integration
|
||||
- **Secondary**: Web browser - Extensive reporting, visualization, profile management
|
||||
|
||||
**Rationale**:
|
||||
- **70-80% code sharing** between mobile and web (single language: TypeScript)
|
||||
- **Health sensor integration**: react-native-health (HealthKit), react-native-google-fit (Health Connect)
|
||||
- **QR code scanning**: react-native-camera
|
||||
- **Encryption**: react-native-quick-crypto (AES-256-GCM, PBKDF2)
|
||||
- **Web charts**: Recharts for React (beautiful visualizations)
|
||||
- **Team skills**: Single language (JavaScript/TypeScript) reduces development cost
|
||||
- **Time to market**: Faster than native or Flutter
|
||||
|
||||
**Reference**: [2026-02-14-frontend-mobile-research.md](./2026-02-14-frontend-mobile-research.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. Web Framework: React
|
||||
**Decision**: React 18+ for web companion app
|
||||
|
||||
**Rationale**:
|
||||
- **70-80% code sharing** with React Native (business logic, state, API, encryption)
|
||||
- **Charts**: Recharts for beautiful health data visualizations
|
||||
- **Ecosystem**: Largest npm ecosystem
|
||||
- **Team skills**: Single language (TypeScript)
|
||||
|
||||
---
|
||||
|
||||
### 4. State Management: Redux Toolkit
|
||||
**Decision**: Redux Toolkit 2.x for React Native + React
|
||||
|
||||
**Score**: 9.2/10
|
||||
|
||||
**Rationale**:
|
||||
- **Best for complex state**: Family structure, multi-person profiles, permissions
|
||||
- **Built-in normalization**: createEntityAdapter for efficient data management
|
||||
- **Best for offline sync**: RTK Query for server state, optimistic updates, background sync
|
||||
- **Largest ecosystem**: Most resources, tutorials, examples, production deployments
|
||||
- **Best developer experience**: Time-travel debugging, predictable state updates
|
||||
- **TypeScript**: Excellent support, full type safety
|
||||
- **Code sharing**: 100% between React Native and React
|
||||
|
||||
**Trade-offs**:
|
||||
- More boilerplate: More code, but clearer structure
|
||||
- Steeper learning curve: More concepts, but better patterns
|
||||
- Larger bundle: 60KB vs 3KB (negligible impact on 50-100MB app)
|
||||
|
||||
**Reference**: [2026-02-14-state-management-research.md](./2026-02-14-state-management-research.md)
|
||||
|
||||
---
|
||||
|
||||
### 5. Authentication: JWT with Refresh Tokens
|
||||
**Decision**: JWT (JSON Web Tokens) with Refresh Tokens + Recovery Phrases
|
||||
|
||||
**Score**: 9.5/10
|
||||
|
||||
**Rationale**:
|
||||
- **Stateless design**: Scales to 1000+ concurrent connections (no session storage)
|
||||
- **Mobile-friendly**: Works perfectly with React Native (AsyncStorage)
|
||||
- **Zero-knowledge compatible**: Integrates with recovery phrases from encryption.md
|
||||
- **Token revocation**: Refresh token blacklist (MongoDB) + token versioning
|
||||
- **Token rotation**: Prevents reuse of stolen refresh tokens
|
||||
- **Family access control**: Permissions in JWT claims (parent, child, elderly)
|
||||
- **Security best practices**: Short-lived access tokens (15 min), long-lived refresh tokens (30 days)
|
||||
|
||||
**Trade-offs**:
|
||||
- Revocation requires storage (MongoDB for refresh tokens, optional Redis for access tokens)
|
||||
- More complex than sessions (but better for scaling)
|
||||
|
||||
**Reference**: [2026-02-14-jwt-authentication-research.md](./2026-02-14-jwt-authentication-research.md)
|
||||
|
||||
---
|
||||
|
||||
### 6. Database: MongoDB with Zero-Knowledge Encryption
|
||||
**Decision**: MongoDB 6.0+ with client-side encryption (ALL sensitive data + metadata)
|
||||
|
||||
**Score**: 9.8/10
|
||||
|
||||
**Core Principle**: **ALL sensitive data AND metadata must be encrypted client-side before reaching MongoDB**
|
||||
|
||||
**Example: Blood Pressure Reading**:
|
||||
```javascript
|
||||
// Before encryption (client-side)
|
||||
{
|
||||
value: "120/80",
|
||||
type: "blood_pressure",
|
||||
unit: "mmHg",
|
||||
date: "2026-02-14T10:30:00Z"
|
||||
}
|
||||
|
||||
// After encryption (stored in MongoDB)
|
||||
{
|
||||
healthDataId: "health-123",
|
||||
userId: "user-456",
|
||||
profileId: "profile-789",
|
||||
|
||||
// Encrypted (value + metadata)
|
||||
healthData: [
|
||||
{
|
||||
encrypted: true,
|
||||
data: "a1b2c3d4...",
|
||||
iv: "e5f6g7h8...",
|
||||
authTag: "i9j0k1l2..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- **Zero-knowledge**: Server NEVER decrypts data
|
||||
- **Metadata encryption**: Health data type, unit, doctor, lab ALL encrypted
|
||||
- **Privacy-preserving**: No plaintext metadata leaks
|
||||
- **Client-side encryption**: AES-256-GCM, PBKDF2 key derivation
|
||||
- **Plaintext queries**: Query by userId, profileId, familyId, date, tags
|
||||
- **Tagging system**: Client adds searchable tags for encrypted data
|
||||
- **Flexible schema**: MongoDB document structure fits health data
|
||||
- **Scalable**: Horizontal scaling with sharding
|
||||
|
||||
**Collections**:
|
||||
- **users**: Authentication, profiles, family relationships
|
||||
- **families**: Family structure, encrypted family name/metadata
|
||||
- **profiles**: Person profiles, encrypted profile name/metadata
|
||||
- **health_data**: Encrypted health records (value + metadata)
|
||||
- **lab_results**: Encrypted lab data (value + metadata)
|
||||
- **medications**: Encrypted medication data + reminders
|
||||
- **appointments**: Encrypted appointment data + reminders
|
||||
- **shares**: Time-limited access to shared data
|
||||
- **refresh_tokens**: JWT refresh token storage
|
||||
|
||||
**What Must Be Encrypted**:
|
||||
- ✅ Health data values (e.g., "120/80")
|
||||
- ✅ Health data metadata (e.g., "blood_pressure", "mmHg")
|
||||
- ✅ Lab test results (e.g., "cholesterol", "200", "LabCorp")
|
||||
- ✅ Medication data (e.g., "Aspirin", "100mg", "daily")
|
||||
- ✅ Appointment data (e.g., "checkup", "Dr. Smith")
|
||||
- ✅ Profile data (e.g., "John Doe", "1990-01-01")
|
||||
- ✅ Family data (e.g., "Smith Family", "123 Main St")
|
||||
|
||||
**What Can Be Plaintext**:
|
||||
- ✅ User IDs (userId, profileId, familyId) - for queries
|
||||
- ✅ Email addresses - for authentication
|
||||
- ✅ Dates (createdAt, updatedAt) - for sorting
|
||||
- ✅ Data sources (healthKit, googleFit) - for analytics
|
||||
- ✅ Tags (cardio, daily) - for client-side search
|
||||
|
||||
**Reference**: [2026-02-14-mongodb-schema-design-research.md](./2026-02-14-mongodb-schema-design-research.md)
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack Summary
|
||||
|
||||
### Backend
|
||||
- **Framework**: Axum 0.7.x
|
||||
- **Runtime**: Tokio 1.x
|
||||
- **Middleware**: Tower, Tower-HTTP
|
||||
- **Authentication**: JWT with refresh tokens
|
||||
- **Database**: MongoDB 6.0+ (with zero-knowledge encryption)
|
||||
- **Language**: Rust
|
||||
|
||||
### Mobile (iOS + Android)
|
||||
- **Framework**: React Native 0.73+
|
||||
- **Language**: TypeScript
|
||||
- **State Management**: Redux Toolkit 2.x
|
||||
- **Data Fetching**: RTK Query 2.x
|
||||
- **Authentication**: JWT with AsyncStorage
|
||||
- **Navigation**: React Navigation
|
||||
- **Health Sensors**:
|
||||
- react-native-health (iOS HealthKit)
|
||||
- react-native-google-fit (Android Health Connect)
|
||||
- **QR Scanning**: react-native-camera
|
||||
- **Encryption**: react-native-quick-crypto
|
||||
- **Persistence**: Redux Persist 6.x (AsyncStorage)
|
||||
- **HTTP**: Axios
|
||||
|
||||
### Web
|
||||
- **Framework**: React 18+
|
||||
- **Language**: TypeScript
|
||||
- **State Management**: Redux Toolkit 2.x
|
||||
- **Data Fetching**: RTK Query 2.x
|
||||
- **Authentication**: JWT with localStorage (or httpOnly cookies)
|
||||
- **Routing**: React Router
|
||||
- **Charts**: Recharts
|
||||
- **Persistence**: Redux Persist 6.x (localStorage)
|
||||
- **HTTP**: Axios
|
||||
|
||||
### Shared (Monorepo)
|
||||
- **Language**: TypeScript
|
||||
- **State Management**: Redux Toolkit 2.x
|
||||
- **Reducers**: Shared reducers (user, family, encryption)
|
||||
- **Selectors**: Shared selectors (Reselect 5.x)
|
||||
- **API**: Axios
|
||||
- **Encryption**: AES-256-GCM, PBKDF2
|
||||
- **Validation**: Zod
|
||||
- **Date**: date-fns
|
||||
- **Utilities**: Shared package
|
||||
|
||||
---
|
||||
|
||||
## All Major Decisions Complete ✅
|
||||
|
||||
1. ✅ Rust Framework: Axum 0.7.x
|
||||
2. ✅ Mobile Framework: React Native 0.73+
|
||||
3. ✅ Web Framework: React 18+
|
||||
4. ✅ State Management: Redux Toolkit 2.x
|
||||
5. ✅ Authentication: JWT with refresh tokens
|
||||
6. ✅ Database: MongoDB 6.0+ with zero-knowledge encryption
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
- **Phase 1: Research** (COMPLETE)
|
||||
- Rust framework selection
|
||||
- Mobile/web framework selection
|
||||
- State management selection
|
||||
- Authentication design
|
||||
- Database schema design
|
||||
|
||||
- **Phase 2: Backend Development** (NEXT)
|
||||
- Axum server setup
|
||||
- MongoDB connection
|
||||
- JWT authentication
|
||||
- CRUD API endpoints
|
||||
- Zero-knowledge encryption (client-side)
|
||||
|
||||
- **Phase 3: Mobile Development** (AFTER BACKEND)
|
||||
- React Native app setup
|
||||
- Redux Toolkit setup
|
||||
- JWT authentication
|
||||
- Health sensor integration
|
||||
- QR code scanning
|
||||
- Encryption implementation
|
||||
|
||||
- **Phase 4: Web Development** (PARALLEL WITH MOBILE)
|
||||
- React app setup
|
||||
- Redux Toolkit setup
|
||||
- JWT authentication
|
||||
- Charts and visualizations
|
||||
- Profile management
|
||||
- Encryption implementation
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Backend Development** (Axum + MongoDB)
|
||||
- Create Axum server
|
||||
- Setup MongoDB connection
|
||||
- Implement JWT authentication
|
||||
- Create MongoDB indexes
|
||||
- Implement CRUD endpoints
|
||||
|
||||
2. **Client-Side Encryption** (React Native + React)
|
||||
- Implement AES-256-GCM encryption
|
||||
- Implement PBKDF2 key derivation
|
||||
- Create encryption utilities
|
||||
- Test encryption flow
|
||||
|
||||
3. **API Development** (Axum)
|
||||
- Users API (register, login, logout)
|
||||
- Families API (create, update, delete)
|
||||
- Profiles API (CRUD)
|
||||
- Health Data API (CRUD)
|
||||
- Lab Results API (import via QR)
|
||||
- Medications API (reminders)
|
||||
- Appointments API (reminders)
|
||||
- Shares API (time-limited access)
|
||||
|
||||
---
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
- **Phase 1: Research** (COMPLETE)
|
||||
- **Phase 2: Backend Development** (8-10 weeks)
|
||||
- **Phase 3: Mobile Development** (8-12 weeks)
|
||||
- **Phase 4: Web Development** (4-6 weeks)
|
||||
- **Phase 5: Testing & Polish** (4-6 weeks)
|
||||
|
||||
**Total**: 24-34 weeks (6-8.5 months)
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [Axum Performance Research](./2026-02-14-performance-findings.md)
|
||||
- [Frontend Mobile Research](./2026-02-14-frontend-mobile-research.md)
|
||||
- [State Management Research](./2026-02-14-state-management-research.md)
|
||||
- [JWT Authentication Research](./2026-02-14-jwt-authentication-research.md)
|
||||
- [MongoDB Schema Design](./2026-02-14-mongodb-schema-design-research.md)
|
||||
- [Normogen Encryption Guide](../encryption.md)
|
||||
- [Project Introduction](../introduction.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue