# 📊 PHÂN TÍCH CHI TIẾT DỰ ÁN SGW-APP (SeaGateway)

## 🎯 TỔNG QUAN DỰ ÁN

Đây là một ứng dụng **React Native** sử dụng **Expo Router** để quản lý thiết bị GPS trên biển (Marine/Ship tracking). Ứng dụng có các tính năng:

- Đăng nhập với JWT token
- Hiển thị GPS trên bản đồ (react-native-maps)
- Quản lý session/authentication
- Dark/Light mode

---

## 📁 PHÂN TÍCH TỪNG FILE

### **1. Configuration Files (Cấu hình)**

#### `app.json` - Expo Configuration

```json
{
  "expo": {
    "name": "sgw-app",
    "slug": "sgw-app",
    "scheme": "sgwapp",
    "newArchEnabled": true
  }
}
```

**Chức năng:**

- Cấu hình tên app, icon, splash screen
- Enable tính năng mới của React Native (`newArchEnabled: true`)
- Thiết lập routing scheme: `sgwapp://`
- Cấu hình cho iOS, Android và Web

#### `tsconfig.json` - TypeScript Config

```json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]
    }
  }
}
```

**Chức năng:**

- Cho phép import với alias `@/` thay vì `../../`
- VD: `import { api } from "@/config"` thay vì `import { api } from "../../config"`

#### `package.json` - Dependencies

**Các thư viện chính:**

- **expo-router**: File-based routing
- **axios**: HTTP client để call API
- **@react-native-async-storage/async-storage**: Lưu token local
- **react-native-maps**: Hiển thị bản đồ
- **react-native-toast-message**: Thông báo lỗi/thành công

---

### **2. Config Folder (Cấu hình ứng dụng)**

#### `config/axios.ts` - HTTP Client Setup

```typescript
const api: AxiosInstance = axios.create({
  baseURL: "http://192.168.30.102:81",
  timeout: 10000,
});
```

**Chức năng:**

1. **Tạo axios instance** với base URL và timeout
2. **Request Interceptor**:
   - Lấy token từ AsyncStorage
   - Thêm token vào header `Authorization: ${token}`
3. **Response Interceptor**:
   - Xử lý lỗi HTTP (401, 404, 500...)
   - Hiển thị toast message lỗi
   - Map status code sang message Tiếng Anh

**Lưu ý:**

- Base URL đang hard-coded là `192.168.30.102:81` (IP local)
- Token format: `Authorization: ${token}` (không có prefix "Bearer")

#### `config/auth.ts` - Router Management

```typescript
let routerInstance: Router | null = null;

export const setRouterInstance = (router: Router) => {
  routerInstance = router;
};

export const handle401 = () => {
  routerInstance?.replace("/login");
};
```

**Chức năng:**

- Lưu router instance để redirect từ non-component (axios interceptor)
- `handle401()`: Redirect về login khi token hết hạn
- **Hiện tại chưa được dùng** (comment trong axios.ts)

#### `config/toast.ts` - Toast Notifications

```typescript
export const showToastError = (message: string, title?: string): void => {
  Toast.show({
    type: "error",
    text1: title || "error",
    text2: message,
  });
};
```

**Chức năng:**

- Wrapper cho `react-native-toast-message`
- 4 loại toast: Success, Error, Info, Warning
- Export: `showToastSuccess`, `showToastError`, `showToastInfo`, `showToastWarning`

---

### **3. Constants Folder (Hằng số)**

#### `constants/index.ts`

```typescript
export const TOKEN = "token";
export const BASE_URL = "https://sgw-device.gms.vn";

// API Endpoints
export const API_PATH_LOGIN = "/api/agent/login";
export const API_GET_GPS = "/api/sgw/gps";
export const API_PATH_SHIP_INFO = "/api/sgw/shipinfo";
// ... nhiều API endpoints khác
```

**Chức năng:**

- Lưu tất cả constants: API paths, storage keys
- **Lưu ý:** `BASE_URL` ở đây khác với base URL trong axios.ts

---

### **4. Utils Folder (Tiện ích)**

#### `utils/storage.ts` - AsyncStorage Wrapper

```typescript
export async function setStorageItem(
  key: string,
  value: string
): Promise<void> {
  await AsyncStorage.setItem(key, value);
}

export async function getStorageItem(key: string): Promise<string | null> {
  return await AsyncStorage.getItem(key);
}

export async function removeStorageItem(key: string): Promise<void> {
  await AsyncStorage.removeItem(key);
}
```

