# EL3AB Mobile — Architecture Document

## Overview

EL3AB Mobile is a **Flutter-based native shell** wrapping the existing web player at `https://el3ab-player.caprover.al-arcade.com/`. The app provides genuine native functionality (push notifications, haptics, biometric auth, native navigation, offline support) while keeping all game logic, UI, and content updates inside the WebView — meaning updates to the web player propagate instantly to mobile users without app store review.

**Package:** `com.alarcade.el3ab`
**Platforms:** iOS 14+ / Android API 24+ (Android 7.0+)
**Framework:** Flutter 3.x
**Web Player URL:** `https://el3ab-player.caprover.al-arcade.com/`

---

## Why This Won't Get Rejected

Apple (Guideline 4.2) and Google (Minimum Functionality) reject "thin web wrappers." Our app passes because:

| Requirement | How We Satisfy It |
|-------------|-------------------|
| Uses device capabilities | Haptics, biometrics, camera (avatar), contacts, share sheet |
| Native navigation | Flutter bottom tab bar with native transitions |
| Push notifications | FCM/APNs with rich notification content |
| Works offline (partially) | Cached profile, match history, puzzle of the day |
| Native onboarding | Animated splash + first-run tutorial (not a loading spinner) |
| Deep linking | Universal Links (iOS) / App Links (Android) open directly to matches |
| Platform integration | iOS Widgets, App Shortcuts, Spotlight search |

---

## Architecture Diagram

```
┌─────────────────────────────────────────────────────────────┐
│                    FLUTTER APP SHELL                          │
│                                                              │
│  ┌────────────┐  ┌────────────┐  ┌────────────────────────┐ │
│  │  Native    │  │  Native    │  │  Native Services       │ │
│  │  Splash &  │  │  Bottom    │  │  • Push (FCM/APNs)     │ │
│  │  Onboard   │  │  Tab Bar   │  │  • Haptics             │ │
│  │            │  │  (5 tabs)  │  │  • Biometric Auth      │ │
│  └────────────┘  └─────┬──────┘  │  • Share Sheet         │ │
│                         │         │  • Deep Links          │ │
│  ┌──────────────────────┴───────┐ │  • Offline Cache       │ │
│  │                              │ │  • Native Audio        │ │
│  │     InAppWebView             │ │  • App Shortcuts       │ │
│  │     (flutter_inappwebview)   │ │  • Contacts Access     │ │
│  │                              │ │  • Camera (avatar)     │ │
│  │  Loads: el3ab-player web app │ └────────────────────────┘ │
│  │                              │                            │
│  │  ◄──── JS Bridge ────►      │                            │
│  │                              │                            │
│  └──────────────────────────────┘                            │
└─────────────────────────────────────────────────────────────┘
```

---

## Project Structure

```
lib/
├── main.dart                    # App entry, DI setup
├── app.dart                     # MaterialApp, theme, routing
├── config/
│   ├── constants.dart           # URLs, keys, feature flags
│   └── theme.dart               # EL3AB dark theme (matches web)
├── core/
│   ├── bridge/
│   │   ├── js_bridge.dart       # JS ↔ Flutter message handler
│   │   ├── bridge_commands.dart # Command enum + serialization
│   │   └── web_controller.dart  # WebView controller wrapper
│   ├── services/
│   │   ├── push_service.dart    # FCM/APNs registration + handling
│   │   ├── haptics_service.dart # Haptic feedback patterns
│   │   ├── audio_service.dart   # Native audio playback
│   │   ├── auth_service.dart    # Biometric + token storage
│   │   ├── deep_link_service.dart # Universal/App links
│   │   ├── share_service.dart   # Native share sheet
│   │   ├── offline_service.dart # Cache manager
│   │   └── contacts_service.dart# Find friends
│   └── storage/
│       ├── secure_storage.dart  # Flutter Secure Storage (tokens)
│       └── cache_manager.dart   # Offline data cache (Hive)
├── features/
│   ├── splash/
│   │   └── splash_screen.dart   # Animated native splash
│   ├── onboarding/
│   │   └── onboarding_screen.dart # First-run tutorial
│   ├── shell/
│   │   ├── app_shell.dart       # Main scaffold with bottom nav
│   │   ├── bottom_nav.dart      # Native bottom tab bar
│   │   └── webview_container.dart # WebView with bridge
│   ├── notifications/
│   │   └── notification_handler.dart
│   └── settings/
│       └── native_settings.dart # Push prefs, biometric toggle
├── models/
│   ├── player.dart              # Cached player model
│   ├── notification.dart        # Push notification model
│   └── match_summary.dart       # Offline match history
└── utils/
    ├── platform_utils.dart      # iOS/Android helpers
    └── connectivity.dart        # Network state monitoring
```

