# EPower Maps (Flutter rebuild) — Features, Flows, and Processes

**Purpose:** an exhaustive feature / flow / process inventory of the rebuilt Flutter application as it ships today, verified against both the code at [lib/](../lib/) and the latest production screenshots.

**Audience:** UAT testers, QA engineers, onboarding developers.

| Metadata | Value |
|---|---|
| App ID | `kh.com.e_power.maps` (unchanged from legacy) |
| App version | See [pubspec.yaml](../pubspec.yaml) — currently **v2.2.6+226** |
| Framework | Flutter 3.x · Dart `^3.10.7` |
| State | `flutter_bloc ^9.1.0` (Bloc + Cubit) |
| Navigation | `go_router ^15.1.2` (`StatefulShellRoute.indexedStack`) |
| Local DB | `sqflite ^2.4.2` — per-tenant SQLite files |
| Network | `dio ^5.8.0` with `App-Id` interceptor |
| Platforms | **Android (API 21+)** and **iOS** |
| Default language | **Khmer** (user-switchable to English) |
| Brand colour | `#F15A23` (same E-Power orange as legacy) |
| Server base URL | `https://epower-stg.e-power.bz/core/EPowerMap` (override-able) |

---

## 0. System Topology

```
┌─────────────────────────────┐    HTTPS (REST)      ┌────────────────────────────┐
│  Flutter app                 │ ────────────────────►│  E-Power Maps server        │
│  (Android + iOS)              │◄──────── /Sync ──────│  Multi-tenant API           │
│                                │                      │  (App-Id = tenant id)       │
│  • Collect (GPS survey)        │                      │                             │
│  • Admin (CRUD catalogs)       │                      │                             │
│  • Tenant switcher             │                      │                             │
│  • Biometric gate              │                      │                             │
│  • KMZ generator (on-device)   │                      │                             │
│  • AI ERA chat                 │                      │                             │
│  • Offline queue               │                      │                             │
└────────────────────────────────┘                      └────────────────────────────┘
                 │
                 │ KMZ
                 ▼
           Google Earth (optional)
```

No desktop companion is required. The tenant onboards via a QR code, and all subsequent data transfer is HTTPS.

---

## 1. Navigation Shell

**Pattern:** `GoRouter` with `StatefulShellRoute.indexedStack` — 5 persistent tabs + page-level pushes above the shell.

**Bottom tabs (labels match the legacy drawer, verified from screenshots):**

| # | Icon | Label (km) | Route | Role |
|---|---|---|---|---|
| 1 | 📍 | ស្រង់ទីតាំង | `/` | Collect / survey (default landing) |
| 2 | 🗂 | គ្រប់គ្រងទូទៅ | `/admin` | Admin hub (overview + catalog CRUD) |
| 3 | 🗺 | ទីតាំងផែនទី | `/maps` | Map view (opens Google Earth) |
| 4 | ↔️ | បញ្ជូន និងទាញ | `/communication` | Communication / Sync |
| 5 | ⚙️ | ការកំណត់ | `/settings` | Settings (includes about + exit + dev) |

**Active tab styling:** orange pill background (brand @12% alpha) + bold label. Nav bar has 20 px rounded top corners and a soft top shadow.

**Pushed-above-shell pages (hide the nav while visible):**

| Route | Page | Access |
|---|---|---|
| `/admin/accessories` + `/:id` | Accessory list / detail | From Admin hub |
| `/admin/packages` + `/:id` | Package list / detail | From Admin hub |
| `/admin/places` + `/:id` | Place list / detail | From Admin hub |
| `/admin/styles` + `/:id` | Style list / detail | From Admin hub |
| `/admin/transformers` + `/:id` | Transformer list / detail | From Admin hub |
| `/admin/analysis` | Analysis (pie chart) | From Admin overview card |
| `/tenant` + `/tenant/scan` | Tenant management + QR scanner | From Settings |
| `/developer` | Developer tools | From Settings (after 7-tap unlock) |
| `/ai-chat` | AI ERA chat assistant | From Settings |
| `/splash` | Splash screen | Cold start only |