**Chức năng:**

- Wrapper cho AsyncStorage với error handling
- Lưu/đọc/xóa dữ liệu local (chủ yếu là token)

#### `utils/token.ts` - JWT Parser

```typescript
export function parseJwtToken(token: string) {
  const base64Url = token.split('.')[1];
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
  const jsonPayload = decodeURIComponent(
    atob(base64).split('').map(...)
  );
  return JSON.parse(jsonPayload);
}
```

**Chức năng:**

- Parse JWT token để lấy payload (exp, userId...)
- Decode base64url thành JSON object
- Dùng để check token expiration

---

### **5. Controller Folder (API Calls)**

#### `controller/typings.d.ts` - Type Definitions

```typescript
declare namespace Model {
  interface LoginRequestBody {
    username: string;
    password: string;
  }

  interface LoginResponse {
    token?: string;
  }

  interface GPSResonse {
    lat: number;
    lon: number;
    s: number; // speed
    h: number; // heading
    fishing: boolean;
  }
}
```

**Chức năng:**

- Define TypeScript interfaces cho API request/response
- Namespace `Model` để tránh conflict

#### `controller/AuthController.ts`

```typescript
export async function login(body: Model.LoginRequestBody) {
  return api.post<Model.LoginResponse>(API_PATH_LOGIN, body);
}
```

**Chức năng:**

- Gọi API login với username/password
- Return response chứa JWT token

#### `controller/DeviceController.ts`

```typescript
export async function fetchGpsData() {
  return api.get<Model.GPSResponse>(API_GET_GPS);
}
```

**Chức năng:**

- Gọi API lấy GPS data của thiết bị
- Return lat, lon, speed, heading, fishing status

---

### **6. App Folder (Screens & Routes)**

#### `app/_layout.tsx` - Root Layout

```typescript
export default function RootLayout() {
  const router = useRouter();

  useEffect(() => {
    setRouterInstance(router); // Lưu router instance
  }, [router]);

  return (
    <Stack initialRouteName="auth/login">
      <Stack.Screen name="auth/login" />
      <Stack.Screen name="(tabs)" />
      <Stack.Screen name="modal" />
    </Stack>
  );
}
```

**Chức năng:**

1. **Root layout** của toàn bộ app
2. Set router instance cho config/auth
3. Cấu hình Stack Navigator với 3 screens:
   - `auth/login`: Màn hình đăng nhập
   - `(tabs)`: Tabs navigator (Home, Explore, Settings)
   - `modal`: Modal demo
4. Áp dụng theme (dark/light mode)
5. Render Toast component ở root

#### `app/index.tsx` - Entry Point

```typescript
export default function Index() {
  return <Redirect href="/auth/login" />;
}
```

**Chức năng:**

- Redirect root path `/` về `/auth/login`
- Entry point của app

#### `app/auth/login.tsx` - Login Screen

**Luồng hoạt động:**

1. **Check existing login on mount:**

```typescript
useEffect(() => {
  checkLogin(); // Kiểm tra token đã lưu
}, []);

const checkLogin = async () => {
  const token = await getStorageItem(TOKEN);
  if (!token) return;

  const parsed = parseJwtToken(token);
  const { exp } = parsed;
  const now = Math.floor(Date.now() / 1000);

  // Nếu token còn > 1 giờ → auto login
  if (exp - now > 3600) {
    router.replace("/(tabs)");
  } else {
    await removeStorageItem(TOKEN); // Xóa token hết hạn
  }
};
```

2. **Handle login submit:**

```typescript
const handleLogin = async () => {
  // Validate input
  if (!username.trim() || !password.trim()) {
    showToastError("Lỗi", "Vui lòng nhập tài khoản và mật khẩu");
    return;
  }

  setLoading(true);

  const body = { username, password };
  const response = await login(body);

  if (response?.data.token) {
    await setStorageItem(TOKEN, response.data.token);
    router.replace("/(tabs)"); // Chuyển sang tabs
  }
};
```

**UI:**

- Form đăng nhập với username/password
- Loading indicator khi đang submit
- KeyboardAvoidingView cho iOS
- Support dark/light mode

#### `app/(tabs)/_layout.tsx` - Tabs Layout

```typescript
export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen name="index" options={{ title: "Home" }} />
      <Tabs.Screen name="explore" options={{ title: "Explore" }} />
      <Tabs.Screen name="setting" options={{ title: "Setting" }} />
    </Tabs>
  );
}
```

