first commit
This commit is contained in:
@@ -1,584 +1,57 @@
|
||||
# Fitness Tracking App - Production-Ready Implementation
|
||||
# SportPath
|
||||
|
||||
**Version:** 1.0.0
|
||||
**Architecture:** Flutter (Mobile) + PHP (Backend) + MySQL (Database)
|
||||
**Status:** Production-Ready
|
||||
SportPath تطبيق لياقة عربي قيد التطوير: تطبيق Flutter لـiOS وAndroid، واجهة ويب ولوحة إدارة، وواجهة PHP API مع MySQL. يدعم التتبع المحلي للتمارين، خطط التدريب ومكتبة الحركات، سجل الوجبات، تحليل صورة اختياري، وتذكيرات محلية. لا يُعد جاهزًا للإنتاج قبل إعداد مزود OTP وبيئة CloudPanel، واختبار قاعدة البيانات والنشر على staging.
|
||||
|
||||
## 📋 Project Overview
|
||||
## بنية المشروع
|
||||
|
||||
A comprehensive fitness tracking application for recording and analyzing running and walking workouts. Built with production-grade architecture, HMAC-secured API endpoints, background GPS tracking, and MapLibre map visualization.
|
||||
- `mobile/`: تطبيق Flutter، التخزين المحلي SQLite، المصادقة، المزامنة، التذكيرات، وتجربة التمرين والوجبات.
|
||||
- `backend/`: PHP API والمصادقة والتحقق ومخطط MySQL والترحيلات.
|
||||
- `public/`: نقطة دخول الموقع وصفحات `/api/v1/` ولوحة `/admin/`.
|
||||
- `deploy/`: أدوات نشر الإصدارات وترحيلات قاعدة البيانات إلى CloudPanel.
|
||||
- `IMPLEMENTATION_ROADMAP_AR.md`: الحالة التنفيذية والمراحل والمتطلبات التي ما زالت تنتظر إعدادًا أو تحققًا خارجيًا.
|
||||
- `FITNESS_PRODUCT_PLAN_AR.md`: خطة المنتج والمراجع البحثية.
|
||||
|
||||
### Key Features
|
||||
## التطوير والاختبارات المحلية
|
||||
|
||||
✅ Real-time GPS tracking with SQLite local storage
|
||||
✅ MapLibre map visualization with route overlay
|
||||
✅ Encoded polyline route compression (~75% reduction)
|
||||
✅ HMAC-SHA256 authenticated API endpoints
|
||||
✅ Background location tracking capability
|
||||
✅ Workout statistics and analytics
|
||||
✅ Secure credential management
|
||||
✅ Audit logging and analytics
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
fitness/
|
||||
├── backend/ # PHP REST API
|
||||
│ ├── schema.sql # MySQL database schema
|
||||
│ ├── Database.php # Database singleton connection
|
||||
│ ├── AuthenticationHandler.php # HMAC validation & security
|
||||
│ ├── api_workouts.php # POST /api/v1/workouts endpoint
|
||||
│ ├── PolylineUtility.php # Polyline encoding/decoding
|
||||
│ ├── WorkoutValidator.php # Request payload validation
|
||||
│ └── API_HMAC_GUIDE.md # HMAC implementation guide
|
||||
│
|
||||
├── mobile/ # Flutter application
|
||||
│ ├── main.dart # App entry point & home screen
|
||||
│ ├── workout_controller.dart # GetX controller & models
|
||||
│ ├── workout_tracking_screen.dart # Map & workout UI
|
||||
│ ├── pubspec.yaml # Flutter dependencies
|
||||
│ └── assets/ # Images, fonts, etc.
|
||||
│
|
||||
├── DEPLOYMENT_GUIDE.md # Production deployment instructions
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## 🏗️ Architecture Details
|
||||
|
||||
### Backend Layer (PHP)
|
||||
|
||||
#### Database Schema
|
||||
|
||||
- **users**: User accounts with API credentials
|
||||
- **workouts**: Completed workout records with polyline routes
|
||||
- **workout_segments**: Optional detailed route segments
|
||||
- **api_logs**: Audit trail for all API requests
|
||||
- **user_stats_cache**: Cached user statistics for performance
|
||||
|
||||
#### API Endpoints
|
||||
|
||||
**POST /api/v1/workouts**
|
||||
|
||||
```
|
||||
Receives completed workout with HMAC authentication
|
||||
- Validates HMAC-SHA256 signature
|
||||
- Validates timestamp (5-minute window)
|
||||
- Validates workout payload schema
|
||||
- Decodes polyline and stores in database
|
||||
- Returns: 201 with workout_uuid on success
|
||||
```
|
||||
|
||||
**Authentication Headers Required:**
|
||||
|
||||
```
|
||||
X-API-Key: <64-char hex string>
|
||||
X-Signature: <HMAC-SHA256 hash>
|
||||
X-Timestamp: <unix timestamp>
|
||||
```
|
||||
|
||||
#### Request Payload Example
|
||||
|
||||
```json
|
||||
{
|
||||
"workout_type": "running",
|
||||
"distance_meters": 5000,
|
||||
"duration_seconds": 1800,
|
||||
"elevation_gain_meters": 150,
|
||||
"elevation_loss_meters": 100,
|
||||
"calories_burned": 350.5,
|
||||
"max_speed_mps": 4.5,
|
||||
"route_polyline": "encoded_polyline_string",
|
||||
"start_time": "2026-04-21T14:30:00.000Z",
|
||||
"end_time": "2026-04-21T14:45:00.000Z",
|
||||
"weather_condition": "sunny",
|
||||
"temperature_celsius": 22.5,
|
||||
"notes": "Great workout!",
|
||||
"is_public": false,
|
||||
"segments": []
|
||||
}
|
||||
```
|
||||
|
||||
#### Response Example (201 Created)
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"workout_id": 123,
|
||||
"workout_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"message": "Workout submitted successfully",
|
||||
"timestamp": "2026-04-21T14:45:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Mobile Layer (Flutter)
|
||||
|
||||
#### State Management (GetX)
|
||||
|
||||
```
|
||||
WorkoutController (GetxController)
|
||||
├── LocationService (GetxService)
|
||||
│ ├── SQLite database for offline storage
|
||||
│ ├── Save coordinates in background
|
||||
│ └── Retrieve coordinates on workout end
|
||||
├── _currentWorkout (WorkoutSession)
|
||||
│ ├── Tracks time, distance, coordinates
|
||||
│ ├── Manages pause/resume state
|
||||
│ └── Calculates statistics
|
||||
├── GpsCoordinate (Model)
|
||||
│ ├── latitude, longitude
|
||||
│ ├── altitude, accuracy
|
||||
│ └── timestamp
|
||||
└── PolylineUtility (Utility)
|
||||
├── Encode coordinates to polyline
|
||||
└── Decode polyline to coordinates
|
||||
```
|
||||
|
||||
#### Views
|
||||
|
||||
**HomeScreen**: Landing page with start workout button
|
||||
**WorkoutTrackingScreen**: Main tracking interface with:
|
||||
|
||||
- MapLibre map showing live route
|
||||
- Real-time stats (distance, time, pace, speed)
|
||||
- Start/Pause/Stop controls
|
||||
- Workout type selector
|
||||
|
||||
**WorkoutSummaryDialog**: Post-workout review with submission
|
||||
|
||||
#### Key Classes
|
||||
|
||||
**WorkoutSession**
|
||||
|
||||
- Manages single workout instance
|
||||
- Calculates distance using Haversine formula
|
||||
- Tracks pause/resume durations
|
||||
- Handles start/end times
|
||||
|
||||
**LocationService (GetxService)**
|
||||
|
||||
- SQLite database for persistent offline storage
|
||||
- Async coordinate saving
|
||||
- Batch retrieval for polyline encoding
|
||||
- Automatic cleanup after submission
|
||||
|
||||
**WorkoutController (GetxController)**
|
||||
|
||||
- Orchestrates entire workout lifecycle
|
||||
- Manages GPS updates via timer
|
||||
- Generates HMAC signatures
|
||||
- Submits workouts to API
|
||||
|
||||
## 🔐 Security Implementation
|
||||
|
||||
### HMAC-SHA256 Authentication
|
||||
|
||||
**Signature Generation Algorithm:**
|
||||
|
||||
```
|
||||
message = timestamp + "|" + api_key + "|" + raw_request_body
|
||||
signature = HMAC-SHA256(message, api_secret)
|
||||
hex_signature = hex_encode(signature)
|
||||
```
|
||||
|
||||
**Implementation (Dart):**
|
||||
|
||||
```dart
|
||||
String generateHmacSignature(
|
||||
String apiKey,
|
||||
String apiSecret,
|
||||
String payload,
|
||||
int timestamp,
|
||||
) {
|
||||
final message = '$timestamp|$apiKey|$payload';
|
||||
final hmac = Hmac(sha256, utf8.encode(apiSecret));
|
||||
final digest = hmac.convert(utf8.encode(message));
|
||||
return digest.toString();
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation (PHP):**
|
||||
|
||||
```php
|
||||
$message = $timestamp . '|' . $api_key . '|' . $payload;
|
||||
$signature = hash_hmac('sha256', $message, $api_secret);
|
||||
```
|
||||
|
||||
### Security Features
|
||||
|
||||
1. **Replay Attack Prevention**: Timestamps validated within 5-minute window
|
||||
2. **Timing-Safe Comparison**: `hash_equals()` prevents timing attacks
|
||||
3. **Password Hashing**: bcrypt with cost=12
|
||||
4. **Input Validation**: All payloads validated against schema
|
||||
5. **SQL Injection Prevention**: Prepared statements on all queries
|
||||
6. **HTTPS Only**: Enforced in production
|
||||
7. **API Key Rotation**: Credentials can be regenerated
|
||||
8. **Audit Logging**: All API requests logged with metadata
|
||||
|
||||
## 📊 Data Models
|
||||
|
||||
### GpsCoordinate
|
||||
|
||||
```dart
|
||||
latitude: double (-90 to 90)
|
||||
longitude: double (-180 to 180)
|
||||
altitude: double? (meters)
|
||||
accuracy: double? (meters)
|
||||
timestamp: DateTime (UTC)
|
||||
```
|
||||
|
||||
### WorkoutSession
|
||||
|
||||
```dart
|
||||
id: String (unique session identifier)
|
||||
workoutType: String ('running' | 'walking')
|
||||
startTime: DateTime?
|
||||
endTime: DateTime?
|
||||
coordinates: List<GpsCoordinate>
|
||||
isPaused: bool
|
||||
totalPausedDuration: int (milliseconds)
|
||||
```
|
||||
|
||||
### Workout (Database)
|
||||
|
||||
```sql
|
||||
workout_uuid: UUID (unique)
|
||||
user_id: int (FK to users)
|
||||
workout_type: ENUM ('running', 'walking')
|
||||
distance_meters: int
|
||||
duration_seconds: int
|
||||
elevation_gain_meters: int
|
||||
elevation_loss_meters: int
|
||||
calories_burned: float
|
||||
average_pace_mps: float
|
||||
max_speed_mps: float
|
||||
route_polyline: LONGTEXT (encoded polyline)
|
||||
coordinate_count: int
|
||||
start_lat/lng, end_lat/lng: DECIMAL
|
||||
start_time, end_time: DATETIME
|
||||
weather_condition: VARCHAR
|
||||
temperature_celsius: FLOAT
|
||||
notes: TEXT
|
||||
is_public: BOOLEAN
|
||||
synced_at: TIMESTAMP
|
||||
```
|
||||
|
||||
## 🗺️ Map Integration
|
||||
|
||||
### MapLibre Configuration
|
||||
|
||||
```dart
|
||||
MapLibreMap(
|
||||
styleString: 'https://map-saas.intaleqapp.com/styles/basic-preview/style.json',
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: LatLng(37.7749, -122.4194),
|
||||
zoom: 15,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### Route Visualization
|
||||
|
||||
- User location marker updated every 5 seconds
|
||||
- Route polyline rendered with opacity and color
|
||||
- Map camera follows user location
|
||||
- Supports 50,000+ coordinate points
|
||||
|
||||
## 📈 Performance Metrics
|
||||
|
||||
### Polyline Compression
|
||||
|
||||
- Raw coordinates: ~100 bytes per point (2 doubles)
|
||||
- Encoded polyline: ~4-5 bytes per point (average)
|
||||
- **Compression Ratio: ~95%**
|
||||
|
||||
Example: 5km route with coordinates every 5m
|
||||
|
||||
- Uncompressed: 1000 points × 100 bytes = 100 KB
|
||||
- Compressed: 1000 points × 5 bytes = 5 KB
|
||||
|
||||
### Database Query Performance
|
||||
|
||||
All critical queries use indexes:
|
||||
|
||||
```sql
|
||||
-- User authentication
|
||||
SELECT * FROM users WHERE api_key = ? -- idx_api_key
|
||||
-- User history
|
||||
SELECT * FROM workouts WHERE user_id = ? ORDER BY created_at DESC -- idx_user_created
|
||||
-- Audit logs
|
||||
SELECT * FROM api_logs WHERE user_id = ? -- idx_user_id
|
||||
```
|
||||
|
||||
### API Response Times
|
||||
|
||||
- Typical response: 150-300ms
|
||||
- P95 latency: < 500ms
|
||||
- Database write: ~50ms
|
||||
- HMAC validation: < 5ms
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Flutter 3.13+
|
||||
- PHP 7.4+ with MySQL
|
||||
- MySQL 5.7+
|
||||
- Xcode (iOS) or Android Studio (Android)
|
||||
|
||||
### Backend Setup
|
||||
|
||||
1. **Initialize Database**
|
||||
|
||||
```bash
|
||||
mysql -u root -p < backend/schema.sql
|
||||
```
|
||||
|
||||
2. **Configure Credentials**
|
||||
|
||||
```php
|
||||
# Edit backend/Database.php
|
||||
private $db_host = 'your-db-host';
|
||||
private $db_user = 'fitness_app_user';
|
||||
private $db_pass = 'secure_password';
|
||||
```
|
||||
|
||||
3. **Deploy API Files**
|
||||
```bash
|
||||
cp backend/*.php /var/www/html/api/v1/
|
||||
chmod 644 /var/www/html/api/v1/*.php
|
||||
```
|
||||
|
||||
### Mobile Setup
|
||||
|
||||
1. **Install Dependencies**
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
2. **Generate API Credentials**
|
||||
|
||||
```bash
|
||||
# On server
|
||||
php -r "require 'AuthenticationHandler.php'; print_r(AuthenticationHandler::generateApiCredentials());"
|
||||
```
|
||||
|
||||
3. **Configure in App**
|
||||
- Launch app and go to Settings
|
||||
- Enter API key and secret
|
||||
- Credentials stored securely via flutter_secure_storage
|
||||
|
||||
4. **Run App**
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### API Testing (cURL)
|
||||
يتطلب التطبيق Flutter SDK، ويتطلب الخادم PHP 8+ مع إضافات MySQL وملف إعدادات بيئة. شغّل الاختبارات من جذر المشروع:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
API_KEY="your_api_key"
|
||||
API_SECRET="your_api_secret"
|
||||
TIMESTAMP=$(date +%s)
|
||||
PAYLOAD='{"workout_type":"running",...}'
|
||||
MESSAGE="${TIMESTAMP}|${API_KEY}|${PAYLOAD}"
|
||||
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $NF}')
|
||||
|
||||
curl -X POST https://your-api.com/api/v1/workouts \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: $API_KEY" \
|
||||
-H "X-Signature: $SIGNATURE" \
|
||||
-H "X-Timestamp: $TIMESTAMP" \
|
||||
-d "$PAYLOAD"
|
||||
for test_file in backend/tests/*_test.php; do php "$test_file" || exit 1; done
|
||||
find backend public deploy -type f -name '*.php' -print0 | xargs -0 -n1 php -l
|
||||
cd mobile
|
||||
flutter pub get
|
||||
flutter test
|
||||
flutter analyze
|
||||
```
|
||||
|
||||
### Unit Tests (Flutter)
|
||||
|
||||
```dart
|
||||
test('HMAC signature generation', () {
|
||||
final signature = HmacSignatureGenerator.generateSignature(
|
||||
'test_key',
|
||||
'test_secret',
|
||||
'{"test":"payload"}',
|
||||
1629907200,
|
||||
);
|
||||
expect(signature.length, 64); // SHA256 hex
|
||||
});
|
||||
```
|
||||
|
||||
## 📚 API Documentation
|
||||
|
||||
See [API_HMAC_GUIDE.md](backend/API_HMAC_GUIDE.md) for:
|
||||
|
||||
- Complete HMAC signing guide
|
||||
- PHP/Dart/cURL examples
|
||||
- Error response formats
|
||||
- Rate limiting details
|
||||
- Best practices
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables (Production)
|
||||
بناء التطبيق يحتاج عنوان API حقيقي عبر HTTPS:
|
||||
|
||||
```bash
|
||||
DB_HOST=prod-db.example.com
|
||||
DB_USER=fitness_app
|
||||
DB_PASSWORD=secure_password
|
||||
API_RATE_LIMIT=100 # requests per minute
|
||||
TILE_SERVER_URL=https://map-saas.intaleqapp.com/styles/basic-preview/style.json
|
||||
cd mobile
|
||||
flutter build apk --dart-define=API_BASE_URL=https://your-domain.example
|
||||
flutter build ios --dart-define=API_BASE_URL=https://your-domain.example
|
||||
```
|
||||
|
||||
### Feature Flags
|
||||
لا تضع كلمات مرور أو مفاتيح OTP أو AI أو JWT في `--dart-define` أو Git. تبقى الأسرار على الخادم خارج جذر الويب. `mobile/README.md` يشرح إعداد عنوان API وسلوك البيانات المحلية والمزامنة.
|
||||
|
||||
```dart
|
||||
// Enable debug logging
|
||||
const kDebugLogging = true;
|
||||
## المصادقة والبيانات
|
||||
|
||||
// API endpoint
|
||||
const kApiEndpoint = 'https://api.fitness-app.com/api/v1';
|
||||
تسجيل الدخول برقم هاتف دولي ورمز OTP، ثم رموز وصول وتجديد للجلسة. رمز التجديد في تطبيق الهاتف محفوظ عبر التخزين الآمن للنظام. يتطلب تشغيل OTP إعداد موفر الرسائل وبياناته السرية في بيئة الخادم؛ لا يُفترض أن التكامل الحي جاهز لمجرد وجود الواجهات.
|
||||
|
||||
// Location update interval (seconds)
|
||||
const kLocationUpdateInterval = 5;
|
||||
SQLite هو مخزن الهاتف للعمل دون اتصال، وMySQL مصدر البيانات المشتركة بعد المزامنة. التمارين والوجبات مرتبطة بمالك الحساب محليًا، وسجلات outbox تنتظر الاتصال والمصادقة. تذكيرات التدريب إشعارات محلية على الجهاز. يستخدم تحليل صور الوجبات نقطة API اختيارية، ومغلق افتراضيًا إلى أن يُضبط المزود ويُفعّل على الخادم؛ نتائج السعرات تقديرية ويجب مراجعتها قبل الحفظ.
|
||||
|
||||
// Map zoom level
|
||||
const kMapZoomDefault = 15;
|
||||
```
|
||||
## إعداد قاعدة البيانات وCloudPanel
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
توجد القاعدة الأولية في `backend/schema.sql`، والترحيلات الإضافية في `backend/migrations/`. لقاعدة جديدة، جهّز مستخدم MySQL محدودًا بقاعدة التطبيق واستورد المخطط وفق `deploy/README.md`. لقواعد موجودة، راجع إصدارها وخذ نسخة احتياطية قابلة للاستعادة قبل اختيار baseline أو تطبيق أي migration. لا يشغّل نشر Git ترحيلات قاعدة البيانات تلقائيًا.
|
||||
|
||||
### HMAC Signature Mismatch
|
||||
يقرأ PHP إعداداته من environment أو من ملف `.env` خارج `public/`؛ راجع `.env.example` للأسماء المطلوبة. إعداد OTP وAI وJWT وMySQL وقيم CloudPanel الخاصة مسؤولية بيئة الخادم وليست محفوظة في المستودع. ابدأ بـstaging، ثم تحقق من migrations و`/api/v1/health.php` وواجهات الدخول قبل توجيه الإنتاج.
|
||||
|
||||
- Verify raw request body hasn't been modified
|
||||
- Check timestamp is within server tolerance
|
||||
- Ensure API secret is correct
|
||||
- Confirm SHA256 algorithm is used
|
||||
## النشر
|
||||
|
||||
### Location Not Tracking
|
||||
`deploy/sync-to-server.sh` ينشر commit منشورًا ونظيفًا إلى إصدار مستقل، ثم يبدل رابط `current`. المنفذ الافتراضي SSH هو `2101`، ويمكن تغييره بـ`DEPLOY_PORT`. لا ينشئ موقع CloudPanel أو قاعدة بيانات أو DNS/TLS، ولا يرسل بيانات اعتماد، ولا ينفذ migrations. يحتاج إلى Site User ومفتاح SSH موثوق، Git Deploy Key على الخادم، ملف بيئة خاص، وdocument root مضبوط على `current/public`.
|
||||
|
||||
- Check device location permissions
|
||||
- Verify GPS is enabled
|
||||
- Ensure app has foreground/background permission
|
||||
- Check Location service initialization
|
||||
راجع `deploy/README.md` للإعداد والمتغيرات وفحوص dry-run والاسترجاع. لا تنفذ نشرًا فعليًا قبل توفير نطاق وبيانات اتصال مصرح بها واختبار staging؛ وجود عنوان Git وحده لا يعني أن الخادم أو موفر الرسائل جاهز.
|
||||
|
||||
### Map Not Loading
|
||||
## حالة الإطلاق
|
||||
|
||||
- Verify tile server URL is accessible
|
||||
- Check internet connection
|
||||
- Validate MapLibre API key
|
||||
- Inspect browser console for errors
|
||||
|
||||
See [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md#troubleshooting) for more solutions.
|
||||
|
||||
## 📦 Dependencies
|
||||
|
||||
### Critical Dependencies
|
||||
|
||||
- **get**: State management (4.6.5+)
|
||||
- **maplibre_gl**: Map rendering (0.20.0+)
|
||||
- **sqflite**: Local database (2.3.0+)
|
||||
- **crypto**: HMAC cryptography (3.0.2+)
|
||||
- **http**: HTTP requests (1.1.0+)
|
||||
|
||||
### Security Dependencies
|
||||
|
||||
- **flutter_secure_storage**: Credential storage
|
||||
- **crypto**: HMAC/SHA256 functions
|
||||
|
||||
See [mobile/pubspec.yaml](mobile/pubspec.yaml) for complete list.
|
||||
|
||||
## 📝 API Contracts
|
||||
|
||||
### Error Response (400, 401, 422, 500)
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"error": "Description of error",
|
||||
"timestamp": "2026-04-21T14:45:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Success Response (201)
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"workout_id": 123,
|
||||
"workout_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"message": "Workout submitted successfully",
|
||||
"timestamp": "2026-04-21T14:45:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 Workflow
|
||||
|
||||
### Workout Tracking Flow
|
||||
|
||||
1. User opens app and taps "Start Workout"
|
||||
2. App requests location permission
|
||||
3. GPS coordinates saved to SQLite every 5 seconds
|
||||
4. Map displays real-time route overlay
|
||||
5. Stats updated: distance, time, pace, speed
|
||||
6. User taps "Stop" to end workout
|
||||
7. Dialog shows workout summary
|
||||
8. User taps "Submit" to send to server
|
||||
9. App generates HMAC signature with timestamp
|
||||
10. Workout submitted via HTTPS POST request
|
||||
11. Server validates signature, stores in MySQL
|
||||
12. Local coordinates deleted after confirmation
|
||||
|
||||
### Security Validation Flow
|
||||
|
||||
1. Client generates timestamp (current Unix time)
|
||||
2. Client creates message: `timestamp|api_key|payload`
|
||||
3. Client computes HMAC-SHA256(message, api_secret)
|
||||
4. Client converts to hex and sends with headers
|
||||
5. Server receives request
|
||||
6. Server validates timestamp (within 5 minutes)
|
||||
7. Server retrieves api_secret from users table
|
||||
8. Server recomputes expected HMAC
|
||||
9. Server compares using hash_equals() (timing-safe)
|
||||
10. Request processed only if signature matches
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is provided as-is for educational and commercial use.
|
||||
|
||||
## 👥 Support
|
||||
|
||||
For issues, feature requests, or documentation clarifications:
|
||||
|
||||
- Create an issue in the repository
|
||||
- Contact: support@fitness-app.com
|
||||
- Documentation: [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md)
|
||||
|
||||
## ✅ Production Checklist
|
||||
|
||||
- [ ] All dependencies installed and updated
|
||||
- [ ] Database initialized with schema.sql
|
||||
- [ ] PHP files deployed to web server
|
||||
- [ ] HTTPS/SSL certificates configured
|
||||
- [ ] API credentials generated for testing
|
||||
- [ ] HMAC signature validation tested
|
||||
- [ ] Map tile server accessible
|
||||
- [ ] Location permissions configured
|
||||
- [ ] Secure storage enabled for credentials
|
||||
- [ ] Error logging configured
|
||||
- [ ] Rate limiting implemented
|
||||
- [ ] Backup strategy in place
|
||||
- [ ] Monitoring and alerts set up
|
||||
- [ ] Security audit completed
|
||||
- [ ] Load testing performed
|
||||
|
||||
---
|
||||
|
||||
**Built with ❤️ for production fitness tracking**
|
||||
|
||||
Last Updated: 2026-04-21
|
||||
المشروع يتقدم محليًا، لكن ذلك لا يثبت تشغيله على خادم المستخدم. ما زالت هناك بوابات إطلاق، منها اختيار وربط موفر OTP الفعلي، إنشاء بيئة CloudPanel وقاعدة تشغيلية، اختبار migrations والنسخ الاحتياطي والاسترجاع، تعيين معرّف التطبيق النهائي، واختبار سلوك iOS وAndroid على أجهزة فعلية. قائمة مفصلة ومحدثة موجودة في `IMPLEMENTATION_ROADMAP_AR.md`.
|
||||
|
||||
Reference in New Issue
Block a user