---

## 2. Feature Inventory

### 2.1 ស្រង់ទីតាំង — Field Collection

**Page:** [lib/features/collect/ui/collect_page.dart](../lib/features/collect/ui/collect_page.dart) → `CollectPage` driven by `CollectBloc`.

**Three stacked cards (exact layout from production screenshot):**

#### Card 1 — ទីតាំង (Location)
- Tinted orange header (`rgba(241,90,35,0.06)`) with a target/bullseye icon on the left and a GPS-recenter icon on the right.
- Live badge (green dot + `LIVE` text) when the GPS stream is active.
- **3-column split**: `Lat` / `Lng` / `Acc` with vertical dividers.
- Acc value is colour-coded: green when good, red when poor.

**GPS stream source:** `geolocator` package, `PRIORITY_HIGH_ACCURACY`, minimum displacement filter.
**Error states** each raise a Snackbar with an action:
- Service disabled → action opens location settings.
- Permission denied → inline prompt.
- Permission denied forever → action opens app settings.
- Stream error → retry message.

#### Card 2 — ព័ត៌មានបង្គាល (Pole Information)
- Tinted header with an orange `⚡` icon + label.
- **`ជ្រើសយកបង្គាល`** — searchable dropdown (`A001`, `A002`, …). Typing filters as-you-type; a distinct "បន្ថែមសសរថ្មី" entry opens a creation sheet.
- **`របនាំប់ទ`** (Style) — dropdown; populated from `tbl_style` synced from the server.
- **`☑ ជាកម្មសិទ្ធ`** — ownership checkbox with orange-filled state.

#### Card 3 — គ្រឿងអគ្គិសនី (Accessories)
- Teal-tinted header with count badge (e.g. `3`).
- Per-row layout: teal index chip + accessory name + editable qty field + red delete icon (`🗑`).
- Qty field supports numeric input only.

#### Sticky bottom action bar (above the nav)
- Full-width outline button `គ្រឿងអគ្គិសនី (N)` — opens the accessory/package picker sheet.
- Row below: `◀` | **`វក្សាទុក ✓`** (solid orange, primary action) | `▶`.

**Save flow (`CollectBloc.saveCurrentPlace`):**
1. Validate — pole selected, style selected, GPS acquired with acceptable accuracy.
2. `PlaceRepository.saveCollectedPlace()` writes: `latitude`, `longitude`, `style_id`, `is_own`, `collected_date = now()`, `is_collected = true`.
3. `PlaceDetailRepository.syncPlaceDetails()` cascades add/update/soft-delete of accessories.
4. If online → POST to `/Place/Collect`; if offline → enqueue to `tbl_pending_sync` with `operation='create'|'update'`.
5. Auto-advance to next pole (direction remembered from last ◀/▶ press).

**Prev / Next:** cyclic over `CollectBloc.state.places`; same wrap-around behaviour as the legacy `btnPrevious` / `btnNext`.

**Visual cues preserved from v-1.0.0:**
- Collected poles show the pole label in primary colour (sea-blue accent).
- Acc value goes green when accurate, red when not — `Save` stays disabled until acceptable.

**Accessory / package picker sheet:**
- Bottom sheet with two tabs: **Accessories** (checkboxes) and **Packages** (checkboxes).
- Checking a package adds all its `PackageDetail` rows as `PlaceDetail` rows on the pole, skipping duplicates.
- Unchecking a package removes only rows it added.

---

### 2.2 គ្រប់គ្រងទូទៅ — Admin Hub

**Page:** [lib/features/admin/ui/admin_page.dart](../lib/features/admin/ui/admin_page.dart) driven by `AdminBloc`.

Two sections, top-to-bottom (verified against screenshot):

