Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • A Ahad Mobile
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 1
    • Merge requests 1
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • holatech
  • Ahad Mobile
  • Merge requests
  • !36

feat(updates): bật cập nhật OTA (EAS Update) cho staging

  • Review changes

  • Download
  • Patches
  • Plain diff
Merged Khanh Pham requested to merge feat/eas-update-ota into develop Sep 03, 2026
  • Overview 0
  • Commits 11
  • Pipelines 1
  • Changes 16

Mục tiêu

Bật cập nhật OTA (EAS Update) cho bản staging, để mỗi lần đổi code JS là app tự nhận bản mới, không cần gỡ và cài lại APK.

Phạm vi: chỉ staging

OTA_ENABLED_ENVS trong app.config.ts chỉ chứa 'staging'. Các môi trường còn lại không được gán updates.url, nên expo-updates tắt hẳn ở tầng native.

APP_ENV updates.url Nhận OTA
staging có Có
production không Không
development / ui không Không

Vì sao production bị loại: expo-updates codesigning:configure nhúng chứng chỉ vào binary lúc build, nên code signing không thể thêm bằng OTA. Bật updates.url cho production trước khi có code signing đồng nghĩa mọi bản đang lưu hành mang một đường nhận-mã-từ-xa không ký, và ranh giới tin cậy duy nhất là quyền truy cập tài khoản EAS. Với một app tài chính thì không đánh đổi được. Các bước bắt buộc để bật về sau đã ghi trong runbook.

Thay đổi chính

  • app.config.ts — cổng chặn OTA_ENABLED_ENVS; runtimeVersion: { policy: 'fingerprint' } đặt cho mọi môi trường, chỉ updates.url là có điều kiện.
  • src/lib/hooks/use-app-update.ts — module duy nhất được import expo-updates. Kiểm tra bản mới lúc khởi động và mỗi lần app trở lại active.
  • src/components/update-banner.tsx — banner + nút khởi động lại, chỉ hiện ở route an toàn.
  • fingerprint.config.js — làm fingerprint tất định giữa máy local và EAS builder.
  • env.js — đổi URL scheme MoanaPay → ahad.
  • docs/ota-updates.md — runbook.
  • Test: 15 test mới (9 cho hook, 6 cho banner).

Ba chỗ đáng review kỹ

1. runtimeVersion đặt không điều kiện — cố ý

Thứ thật sự bật expo-updates là updates.url, không phải runtimeVersion. Nếu chỉ đặt runtimeVersion cho staging thì chạy prebuild:staging rồi prebuild:production sẽ chết, vì prebuild tái dùng thư mục native sẵn có:

A runtime version is set in your AndroidManifest.xml, but is missing from your Expo app config

Đã kiểm chứng cả hai chiều prebuild sạch, và production vẫn ENABLED=false, không có URL.

2. Banner dùng allowlist route, không phải denylist

RESTART_SAFE_ROUTES = ['/home']. Một màn hình thêm về sau bị loại cho tới khi có người review — mặc định an toàn cho app tài chính.

useIsMutating() chỉ là lớp thứ hai, không thể là lớp duy nhất: KYC gọi client.post trực tiếp (src/api/verification/index.ts:18) và chạy qua state cục bộ + SDK native (src/hooks/use-sumsub-verification.ts:63), React Query không thấy. Một lần restart không được phép cắt ngang giao dịch hay phiên KYC.

3. Nhánh rollback là bắt buộc

Chỉ thị rollback của EAS mang isAvailable: false và isRollBackToEmbedded: true. Hook chỉ kiểm tra isAvailable sẽ lặng lẽ bỏ qua mọi rollback, làm eas update:roll-back-to-embedded mất tác dụng hoàn toàn — tức là mất luôn đường thoát khi đẩy nhầm bản hỏng. Đã có test riêng cho cả hai nhánh.

Đổi scheme sang ahad

EAS Update validate manifest theo ^[a-z][a-z0-9+.-]*$ và từ chối publish nếu scheme không khớp; EAS Build thì không kiểm tra, nên scheme: 'MoanaPay' tồn tại rất lâu mà không ai phát hiện — chỉ vỡ ra ở lần publish OTA đầu tiên. Dạng array cũng bị từ chối (từng phần tử vẫn phải khớp).

Scheme cũ bỏ hoàn toàn, không đăng ký lại ở tầng native — đã xác nhận với chủ dự án là chưa có QR thanh toán nào phát hành ra ngoài.

Mọi chỗ sinh/quét QR giờ đọc Env.SCHEME, không hardcode.

⚠️ Cần reviewer để ý: src/lib/web3/appkit.tsx có redirect.native đi theo scheme mới. Luồng quay lại app sau khi ký ví WalletConnect chưa kiểm chứng được trên thiết bị thật. Ngoài ra name: 'MoanaPay' / url: 'https://moanapay.app' trong file đó cố ý để nguyên — đổi là quyết định thương hiệu và cần domain ahad thật.

Giới hạn đã biết: AppDelegate.swift và Podfile

expo-updates loại cứng toàn bộ ios/ và android/ khỏi fingerprint với project CNG, nên sửa hai file này KHÔNG làm đổi runtimeVersion — bản OTA publish sau đó vẫn lọt xuống binary build trước khi sửa, và chạy JS mới trên native cũ.

Đã thử ba cách bịt, đều không được (chi tiết trong runbook, mục "Ngoại lệ đã biết"): extraSources kiểu file bị chính ignorePaths lọc; kiểu contents không tất định vì eas-cli upload bằng git clone --no-checkout rồi chép đè từ đĩa local; git show HEAD: thì .git không tới được builder EAS.

Kiểm soát bằng quy trình, vì không có kiểm soát kỹ thuật: sau khi sửa một trong hai file đó, bắt buộc build lại và phát bản mới cho tester trước khi publish bất kỳ bản OTA nào.

Đã kiểm chứng

  • pnpm check-all sạch — 320 test / 48 suite pass, lint + type-check + translations OK.
  • Build EAS staging Android thành công, runtime 7acadc7291de6d270c265e2cb0dc2423107b0bd1, channel staging.
  • Tính an toàn của fingerprint chạy đúng cả hai chiều: đổi native (scheme) làm runtimeVersion đổi fb5cb0fa… → 12b2aeb4… → 7acadc72…; đổi riêng JS thì giữ nguyên.
  • Publish OTA lên channel staging thành công, runtime khớp APK.
  • Codex review (gate 3, git diff 8872c8b..HEAD): APPROVED, không có finding.

Chưa kiểm chứng

Xác nhận trên thiết bị Android thật: banner hiện → bấm khởi động lại → thấy code mới. Máy dev không có thiết bị cắm vào và không có emulator. Đang nhờ chủ dự án test tay trên máy thật.

Hai commit thử nghiệm (đổi chuỗi Deposit để test bằng mắt) đã được revert, nhánh này không mang chúng.

Ngoài phạm vi lần này

Tự động publish qua GitLab CI; OTA cho production/development/ui; code signing; rollout theo phần trăm.

🤖 Generated with Claude Code

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: feat/eas-update-ota