**Chức năng:**

- Cấu hình Bottom Tabs với 3 tabs
- Mỗi tab có icon riêng
- Haptic feedback khi tap tab

#### `app/(tabs)/index.tsx` - Home Screen (GPS Map)

**Luồng hoạt động:**

1. **State management:**

```typescript
const [gpsData, setGpsData] = useState<Model.GPSResponse | null>(null);
```

2. **Fetch GPS data:**

```typescript
const getGpsData = async () => {
  const response = await fetchGpsData();
  setGpsData(response.data);
};
```

3. **Render map:**

```typescript
<MapView
  initialRegion={{
    latitude: 15.70581,
    longitude: 116.152685,
    latitudeDelta: 2,
    longitudeDelta: 2,
  }}
>
  {gpsData && (
    <Marker
      coordinate={{ latitude: gpsData.lat, longitude: gpsData.lon }}
      title="Device Location"
    />
  )}
</MapView>
```

**Chức năng:**

- Hiển thị bản đồ với react-native-maps
- Button "Get GPS Data" để fetch vị trí thiết bị
- Hiển thị marker trên bản đồ khi có data

#### `app/(tabs)/explore.tsx` - Explore Screen

**Chức năng:**

- Demo screen với Collapsible components
- Giới thiệu về file-based routing, dark mode, animations
- Không có logic nghiệp vụ

#### `app/(tabs)/setting.tsx` - Settings Screen

**Luồng hoạt động:**

1. **Logout:**

```typescript
<ThemedView
  onTouchEnd={() => {
    removeStorageItem(TOKEN); // Xóa token
    router.replace("/auth/login"); // Về login
  }}
>
  <ThemedText>Đăng xuất</ThemedText>
</ThemedView>
```

2. **Demo API call:**

```typescript
const getData = async () => {
  const response = await api.get("/todos/1");
  setData(response.data);
};
```

**Chức năng:**

- Nút đăng xuất (xóa token + redirect login)
- Demo fetch data từ API

---

## 🔄 LUỒNG CHẠY CHI TIẾT

### **1. App Startup Flow**

```
📱 App Launch
    ↓
expo-router/entry
    ↓
app/_layout.tsx (RootLayout)
    ↓
setRouterInstance(router)  ← Lưu router instance
    ↓
Stack Navigator initialized
    ↓
app/index.tsx
    ↓
<Redirect href="/auth/login" />
    ↓
app/auth/login.tsx
```

### **2. Login Flow (Chi tiết)**

```
🔐 Login Screen Mount
    ↓
useEffect(() => checkLogin())
    ↓
getStorageItem(TOKEN)
    ↓
┌─────────────────┐
│ Token exists?   │
└─────────────────┘
    ├─ NO → Hiển thị form login
    │
    └─ YES → parseJwtToken(token)
            ↓
        Check exp time
            ↓
        ┌───────────────────┐
        │ Token còn > 1h?   │
        └───────────────────┘
            ├─ YES → router.replace("/(tabs)")  ← Auto login
            │
            └─ NO → removeStorageItem(TOKEN)    ← Xóa token hết hạn
                    Hiển thị form login
```

### **3. Submit Login Flow**

```
👤 User nhập username/password
    ↓
Press "Đăng nhập"
    ↓
handleLogin()
    ↓
Validate input (username && password)
    ├─ Invalid → showToastError("Vui lòng nhập...")
    │
    └─ Valid
        ↓
    setLoading(true)
        ↓
    login({ username, password })  ← AuthController
        ↓
    api.post("/api/agent/login", body)
        ↓
    ┌─ Request Interceptor ─┐
    │ Thêm Authorization    │
    │ header (nếu có token) │
    └───────────────────────┘
        ↓
    Call API backend
        ↓
    ┌─ Response Interceptor ─┐
    │ Check status code      │
    │ 401 → handle401()      │
    │ 500 → showToastError() │
    └────────────────────────┘
        ↓
    ┌──────────────────┐
    │ Response success?│
    └──────────────────┘
        ├─ NO → showToastError(error.message)
        │       setLoading(false)
        │
        └─ YES → Kiểm tra response.data.token
                ├─ Token exists?
                │   ├─ YES
                │   │   ↓
                │   │ setStorageItem(TOKEN, token)
                │   │   ↓
                │   │ router.replace("/(tabs)")
                │   │   ↓
                │   │ app/(tabs)/_layout.tsx
                │   │
                │   └─ NO → Không làm gì
                │
                └─ setLoading(false)
```