---

## JS Bridge Protocol

The bridge enables bidirectional communication between the web player and Flutter native layer.

### Web → Flutter (JavaScript Channel)

The web player calls `window.flutter_bridge.postMessage(JSON.stringify(payload))`:

```javascript
// Haptic feedback
{ "cmd": "haptic", "type": "light" | "medium" | "heavy" | "success" | "error" | "selection" }

// Share content
{ "cmd": "share", "title": "...", "text": "...", "url": "..." }

// Play native audio
{ "cmd": "audio", "sound": "click" | "move" | "capture" | "win" | "lose" | "dice" | "coin" }

// Sync navigation state (web tells Flutter which tab is active)
{ "cmd": "nav_sync", "world": "play" | "rank" | "social" | "tournaments" | "profile" }

// Auth state changed
{ "cmd": "auth_ready", "token": "jwt...", "userId": "uuid" }
{ "cmd": "auth_logout" }

// Badge update
{ "cmd": "badge", "count": 3 }

// Game state (for offline caching)
{ "cmd": "cache_profile", "data": { ... } }
{ "cmd": "cache_match", "data": { ... } }

// Request native feature
{ "cmd": "request_contacts" }
{ "cmd": "request_camera" }  // avatar upload
```

### Flutter → Web (evaluateJavascript)

Flutter injects calls into the WebView:

```javascript
// Handle deep link navigation
window.el3ab_native.onDeepLink({ route: "match", id: "abc123" })

// Handle push notification tap
window.el3ab_native.onPushTap({ type: "match_invite", matchId: "abc123" })

// Network state changed
window.el3ab_native.onConnectivityChanged({ online: true })

// Token refreshed (biometric re-auth)
window.el3ab_native.onTokenRefreshed({ token: "new_jwt..." })

// Native nav tab tapped
window.el3ab_native.onNavTap({ world: "play" })
```

### Web Player Integration (Minimal Changes)

Add to the web player's `engine.js` boot sequence:

```javascript
// Detect native app environment
window.IS_NATIVE_APP = !!window.flutter_bridge;

// Register native bridge listener
if (window.IS_NATIVE_APP) {
  window.el3ab_native = {
    onDeepLink: (data) => bus.emit('native:deeplink', data),
    onPushTap: (data) => bus.emit('native:push_tap', data),
    onConnectivityChanged: (data) => bus.emit('native:connectivity', data),
    onTokenRefreshed: (data) => store.set('auth.token', data.token),
    onNavTap: (data) => scene.switchWorld(data.world)
  };

  // Hide web bottom nav (Flutter renders it natively)
  document.documentElement.classList.add('native-app');

  // Override haptic calls to use native
  const originalHaptic = input.haptic;
  input.haptic = (type) => {
    window.flutter_bridge.postMessage(JSON.stringify({ cmd: 'haptic', type }));
  };
}
```

And in CSS:
```css
.native-app #hud .bottom-nav { display: none; }
.native-app #game { padding-bottom: 0; }
```

---

## Native Bottom Navigation Bar

Flutter renders a native bottom tab bar that mirrors the web player's 5 worlds:

| Index | Label | Icon | Color (active) |
|-------|-------|------|----------------|
| 0 | الترتيب (Rank) | trophy | #F5B731 (gold) |
| 1 | اجتماعي (Social) | people | #00D4FF (cyan) |
| 2 | العب (Play) | gamepad | #F5B731 (gold) — center, larger |
| 3 | البطولات (Tournaments) | medal | #8B5CF6 (purple) |
| 4 | حسابي (Profile) | person | #94A3B8 (slate) |

- Tab bar background: `#050810` with top border `rgba(255,255,255,0.08)`
- Active indicator: game-color glow beneath icon
- Tab taps → Flutter sends `onNavTap` to WebView → web switches world
- Web nav changes → web sends `nav_sync` to Flutter → bottom bar updates

---

## Push Notifications

### Registration Flow
1. App boot → request notification permission
2. Get FCM token (Android) / APNs device token (iOS)
3. Send token to backend: `POST /api/push.php { action: "register", token, platform, userId }`
4. Backend stores in `push_tokens` table

### Notification Types