#### Section A — ទិដ្ឋភាពទូទៅ (Overview)
A single bordered card:
- Left: pole icon + label `ទីតាំងសរុប`.
- Right: total count (e.g. `1213`) + percentage (e.g. `0.2%`).
- Below: thin orange progress bar (8 px tall, 4 px corners).
- Legend row: `● 2 បានប្រមូល`  `● 1211 មិនទាន់ប្រមូល`.
- Footer: `ការវិភាគការប្រមូល ›` in orange — taps → `/admin/analysis`.

#### Section B — គ្រប់គ្រងបញ្ជី (Manage Catalog)
Single card with 5 tiles separated by thin dividers; each tile has a 28 px rounded icon bg (coloured) + name + count badge + `›`:

| # | Label (km) | Icon colour | Route | Screenshot count |
|---|---|---|---|---|
| 1 | គ្រឿងអគ្គិសនី | Orange (primary) | `/admin/accessories` | 30 |
| 2 | កញ្ចប់គ្រឿងអគ្គិសនី | Cyan (accent) | `/admin/packages` | 5 |
| 3 | ទីតាំង | Green (success) | `/admin/places` | 1213 |
| 4 | របនាំប់ទ | Brown | `/admin/styles` | 8 |
| 5 | ត្រង់ស្វូ | Purple | `/admin/transformers` | 66 |

Pull-to-refresh reloads counts from the DB and (if online) re-fetches reference data from `/Sync`.

#### CRUD pages (one per entity)
All five list pages follow the same pattern:
- Paginated `ListView` with search bar + multi-select mode.
- Add FAB opens a detail sheet.
- Row-level actions: edit, soft-delete.
- Writes hit the REST endpoint when online; otherwise queue to `tbl_pending_sync`.
- Detail pages use same validation as v-1.0.0 (upper-case pole names, duplicate check, required name).

**Analysis page (`/admin/analysis`):**
- `fl_chart` pie chart — collected vs. uncollected.
- Lists of collected and pending poles.

---

### 2.3 ទីតាំងផែនទី — Map View

**Shell route:** `/maps`.
**Behaviour:** generates a KMZ on-device from current tenant's collected places using the `archive` package, then opens it in Google Earth via platform channel intent.

**On-device generation:**
1. `MapsBloc.generateKmz()` walks `tbl_place` where `is_collected = true`.
2. Builds a folder hierarchy grouped by area (e.g. `No Area`, `A`, `A01`).
3. Each pole becomes a `Placemark` with lat/lng + `ExtendedData` for style, owner, date, accessories.
4. Writes `doc.kml` + any icon images into a `.kmz` archive.
5. Calls `url_launcher` / platform channel to launch Google Earth with the resulting file.

**Inside Google Earth (per screenshot):**
- Markers: red pole icons + blue transformer icons.
- Bottom sheet reads `E-Power Maps` with a folder tree (`No Area`, `A`, `A01`).
- Supports 2D/3D toggle, measurement, Street View.

**Fallback:** if Google Earth is not installed → Play Store / App Store link via `url_launcher`.

---

### 2.4 បញ្ជូន និងទាញ — Communication / Sync

**Page:** [lib/features/communication/ui/communication_page.dart](../lib/features/communication/ui/communication_page.dart) driven by `SyncBloc`.

**Empty state** (no tenant registered):
- Large 88×88 circle icon, headline, description.
- Primary button: `ចុះឈ្មោះអតិថិជន` (Register Tenant) → routes to `/tenant`.

**With-tenant state** (per screenshot):

#### Tenant chip (top)
- Green pill (`rgba(76,175,80,0.1)` bg, `rgba(76,175,80,0.3)` border).
- Building icon + tenant name (e.g. `EPower234_DEMO`) + `បានភ្ជាប់` trailing label.
- Tappable → `/tenant`.

#### Sync status card
Two rows separated by a divider:
- **Row 1:** clock icon (warning tint) + `ទិន្នន័យចំនួន N ដែលមិនទាន់ផ្ទៀងផ្ទាត់ភាព` + solid-orange button `ផ្ទៀងផ្ទាត់ភាព`. When nothing is pending: green check icon + `បានផ្ទៀងផ្ទាត់ភាពទាំងអស់`.
- **Row 2:** lightning icon + `ផ្ទៀងផ្ទាត់ភាពដោយស្វ័យប្រវត្តិ` (Auto-sync) + description + Material `Switch` (green when ON).