### **4. Tabs Navigation Flow**

```
📱 app/(tabs)/_layout.tsx
    ↓
Bottom Tabs Navigator
    ├─ Tab 1: index.tsx (Home/GPS Map)
    ├─ Tab 2: explore.tsx (Explore)
    └─ Tab 3: setting.tsx (Settings)
```

### **5. GPS Data Fetch Flow**

```
🗺️ Home Screen (index.tsx)
    ↓
User tap "Get GPS Data" button
    ↓
getGpsData()
    ↓
fetchGpsData()  ← DeviceController
    ↓
api.get("/api/sgw/gps")
    ↓
┌─ Request Interceptor ─┐
│ getStorageItem(TOKEN) │
│ Add Authorization     │
└───────────────────────┘
    ↓
Call API backend
    ↓
┌─ Response ─┐
│ {          │
│   lat,     │
│   lon,     │
│   s,       │
│   h,       │
│   fishing  │
│ }          │
└────────────┘
    ↓
setGpsData(response.data)
    ↓
Re-render MapView
    ↓
<Marker coordinate={{ lat, lon }} />
```

### **6. Logout Flow**

```
⚙️ Settings Screen
    ↓
User tap "Đăng xuất"
    ↓
removeStorageItem(TOKEN)  ← Xóa token khỏi AsyncStorage
    ↓
router.replace("/auth/login")
    ↓
Back to Login Screen
```

---

## 🔧 CƠ CHẾ HOẠT ĐỘNG CHI TIẾT

### **1. Authentication Mechanism**

```
Token Storage:
AsyncStorage (local device storage)
    Key: "token"
    Value: JWT string

Token Format:
Authorization: <token>  ← Không có "Bearer" prefix

Token Validation:
1. Parse JWT → lấy exp (expiration time)
2. So sánh với thời gian hiện tại
3. Nếu còn > 1 giờ → valid
4. Nếu < 1 giờ → expired → xóa token
```

### **2. API Request Flow với Interceptors**

```
┌───────────────────────────────────────┐
│        APPLICATION CODE               │
│  api.post("/api/login", body)         │
└───────────────┬───────────────────────┘
                ↓
┌───────────────────────────────────────┐
│    REQUEST INTERCEPTOR                │
│  1. getStorageItem("token")           │
│  2. config.headers.Authorization      │
│     = token                           │
└───────────────┬───────────────────────┘
                ↓
┌───────────────────────────────────────┐
│    NETWORK REQUEST                    │
│  POST http://192.168.30.102:81/...   │
│  Headers: { Authorization: <token> }  │
└───────────────┬───────────────────────┘
                ↓
┌───────────────────────────────────────┐
│    BACKEND SERVER                     │
│  Validate token → Process request     │
└───────────────┬───────────────────────┘
                ↓
┌───────────────────────────────────────┐
│    RESPONSE INTERCEPTOR               │
│  1. Check status code                 │
│  2. If error:                         │
│     - Map to message                  │
│     - showToastError()                │
│     - If 401: handle401()             │
└───────────────┬───────────────────────┘
                ↓
┌───────────────────────────────────────┐
│    APPLICATION CODE                   │
│  Handle response.data                 │
└───────────────────────────────────────┘
```

### **3. Routing Mechanism (Expo Router)**

```
File System                    Routes
───────────────────────────────────────
app/
├─ index.tsx            →    /
├─ _layout.tsx          →    (Root layout)
├─ auth/
│  └─ login.tsx         →    /auth/login
├─ (tabs)/
│  ├─ _layout.tsx       →    (Tabs layout)
│  ├─ index.tsx         →    /(tabs)
│  ├─ explore.tsx       →    /(tabs)/explore
│  └─ setting.tsx       →    /(tabs)/setting
└─ modal.tsx            →    /modal
```

### **4. State Management**

Dự án **KHÔNG dùng Redux/MobX**, chỉ dùng:

- `useState` cho local state
- `AsyncStorage` cho persistent storage (token)
- Props drilling (không nhiều level)

### **5. Error Handling Strategy**

```
Levels of Error Handling:
─────────────────────────────────────
1. Component Level (try-catch):
   try {
     await login(body);
   } catch (error) {
     showToastError(error.message);
   }

2. Axios Response Interceptor:
   - Catch ALL HTTP errors
   - Map status code → message
   - Show toast automatically

3. Utils Error Handling:
   - Storage errors → console.error
   - Token parse errors → return null
```