| Type | Trigger | Behavior on Tap |
|------|---------|-----------------|
| `match_invite` | Friend invites to play | Open match lobby |
| `your_turn` | Turn-based game, opponent moved | Open active match |
| `match_result` | Game ended while app backgrounded | Open results screen |
| `tournament_start` | Tournament about to begin | Open tournament lobby |
| `friend_online` | Close friend came online | Open social tab |
| `daily_reward` | Daily streak available | Open play tab |
| `chat_message` | Org/friend chat message | Open chat scene |

### Payload Structure
```json
{
  "notification": {
    "title": "دورك! ♟️",
    "body": "أحمد لعب e4 — ردّ عليه"
  },
  "data": {
    "type": "your_turn",
    "match_id": "abc123",
    "game_type": "chess",
    "route": "/match/abc123"
  }
}
```

---

## Haptic Feedback Patterns

| Game Event | Haptic Type | iOS | Android |
|------------|------------|-----|---------|
| Button press | Light | UIImpactFeedbackGenerator(.light) | HapticFeedbackConstants.lightImpact |
| Piece move | Medium | UIImpactFeedbackGenerator(.medium) | HapticFeedbackConstants.mediumImpact |
| Capture/eat | Heavy | UIImpactFeedbackGenerator(.heavy) | VibrationEffect (50ms) |
| Win | Success | UINotificationFeedbackGenerator(.success) | Pattern: [0, 50, 30, 50, 30, 100] |
| Lose | Error | UINotificationFeedbackGenerator(.error) | Pattern: [0, 100, 50, 100] |
| Dice roll | Selection (repeated) | UISelectionFeedbackGenerator × 3 | Pattern: [0, 20, 20, 20, 20, 20] |
| Coin earned | Light × 3 rapid | Triple light impact | Pattern: [0, 10, 30, 10, 30, 10] |
| Tab switch | Selection | UISelectionFeedbackGenerator | HapticFeedbackConstants.selectionClick |

---

## Offline Support

### What Works Offline
- View cached player profile (name, avatar, stats, rating)
- Browse match history (last 50 matches cached)
- Daily puzzle (pre-fetched each day, playable offline)
- Settings and preferences
- View friends list (last known state)

### What Shows "Offline" State
- Play tab: grayed-out matchmaking, shows "Connect to play"
- Social: shows cached friends with "last seen" timestamps
- Tournaments: "Connect to view live tournaments"
- Shop: "Connect to browse shop"

### Cache Strategy
- **Hive** (local DB) for structured data (profile, match history, friends)
- **flutter_cache_manager** for images (avatars, assets)
- **SharedPreferences** for simple flags (onboarding complete, push prefs)
- **Flutter Secure Storage** for auth tokens (encrypted, biometric-gated)

### Sync on Reconnect
When connectivity returns:
1. Re-validate auth token
2. Fetch fresh profile data
3. Check for pending notifications
4. Resume WebView connection

---

## Deep Links / Universal Links

### URL Scheme
```
el3ab://match/{matchId}         → Open active match
el3ab://invite/{code}           → Accept friend/org invite
el3ab://tournament/{id}         → Open tournament detail
el3ab://profile/{userId}        → View player profile
el3ab://play/{gameType}         → Jump to game lobby
```

### Universal Links (HTTPS)
```
https://el3ab-player.caprover.al-arcade.com/match/{id}
https://el3ab-player.caprover.al-arcade.com/invite/{code}
https://el3ab-player.caprover.al-arcade.com/tournament/{id}
```

### iOS Configuration
- `apple-app-site-association` file on web server
- Associated Domains entitlement in Xcode

### Android Configuration
- `assetlinks.json` on web server at `/.well-known/`
- `<intent-filter>` in AndroidManifest.xml with `autoVerify="true"`

---

## Biometric Authentication

### Flow
1. First login: user enters credentials in WebView (normal auth flow)
2. On auth success, web sends `{ cmd: "auth_ready", token, userId }` to Flutter
3. Flutter stores token in Secure Storage (encrypted)
4. Flutter prompts: "Enable Face ID / fingerprint login?"
5. If yes: next app launch → biometric prompt → retrieve token → inject into WebView

### Re-auth
- Token expired while app backgrounded → biometric re-auth → refresh token
- Avoids forcing users to re-enter password after every background

---

## Native Audio (Optional Enhancement)

If web audio has issues on certain devices (common on older Android WebViews):

