Software Requirements Specification
(SRS)
for EV Power Mobile Application
Production-grade specification for the EV Power Electric Vehicle charging client and digital wallet ecosystem across Vietnam
1. Introduction
1.1 Purpose & Objectives
This Software Requirements Specification (SRS) establishes the authoritative, definitive technical and
functional requirements for the EV Power Mobile Application (internal package identifier
com.evpower.chargingapp, repository moniker evp-app). The EV Power Mobile
Application
is an enterprise-grade mobile client designed specifically for Electric Vehicle (EV) drivers, commercial fleet
operators, and charging station hosts operating across Vietnam.
The primary objective of this document is to provide an unambiguous, rigorous contractual specification governing the mobile client application's user interface flows, hardware interactions (camera QR recognition, geolocation, secure enclave storage), communications with the backend Cloud Edge API Gateway, coordination with the Central Charge Point Management System (CPMS) executing Open Charge Point Protocol (OCPP) versions 1.6-J and 2.0.1, and financial transactions via the internal EVP point wallet.
charge-card), EVP digital wallet operations, and statutory electronic VAT invoice delivery.
1.2 Document Conventions
This document adheres strictly to the requirement conformance guidelines defined in RFC 2119. The following normative keywords dictate contractual obligations:
- SHALL / MUST: An absolute, non-negotiable requirement of the engineering specification.
- SHALL NOT / MUST NOT: An absolute, non-negotiable prohibition of behavior.
- SHOULD / RECOMMENDED: A strong recommendation where valid engineering justifications may exist in particular circumstances to deviate, subject to architecture review.
- MAY / OPTIONAL: A truly discretionary capability.
1.2.1 Requirement Identification Taxonomy
Requirements are uniquely cataloged using hierarchical prefixes corresponding to system domains:
| Prefix Pattern | Subsystem Domain | Description & Scope |
|---|---|---|
FR-AUTH-xx |
Authentication & User Profile | Phone OTP onboarding, credential login, password reset lockout, profile metadata, and debt tracking. |
FR-STN-xx |
Charging Stations & Connectors | Interactive map discovery, station clustering, connector standard filtering, and real-time status. |
FR-CHG-xx |
QR Scanning & Charging Session | Camera QR optical parsing, session budgeting, 5-phase state machine, telemetry, and order receipts. |
FR-VEH-xx |
Vehicle Garage & Fleet | EV registration, VIN binding, per-session spending caps (maxPointPerSession), and
deletion guardrails. |
FR-CRD-xx |
RFID Charge Cards | Physical RFID Charge Card management (charge-card), status tabs, and scratch card
activation. |
FR-WAL-xx |
EVP Wallet & Transactions | Point balances (1 EVP = 1,000 VND), VNPay top-ups, transaction logs, and double-entry ledger auditing. |
FR-INV-xx |
Invoices & VAT Tax Profiles | Corporate/Personal VAT profiles, automated tax invoice generation, and signed PDF downloads. |
FR-NTF-xx |
Notifications | REST inbox synchronization, Expo push notification channels, and transaction alerts. |
NFR-PRF-xx |
Performance Attributes | Application bootstrap, cache invalidation, frame rates, and telemetry polling cadence. |
NFR-SAF-xx |
Safety & Hardware Interlocking | Emergency stop response, current cessation (<100 ms), and ground-fault cable locks. |
NFR-SEC-xx |
Security & Cryptography | Hardware KeyStore/Keychain AES-256 storage, 401 JWT refresh mutex queue, and brute-force lockout. |
NFR-QLT-xx |
Quality, Resiliency & i18n | Network failure degradation, crash session recovery, and multi-language localization. |
1.2.2 Units of Measurement and Currency Standard
All quantitative requirements and system computations comply with the following standardized units:
- Internal Platform Currency (EVP): The point currency unit is the EVP (EV Power Point).
The
conversion rate between Vietnamese Dong (VND) and EVP is strictly invariant across the entire system:
INVARIANT: 1 EVP = 1,000 VND (1,000 Vietnamese Dong equals exactly 1 EVP Point).All user financial balances, connector charging tariffs, and transaction records SHALL adhere to this conversion factor. For example, a driver topping up 500,000 VND SHALL be credited exactly 500 EVP; a charging session consuming 120 EVP represents a financial cost of 120,000 VND.
- Electrical Power: Measured in Kilowatts (kW), representing instantaneous charging capacity delivered by alternating current (AC) or direct current (DC) Electric Vehicle Supply Equipment (EVSE).
- Electrical Energy: Measured internally in Watt-hours (Wh) at the hardware and telemetry abstraction layer, and formatted as Kilowatt-hours (kWh, where 1 kWh = 1,000 Wh) for user display and billing reconciliation.
- Battery State-of-Charge (SoC): Expressed as a percentage integer from 0% to 100%, representing the current usable capacity of the EV battery pack.
- Time & Latency: Expressed in milliseconds (ms) for network operations, polling
cadences, and hardware interlocks, and in seconds (s) or formatted strings (
hh:mm:ss) for elapsed session durations.
1.3 Intended Audience & Reading Suggestions
This document is structured for multiple engineering and operational disciplines:
- Mobile Engineering Team: Focus on Part 3.A (External Interface Requirements, Screen Hierarchy, Hardware Interfaces), Part 3.B (System Features 3.1 through 3.8), and Part 3.C (Non-Functional Requirements: State Stores, Caching, and 401 Mutex Interceptors).
- Cloud & Backend API Engineers: Review Section 3.A.3 (REST API Catalog), Section 3.B (Business Rules, Invariant Rate: 1 EVP = 1,000 VND, Ledger Schemas), and Section 4.2 (Canonical Domain Data Models).
- CPMS & Hardware Firmware Engineers: Review Section 3.2 (Charging Stations & Connectors), Section 3.3 (5-Phase Charging State Machine, Telemetry Polling, Emergency Stop Interlocking), and Section 4.3 (Connector Status Enumerations).
- QA, Security & Compliance Auditors: Focus on RFC 2119 requirement clauses, Section 3.C.3 (Security & Mutex Protections), Section 3.7 (Statutory Electronic VAT Invoicing), and verification protocols.
- Fleet Operations & Product Management: Review Section 2 (Overall Description, User Persona Hierarchy, Constraints) and Section 3.4 (Vehicle Garage & Spending Caps).
1.4 Project Scope & System Boundaries
The EV Power Mobile Application is the client interface connecting individual drivers and enterprise fleet drivers to physical charging stations across the Vietnamese national transportation corridor.
1.4.1 Functional Inclusions
- Driver Lifecycle & Security: Secure phone OTP onboarding, dual-tab login (phone+password or phone+OTP), 24-hour lockout defenses, profile avatar management, and outstanding negative balance tracking.
- Station Discovery & Navigation: High-performance interactive map with marker clustering, multi-standard connector filters (Type 2, CCS 2, CHAdeMO, GB/T AC, GB/T DC), real-time connector availability, and external map routing (Google Maps, Apple Maps).
- Optical QR Scanning & Session Configuration: Fast camera barcode scanning with torch and photo gallery support, manual code entry, and preset charging budget selection (100k, 200k, 300k, 500k, 800k, 1M VND).
- 5-Phase Charging State Machine: Real-time progression through
plug,connecting(with 1,800 ms hardware stabilization delay),charging(with 10-second telemetry polling: kW, kWh, battery SoC %, accrued cost, elapsed duration), and graceful termination (successorcanceled). - Vehicle Garage & Fleet Constraints: Vehicle registration linked to Vehicle
Identification Numbers (VIN), status indicators, and driver-configured per-session spending caps
(
maxPointPerSession). - Physical RFID Charge Cards: Management of physical RFID charge cards
(
charge-card) across life cycle tabs (ALL,ACTIVE,EXPIRING_SOON,USED_UP,EXPIRED), and instant balance redemption via physical scratch card codes (POST /api/v1/wallet/cards/activate). - Financial Wallet & Ledger: EVP digital point wallet adhering strictly to
1 EVP = 1,000 VND, multi-channel top-ups via VNPay in-app webviews, transaction history, and double-entry ledger audits. - Statutory VAT Invoicing: Corporate and personal electronic VAT invoice profile management (compliant with Vietnamese tax regulations), automated invoice generation against top-up events, and binary PDF streaming and sharing.
- Communications & Engagement: REST-based notification inbox with unread tracking, and
native Expo Push Notification channels (
default,charging).
1.4.2 Functional Exclusions
- Zero Retail Operations: The application does NOT support physical goods purchasing, merchant portals, or parcel logistics.
- Streamlined Communications: The application does NOT utilize legacy WebSocket messaging channels; real-time updates are driven exclusively by disciplined HTTP REST polling and native Expo Push Notifications.
buyerName and
buyerTaxCode represent official statutory fields defined by the Ministry of Finance and General
Department of Taxation of Vietnam (Circular 78/2021/TT-BTC) designating the legal invoice recipient ("Người
mua hàng / Tên doanh nghiệp"). These fields are strictly statutory tax accounting terminology.
1.5 References & Industry Standards
The system design conforms to the following standards, protocols, and regulatory statutes:
- IEEE Std 830-1998: IEEE Recommended Practice for Software Requirements Specifications.
- OCPP 1.6-J & OCPP 2.0.1: Open Charge Point Protocol JSON over WebSockets, Open Charge Alliance.
- RFC 6749: The OAuth 2.0 Authorization Framework.
- RFC 7519: JSON Web Token (JWT) Architecture.
- RFC 2119: Key words for use in RFCs to Indicate Requirement Levels.
- Expo SDK 57 / React Native 0.86.3: Pure Bridgeless New Architecture (Fabric Renderer + TurboModules) utilizing Hermes v1 runtime, decoupled Expo Router v57, and Android 15 edge-to-edge windowing.
- React 19.2.3 & React DOM 19.2.3: Core rendering runtime and mandatory peer dependencies for pure Bridgeless Expo execution.
- Decree 123/2020/ND-CP & Circular 78/2021/TT-BTC: Legal regulations governing electronic invoices, tax codes, and digital financial reporting in the Socialist Republic of Vietnam.
2. Overall Description
2.1 Product Perspective & System Topology
The EV Power Mobile Application operates as a critical node within a distributed, high-availability electric mobility ecosystem. Built upon Expo SDK 57 (v57.0.22), React Native 0.86.3, and React 19.2.3 operating in pure Bridgeless New Architecture (with the legacy Paper renderer and JavaScript-to-native Bridge permanently eliminated), the mobile client connects securely over HTTPS / TLS 1.3 to the cloud-native EV Power Edge API Gateway using RFC 6750 Bearer JSON Web Tokens (JWT).
Downstream from the API Gateway, the system orchestrates charging hardware via the Central Charge Point Management System (CPMS) executing OCPP 1.6-J and 2.0.1 protocols over WebSockets, coordinates financial transactions with third-party payment gateways (VNPAY), pushes critical charging alerts via the Expo Push Notification Service (APNs/FCM), and interfaces with the General Department of Taxation for statutory electronic VAT invoice dispatch.
2.2 Product Functions Summary
The following matrix summarizes the 8 primary functional areas of the EV Power mobile application, mapping each capability to its business purpose, targeted user personas, and engineering priority:
| # | Functional Area | Primary Capabilities & Workflows | User Personas | Priority |
|---|---|---|---|---|
| 1 | User Authentication & Profile | Dual-tab login (Phone+Password or Phone+OTP), registration with SMS verification, password reset with 24-hour lockout protection, avatar upload, and outstanding debt monitoring. | Guest, EV Driver, Fleet Driver | High |
| 2 | Charging Stations & Connectors | Interactive GPS map with marker clustering, multi-standard connector filters (Type 2, CCS 2, CHAdeMO, GB/T), station amenities, 24h status, and real-time connector availability pills. | Guest, EV Driver, Fleet Driver | High |
| 3 | QR Scanning & Charging Flow | Camera optical QR parsing, manual code entry, preset charging budget configuration (100k–1M VND), 5-phase charging state machine, live telemetry monitoring, and order receipts. | Authenticated EV Driver, Fleet Driver | High |
| 4 | Vehicle Garage & Fleet Caps | Add/manage user electric vehicles, VIN binding, vehicle status indicators, and per-session spending
ceiling enforcement (maxPointPerSession). |
EV Driver, Commercial Fleet Driver | Medium |
| 5 | RFID Charge Cards (charge-card) |
Catalog of linked RFID cards with status tabs (ALL, ACTIVE,
EXPIRING_SOON, USED_UP, EXPIRED), and physical scratch card
activation (POST /wallet/cards/activate).
|
EV Driver, Fleet Operator | High |
| 6 | EVP Wallet & Transactions | Point wallet balance tracking with invariant 1 EVP = 1,000 VND, minimum 100 EVP charging rule, VNPay in-app webview top-ups, and double-entry transaction ledger auditing. | Authenticated EV Driver, Fleet Driver | High |
| 7 | Invoices & VAT Tax Profiles | Personal and corporate tax profile management (buyerName, buyerTaxCode),
automatic tax invoice generation linked to top-ups, and signed PDF downloads via native sharing. |
EV Driver, Enterprise Fleet Driver | Medium |
| 8 | Notifications & Alerts | REST-based notification feed with unread counters, and native Expo Push Notification channels
(default, charging). |
All Authenticated Users | Low |
2.3 User Classes & Persona Hierarchy
The system defines four distinct user classes with specific privileges and system access boundaries:
2.3.1 Guest (Unauthenticated EV Driver)
An unregistered or logged-out user launching the mobile application. Guests have read-only access to public station infrastructure data.
- Permissions: Browse interactive map, search stations by location and connector standard,
view station operating hours, hotline, and tariffs. Access language preferences (
en,vi,zh-Hans) and Help Center FAQs. - Restrictions: Cannot initiate optical QR scans, cannot configure charging sessions, cannot access digital wallet or vehicle garage. Attempting protected actions presents an authenticated login modal.
2.3.2 Authenticated EV Driver (Individual User)
A verified consumer EV driver with an active phone number and authenticated session.
- Permissions: Full access to all 8 functional areas. Can register personal electric vehicles, initiate camera QR scanning, configure charging sessions, monitor live telemetry, execute VNPay wallet top-ups, link RFID Charge Cards, activate scratch cards, manage personal VAT invoice profiles, and receive push notifications.
- Restrictions: Cannot initiate a session if wallet balance is below 100 EVP or if account
is flagged with
chargingBlocked: truedue to unsettled negative debt.
2.3.3 Commercial Fleet Driver / Operator
A professional corporate driver or fleet manager operating enterprise-owned electric vehicles (taxis, delivery vans, corporate fleet).
- Permissions: Inherits all Authenticated EV Driver privileges. Additionally utilizes
corporate VAT invoice profiles with enterprise tax codes (
buyerTaxCode) for centralized tax deduction, and configures strict per-vehicle spending caps (maxPointPerSession) to enforce corporate energy allowances. - Restrictions: Charging sessions automatically terminate if the session energy cost
reaches the vehicle's assigned
maxPointPerSessionceiling.
2.3.4 System Administrator & CPMS Operator (External Boundary)
Centralized back-office engineering and operations personnel interacting through enterprise web consoles (outside mobile client boundary).
- Capabilities: Provision charge boxes, configure connector tariffs (VND per kWh), review OCPP heartbeat logs, manage RFID point lots, and inspect double-entry financial ledger records.
2.4 Operating Environment & Runtime Architecture
The EV Power Mobile Application is built on modern cross-platform mobile standards to ensure native performance, hardware security, and long-term maintainability:
| Architecture Layer | Technology Specification | Operational Function & Purpose |
|---|---|---|
| Target Platforms | iOS 16.4+ • Android 15.0+ (API 35, minSdk 24/26, compileSdk 35) | Requires Xcode 26+; enforces Android 15 mandatory edge-to-edge windowing insets via safe-area context. |
| Core Runtime Framework | Expo SDK 57.0.22 • React Native 0.86.3 • React 19.2.3 • react-dom 19.2.3 | Pure Bridgeless Mode default; Paper and legacy Bridge dropped; Fabric renderer, TurboModules, Hermes v1. |
| Navigation Architecture | Expo Router ~57.0.21 (Decoupled Navigation) | Decoupled from upstream @react-navigation/*; native tab transitions, unified SDK versioning, auth route guards. |
| UI Worklets & Animations | React Native Reanimated 4.5.1 • react-native-worklets 0.10.1 | Standalone C++ worklet runtime executing on UI thread without bridge latency; auto-injected Babel AST visitor. |
| Styling & Design Engine | NativeWind v4.2.7 • react-native-css-interop 0.2.7 • Tailwind CSS 3.4.19 | Tailwind utility compilation tested against React 19.2.3 and RN 0.86.3 Fabric; theme token orchestration. |
| Client State Management | Zustand v5.0.15 | Lightweight, hook-based global stores for auth tokens, user profile, multi-session charging, and station filters. |
| Server Cache & Synchronization | TanStack React Query v5.102.8 | Optimistic updates, 30s staleTime, 5m gcTime, window focus refetch, and background polling. |
| Networking & Interceptors | Axios ^1.7.7 | Dual-instance HTTP client with automatic Bearer injection, 401 JWT refresh mutex queue, and rotatedByOtherFlow. |
| Secure Storage Engine | Expo SecureStore ~57.0.4 | Hardware-backed AES-256 encryption using iOS Keychain (kSecAttrAccessibleAfterFirstUnlock) and Android KeyStore. |
| Mapping & Geolocation | React Native Maps 1.27.2 • Expo Location ~57.0.17 | Fabric codegen (RNMapsSpecs); custom marker collapsable={false} preventing Android View Flattening 0x0 collapse. |
| Camera & Vision Engine | Expo Camera ~57.0.5 | Native MLKit barcode scanning plugin; audio recording permission (RECORD_AUDIO) decoupled from Android manifest. |
| Push Notifications | Expo Notifications ~57.0.18 | Mandatory config plugin in app.json; channels (default, charging), APNs and FCM delivery, sub.remove(). |
| Application Startup & Splash | Expo Splash Screen ~57.0.9 | Config plugin in app.json; synchronous SplashScreen.hide() alongside async hide. |
| File System & Document Cache | Expo FileSystem ~57.0.7 • Expo Sharing ~57.0.19 | Modern next-gen FileSystem using Paths.cache.uri and Paths.document for PDF invoice streaming. |
| Localization (i18n) | i18next • react-i18next | Zero-restart dynamic language switching across English (en), Vietnamese (vi), and Chinese (zh-Hans). |
2.5 Design & Implementation Constraints
The system is governed by strict architectural, mathematical, and security invariants:
- Strict Conversion Rate Invariant: The rate
1 EVP = 1,000 VNDis immutable across the entire software ecosystem. No user or screen may apply alternative ratios. - Minimum Balance Charging Gate: A driver MUST maintain a minimum balance of
100 EVP(100,000 VND) in their digital wallet to authorize the initiation of a charging session. - Single Active Session per Connector: An EVSE connector can service exactly one vehicle at
any time. If a connector reports status other than
AVAILABLE, session initiation is rejected. - Strict Polling Cadence: During pre-charge (
plugstep), connector status is polled every 5,000 ms (connectorStatusMs). During active charging, session telemetry is polled every 10,000 ms (transactionDetailMs). The physical handshake delay enforces a minimum wait of 1,800 ms (connectingMinDurationMs) to prevent hardware race conditions. - 401 JWT Refresh Mutex Lock: If multiple concurrent API requests receive HTTP 401
Unauthorized, an interceptor mutex lock ensures that exactly ONE token refresh request is dispatched to
POST /api/v1/auth/refresh, while all other requests are queued in a Promise array until the new token is acquired. - 24-Hour Account Lockout Defense: If a user fails OTP or password verification 5 consecutive times within a 15-minute window, the account is locked for 24 hours to prevent brute-force credential stuffing.
- Mandatory Bridgeless Mode Invariant: The legacy Paper renderer and JavaScript-to-native
Bridge are permanently eliminated. All native communication operates synchronously or via TurboModules JSI
bindings. Specifying
newArchEnabled: trueinapp.jsonor build configurations is forbidden. - Decoupled Navigation Invariant: Application screens and hooks must NOT import navigation
primitives directly from
@react-navigation/native. All navigation state queries (specificallyuseIsFocused) must be consumed directly fromexpo-routerto maintain synchronized routing state. - Android 15 Edge-to-Edge Windowing Invariant: Under Android 15 (API 35), edge-to-edge window drawing
is enforced by the operating system. System calls like
StatusBar.setBackgroundColor()andStatusBar.setTranslucent()are no-ops; viewport safe areas must strictly derive fromreact-native-safe-area-context. - Android Map Marker Fabric Invariant: Custom marker views inside
<Marker>must declarecollapsable={false}to prevent Android View Flattening under Fabric from collapsing the marker view to 0x0 pixels during Google Maps canvas snapshot capture.
2.6 Assumptions & Upstream Dependencies
- CPMS & Charger Hardware SLA: The Central Charge Point Management System communicates with physical chargers via OCPP 1.6-J / 2.0.1 over cellular/Ethernet. Charger heartbeat latency is assumed ≤ 2,000 ms, and remote start/stop acknowledgment latency is assumed ≤ 3,000 ms.
- Expo Push Notification Delivery: Remote charging lifecycle push notifications
(
ORDER_CREATED,CHARGING_STOPPED) rely on Apple Push Notification service (APNs) and Google Firebase Cloud Messaging (FCM). Device network connectivity is assumed. - Payment Gateway Availability: VNPAY payment processing and instant payment notification (IPN) webhooks operate with an assumed 99.9% uptime SLA.
- Tax Authority Invoicing Engine: Electronic VAT invoice XML signing and verification comply with Vietnam General Department of Taxation digital certificate infrastructure.
3. Specific Requirements
Part 3.A: External Interface Requirements
3.A.1 User Interfaces & Screen Hierarchy
The EV Power mobile client user interface is structured using Expo Router ~57.0.21 (Expo SDK 57 decoupled navigation). All application routes, screens, and authentication guards are cataloged below:
| Route Path | Component / Screen File | Operational Purpose & Screen Description | Auth Guard |
|---|---|---|---|
app/index.tsx |
screens/common/SplashScreen.tsx |
Application entry gate; performs auth bootstrap, token validation, and redirect. | Public |
app/(auth)/login.tsx |
screens/auth/LoginScreen.tsx |
Dual-tab driver authentication: Phone + Password or Phone + SMS OTP. | Unauthenticated |
app/(auth)/register.tsx |
screens/auth/RegisterScreen.tsx |
Driver registration with phone number, password, and SMS OTP verification. | Unauthenticated |
app/(auth)/forgot-password.tsx |
screens/auth/ForgotPasswordScreen.tsx |
Two-step password recovery requesting and verifying phone reset OTP. | Unauthenticated |
app/(auth)/reset-password.tsx |
screens/auth/ResetPassword.tsx |
New password submission secured by verified resetToken. |
Unauthenticated |
app/(tabs)/home.tsx |
screens/home/HomeScreen.tsx |
Main driver home dashboard, wallet summary, charging status, and quick station search. | Public / Hybrid |
app/(tabs)/stations.tsx |
screens/stations/StationMapScreen.tsx |
Interactive station map with marker clustering, search bar, and connector filters. | Public |
app/(tabs)/qr-scan.tsx |
screens/qr/QRScanScreen.tsx |
Hardware camera QR code scanner, torch toggle, and manual connector code modal. | Protected |
app/(tabs)/orders/index.tsx |
screens/orders/OrdersScreen.tsx |
Historical EV charging sessions with status tabs (all, charging, completed, failed). | Protected |
app/(tabs)/profile/index.tsx |
screens/profile/ProfileScreen.tsx |
Driver profile overview, ProfileUserCard with modular VirtualEvCard (wallet balance & top-up CTA), debt points, and garage. | Protected |
app/charging/connect.tsx |
screens/charging/PlugInStep.tsx |
Physical cable connection guide; monitors charger status until PREPARING. | Protected |
app/charging/setup.tsx |
screens/charging/SetupScreen.tsx |
Session configuration; preset amount selection (100k–1M VND) and energy budget. | Protected |
app/charging-detail.tsx |
screens/charging/ChargingSessionScreen.tsx |
Active charging dashboard with real-time telemetry (kW, kWh, SoC %, cost, timer) and AC SoC fallback handling. | Protected |
app/order/[id].tsx |
screens/orders/OrderDetailScreen.tsx |
Comprehensive receipt for completed session; energy delivered, duration, EVP points billed. | Protected |
app/charging-card.tsx |
screens/profile/ChargeCardScreen.tsx |
RFID Charge Cards management; displays linked cards and scratch card activation. | Protected |
app/(tabs)/profile/vehicles/* |
screens/profile/vehicles/* |
Electric vehicle garage: list vehicles, bind VIN, set per-session point cap. | Protected |
app/(tabs)/profile/top-up.tsx |
screens/top-up/TopUpScreen.tsx |
EVP digital wallet top-up; VNPay payment gateway selection and in-app webview. | Protected |
app/(tabs)/profile/invoices/* |
screens/profile/invoices/* |
Electronic VAT tax invoices list, invoice details, and binary signed PDF export. | Protected |
app/(tabs)/profile/invoice-profiles/* |
screens/profile/InvoiceProfilesScreen.tsx |
Personal and company VAT invoice billing profiles (tax code, company name, address). | Protected |
app/(tabs)/profile/transactions/* |
screens/transactions/TransactionHistoryScreen.tsx |
Double-entry point ledger audit trail: TOPUP, CHARGE_DEDUCT, CARD_ACTIVATE. | Protected |
app/notifications.tsx |
screens/notifications/NotificationsScreen.tsx |
REST-based notifications list, unread badge counters, and mark-as-read actions. | Protected |
3.A.2 Hardware & Physical Device Interfaces
The mobile application interacts directly with mobile device hardware peripherals:
-
Camera Hardware Subsystem (
expo-camera): The application accesses the device camera sensor with hardware-accelerated 2D optical barcode recognition configured strictly forqrtypes. Provides real-time viewfinder rendering, hardware LED torch control for low-light charging environments, camera lens flipping, and photo library optical decoding viaexpo-image-picker. -
Geolocation Hardware Subsystem (
expo-location): Utilizes balanced-power and high-accuracy GPS positioning sensors to compute current driver coordinates. Coordinates are used to calculate Haversine great-circle distances to nearby stations, cluster pins within bounding viewports, and launch native external navigation apps (Apple Maps, Google Maps) viaLinking.openURL(). -
Secure Enclave Subsystem (
expo-secure-store): Hardware-backed cryptographic storage utilizing the iOS Keychain Services and Android KeyStore System with AES-256 encryption. StoresaccessToken,refreshToken, and password recoveryresetToken. Prevents extraction via device backup or filesystem inspection. -
Network Radio Sensing (
@react-native-community/netinfo): Monitors active cellular (4G/5G) and Wi-Fi radio states. Automatically presents a non-intrusive offline status indicator when reachability is lost, and immediately triggers TanStack Query cache re-synchronization upon network reconnection.
3.A.3 Software / REST API Catalog
The EV Power mobile client interfaces with 10 backend domain microservices via 50+ strongly-typed REST endpoints over HTTPS. Every endpoint adheres to strict request/response schemas:
| Method | Endpoint Path | Request Payload | Response Model | Operational Function & Business Scope |
|---|---|---|---|---|
| POST | /api/v1/auth/login |
LoginWithPasswordPayload |
AuthTokens |
Authenticate driver via phone number and password. |
| POST | /api/v1/auth/register |
RegisterPayload |
AuthTokens |
Register new driver account with phone, password, and fullName. |
| POST | /api/v1/auth/otp/request |
SendOTPPayload |
SendOTPResponse |
Dispatch 6-digit SMS verification OTP to driver's phone. |
| POST | /api/v1/auth/otp/verify |
LoginWithOTPPayload |
AuthTokens |
Verify SMS OTP and issue authenticated JWT session tokens. |
| GET | /api/v1/auth/me |
— | AuthUser |
Fetch authenticated driver session state and verification status. |
| POST | /api/v1/auth/password |
CreateNewPasswordPayload |
void |
Set initial account password for first-time OTP authenticated drivers. |
| POST | /api/v1/auth/password/skip |
— | void |
Skip optional password creation and continue OTP-only authentication. |
| POST | /api/v1/auth/forgot-password/request |
ForgotPasswordRequestPayload |
SendOTPResponse |
Initiate password reset flow; triggers verification SMS OTP. |
| POST | /api/v1/auth/forgot-password/verify |
ForgotPasswordVerifyPayload |
ForgotPasswordVerifyResponse |
Verify reset OTP; returns short-lived cryptographic resetToken. |
| POST | /api/v1/auth/forgot-password/reset |
ResetPasswordPayload |
void |
Submit new password using verified resetToken. |
| POST | /api/v1/auth/logout |
LogoutPayload |
void |
Revoke active refresh tokens and terminate session across devices. |
| POST | /api/v1/auth/refresh |
{ refreshToken } |
AuthTokens |
Exchange unexpired refresh token for new access/refresh pair. |
| GET | /api/v1/user/profile |
— | UserProfileResponse |
Fetch driver profile, avatar, EVP balance, and debt point status. |
| PUT | /api/v1/user/profile |
UpdateUserProfilePayload |
UserProfileResponse |
Update driver display name and avatar URL. |
| POST | /api/v1/user/push-token |
PushTokenPayload |
void |
Register native Expo Push Notification token for driver account. |
| DELETE | /api/v1/user/push-token |
{ token } |
void |
Unregister device push token upon user logout. |
| GET | /api/v1/stations/map |
lat, lng, radiusKm |
Station[] |
Retrieve charging stations within map viewport for pin clustering. |
| POST | /api/v1/stations/search |
SearchStationPayload |
StationSearchPage |
Search stations with filters: connector type, power rating, keyword. |
| GET | /api/v1/stations/{id} |
— | StationDetail |
Fetch station specifications, amenities, 24h status, and charging points. |
| GET | /api/v1/stations/{id}/pricing |
— | GetStationPricingResponse |
Fetch station charging tariffs, time-of-use rates, and idle fee rules. |
| GET | /api/v1/charge-points/{box}/connectors/{no} |
— | ConnectorStatusResponse |
Query real-time hardware status pill for specific physical connector. |
| GET | /api/v1/connectors |
chargeBoxCode, connectorCode |
ConnectorDetail |
Lookup connector hardware specs and tariff details from scanned QR code. |
| POST | /api/v1/charging/start |
StartTransactionPayload |
StartTransactionResponse |
Initiate remote charging transaction through CPMS; returns transactionId. |
| POST | /api/v1/charging/stop |
StopTransactionPayload |
StopTransactionResponse |
Terminate active charging session and instruct charger to unlock cable. |
| GET | /api/v1/charging/status |
chargeBoxCode, connectorNo |
TransactionStatusResponse |
Poll active connector state during pre-charge connection phase. |
| GET | /api/v1/charging/sessions/{id} |
— | TransactionDetailResponse |
Poll real-time charging telemetry: kW, kWh, battery SoC %, cost EVP. |
| GET | /api/v1/charging/sessions/active |
— | ActiveSessionFromServer[] |
Recover in-flight active charging session on application bootstrap. |
| GET | /api/v1/charging/orders |
page, size, status |
ChargingOrder[] |
Query historical charging orders with pagination and status filtering. |
| GET | /api/v1/charging/orders/{id} |
— | ChargingOrderDetailResponse |
Retrieve finalized session receipt, total points billed, and energy Wh. |
| GET | /api/v1/vehicles |
— | Vehicle[] |
List all electric vehicles registered in the driver's garage. |
| GET | /api/v1/vehicles/{id} |
— | Vehicle |
Fetch vehicle details: VIN, license plate, session spending cap. |
| PATCH | /api/v1/vehicles/{id} |
UpdateVehiclePayload |
Vehicle |
Update vehicle label and maximum session spending cap (maxPointPerSession). |
| DELETE | /api/v1/vehicles/{id} |
— | void |
Remove vehicle from driver garage; disallows deletion if actively charging. |
| GET | /api/v1/wallet/cards |
page, size, state |
GetMyChargeCardsResponse |
Fetch RFID Charge Cards with tabs: ALL, ACTIVE, EXPIRING_SOON, USED_UP, EXPIRED. |
| POST | /api/v1/wallet/cards/activate |
RedeemChargeCardPayload |
RedeemCardResponse |
Activate physical scratch card code; credits face value EVP points to wallet. |
| POST | /api/v1/wallet/topups |
CreateWalletTopupPayload |
CreateTopupResponse |
Create wallet top-up order (1 EVP = 1,000 VND); returns VNPay payment URL. |
| GET | /api/v1/wallet/topups/{id} |
— | TopupStatusData |
Poll VNPay top-up status: PENDING, SUCCEEDED, FAILED, CANCELED, EXPIRED. |
| GET | /api/v1/wallet/topups |
page, size |
TopupHistoryItem[] |
Fetch driver top-up purchase history and payment timestamps. |
| GET | /api/v1/wallet/ledger |
page, size, entryType, from, to |
LedgerEntry[] |
Audit double-entry ledger records: TOPUP, CHARGE_DEDUCT, CARD_ACTIVATE. |
| GET | /api/v1/invoice-profiles |
— | InvoiceProfile[] |
List driver VAT invoice profiles (PERSONAL and COMPANY). |
| POST | /api/v1/invoice-profiles |
CreateInvoiceProfilePayload |
InvoiceProfile |
Create new VAT invoice profile with buyerName, buyerTaxCode, address. |
| PUT | /api/v1/invoice-profiles/{id} |
UpdateInvoiceProfilePayload |
InvoiceProfile |
Modify existing VAT tax profile parameters. |
| DELETE | /api/v1/invoice-profiles/{id} |
— | void |
Delete VAT profile; rejected if set as default profile. |
| PATCH | /api/v1/invoice-profiles/{id}/default |
— | void |
Set specified profile as default for automated invoice dispatch. |
| GET | /api/v1/invoices |
page, size, from, to, status |
InvoiceListResponse |
Query electronic VAT invoices with status: ISSUED, PROCESSING, NEEDS_SUPPORT. |
| GET | /api/v1/invoices/{id} |
— | InvoiceDetailResponse |
Fetch electronic invoice tax breakdown, subtotal, and tax lines. |
| GET | /api/v1/invoices/{id}/download |
— | ArrayBuffer (PDF) |
Stream binary digitally-signed VAT invoice PDF for local saving/sharing. |
| GET | /api/v1/notifications |
page, size, unreadOnly |
GetInboxResponse |
Fetch paginated notifications inbox with unread count. |
| GET | /api/v1/notifications/unread-count |
— | UnreadCountResponse |
Query unread notifications badge count for bottom tab bar. |
| POST | /api/v1/notifications/{id}/read |
— | MarkNotificationAsReadResponse |
Mark specific notification item as read. |
| POST | /api/v1/notifications/read-all |
— | MarkAllNotificationsAsReadResponse |
Mark all inbox notifications as read. |
| POST | /api/v1/notifications/devices |
RegisterDevicePayload |
RegisterDeviceResponse |
Register device token and platform (iOS/Android) with notification service. |
| DELETE | /api/v1/notifications/devices |
UnregisterDevicePayload |
UnregisterDeviceResponse |
Unregister device token from notification delivery broker. |
| POST | /api/v1/upload/image |
FormData (multipart) |
UploadImageResponse |
Upload driver profile avatar image; returns CDN public URL. |
3.A.4 Communications Interfaces
- Transport Protocol: All client-to-gateway traffic SHALL transmit over HTTPS / TLS 1.3 on TCP port 443 with strict cipher suite enforcement. Unencrypted HTTP traffic is rejected.
-
Authentication Tokens: All protected API requests MUST carry an RFC 6750 Bearer JSON Web
Token in the
Authorizationrequest header. -
Asynchronous Push Messaging: Event-driven charging milestone notifications
(
ORDER_CREATED,CHARGING_STOPPED,TOPUP_SUCCESS,CARD_ACTIVATED) are pushed via Apple APNs and Google FCM through the Expo Push Notification broker.
Part 3.B: System Features & Functional Requirements
3.1 User Authentication, Session & Driver Profile
Governs driver identity verification, dual-channel credentials, session token lifecycles, profile metadata, and financial debt checks.
ENABLE_REGISTER_FEATURE is active.- Driver opens
app/(auth)/register.tsx, inputs full name, phone number, and password adhering to complexity criteria (≥8 characters, uppercase, lowercase, digit). - User taps "Register"; client dispatches
POST /api/v1/auth/registerwithRegisterPayload. - Backend generates 6-digit OTP, dispatches via SMS gateway, and returns
SendOTPResponse. - Client transitions to
PhoneOtpVerificationCardwith a 60-second countdown timer. - Driver inputs the 6-digit OTP; client dispatches
POST /api/v1/auth/otp/verifywithLoginWithOTPPayload. - Backend verifies OTP, marks
isPhoneVerified: true, and returnsAuthTokens(JWTaccessTokenandrefreshToken).
authStore sets
authenticated user; user is routed to app/(tabs)/home.tsx.isActive: true.- Driver navigates to
app/(auth)/login.tsxand selects either the "Password" or "OTP" tab. - Password Path: Driver inputs phone and password, taps "Sign In". Client calls
POST /api/v1/auth/loginwithLoginWithPasswordPayload. - OTP Path: Driver inputs phone, taps "Send OTP". Client calls
POST /api/v1/auth/otp/request. Upon receiving OTP, driver inputs 6 digits; client callsPOST /api/v1/auth/otp/verify. - If first-time OTP login without password (
isFirstTimeLogin: trueandhasPassword: false), app routes toCreatePasswordScreen(offering password creation or skip).
GET /api/v1/user/profile,
registers push notification token, and mounts tab navigation.isActive: false), login fails with HTTP 403 Forbidden and displays a customer support
contact modal.- Driver taps "Forgot Password?" on login screen, routing to
app/(auth)/forgot-password.tsx. - Driver enters phone number; client dispatches
POST /api/v1/auth/forgot-password/request. - Driver receives SMS OTP and enters the code; client dispatches
POST /api/v1/auth/forgot-password/verify. - Backend validates OTP and issues a cryptographically random, single-use
resetToken(valid for 15 minutes). - Client saves
resetTokenin secure storage and navigates toapp/(auth)/reset-password.tsx. - Driver inputs new password and confirmation; client dispatches
POST /api/v1/auth/forgot-password/resetwithresetTokenand new password.
retryAfterSeconds.outstandingPoint).- Driver opens
app/(tabs)/profile/index.tsx; client callsGET /api/v1/user/profile. - Client displays
ProfileUserCard, which orchestrates the driver identity bar (UserAvatar, full name, masked phone number viaformatMaskedPhone, and edit profile trigger) and delegates digital wallet presentation to the dedicated, decoupledVirtualEvCard(VirtualCard) component.VirtualEvCardrenders a realistic metallic gold EMV chip, contactless waves, brand EV logo, real-time balance in EVP (with VND equivalent), conditional debt warning strip (outstandingPoint), and an accessible full-width "Top Up" (Nạp tiền) action button routing to/profile/top-up. - To update profile details, driver navigates to
EditProfileScreen.tsx, selects a new photo from library, and triggersPOST /api/v1/upload/image. - Upon receiving uploaded image URL, client dispatches
PUT /api/v1/user/profilewithUpdateUserProfilePayload.
profileStore.
outstandingPoint > 0 or
chargingBlocked === true, the profile displays an alert message and restricts new charging
session initiation until debt is cleared.
ProfileUserCard, while digital wallet balance display and top-up interactions
are encapsulated in the reusable VirtualEvCard (VirtualCard) presentation component.3.2 Charging Stations & Connectors Discovery
Governs geospatial station discovery, marker clustering, connector standard filtering, station amenities, and real-time connector status monitoring.
- Driver opens
app/(tabs)/stations.tsx. HookuseStationMapqueries device GPS coordinates viaexpo-location. - Client queries
GET /api/v1/stations/map?lat={lat}&lng={lng}&radiusKm={radius}for stations within current bounding box. - Map renders individual station markers (
StationMarker) and cluster bubbles (ClusterMarkerAnimated). - Tapping a cluster zooms into the localized cluster region; tapping a station marker opens a station summary bottom sheet.
StationMarker.tsx) must declare collapsable={false} to prevent Android View Flattening
from collapsing marker view bounds to 0x0 pixels, ensuring Google Maps SDK reliably captures non-empty software bitmap textures.- Driver opens
FilterModal.tsx, selecting desired criteria:- Connector Types:
TYPE_2,CCS_2,CHADEMO,GB_T_AC,GB_T_DC,TYPE_1. - Power Standard:
AC(Slow/Medium) orDC(Fast/Ultra-Fast). - Power Rating: ≥7 kW, ≥22 kW, ≥60 kW, ≥120 kW, ≥180 kW.
- Availability: Only show stations with at least 1
AVAILABLEconnector.
- Connector Types:
- Driver taps "Apply Filters"; client executes
POST /api/v1/stations/searchwithSearchStationPayload. - Map and list update reactively to display only qualifying charging facilities.
- Driver navigates to
screens/stations/StationDetailScreen.tsxwithstationId. - Client executes parallel queries:
GET /api/v1/stations/{stationId}andGET /api/v1/stations/{stationId}/pricing. - Screen renders:
StationImageGallerywith station facility photos.- Operational specs:
is24hbadge, operator hotline, full address. StationAmenitiesicons: Restroom, Coffee, Convenience Store, Wi-Fi, Parking Fee.StationChargingPoints: Lists charge boxes and individual connectors with real-time status pills (AVAILABLE,PREPARING,IN_USE,FAULTED,OFFLINE).StationPricing: Tariffs breakdown (VND per kWh, idle fee per minute).
- Driver taps "Get Directions", opening Apple Maps or Google Maps via native URI scheme.
3.3 QR Code Scanning & 5-Step Charging Session Flow
Specifies the core operational workflow of the application: optical QR recognition, pre-charge session budgeting, the 5-phase charging state machine, live telemetry monitoring, and order receipt reconciliation.
- Driver taps the center "QR Scan" tab, launching
screens/qr/QRScanScreen.tsx. - Camera viewfinder initializes using
expo-camera ~57.0.5with native MLKit barcode scanner plugin (barcodeScannerSettings={{ barcodeTypes: ["qr"] }}) and decoupled audio permissions (RECORD_AUDIO omitted from Android manifest). - Driver points camera at QR code on charger. Optical engine parses URL payload (e.g.,
https://evpower.vn/charge?box=HN01&connector=1). - Alternatively, driver taps "Enter Code Manually", opens
ManualCodeModal, inputs charge box and connector number. - Client queries
GET /api/v1/connectors?chargeBoxCode={code}&connectorCode={no}to validate charger hardware existence.
AVAILABLE, app transitions to
SetupScreen.tsx; if faulted/busy, an informative error sheet is displayed.
- Driver views
screens/charging/SetupScreen.tsxwith connector details (connector standard, max kW, status pill). - Screen displays current wallet balance: formatted in both EVP points and Vietnamese Dong using
invariant
1 EVP = 1,000 VND. - Driver selects a session charging limit:
- Preset monetary chips: 100,000đ (100 EVP), 200,000đ (200 EVP), 300,000đ (300 EVP), 500,000đ (500 EVP), 800,000đ (800 EVP), 1,000,000đ (1,000 EVP).
- Custom energy limit (kWh).
- Full Charge Mode (100% SoC or maximum available wallet balance).
- Driver taps "Confirm & Proceed to Plug In", transitioning to
screens/charging/ChargingSessionScreen.tsxin stepplug.
chargingStore
for transaction initiation.app/(tabs)/profile/top-up.tsx.
plug
→ connecting → charging → success /
canceled) with 10-second live telemetry polling and emergency stop capabilities.
- Step 1 (
plug): Screen instructs driver to insert physical charging gun into EV port. Client pollsGET /api/v1/charging/statusevery 5,000 ms. When connector transitions toPREPARING, client automatically advances to Step 2. - Step 2 (
connecting): Client enforces a mandatory hardware stabilization delay (≥1,800 ms) and callsPOST /api/v1/charging/startwithStartTransactionPayload(chargeBoxCode,connectorNo,pointLimit). CPMS signals charger to lock cable and energize contacts. Upon receivingtransactionId, client transitions to Step 3. - Step 3 (
charging): Active charging dashboard renders:BatteryStatusCard: Battery State-of-Charge percentage (socPercent) and animated pulsing charge ring. Conditional AC Behavior: When connected to an AC charger (powerType.toUpperCase() === "AC") and telemetry reports no valid battery State-of-Charge (socPercent == null || socPercent ≤ 0 || batteryPct === 0due to the absence of BMS high-level digital communication over standard IEC 62196 Control Pilot), the client suppresses the battery percentage badge (hideBatteryBadge=true) and halts the vehicle pulsing animation (isActive=false). In its place, an informational frosted glass overlay (BlurView) displays an alert note: "Trụ này không hỗ trợ hiển thị dung lượng pin với dòng xe của bạn" (charging.active.acSocUnsupportedNote) to avoid displaying a misleading 0% reading.CostSummaryCard: Real-time accrued cost in EVP and VND, energy delivered in kWh, and estimated completion time (estimatedFinishAt).StatsGrid: Elapsed duration (formatDurationSeconds), charging speed (maxPowerKw), and power type (AC/DC).- Swipe-to-Stop Slider: Secure swipe gesture requiring driver confirmation to terminate session.
GET /api/v1/charging/sessions/{transactionId}every 10,000 ms. - Step 4/5 (Termination): When driver swipes stop, battery reaches 100%, preset
budget is reached, or CPMS sends push alert
CHARGING_STOPPED:- During stopping confirmation: The mobile client mounts
<StoppingChargeOverlay />as an in-tree full-screen absolute overlay withexpo-blur(BlurViewon Fabric), centered dialog card, and blocked pointer events (replacing legacy native<Modal>to avoid Fabric blur window detachment). - If terminated normally: Client calls
POST /api/v1/charging/stop, queries order detail, and displaysSuccessScreen.tsxwith full invoice receipt. - If aborted due to hardware error or budget too small: Transitions to
FailedScreen.tsxwith specific error cause.
- During stopping confirmation: The mobile client mounts
chargingStore resets.powerType.toUpperCase() === "AC") and the charging station returns socPercent == null || socPercent ≤ 0 (or computed batteryPct === 0), the client SHALL identify this as standard analog PWM signaling without digital BMS communication. The client SHALL suppress the battery badge and pulse animation, displaying an informational warning overlay (charging.active.acSocUnsupportedNote) rather than a deceptive 0% battery level, while continuing full real-time telemetry for duration, energy delivered (kWh), instantaneous power (kW), and EVP point cost.- Driver navigates to
app/(tabs)/orders/index.tsx; client executesGET /api/v1/charging/orders. - Driver filters orders using tabs:
all,charging,completed,failed. - Tapping an order opens
screens/orders/OrderDetailScreen.tsx; client callsGET /api/v1/charging/orders/{id}. - Screen renders itemized inspection cards:
OrderMainInfoCard: Order code, start time, end time, final status.OrderStationInfoCard: Station name, address, charge box, connector number.OrderMetricsCard: Energy consumed in Wh / kWh, total elapsed duration.OrderPointsCard: Total points billed (totalPoint), points paid from wallet (paidPoint), debt points if any.OrderPaymentCard: Payment method (EVP Wallet), conversion to VND (1 EVP = 1,000 VND).
3.4 Vehicle Garage & Fleet Management
Governs the registration of driver electric vehicles, Vehicle Identification Number (VIN) binding, vehicle operational status, and per-session spending caps.
- Driver opens
screens/profile/vehicles/VehicleListScreen.tsx; client callsGET /api/v1/vehicles. - Driver taps "Add Vehicle", inputs VIN (17 characters alphanumeric), license plate label, and initial spending cap.
- Driver taps "Save Vehicle"; client submits vehicle record to backend.
- Tapping a vehicle in the list navigates to
VehicleDetailScreen.tsxdisplayingVehicleDetailHeroCardandVehicleDetailInfoCard.
active
and chargeable: true.status === "blocked"
or chargeable === false, charging initiation for this vehicle is disallowed with
blockedReason displayed.
maxPointPerSession) per vehicle and enforce deletion safety guardrails.
- In
VehicleDetailScreen.tsx, driver taps "Edit Vehicle", openingEditVehicleModal. - Driver modifies
labelor adjustsmaxPointPerSession(e.g., 200 EVP points). - Client dispatches
PATCH /api/v1/vehicles/{id}withUpdateVehiclePayload. - To delete, driver taps "Delete Vehicle", presenting
DeleteVehicleModal; upon confirmation, client callsDELETE /api/v1/vehicles/{id}.
VEHICLE_CURRENTLY_CHARGING.
maxPointPerSession, the CPMS automatically terminates charging.
3.5 RFID Charge Cards (charge-card / Thẻ sạc RFID)
Governs the lifecycle of physical RFID charge cards, category status filtering, point lot expiration tracking, and balance top-up via physical scratch card activation codes.
charge-card) displaying linked physical cards categorized across 5 status tabs:
ALL, ACTIVE, EXPIRING_SOON, USED_UP, and
EXPIRED.
- Driver opens
screens/profile/ChargeCardScreen.tsx(routeapp/charging-card.tsx). - Hook
useChargeCardListqueriesGET /api/v1/wallet/cards?page=1&size=20&state={state}. - Driver switches tabs using
ChargeCardStateTabs:ALL: All registered RFID cards regardless of state.ACTIVE: Cards with remaining points valid for charging (color#088178).EXPIRING_SOON: Cards with points expiring within 30 days (color#f97316).USED_UP: Fully depleted cards with 0 remaining points (color#64748b).EXPIRED: Cards past point expiration date (color#ef4444).
- Screen renders
ChargeCardItemcards showing card serial, masked card number (e.g.•••• 8821), batch name, face points, points remaining, and days to expire.
- In
TopUpScreen.tsx, driver selects payment method "Scratch Card" or taps "Redeem Card" inChargeCardScreen.tsx. - Driver inputs the scratch code into the activation form.
- Driver taps "Activate Card"; client dispatches
POST /api/v1/wallet/cards/activatewithRedeemChargeCardPayload({ code, appVersion }). - Backend validates code validity, checks unredeemed status, credits face value points to driver's
wallet, and returns
RedeemCardResponse. - Client routes to
ScratchCardResultScreen.tsxdisplaying serial, masked code, batch name,pointCredited, expiration date, and newwalletBalance.
CARD_ACTIVATE).CARD_ALREADY_REDEEMED.
pointLotId, pointExpireAt, daysToExpire) and automatically
transition card states when points expire.- When querying
GET /api/v1/wallet/cards, backend evaluates current timestamp againstpointExpireAt. - If
daysToExpire ≤ 30andpointRemaining > 0, state is calculated asEXPIRING_SOON. - If
pointRemaining === 0andpointUsed > 0, state is calculated asUSED_UP. - If
currentDate > pointExpireAt, state is calculated asEXPIRED. - Client highlights expiring points in orange and triggers push notification 7 days prior to expiration.
3.6 EVP Wallet & Financial Transactions
Specifies the digital point wallet, the strict 1 EVP = 1,000 VND conversion standard, VNPay payment gateway integration, transaction logs, and the double-entry point ledger audit trail.
- Client fetches wallet balance via
GET /api/v1/user/profile. - Screen executes
evpToVnd(balance)(formula:balance * 1000) to compute equivalent VND. - Renders dual balance on Home, Profile, and Setup screens (e.g.
500 EVP (≈ 500,000đ)). - If
balance < 100 EVP(100,000 VND), client displays an amber low-balance warning badge.
configs/app-config.ts and utils/currency-format.ts.100 EVP (100,000 VND).- Driver opens
screens/top-up/TopUpScreen.tsx(routeapp/(tabs)/profile/top-up.tsx). - Driver selects a top-up amount from standardized preset chips:
- 50,000đ → 50 EVP
- 100,000đ → 100 EVP
- 200,000đ → 200 EVP
- 500,000đ → 500 EVP
- 1,000,000đ → 1,000 EVP
- Driver optionally attaches an
invoiceProfileIdto request an automated electronic VAT tax invoice. - Driver selects payment provider "VNPAY" and taps "Proceed to Pay".
- Client dispatches
POST /api/v1/wallet/topupswithCreateWalletTopupPayload; backend returnstopupIdandpayUrl. - Client renders
TopupPaymentWebViewloading the secure VNPay payment portal. - Driver completes bank authentication. Upon return redirect, client polls
GET /api/v1/wallet/topups/{id}until status isSUCCEEDED. - Client routes to
TopupResultScreen.tsxdisplaying payment confirmation and updated balance.
EXPIRED.- Driver opens
screens/transactions/TransactionHistoryScreen.tsx; client callsGET /api/v1/wallet/ledger. - Driver filters transactions using entry type chips:
ALL: Complete ledger history.TOPUP: Points credited via VNPay payment gateway (positive change, color green).CHARGE_DEDUCT: Points debited for EV charging sessions (negative change, color red, linked toorderId).CARD_ACTIVATE: Points credited from scratch card redemption (positive change, color green).
- Screen renders itemized ledger cards displaying timestamp, entry type badge, point delta
(
pointChange), and post-transaction balance (balanceAfter).
pointChange values MUST exactly equal current
walletBalance + outstandingPoint.
3.7 Invoices & VAT Invoice Profiles
Governs statutory electronic Value-Added Tax (VAT) invoice profiles, automated invoice generation linked to top-up transactions under Vietnamese tax law, and digitally-signed PDF export.
- Driver opens
screens/profile/InvoiceProfilesScreen.tsx; client callsGET /api/v1/invoice-profiles. - Driver taps "Add Profile", navigating to
InvoiceProfileFormScreen.tsx. - Driver selects profile type:
PERSONALorCOMPANY. - Driver fills statutory tax fields:
buyerName: Individual legal name or registered enterprise name.buyerTaxCode: Enterprise Tax Identification Number (Mã số thuế, required forCOMPANY).buyerAddress: Official registered business address.buyerEmail: Electronic invoice delivery email address.buyerPhone: Contact phone number.
- Driver taps "Save Profile"; client dispatches
POST /api/v1/invoice-profileswithCreateInvoiceProfilePayload. - Driver can set a profile as default via
PATCH /api/v1/invoice-profiles/{id}/default.
cannotDeleteDefault). Another profile must be designated as default
prior to deletion.buyerTaxCode) must pass Vietnamese 10-digit or 13-digit tax code regex validation.SUCCEEDED state;
invoiceProfileId was attached during top-up order creation.
- Upon VNPAY IPN confirmation of top-up payment, backend billing engine retrieves the attached
InvoiceProfile. - System calculates statutory tax breakdown:
subtotal: Amount excluding tax.taxRate: 10% (or statutory 8% reduced rate).taxAmount: Calculated VAT liability.totalAmount: Gross top-up amount paid in VND.
- Electronic invoice record is generated with a unique sequential
invoiceNoand assigned statusISSUED. - Driver navigates to
screens/profile/invoices/InvoiceListScreen.tsx(queryingGET /api/v1/invoices) to view issued invoices.
topupId and ready for inspection and PDF
export.expo-file-system and triggering the native iOS/Android
sharing sheet.ISSUED and downloadable === true.
- Driver views invoice details in
screens/profile/invoices/InvoiceDetailScreen.tsxand taps "Download PDF". - Client dispatches
GET /api/v1/invoices/{id}/downloadwith HTTP headersAccept: "application/pdf"and Axios configurationresponseType: "arraybuffer". - Client writes the returned binary buffer to local document cache storage via
expo-file-system ~57.0.7usingPaths.cache.uriorPaths.document:${Paths.cache.uri}/invoices/invoice_${invoiceNo}.pdf. - Client invokes
expo-sharing:Sharing.shareAsync(localUri), opening the native operating system share sheet (AirDrop, Email, Print, Save to Files).
PROCESSING or
NEEDS_SUPPORT cannot be downloaded until certified by the e-invoicing authority.
3.8 Notifications (Push & In-App Alerts)
Governs the REST notification feed, unread counters, and native Expo Push Notification channels for charging milestones.
- Driver taps bell icon on Home or Profile screen, opening
screens/notifications/NotificationsScreen.tsx. - Client executes
GET /api/v1/notifications?page=1&size=20and updatesnotificationStore. - Unread badge count is retrieved via
GET /api/v1/notifications/unread-count. - Driver taps a single notification item: client dispatches
POST /api/v1/notifications/{id}/read, updating visual state to read. - Driver taps "Mark All as Read": client dispatches
POST /api/v1/notifications/read-all, resetting unread badge to 0.
expo-notifications ~57.0.18 config plugin (with deprecated top-level notification
config removed) and deliver foreground notifications for charging milestones, managing listeners via sub.remove().
- During app bootstrap, client requests push permissions and retrieves token via
Notifications.getExpoPushTokenAsync(). - Client registers device token by calling
POST /api/v1/notifications/devicesandPOST /api/v1/user/push-token. - Client configures native Android notification channels:
default: General announcements, importance MAX, teal LED lights (#088178).charging: Real-time charging progress, importance HIGH, vibration pattern enabled.
- In foreground, push alerts for
CHARGING_STOPPED,CARD_ACTIVATED, andTOPUP_SUCCESSpresent in-app alert notifications.
CHARGING_STOPPED notification opens
screens/orders/OrderDetailScreen.tsx).
Part 3.C: Non-Functional Requirements
3.C.1 Performance Requirements
SplashScreen.hide().staleTime of 30,000 ms (30s) and a gcTime of 300,000 ms (5m). During charging
sessions, connector status is polled strictly every 5,000 ms and active telemetry every
10,000 ms. Upon network reconnection, invalid queries automatically re-synchronize in
the background.
configs/app-config.ts without redundant endpoint calls.
react-native-worklets 0.10.1 on the Fabric
shadow tree, maintaining a steady 60 to 120 frames per second (FPS) with zero JS-thread frame drops.3.C.2 Safety Requirements
POST /api/v1/charging/stop dispatch.3.C.3 Security & Cryptographic Requirements
accessToken,
refreshToken, and resetToken) MUST be stored using
expo-secure-store, leveraging hardware-backed AES-256 encryption via the iOS Keychain and
Android KeyStore. Under no circumstances may tokens be placed in unencrypted AsyncStorage or Redux
stores.
api/interceptors.ts) SHALL implement
a strict single-refresher mutex lock (isRefreshing). If multiple concurrent asynchronous
API calls receive HTTP 401 Unauthorized simultaneously, only the first request SHALL execute
POST /api/v1/auth/refresh. Subsequent 401 requests MUST be queued in a Promise array
(failedQueue[]) and retried with the newly minted access token once refresh completes,
preventing token race conditions.
/api/v1/auth/refresh is executed.authSessionVersion. Whenever a user logs out or the session expires,
invalidateApiAuthSession() increments this counter. Any in-flight network responses
returning after session invalidation MUST be discarded immediately, preventing stale responses from
populating unauthenticated screens.
3.C.4 Software Quality Attributes
GET /api/v1/charging/sessions/active to immediately restore the active session view and
resume telemetry monitoring.
en), Vietnamese (vi), and
Chinese (zh-Hans) via i18next. The theme engine SHALL support
System, Light, and Dark appearance modes reacting dynamically to device OS settings.
4. Appendices, Canonical Data Models & Enums
4.1 Technical Glossary & Domain Acronyms
| Term / Acronym | Full Expansion | Definition & Domain Context in EV Power |
|---|---|---|
| EV | Electric Vehicle | Any pure battery-electric (BEV) or plug-in hybrid (PHEV) road vehicle. |
| EVSE | Electric Vehicle Supply Equipment | Physical charging apparatus (charge box) delivering AC or DC electrical power to an EV. |
| CPMS | Charge Point Management System | Central cloud system communicating with EVSE hardware via OCPP for telemetry and control. |
| OCPP | Open Charge Point Protocol | Standard communication protocol (versions 1.6-J and 2.0.1) operating over WebSockets. |
| EVP | EV Power Point | Internal digital currency unit strictly pegged at 1 EVP = 1,000 VND. |
| SoC | State-of-Charge | Current percentage (0%–100%) of usable electrical energy stored in the EV battery pack. |
| kW | Kilowatt | Unit of instantaneous electrical power delivered during a charging session. |
| kWh | Kilowatt-hour | Standard billing unit of electrical energy consumed over time (1 kWh = 1,000 Wh). |
| Wh | Watt-hour | Granular energy measurement unit delivered by telemetry sensors (energyWh). |
| RFID | Radio-Frequency Identification | Physical card technology used for contactless tap-to-charge station authorization. |
| VIN | Vehicle Identification Number | Unique 17-character ISO 3779 identifier permanently assigned to every motor vehicle. |
| VAT | Value-Added Tax | Statutory Vietnamese consumption tax (Thuế GTGT) governed by Circular 78/2021/TT-BTC. |
| Fabric | Fabric UI Renderer | React Native's concurrent C++ UI rendering engine replacing legacy Paper; supports synchronous layouts and 120Hz animations. |
| TurboModules | Turbo Native Modules | Direct C++ JavaScript Interface (JSI) bindings for native device APIs, completely bypassing asynchronous JSON bridge queues. |
| Bridgeless Mode | Bridgeless Native Runtime | Pure modern React Native execution architecture where the legacy JavaScript-to-native Bridge and Paper renderer are eliminated. |
| Hermes v1 | Hermes v1 JavaScript Engine | Meta's default high-performance JS engine with static bytecode compilation, optimized memory management, and EAS Update bytecode diffing. |
| CNG | Continuous Native Generation | Expo workflow (npx expo prebuild --clean) dynamically generating clean ios and android native directories from app.json. |
4.2 Canonical Domain Data Models (TypeScript Interfaces)
The following canonical TypeScript interfaces represent the core entities utilized across services, state stores, and UI components:
4.2.1 Station & Connector Models
/**
* Core charging station specifications and facility details.
*/
export interface StationDetail {
stationId: string;
code: string;
name: string;
address: string;
latitude: number;
longitude: number;
status: 'ACTIVE' | 'INACTIVE' | 'MAINTENANCE';
is24h: boolean;
images: string[];
operator: {
name: string;
hotline: string;
};
amenities: ('RESTROOM' | 'COFFEE' | 'CONVENIENCE_STORE' | 'WIFI' | 'PARKING_FEE')[];
chargingPoints: ChargePointSummary[];
pricingSummary: StationPricingItem[];
}
/**
* Individual physical connector hardware specifications.
*/
export interface ConnectorDetail {
connectorId: string;
chargeBoxCode: string;
connectorNo: number;
stationName: string;
connectorType: 'TYPE_2' | 'CCS_2' | 'CHADEMO' | 'GB_T_AC' | 'GB_T_DC' | 'TYPE_1';
powerType: 'AC' | 'DC';
maxPowerKw: number;
status: 'AVAILABLE' | 'PREPARING' | 'IN_USE' | 'RESERVED' | 'UNAVAILABLE' | 'FAULTED' | 'OFFLINE';
unitPrice: number; // in EVP per kWh
currency: 'EVP';
pricingPlanId: string;
priceDescription: string;
}
4.2.2 Charging Session & Order Models
/**
* Real-time telemetry payload during active charging.
*/
export interface TransactionDetailResponse {
transactionId: string;
orderId: string;
chargeBoxCode: string;
connectorNo: number;
socPercent: number; // 0 to 100% (null or 0 on AC stations lacking BMS telemetry; triggers BR-CHG-06 fallback)
energyWh: number; // Watt-hours consumed
maxPowerKw: number; // Instantaneous charging speed
powerType: 'AC' | 'DC';
estimatedPoint: number; // Accrued cost in EVP
estimatedFinishAt: string; // ISO timestamp
durationSeconds: number;
status: 'PREPARING' | 'CHARGING' | 'SUSPENDED_EV' | 'SUSPENDED_EVSE' | 'STOPPED';
}
/**
* Finalized historical charging session order record.
*/
export interface ChargingOrder {
id: string;
orderCode: string;
stationName: string;
chargeBoxCode: string;
connectorNo: number;
connectorType: string;
startAt: string;
stopAt: string;
durationMinutes: number;
energyWh: number;
totalPoint: number; // Total points billed
paidPoint: number; // Points settled from wallet
outstandingPoint: number; // Negative debt points if any
status: 'CHARGING' | 'COMPLETED' | 'FAILED' | 'CANCELED';
}
4.2.3 Vehicle & RFID Charge Card Models
/**
* Electric vehicle entity registered in driver garage.
*/
export interface Vehicle {
id: string;
userId: string;
vin: string; // 17-character ISO 3779 identifier
label: string; // License plate or custom moniker
status: 'active' | 'inactive' | 'blocked';
maxPointPerSession: number; // Spending ceiling in EVP
chargeable: boolean;
blockedReason?: string | null;
createdAt: string;
}
/**
* Physical RFID Charge Card entity (charge-card).
*/
export interface ChargeCard {
cardId: number;
serial: string;
cardMasked: string; // e.g., "•••• 8821"
batchName: string;
facePoint: number;
activatedAt: string;
pointLotId: number;
pointUsed: number;
pointRemaining: number;
pointExpired: number;
pointExpireAt: string;
state: 'ACTIVE' | 'EXPIRING_SOON' | 'USED_UP' | 'EXPIRED';
daysToExpire: number;
}
4.2.4 Wallet, Ledger & VAT Invoice Models
/**
* Double-entry financial point ledger audit record.
*/
export interface LedgerEntry {
id: number;
entryType: 'TOPUP' | 'CHARGE_DEDUCT' | 'CARD_ACTIVATE';
pointChange: number; // Positive for credits, negative for debits
balanceAfter: number; // Post-transaction balance in EVP
orderId?: number; // Linked charging session order ID
topupId?: number; // Linked VNPay top-up ID
createdAt: string;
}
/**
* Statutory electronic VAT invoice billing profile.
* Note: buyerName and buyerTaxCode represent legal statutory tax fields.
*/
export interface InvoiceProfile {
id: string;
userId: string;
profileType: 'PERSONAL' | 'COMPANY';
buyerName: string; // Legal individual or corporate name
buyerTaxCode?: string; // Enterprise tax identification number
buyerAddress: string; // Registered fiscal address
buyerEmail: string; // E-invoice delivery email
buyerPhone: string; // Contact telephone number
isDefault: boolean;
createdAt: string;
updatedAt: string;
}
/**
* Electronic VAT tax invoice response model.
*/
export interface InvoiceDetailResponse {
id: string;
invoiceNo: string;
topupId: string;
createdAt: string;
subtotal: number; // Amount in VND excluding VAT
taxAmount: number; // Calculated VAT in VND
totalAmount: number; // Gross amount paid in VND
currency: 'VND';
buyerName: string;
buyerTaxCode?: string;
buyerAddress: string;
buyerEmail: string;
buyerPhone: string;
taxLines: {
taxCode: string;
taxRate: number; // e.g., 0.10 for 10%
taxableAmount: number;
taxAmount: number;
}[];
displayStatus: 'ISSUED' | 'PROCESSING' | 'NEEDS_SUPPORT';
downloadable: boolean;
}
4.3 Status Enumerations & State Machines
4.3.1 Connector Operational Status (ConnectorStatus)
| Status Code | Badge Style | Hardware Definition & Application UX Behavior |
|---|---|---|
AVAILABLE |
Available | Connector is idle, cable unlocked, and ready for session initiation. |
PREPARING |
Preparing | Physical gun is inserted into EV inlet; vehicle handshake in progress. |
IN_USE |
In Use | Active charging session in progress; electrical current is flowing. |
FAULTED |
Faulted | Hardware ground-fault, over-temperature, or emergency stop active. |
OFFLINE |
Offline | Charge box disconnected from CPMS network; unavailable for booking. |
4.3.2 Charge Card Lifecycle State (ChargeCardState)
| State Code | Color | Operational Definition & Expiration Logic |
|---|---|---|
ACTIVE |
#088178 |
Card has remaining points (pointRemaining > 0) and
daysToExpire > 30.
|
EXPIRING_SOON |
#f97316 |
Card has points expiring within 30 days (0 < daysToExpire ≤ 30). |
USED_UP |
#64748b |
All face points have been consumed (pointRemaining === 0). |
EXPIRED |
#ef4444 |
Points are past their validity date (daysToExpire ≤ 0). |