Before you start
What you need
Startup & global behavior
1.1 Splash screen / app startup
Shows the EAC logo and a spinner while the app loads its environment, theme, language, and saved login. If a valid session exists it goes straight to the Dashboard; otherwise to Login.
1.2 Under maintenance
When the server flags maintenance (via the environment file or a push message on the maintenance topic), every screen redirects to a full-screen blue "System Maintenance" page.
1.3 App update dialogs
The server can announce a newer build. An optional update shows a dismissible dialog; a forced update shows a dialog that cannot be dismissed.
1.4 Offline behavior
The app has no offline cache — every screen needs the network. A connectivity banner appears at the bottom of the Dashboard, and API calls made while offline are blocked with a "No internet access" dialog.
1.5 Route protection (web especially)
Login & registration
2.1 Login (phone number)
Phone-number-only login. First login on a device goes through OTP; a returning login on the same device skips OTP and asks for the PIN instead.
Phone rules: starts with 0, then 8–9 digits (e.g. 012 345 678). The leading 0 is fixed in the field; input is masked as *# ### ####.
2.2 OTP screen (shared by login, registration, reset PIN)
Four digit boxes, a countdown, and a Resend link. The code auto-submits the moment the 4th digit is entered — the Verify button is a fallback.
2.3 Registration
Create an account with full name, date of birth, gender, phone, and email, then confirm by OTP. After the OTP, the new account is logged in and forced to set up a PIN.
PIN & biometric security
The PIN is 4 digits, verified against the account's server-side setting. It protects login, profile editing, account unlinking, and deactivation. Two UI forms exist: a full-screen gate and a pop-up dialog — behavior must match between them.
3.1 Setup PIN (first time)
3.2 PIN entry (gate & dialog)
Mobile shows a numeric pad with 4 dots; web shows a single text field. After the 4th digit it verifies automatically.
3.3 Change PIN
3.4 Reset PIN (forgot PIN)
Enter a new PIN, then confirm with an OTP sent to the account's phone (shown masked). The old PIN is never asked.
3.5 Biometric login (fingerprint / Face ID)
Dashboard
4.1 Dashboard overview
The home screen: quick actions (News, Service, About EAC, Notifications), the active customer account with its supplier, the outstanding debt with a Pay button, recent invoices, and a 12-month usage chart.
4.2 Debt & Pay button
4.3 Invoices & usage chart
4.4 Account actions from the dashboard
Linked accounts
5.1 Linked account list
5.2 Link an account (wizard)
Three steps: enter/scan the customer code → verify ownership with two invoice numbers → optionally tag a label.
5.3 QR / barcode scanner
5.4 Account labels
Pick a colored label for an account (e.g. "Home", "Shop"), or create/edit labels with a title and one of 15 colors.
Invoice detail
6.1 Invoice detail screen
Full invoice: customer info, total due banner colored by status, invoice numbers/dates, consumption breakdown by meter, totals, and the 12-month usage chart.
6.2 Add due date to calendar
Creates a reminder in a dedicated "EAC App" device calendar at 7:00 on the due date, with a reminder N days before.
6.3 Save invoice as image
Payments (Bill24)
Two entry points: paying the active account's debt from the Dashboard ("single payment"), and paying several accounts at once via "Pay by account". Both hand over to the Bill24 payment window and land on the payment-result screen. The whole payment feature can be switched off from Developer Options.
7.1 Checkout (single payment)
7.2 Pay by account (multi-account)
7.3 Payment result
Verifies the transaction and shows a receipt (bank, transaction number, date, account count, amount) plus a 5-second "processing" animation before the Done button appears.
Notifications
8.1 Notification list & detail
8.2 Push notifications
News
9.1 News hub, list & article
About EAC & information
10.1 About EAC hub
10.2 Connection price
10.3 Tariffs
10.4 Legal documents & Q&A
10.5 PDF viewer
10.6 Terms & Conditions viewer
Services (WFF) & festival
11.1 Service requests
Electricity service requests, powered by the embedded Oone workflow SDK: a "Service" tab with the request menu and a "My request" tab listing submitted requests (with timeline detail pages).
11.2 Festival branding
Profile & settings
12.1 Settings screen
12.2 Edit profile
Guarded by PIN/biometric. Change photo, name, date of birth, gender, email. The phone number is visible but locked.
12.3 Theme (appearance)
12.4 Language
12.5 About
12.6 Account deactivation
Developer options (internal)
13.1 Developer options screen
Internal screen guarded by the static code 2025. Reachable in any app state — including under maintenance and logged out.
13.2 Environment switching
Web vs mobile differences
The web build intentionally lacks several mobile capabilities. Don't file these as bugs — but do verify each web fallback behaves as listed.
| Feature | Mobile (Android / iOS) | Web |
|---|---|---|
| Biometric login | Fingerprint / Face ID | Not available; settings row hidden |
| PIN entry | Numeric pad with dots + vibration on error | Single text field, no vibration |
| OTP autofill | Android SMS autofill; iOS keyboard suggestion | Manual entry (field auto-focused) |
| QR scan (link account) | Camera scanner | Button hidden — typed entry only |
| Link-account keypad | Overlay (portrait) / side-by-side (landscape) | Inline below the form |
| Invoice → calendar | Adds to device calendar | Icon hidden |
| Save invoice image | Saves to gallery + confirmation dialog | Downloads a PNG, no confirmation |
| Push notifications | Full support incl. tap-to-open | Not handled |
| Terms & Conditions | In-app webview (links copy to clipboard) | Rendered as in-app text |
| Profile photo | Camera or gallery + native crop | Gallery only + custom crop dialog |
| App update button | Opens Play Store / App Store | No store — expect no action/error |
| URL refresh/deep entry | n/a | Route guards apply; OTP pages bounce to /login |
Known issues & code-review findings to verify
Found by reading the code, not by running it. Please reproduce each one, confirm or refute it, and report — several may be intended behavior that only the dev team can judge.
| # | Severity | Area | What to verify |
|---|---|---|---|
| 1 | High | PIN | No limit on wrong PIN attempts — no lockout, no delay, ever. |
| 2 | High | Payments | The payment result screen shows success styling for any verified transaction without checking its status field. |
| 3 | High | Payments | An overdue debt hides the Pay button entirely — overdue bills cannot be paid in-app. Intended? |
| 4 | Medium | Security | Biometric can be disabled with only a yes/no dialog — no PIN required. |
| 5 | Medium | Security | Logout keeps the phone's saved session, so the next login skips OTP (PIN only). Risk on shared devices — intended? |
| 6 | Medium | Payments | Pay-by-account invoice amounts are computed (debt ÷ count) and its Paid tab uses a different rule than the cards — counters can disagree. |
| 7 | Medium | Payments | A server error while loading debts in Pay-by-account looks identical to "no data". |
| 8 | Medium | About EAC | Missing/invalid contact data or map coordinates from the server can crash the page. |
| 9 | Medium | Tariffs | Search over-filters by ID (case-sensitive); failure view lacks a Retry button; PDF title shows the raw ID. |
| 10 | Medium | Q&A | Only the first 20 FAQs ever display — load-more never triggers. |
| 11 | Medium | Profile | A failed profile save gives no feedback at all (silent failure). |
| 12 | Medium | Festival | Festival data comes from a hard-coded mock endpoint — must be confirmed before production. |
| 13 | Medium | Calendar | iOS: adding a bill to the calendar fails when the default calendar is a non-iCloud account (known bug). |
| 14 | Low | Register | DOB and gender are never validated; the gender field displays the DOB error state. |
| 15 | Low | Change PIN | The new PIN may equal the old PIN; the form itself never asks the old PIN (the gate does). |
| 16 | Low | Labels | Empty label titles allowed; duplicate check applies on create but not on rename. |
| 17 | Low | T&C | Links inside the document copy to the clipboard instead of opening (mobile), with no user feedback. |
| 18 | Low | PDF share | Sharing a PDF with a broken URL leaves the spinner stuck. |
| 19 | Low | i18n | Some payment-flow strings are hard-coded English (result screen retry/errors, supplier search sheet). |
| 20 | Low | Web invoice | Saving an invoice image on web downloads silently with no confirmation. |
Quick reference
| Item | Value |
|---|---|
| PIN | 4 digits; unlimited attempts (see issue #1); verified against the account, not the device |
| OTP | 4 digits; auto-submits on the 4th digit; resend unlocks after 2:00 |
| Phone number format | Starts with 0 + 8–9 digits, e.g. 012 345 678 |
| Customer code format | 123-456789 (enforced on QR scans) |
| Currencies | KHR (no decimals; min payment 100) and USD (2 decimals) |
| Invoice statuses | Pending · Partially paid · Reversed · Paid |
| List page sizes | Accounts 10 · news / notifications / tariffs / laws / FAQ 20 — more loads near the bottom of the scroll |
| Session | Tokens auto-refresh ~10 min before expiry; a dead session shows the "Unauthorized" dialog and logs out |
| Languages | Khmer (default) · English — saved to the account, follows the user across devices |
| Themes | Light · Dark · System (default System) |
| Environments | PRODUCTION · EAC STAGING · DEMO — switch via Developer Options (code 2025); switching logs everyone out |
| Payment provider | Bill24 popup; result returns via tran_id deep links |
Guide compiled from the app source (branch flutter_migration, v2.4.9 build 222) on 12 Aug 2026. If a behavior here doesn't match the build you're testing, note the build number in your report.