- Web sends `{ cmd: "audio", sound: "move" }` to Flutter
- Flutter plays from pre-bundled audio assets using `audioplayers` package
- Fallback only: web audio still works, native is for reliability + lower latency

---

## App Shortcuts (Quick Actions)

### iOS (UIApplicationShortcutItem)
- Long-press app icon reveals:
  - "Quick Play Chess ♟️" → opens Play tab with chess pre-selected
  - "Quick Play Ludo 🎲" → opens Play tab with ludo pre-selected
  - "Daily Puzzle 🧩" → opens puzzle of the day

### Android (ShortcutInfo)
- Same 3 shortcuts in long-press menu
- Also supports pinned shortcuts for favorite game

---

## Dependencies (pubspec.yaml)

```yaml
dependencies:
  flutter:
    sdk: flutter

  # WebView
  flutter_inappwebview: ^6.0.0      # Full-featured WebView with JS bridge

  # Push Notifications
  firebase_core: ^3.0.0
  firebase_messaging: ^15.0.0
  flutter_local_notifications: ^17.0.0

  # Storage
  flutter_secure_storage: ^9.0.0    # Encrypted token storage
  hive_flutter: ^1.1.0              # Fast local DB for offline cache
  shared_preferences: ^2.2.0        # Simple key-value

  # Auth
  local_auth: ^2.2.0                # Biometric auth (Face ID / fingerprint)

  # Native Features
  share_plus: ^9.0.0                # Native share sheet
  url_launcher: ^6.2.0              # External links
  connectivity_plus: ^6.0.0         # Network state monitoring
  permission_handler: ^11.0.0       # Runtime permissions
  contacts_service: ^0.6.3          # Find friends via contacts
  image_picker: ^1.0.0              # Camera for avatar upload
  app_links: ^6.0.0                 # Deep links / Universal links
  quick_actions_ios: ^1.0.0         # Home screen shortcuts (iOS)
  quick_actions_android: ^1.0.0     # Home screen shortcuts (Android)

  # UI
  flutter_svg: ^2.0.0               # SVG icons
  cached_network_image: ^3.3.0      # Image caching
  shimmer: ^3.0.0                   # Loading states
  lottie: ^3.0.0                    # Animated splash/onboarding

  # Utils
  path_provider: ^2.1.0
  package_info_plus: ^8.0.0
```

---

## App Lifecycle

```
┌──────────────────────────────────────────────────┐
│                  APP LAUNCH                        │
├──────────────────────────────────────────────────┤
│                                                   │
│  1. Native Splash (Lottie animation, 1.5s)       │
│     └─ Initialize services (push, connectivity)  │
│                                                   │
│  2. Check auth state                              │
│     ├─ Has biometric + stored token?             │
│     │   └─ Biometric prompt → inject token       │
│     ├─ Has stored token (no biometric)?          │
│     │   └─ Load WebView with token               │
│     └─ No token?                                 │
│         └─ Load WebView (shows auth-splash)      │
│                                                   │
│  3. Load App Shell                                │
│     ├─ Native bottom tab bar (5 tabs)            │
│     ├─ WebView (loads player URL)                │
│     └─ Register JS bridge handlers              │
│                                                   │
│  4. WebView Ready                                 │
│     ├─ Web sends auth_ready → register push     │
│     ├─ Web sends nav_sync → sync bottom bar     │
│     └─ App is fully interactive                  │
│                                                   │
├──────────────────────────────────────────────────┤
│              APP BACKGROUNDED                     │
├──────────────────────────────────────────────────┤
│  • Keep WebSocket alive (5 min grace)            │
│  • Cache current state                           │
│  • Push notifications remain active              │
│                                                   │
├──────────────────────────────────────────────────┤
│              APP FOREGROUNDED                     │
├──────────────────────────────────────────────────┤
│  • Check token validity                          │
│  • Reconnect WebSocket if dropped                │
│  • Sync missed notifications                     │
│  • Resume WebView (no reload if < 5 min)         │
└──────────────────────────────────────────────────┘
```

---

## Web Player Changes Required

Minimal changes to the existing web player — a single file addition:

### New file: `public/js/core/native-bridge.js`

Handles all native app communication. Loaded conditionally only when running inside the Flutter app (detected via `window.flutter_bridge` existence).

### Changes to existing files:

1. **`engine.js`** — Add one import + 3 lines at boot:
   ```javascript
   import * as nativeBridge from './core/native-bridge.js';
   // In boot():
   if (window.flutter_bridge) nativeBridge.init();
   ```