#### Data sync section — `បច្បូលភាពទិន្នន័យ`
Two action tiles in a bordered card:

| Tile | Icon bg | Action |
|---|---|---|
| ទាញយកទិន្នន័យ (Import Data) | Green | `GET /Sync` — pulls catalog; `DatabaseSeeder` upserts locally |
| ផ្ទៀងផ្ទាត់ភាពពេញ (Full Sync) | Purple | Import + posts every unsynced local write |

Both show an inline spinner while running.

#### Sync history — `ប្រវត្តិផ្ទៀងផ្ទាត់ភាព`
- Grouped by date: `ថ្ងៃនេះ` (Today) / `ម្សិលមិញ` (Yesterday) / `MMM dd, YYYY`.
- Each entry: coloured icon (by sync type) + label + timestamp + item count + trailing `ជោគជ័យ` (success, green) or `បរាជ័យ` (failed, red).
- Tap a failed entry to see the error payload.

**Auto-sync trigger flow:**
```
ConnectivityService emits ONLINE
  → SyncBloc listens → if (autoSync && hasTenant && pendingCount > 0)
  → SyncQueueProcessor.processQueue()
  → for each row in tbl_pending_sync:
      • invoke matching REST endpoint
      • on 2xx  → delete from queue, append to tbl_sync_history (success)
      • on error → leave in queue, append to tbl_sync_history (failed, with error)
```

---

### 2.5 ការកំណត់ — Settings

**Page:** [lib/features/settings/ui/settings_page.dart](../lib/features/settings/ui/settings_page.dart).
**Scroll container:** `CustomScrollView` with a `SliverPersistentHeader` (collapsing 220 → 56 px).

#### Hero header (verified from screenshot)
- Orange solid background with soft gradient overlay.
- Large circular app icon (centred).
- Title `E-Power Maps` (white, `w800`, `headlineSmall`).
- Version pill (e.g. `v2.2.6`) in a lighter orange.
- **7× tap on the version pill** unlocks Developer Mode (hidden until PIN entered).

#### ទំនាក់ទំនងអ្នកចែកចុះទេស (Contact)
Bordered card with orange-tinted header `🏢`. Rows:
- Company row: building icon + `អ៊ី-ផៅរ័ សុីស៊ីអិល`.
- Phone rows with green phone icon + green call button on the right. Tapping opens the dialer.
  - `(+855) 90 65 99 00`
  - `(+855) 10 65 99 00`

#### ក្រុមហ៊ុន (Company / Tenant)
- Bordered card with orange header `🏢`.
- Active tenant: building icon + `EPower234_DEMO` + UUID subtitle + `›`.
- Tap → `/tenant`.

#### ភាសា (Language)
- Bordered card, orange header `🌐`.
- Two rows:
  - 🇰🇭 `ខ្មែរ (Khmer)` + orange `✓` when selected.
  - 🇬🇧 `English`.
- Tapping instantly rebuilds the UI in the chosen locale (no restart required).

#### រូបរាង (Appearance)
Orange-tinted header `🎨`. Contains:

- **ទម្រង់ (Theme Mode)** — three preview cards (aspect 1:1.45):
  - `ភ្លឺ` (Light), `ងងឹត` (Dark), `ប្រព័ន្ធ` (System).
  - Each card renders a miniature preview of window chrome.
  - Selected card gets a 2 px primary border + a checkmark badge in the top-right.
- **ពណ៌ចម្បង (Primary Color)** — row with a 28 px circular swatch on the right; tap opens a bottom sheet with a 12-colour palette.
- **ទម្រង់អក្សរ (Font Size)** — segmented control with `S / M / L` (13 / 16 / 20 px). Selected segment has solid primary background.
- **ពុម្ពអក្សរ (Font Family)** — row showing current family name (`លំនាំដើម` by default); tap opens a bottom sheet with font previews:
  - Kantumruy Pro, Noto Sans Khmer, Noto Serif Khmer, Battambang, Hanuman, Suwannaphum, Siemreap.