---

## 🎯 KẾT LUẬN

### **Điểm Mạnh:**

✅ Cấu trúc rõ ràng (config, controller, utils, app)  
✅ TypeScript với type definitions đầy đủ  
✅ Axios interceptors xử lý auth tự động  
✅ JWT token validation với expiration check  
✅ Toast notifications thống nhất  
✅ File-based routing với Expo Router  
✅ Support dark/light mode

### **Điểm Cần Cải Thiện:**

⚠️ Base URL hard-coded (nên dùng env variables)  
⚠️ `handle401()` chưa được enable trong axios  
⚠️ Thiếu refresh token mechanism  
⚠️ Không có loading state global  
⚠️ Constants có 2 BASE_URL khác nhau (confusing)  
⚠️ GPS data fetch chưa tự động (phải tap button)

### **Tech Stack Summary:**

- **Framework:** React Native + Expo
- **Navigation:** Expo Router (file-based)
- **HTTP Client:** Axios với interceptors
- **Storage:** AsyncStorage
- **Maps:** react-native-maps
- **UI:** Custom themed components
- **Notifications:** react-native-toast-message

---

## 📋 CẤU TRÚC THƯ MỤC

```
SeaGateway-App/
├── app/                          # Screens & Routes (Expo Router)
│   ├── _layout.tsx              # Root layout + Stack Navigator
│   ├── index.tsx                # Entry point (redirect to login)
│   ├── modal.tsx                # Modal demo screen
│   ├── (tabs)/                  # Tab Navigator Group
│   │   ├── _layout.tsx          # Tabs layout config
│   │   ├── index.tsx            # Home screen (GPS Map)
│   │   ├── explore.tsx          # Explore screen (demo)
│   │   └── setting.tsx          # Settings screen (logout)
│   └── auth/
│       └── login.tsx            # Login screen
│
├── assets/                       # Static resources
│   └── images/                  # Images, icons, splash
│
├── components/                   # Reusable UI components
│   ├── themed-text.tsx          # Text với theme support
│   ├── themed-view.tsx          # View với theme support
│   ├── haptic-tab.tsx           # Tab với haptic feedback
│   ├── parallax-scroll-view.tsx # Parallax scroll
│   └── ui/                      # UI components
│       ├── collapsible.tsx
│       └── icon-symbol.tsx
│
├── config/                       # App configuration
│   ├── index.ts                 # Export all configs
│   ├── axios.ts                 # Axios instance + interceptors
│   ├── auth.ts                  # Router management cho auth
│   └── toast.ts                 # Toast notification helpers
│
├── constants/                    # Constants & API paths
│   ├── index.ts                 # API endpoints, storage keys
│   └── theme.ts                 # Theme colors
│
├── controller/                   # API Controllers (Business Logic)
│   ├── index.ts                 # Export all controllers
│   ├── typings.d.ts             # TypeScript type definitions
│   ├── AuthController.ts        # Auth APIs (login)
│   └── DeviceController.ts      # Device APIs (GPS data)
│
├── hooks/                        # Custom React hooks
│   ├── use-color-scheme.ts      # Detect dark/light mode
│   └── use-theme-color.ts       # Get theme colors
│
├── utils/                        # Utility functions
│   ├── storage.ts               # AsyncStorage wrapper
│   └── token.ts                 # JWT token parser
│
├── scripts/                      # Build/dev scripts
│   └── reset-project.js         # Reset project script
│
├── app.json                      # Expo configuration
├── package.json                  # Dependencies
├── tsconfig.json                 # TypeScript config
└── .gitignore                    # Git ignore rules
```

---

## 🔑 CÁC FILE QUAN TRỌNG

### **1. Entry Points:**

- `app/_layout.tsx` - Root của toàn bộ app
- `app/index.tsx` - Redirect đầu tiên
- `package.json` - "main": "expo-router/entry"

### **2. Authentication Core:**

- `app/auth/login.tsx` - Login UI + logic
- `config/auth.ts` - Router management
- `config/axios.ts` - Token injection
- `utils/token.ts` - JWT parsing
- `utils/storage.ts` - Token storage

### **3. API Layer:**

- `config/axios.ts` - HTTP client
- `controller/AuthController.ts` - Login API
- `controller/DeviceController.ts` - GPS API
- `constants/index.ts` - API endpoints