2. **`core/input.js`** — Override haptic function when native:
   ```javascript
   // Already handled by native-bridge.js patching
   ```

3. **`public/css/core.css`** — Add native-app overrides:
   ```css
   .native-app .bottom-nav { display: none !important; }
   .native-app .scene-container { padding-bottom: 0 !important; }
   .native-app body { padding-bottom: env(safe-area-inset-bottom); }
   ```

**Total web changes: ~50 lines across 3 files.**

---

## Build & Release Pipeline

### iOS
- Xcode 15+, iOS deployment target 14.0
- Signing: Apple Development identity (aglantech@gmail.com)
- Capabilities: Push Notifications, Associated Domains, Background Modes
- TestFlight for beta → App Store submission

### Android
- Gradle 8.x, Android SDK 34, minSdk 24
- Signing: upload keystore (generate before first release)
- Google Play Console: Internal testing → Production

### CI/CD (future)
- GitHub Actions or Codemagic
- On push to `release/*`: build iOS + Android → upload to stores

---

## Testing Strategy

| Layer | Tool | What |
|-------|------|------|
| Unit | flutter_test | Bridge command parsing, cache logic |
| Widget | flutter_test | Bottom nav, splash, settings screens |
| Integration | integration_test | Full app boot → WebView load → bridge communication |
| Manual | Real devices | Push notifications, haptics, biometrics, deep links |

---

## Security Considerations

- Auth tokens stored in Flutter Secure Storage (Keychain on iOS, EncryptedSharedPreferences on Android)
- WebView: disable file access, restrict navigation to `al-arcade.com` domains
- Certificate pinning for API calls (optional, adds protection against MITM)
- No sensitive data in WebView cache (tokens passed via bridge, not URL params)
- Biometric gate on app resume (optional user preference)

---

## Estimated Implementation Timeline

| Phase | Duration | Deliverable |
|-------|----------|-------------|
| 1. Core shell + WebView + Bridge | 2-3 days | App loads web player, bridge works |
| 2. Native bottom nav + sync | 1 day | Tabs work bidirectionally |
| 3. Push notifications (FCM) | 1-2 days | Registration + handling |
| 4. Haptics + audio | 0.5 day | All patterns wired |
| 5. Biometric auth | 0.5 day | Face ID / fingerprint |
| 6. Deep links | 1 day | Universal links + scheme |
| 7. Offline support | 1-2 days | Cache layer + offline UI |
| 8. Splash + onboarding | 0.5 day | Animated native intro |
| 9. Share + contacts + shortcuts | 0.5 day | Native integrations |
| 10. Web player bridge code | 0.5 day | ~50 lines on web side |
| 11. Testing + polish | 2-3 days | Real device testing |
| **Total** | **~10-14 days** | Store-ready build |

---

## Store Submission Checklist

### App Store (iOS)
- [ ] App icon (1024×1024)
- [ ] Screenshots (6.7", 6.5", 5.5" — Arabic, RTL)
- [ ] App Preview video (optional but recommended)
- [ ] Privacy policy URL
- [ ] App description (Arabic + English)
- [ ] Age rating: 12+ (competitive gaming, mild language in chat)
- [ ] In-App Purchases: None (for now)
- [ ] Review notes: explain native features (haptics, push, biometric, offline)

### Google Play
- [ ] App icon (512×512)
- [ ] Feature graphic (1024×500)
- [ ] Screenshots (phone + tablet)
- [ ] Privacy policy URL
- [ ] Content rating questionnaire
- [ ] Target audience declaration
- [ ] Data safety form

---

## Key Decision: Why Flutter (not React Native / Kotlin+Swift)

| Factor | Flutter | React Native | Native (Kotlin/Swift) |
|--------|---------|-------------|----------------------|
| Single codebase | ✅ | ✅ | ❌ (2 codebases) |
| WebView quality | ✅ (flutter_inappwebview is excellent) | ⚠️ (react-native-webview has quirks) | ✅ |
| Native feel | ✅ (Cupertino + Material) | ✅ | ✅✅ |
| Team knowledge | ✅ (Dart is simple) | ⚠️ (JS ecosystem complexity) | ❌ (need both Kotlin + Swift) |
| Build speed | ✅ | ⚠️ | ⚠️ |
| Store approval | ✅ (used by major apps) | ✅ | ✅✅ |

Flutter with `flutter_inappwebview` gives us the best balance: one codebase, excellent WebView bridge, truly native bottom nav and services, and fast iteration.