#### មុខងារអ្នកអភិវឌ្ឍន៍ (Developer Options)
Visible only after the 7-tap unlock on the version pill:
- Enter the PIN (current year, e.g. `2026`).
- Single row `មុខងារអ្នកអភិវឌ្ឍន៍ ›` → opens `/developer`.

#### ចាកចេញកម្មវិធី (Exit App)
- Outline button, red border, bottom of scroll.
- Confirmation dialog: `យល់ព្រម` / `មិនយល់ព្រម`.
- Hardware F1/F2 key fallback (legacy compatibility).

All controls apply **instantly** — no "Save" button, no restart required.

---

### 2.6 Tenant Management

**Pages:**
- `/tenant` → [lib/features/tenant/ui/tenant_page.dart](../lib/features/tenant/ui/tenant_page.dart) (`Manage Tenants` — pushed above shell).
- `/tenant/scan` → [lib/features/tenant/ui/qr_scanner_page.dart](../lib/features/tenant/ui/qr_scanner_page.dart) (`mobile_scanner`).

**Layout:**
- Back-nav AppBar titled `គ្រប់គ្រងអតិថិជន`.
- **Current tenant card** with `ផ្តាច់` (Disconnect) outline button in red.
- **Add row (2 buttons side-by-side):** `Scan QR` + `បំពេញដៃ` (Manual).
  - Manual opens a bottom sheet with `Company Name` + `Tenant ID` text fields + Register button.
- **Registered tenants list**:
  - Active tenant: 2 px orange border, `Active` pill, pencil (rename) icon.
  - Others: normal border, swipe-to-delete with a red trash-reveal.

**Switch flow (`TenantManager.setCurrentTenant`):**
```
1. Close current sqflite database connection.
2. Open MobileDB_<newId>.db  (or create if first time).
3. EMapApiClient.updateTenantId(newId)  → updates App-Id header.
4. Emit TenantChanged event.
5. All feature Blocs listen and reload (*Started events re-dispatched).
```

**Data isolation:** each tenant has its own SQLite file (`MobileDB_<tenantId>.db`); no records bleed across tenants.

---

### 2.7 Developer Mode

**Page:** [lib/features/developer/ui/developer_page.dart](../lib/features/developer/ui/developer_page.dart).

**Unlock flow:**
1. Open Settings.
2. Tap the version pill in the hero **7 times** within 5 seconds.
3. Enter PIN = current year (`DateTime.now().year.toString()`), e.g. `2026`.
4. Developer options row appears in Settings.

**Exposed controls:**
- **Base URL override** — list of `tbl_dev_base_url` rows; mark one active; all future Dio calls use it.
- **Biometric lock toggle** — when enabled, cold start prompts for fingerprint / Face ID via `local_auth`.
- **Reset** — clear all dev overrides back to the hard-coded `AppConstants.apiBaseUrl`.

---

### 2.8 AI ERA Chat

**Page:** [lib/features/ai_chat/ui/ai_chat_page.dart](../lib/features/ai_chat/ui/ai_chat_page.dart).

- In-app chat assistant (E-Power specific prompts).
- `speech_to_text` input for Khmer and English.
- Message history persisted in memory for the session.

---

## 3. Data Model (SQLite — schema v5)

One database file per tenant: `MobileDB_<tenantId>.db` (or default `MobileDB.db`).

**Catalog tables (same as v-1.0.0):**

| Table | Columns | v1 parity |
|---|---|---|
| `tbl_accessory` | id, name, note, is_active, is_new | ✅ |
| `tbl_style` | id, name, note, **is_active** | ✅ + `is_active` added (now soft-deletable) |
| `tbl_package` | id, name, is_active, is_new | ✅ |
| `tbl_package_detail` | id, package_id, item_id, qty, is_active | ✅ |
| `tbl_place` | id, ref_id, object_id, style_id, area, pole, lat, lng, is_own, collected_date, is_collected | ✅ |
| `tbl_place_detail` | id, place_id, accessory_id, qty, is_active | ✅ |
| `tbl_transformer` | id, ref_id, object_id, area, code, lat, lng | ✅ |