### **4. Main Features:**

- `app/(tabs)/index.tsx` - GPS Map
- `app/(tabs)/setting.tsx` - Logout
- `components/themed-*.tsx` - Theme components

---

## 🚀 HƯỚNG DẪN CHẠY DỰ ÁN

### **1. Cài đặt dependencies:**

```bash
npm install
# hoặc
yarn install
```

### **2. Chạy development server:**

```bash
npm start
# hoặc
npx expo start
```

### **3. Chạy trên thiết bị:**

- **iOS Simulator:** Press `i` trong terminal
- **Android Emulator:** Press `a` trong terminal
- **Physical Device:** Scan QR code với Expo Go app

### **4. Build production:**

```bash
# iOS
npx expo run:ios

# Android
npx expo run:android
```

---

## 📝 LƯU Ý KHI PHÁT TRIỂN

### **1. Thêm API mới:**

```typescript
// 1. Define type trong controller/typings.d.ts
declare namespace Model {
  interface NewAPIResponse {
    data: string;
  }
}

// 2. Thêm endpoint trong constants/index.ts
export const API_NEW_ENDPOINT = "/api/new/endpoint";

// 3. Tạo controller function
// controller/NewController.ts
export async function fetchNewData() {
  return api.get<Model.NewAPIResponse>(API_NEW_ENDPOINT);
}
```

### **2. Thêm screen mới:**

```typescript
// 1. Tạo file trong app/
// app/new-screen.tsx
export default function NewScreen() {
  return <ThemedView>...</ThemedView>;
}

// 2. Route tự động: /new-screen
// 3. Navigate: router.push("/new-screen")
```

### **3. Environment Variables:**

**Nên tạo file `.env`:**

```bash
API_BASE_URL=http://192.168.30.102:81
API_TIMEOUT=10000
```

**Sử dụng:**

```typescript
import Constants from "expo-constants";

const api = axios.create({
  baseURL: Constants.expoConfig?.extra?.apiUrl,
});
```

### **4. Debugging Tips:**

- Check console logs trong terminal (metro bundler)
- Network requests: React Native Debugger
- Token issues: Log token trong axios interceptor
- Routing issues: Log router navigation events

---

## 🐛 CÁC LỖI THƯỜNG GẶP & CÁCH XỬ LÝ

### **1. Token expired không redirect:**

**Nguyên nhân:** `handle401()` bị comment  
**Giải pháp:** Uncomment dòng `handle401()` trong `config/axios.ts`

### **2. Map không hiển thị:**

**Nguyên nhân:**

- Chưa config Google Maps API key
- MapView `mapType="none"` (không có tile)

**Giải pháp:**

```typescript
<MapView mapType="standard" /> // Thay vì "none"
```

### **3. AsyncStorage warning:**

**Nguyên nhân:** AsyncStorage deprecated trong React Native core  
**Giải pháp:** Đã dùng `@react-native-async-storage/async-storage` ✅

### **4. Build failed trên iOS:**

**Nguyên nhân:** Chưa install CocoaPods  
**Giải pháp:**

```bash
cd ios && pod install
```

---

## 🔐 BẢO MẬT & BEST PRACTICES

### **1. Token Security:**

✅ Lưu trong AsyncStorage (secure trên device)  
✅ Check expiration trước khi dùng  
❌ Không có refresh token (nên thêm)  
❌ Không encrypt token (AsyncStorage không encrypted mặc định)

### **2. API Security:**

✅ HTTPS cho production (BASE_URL: https://...)  
❌ Hard-coded credentials (không có trong code ✅)  
⚠️ IP local trong axios base URL (đổi thành domain cho prod)

### **3. Code Security:**

✅ TypeScript strict mode  
✅ Try-catch cho async operations  
✅ Validate input trước khi gửi API  
❌ Không có rate limiting (phụ thuộc backend)

---

## 📚 TÀI LIỆU THAM KHẢO

- **Expo Router:** https://docs.expo.dev/router/introduction/
- **React Native:** https://reactnative.dev/
- **Axios:** https://axios-http.com/
- **React Native Maps:** https://github.com/react-native-maps/react-native-maps
- **AsyncStorage:** https://react-native-async-storage.github.io/async-storage/

---

_Document được tạo ngày: October 30, 2025_  
_Version: 1.0.0_  
_Author: GitHub Copilot Analysis_