**New tables in the rebuild:**

| Table | Columns | Role |
|---|---|---|
| `tbl_pending_sync` | id, entity_type, operation, entity_id, payload, created_at, synced | Offline-write queue |
| `tbl_sync_history` | id, sync_type, status, item_count, error, created_at | Audit log for Communication page |
| `tbl_dev_base_url` | id, name, url, is_active | Developer-configurable API URLs |

**Soft-delete:** universal (`is_active = 0`). Every list query filters `is_active = 1`. Deletes are never hard in normal flow.

---

## 4. API surface

Base: `https://epower-stg.e-power.bz/core/EPowerMap` (overridable via Developer Mode).

| Endpoint | Verb | Purpose |
|---|---|---|
| `/Accessory` | GET | Paginated list |
| `/Accessory/:id` | GET / PUT / DELETE | Single CRUD |
| `/Accessory` | POST | Create |
| `/Style` | GET / POST / PUT / DELETE | Style CRUD |
| `/Package` | GET / POST / PUT / DELETE | Package CRUD |
| `/Place` | GET / POST / PUT / DELETE | Place CRUD |
| `/Place/Collect` | POST | Submit collected pole + PlaceDetails |
| `/Transformer` | GET / PUT / DELETE | Transformer CRUD |
| `/Sync` | GET | Full reference-data pull for the tenant |

Every request carries `App-Id: <tenant_id>`, injected by `AppIdInterceptor`. Auth interceptor adds the bearer token if present.

---

## 5. Permissions Requested

| Permission | Used for |
|---|---|
| Location (Fine + Coarse) | GPS stream on Collect |
| Camera | QR scan for tenant onboarding |
| Microphone | Speech-to-text input in AI ERA |
| Biometric (Face / Touch) | Optional cold-start gate |
| Internet | API calls |
| Storage (Android < 30) | KMZ export target directory |

Each permission is requested on first use with a rationale prompt, and has a graceful deny-recovery path (Snackbar + Settings shortcut).

---

## 6. End-to-End Process Diagrams

### 6.1 First-run onboarding

```
Cold start
  │
  ▼
SplashPage (2 s)
  │
  ▼
Collect tab shown — but TenantManager.hasTenant == false
  │  → all feature pages prompt "Register tenant"
  ▼
Settings → ក្រុមហ៊ុន → /tenant
  │
  ▼
Scan QR  OR  Manual entry
  │
  ▼
TenantManager.registerTenant(...)
  │  → save to SharedPreferences
  │  → open MobileDB_<id>.db
  │  → update App-Id header
  ▼
SyncBloc.importCatalog() (GET /Sync)
  │
  ▼
Ready to collect
```

### 6.2 Collect + save (online)

```
CollectPage
  │  (GPS accurate, pole selected, accessories set)
  ▼
Save pressed
  │
  ▼
PlaceRepository.saveCollectedPlace()
  │
  ├──► Local DB: update tbl_place + cascade tbl_place_detail
  │
  └──► POST /Place/Collect  (App-Id header)
             │
       (2xx) ▼
       mark place.is_synced = true
             │
             ▼
       AutoAdvance → next pole
```

### 6.3 Collect + save (offline) + auto-sync

```
CollectPage (device is offline)
  │
  ▼
Save pressed
  │
  ▼
PlaceRepository.saveCollectedPlace()
  │
  ├──► Local DB write (as above)
  │
  └──► PendingSyncRepository.add(entity='Place', operation='create', payload=...)
             │
             ▼
       tbl_pending_sync gains a row

... later ...

ConnectivityService emits ONLINE
  │
  ▼
SyncBloc triggers SyncQueueProcessor
  │
  ▼
for row in tbl_pending_sync:
  • call the matching endpoint
  • 2xx  → remove from queue + log to tbl_sync_history (success)
  • err  → leave in queue + log failure

Communication page → history list refreshes; pending counter decrements
```

### 6.4 Tenant switch

```
Settings → ក្រុមហ៊ុន → tap another tenant row
  │
  ▼
TenantManager.setCurrentTenant(id)
  │
  ├── DatabaseHelper.switchDatabase(id) ... close old, open MobileDB_<id>.db
  ├── EMapApiClient.updateTenantId(id)  ... update interceptor
  │
  ▼
RepositoryFactory re-instantiates all repositories
  │
  ▼
Global listeners (CollectBloc, AdminBloc, SyncBloc) receive TenantChanged
  │
  ▼
Each Bloc re-emits *Started events → feature pages repopulate
```

---

## 7. Differences vs. v-1.0.0 (quick reference)

| Area | v-1.0.0 | Flutter |
|---|---|---|
| Platforms | Android only | Android + iOS |
| Sync | USB / TCP :59900 | HTTPS REST with `App-Id` header |
| Offline capture | Yes (DB only) | Yes + **pending-sync queue + auto-sync** |
| Multi-tenant | No | **Yes** — per-tenant SQLite + QR onboarding |
| Preferences | Forced Khmer | **Language / theme / colour / font family / font size** |
| Auth | None | Optional biometric |
| Maps | Google Earth (external KMZ pushed from desktop) | **KMZ generated on device** (still opens in Google Earth) |
| Admin | Edit-only for Accessory/Transformer | **Full CRUD on every entity** including Styles |
| Dashboard | — | **Overview + Analysis pie chart** |
| AI | — | **AI ERA chat + voice** |
| Testing | None | **Unit + Bloc + widget + integration** |
| Navigation | Side drawer (6 items) | Bottom tabs (5) + pushed sub-pages |

See [uat_v1_vs_flutter_comparison.md](uat_v1_vs_flutter_comparison.md) for the UAT-style feature parity matrix and acceptance criteria, and [legacy_v1_features.md](legacy_v1_features.md) for the corresponding v-1.0.0 inventory.

---

## 8. Source References

| Area | Path in repo |
|---|---|
| Entry point | [lib/main.dart](../lib/main.dart), [lib/app.dart](../lib/app.dart) |
| Router | [lib/router/app_router.dart](../lib/router/app_router.dart) |
| Shell | [lib/core/widgets/app_scaffold.dart](../lib/core/widgets/app_scaffold.dart) |
| App bar | [lib/core/widgets/emap_app_bar.dart](../lib/core/widgets/emap_app_bar.dart) |
| Theme | [lib/core/theme/app_theme.dart](../lib/core/theme/app_theme.dart), [lib/core/constants/app_colors.dart](../lib/core/constants/app_colors.dart) |
| Collect | [lib/features/collect/](../lib/features/collect/) |
| Admin | [lib/features/admin/](../lib/features/admin/) |
| Communication | [lib/features/communication/](../lib/features/communication/) |
| Tenant | [lib/features/tenant/](../lib/features/tenant/) |
| Settings | [lib/features/settings/](../lib/features/settings/) |
| Developer | [lib/features/developer/](../lib/features/developer/) |
| AI ERA | [lib/features/ai_chat/](../lib/features/ai_chat/) |
| Core data (pending-sync, history) | [lib/core/data/](../lib/core/data/) |
| Database | [lib/core/database/](../lib/core/database/) |
| Network | [lib/core/network/](../lib/core/network/) |
| Tenant manager | [lib/core/tenant/tenant_manager.dart](../lib/core/tenant/tenant_manager.dart) |
| Localisation ARB | [lib/l10n/](../lib/l10n/) |
| API contract | [plans/EPowerMap_API_Document.md](EPowerMap_API_Document.md) |
| Sync protocol notes | [plans/communication_sync.md](communication_sync.md) |

---

*Prepared for UAT reference — reflects the Flutter rebuild at v2.2.6 as captured from production screenshots and source inspection in April 2026. Any ambiguity defers to the source code under `lib/`.*
