# DAE / Defibrillator integration plan (agent-splittable)

## Common plan prefix (include this at the top of every coding-agent prompt)

### Product goal

Integrate defibrillator (DAE) discovery into the app using the embedded SQLite DB query helper [`getNearbyDefibs()`](src/data/getNearbyDefibs.js:37). Provide:

- A new left-drawer link to a new view `DAEList`.
- In an active alert `Situation` view, a button `Afficher les défibrillateurs` that:
  1) enables DAE display around the **10km corridor around the segment** between user location and alert location,
  2) then navigates to the alert map.
- In alert map, render DAE markers; tapping a DAE opens `DAEItem`.
- `DAEList` screen with bottom navigation: `Liste` (default) and `Carte`, showing defibs nearest→farthest around the user, **within 10km**.
- `DAEItem` screen with bottom navigation: `Infos` (default) and a map/itinerary to reach the selected DAE (mimic alert routing).
- During alert posting, if a cardiac-related keyword is detected in the alert subject, show a **persistent modal** (must remain on top even after redirect to the alert view, and must work offline) with two actions:
  - `Chercher un défibrillateur` → go to `DAEList`
  - `Non merci` → dismiss

### v1 decisions already made

1) Availability filter: **only** use `disponible_24h === 1` for now; no parsing of `horaires` string yet (later iteration).
2) Corridor filter: **within 10km of the user↔alert segment** (not union of circles).
3) Location permission denied: use last-known location; if none, show an explanatory empty state (no hard block).

### Known architecture + relevant anchors in codebase

- Defib query wrapper: [`src/data/getNearbyDefibs.js`](src/data/getNearbyDefibs.js:1) exports [`getNearbyDefibs()`](src/data/getNearbyDefibs.js:37) which calls repo H3 query and falls back to bbox on error.
- Repo query + distance rank: [`src/db/defibsRepo.js`](src/db/defibsRepo.js:1) provides [`getNearbyDefibs()`](src/db/defibsRepo.js:62) and [`getNearbyDefibsBbox()`](src/db/defibsRepo.js:159).
- Embedded DB bootstrap: [`getDb()`](src/db/openDb.js:11) expects a bundled asset `require('../assets/db/geodae.db')` in [`src/db/openDb.js`](src/db/openDb.js:31). **Note:** current repo listing shows `src/assets/db/` empty, so packaging must be validated.
- Drawer navigation screens declared in [`src/navigation/Drawer.js`](src/navigation/Drawer.js:85).
- Root stack only defines `Main` and `ConnectivityError` in [`src/navigation/RootStack.js`](src/navigation/RootStack.js:142). Drawer contains “hidden” stack-like screens (e.g. `SendAlertConfirm`) already.
- Alert current tabs: `Situation`, `Messages`, `Carte` in [`src/scenes/AlertCur/Tabs.js`](src/scenes/AlertCur/Tabs.js:25).
- Alert map uses MapLibre and has route computation (OSRM) already in [`src/scenes/AlertCurMap/index.js`](src/scenes/AlertCurMap/index.js:170).
- Map features clustering uses Supercluster in [`useFeatures()`](src/scenes/AlertCurMap/useFeatures.js:8) and map press routing in [`useOnPress()`](src/scenes/AlertCurMap/useOnPress.js:17).
- Persistent top-layer UI is implemented elsewhere via `react-native-paper` [`Portal`](src/containers/SmsDisclaimerModel/index.js:37) + [`Modal`](src/containers/SmsDisclaimerModel/index.js:38).
- Alert posting flow navigates to `AlertCurOverview` in [`onSubmit()`](src/scenes/SendAlertConfirm/useOnSubmit.js:32) after `alertActions.setNavAlertCur()` in [`src/scenes/SendAlertConfirm/useOnSubmit.js`](src/scenes/SendAlertConfirm/useOnSubmit.js:127).

### Data model (canonical Defib object for UI)

Base DB row shape (from repo select) is:

- `id: string`
- `latitude: number`
- `longitude: number`
- `nom: string`
- `adresse: string`
- `horaires: string` (unused in v1)
- `acces: string`
- `disponible_24h: 0|1`
- plus computed `distanceMeters: number`

Represent coordinates consistently as:

- Map coordinates arrays `[lon, lat]` to match existing map usage (see `alert.location.coordinates` in [`src/scenes/AlertCurMap/index.js`](src/scenes/AlertCurMap/index.js:157)).

### Filtering logic requirements

**Near-user list (DAEList):**

- Input: user location (current if available, else last-known)
- Filter: distance ≤ 10_000m
- Sort: nearest→farthest
- Availability: if `disponible_24h === 1` keep; else exclude in v1 (until horaires parsing)

**Alert-axis corridor overlay (Alert map + Situation button):**

- Input: user location + alert location
- Filter: points within `corridorMeters = 10_000` of the line segment user→alert
- Also restrict to a sensible max radius around user to limit query size (see “Query strategy” below)

Corridor math recommendation:

- Use existing Turf dependency already present in map stack: `@turf/helpers` [`lineString()`](src/scenes/AlertCurMap/index.js:24), `@turf/nearest-point-on-line` [`nearestPointOnLine()`](src/scenes/AlertCurMap/index.js:25), and a distance function (`geolib` or Turf `distance`).

### Query strategy (performance + offline)

Use the existing local SQLite query API (no network) via [`getNearbyDefibs()`](src/data/getNearbyDefibs.js:37).

- For near-user list: query radiusMeters = `10_000`, limit = e.g. 200–500 (tune later).
- For corridor overlay:
  - First query a radius around the **midpoint** or around **user** large enough to include the whole segment + corridor.
  - Practical v1 approach: compute `segmentLengthMeters` and query radius = `segmentLengthMeters/2 + corridorMeters` around the midpoint.
  - Then apply corridor filter in JS and cap results to a max marker count (e.g. 200) to keep map responsive.

### Navigation and UX conventions

- Drawer items come from `<Drawer.Screen>` options in [`src/navigation/Drawer.js`](src/navigation/Drawer.js:100) and are rendered by [`menuItem()`](src/navigation/DrawerNav/menuItem.js:4). Hidden routes should set `options.hidden = true`.
- Bottom tab patterns exist (see alert tabs in [`src/scenes/AlertCur/Tabs.js`](src/scenes/AlertCur/Tabs.js:25)).
- For “persistent modal on top even after redirect”, implement modal at a global provider level (within [`LayoutProviders`](src/layout/LayoutProviders.js:30) tree) using `Portal` so it survives navigation.

---

## Split tasks (agent-ready prompts)

Each task below is designed to be handed to a coding agent. Include the **Common plan prefix** above in every prompt.

### Task 1 — Validate embedded DB asset packaging and repo schema assumptions

**Objective:** Ensure the bundled SQLite `geodae.db` is present and accessible on-device, and confirm schema columns used by [`defibsRepo`](src/db/defibsRepo.js:120) exist.

**Implementation notes:**

- [`initDb()`](src/db/openDb.js:18) copies `require('../assets/db/geodae.db')` to documents.
- Current workspace shows `src/assets/db/` empty; find where DB is stored or add it.

**Acceptance criteria:**

- App can open DB without throwing at [`require('../assets/db/geodae.db')`](src/db/openDb.js:31).
- Query `SELECT ... FROM defibs` works with columns: `id, latitude, longitude, nom, adresse, horaires, acces, disponible_24h` and `h3`.

**Likely files touched:**

- [`src/db/openDb.js`](src/db/openDb.js:1)
- DB asset under [`src/assets/db/`](src/assets/db:1)
- Possibly Expo config / bundling rules (if needed)

---

### Task 2 — Define and implement defib filtering utilities (10km near-user + 10km corridor)

**Objective:** Create pure utility functions to:

- compute query radius for corridor overlay
- filter a list of defibs to those inside corridor
- normalize coordinates and compute distances

**Implementation notes:**

- Prefer reusing Turf already used in map stack (see imports in [`src/scenes/AlertCurMap/index.js`](src/scenes/AlertCurMap/index.js:24)).
- Keep utilities side-effect free and unit-testable.

**Suggested exports:**

- `computeCorridorQueryRadiusMeters({ userLonLat, alertLonLat, corridorMeters })`
- `filterDefibsInCorridor({ defibs, userLonLat, alertLonLat, corridorMeters })`
- `toLonLat({ latitude, longitude })`

**Acceptance criteria:**

- Given synthetic points, corridor filter behaves as “distance to segment ≤ 10km”.

**Likely files touched:**

- New: [`src/utils/geo/defibsCorridor.js`](src/utils/geo/defibsCorridor.js:1)
- Possibly reuse existing [`haversine`](src/db/defibsRepo.js:5) logic as reference

---

### Task 3 — Add a Defibs store (zustand atom) to manage caching + overlay enablement + modal state

**Objective:** Add centralized state to avoid repeated DB queries and to coordinate UI across screens.

**State concerns:**

- cached near-user defibs list
- cached corridor defibs for current alert id
- flag `showDefibsOnAlertMap` (or `defibsOverlayEnabledByAlertId`)
- selected defib id for `DAEItem`
- “DAE suggestion modal” visibility (global)

**Integration points:**

- Mirror patterns used by alert store in [`createAtom()`](src/stores/alert.js:6).

**Acceptance criteria:**

- Other tasks can simply call actions like `defibsActions.loadNearUser()` and `defibsActions.enableCorridorOverlay(alertId)`.

**Likely files touched:**

- New: [`src/stores/defibs.js`](src/stores/defibs.js:1)
- Update exports/hooks in [`src/stores/index.js`](src/stores/index.js:1)

---

### Task 4 — Add navigation routes: `DAEList` in drawer + `DAEItem` as hidden route

**Objective:** Add new screens to navigation so they can be opened from:

- left drawer (DAEList)
- map marker press (DAEItem)
- modal CTA (DAEList)

**Implementation notes:**

- Drawer routes are defined in [`src/navigation/Drawer.js`](src/navigation/Drawer.js:85).
- If `DAEItem` is a detail view, set `options.hidden = true` (see existing hidden screens around [`SendAlertConfirm`](src/navigation/Drawer.js:490)).
- Decide where to place the DAE link in drawer sections:
  - Sections are sliced by indices in [`src/navigation/DrawerNav/DrawerItemList.js`](src/navigation/DrawerNav/DrawerItemList.js:4). Adding a new Drawer.Screen will shift indices; adjust `index1/index2` or reorder screens.

**Acceptance criteria:**

- A new drawer link navigates to `DAEList`.
- `DAEItem` route can be navigated to programmatically.

**Likely files touched:**

- [`src/navigation/Drawer.js`](src/navigation/Drawer.js:85)
- [`src/navigation/DrawerNav/DrawerItemList.js`](src/navigation/DrawerNav/DrawerItemList.js:1)

---

### Task 5 — Situation button on active alert: enable DAE overlay and navigate to alert map

**Objective:** In `Situation` view for current alert, add button `Afficher les défibrillateurs`.

**Behavior:**

1) Determine user coords (prefer current; fall back to last-known as in alert map’s `useLocation` usage in [`src/scenes/AlertCurMap/index.js`](src/scenes/AlertCurMap/index.js:83)).
2) Query defibs from DB with a computed radius around midpoint.
3) Filter to corridor (10km).
4) Store result + enable overlay flag.
5) Navigate to map tab: `Main → AlertCur → AlertCurTab → AlertCurMap` (same pattern used in [`AlertCurOverview`](src/scenes/AlertCurOverview/index.js:276)).

**Acceptance criteria:**

- Button exists only when alert has coordinates.
- After tap, map opens and defib markers appear.

**Likely files touched:**

- [`src/scenes/AlertCurOverview/index.js`](src/scenes/AlertCurOverview/index.js:61)
- Store from Task 3
- Utilities from Task 2

---

### Task 6 — Alert map: render DAE markers and open `DAEItem` on tap

**Objective:** Display defib markers as a separate feature layer on alert map.

**Implementation notes:**

- Existing feature system creates a GeoJSON FeatureCollection for alerts in [`useFeatures()`](src/scenes/AlertCurMap/useFeatures.js:42).
- Add DAE features when overlay is enabled.
- Add a new marker icon to map images by extending [`FeatureImages`](src/containers/Map/FeatureImages.js:13).
- Update press handler in [`useOnPress()`](src/scenes/AlertCurMap/useOnPress.js:17) to recognize `properties.defib` and navigate to `DAEItem`.

**Acceptance criteria:**

- Markers appear/disappear based on overlay flag.
- Tapping a marker navigates to `DAEItem`.
- Clustering behavior is acceptable (either include in cluster or keep separate; v1 can skip clustering by rendering as a separate layer).

**Likely files touched:**

- [`src/scenes/AlertCurMap/useFeatures.js`](src/scenes/AlertCurMap/useFeatures.js:8)
- [`src/scenes/AlertCurMap/useOnPress.js`](src/scenes/AlertCurMap/useOnPress.js:17)
- [`src/containers/Map/FeatureImages.js`](src/containers/Map/FeatureImages.js:1)

---

### Task 7 — Implement `DAEList` screen with bottom tabs: List (default) + Map

**Objective:** Create `DAEList` scene with bottom navigation and two tabs:

- `Liste`: list view nearest→farthest
- `Carte`: map view of same defibs

**Behavior:**

- Load near-user defibs within 10km using [`getNearbyDefibs()`](src/data/getNearbyDefibs.js:37).
- Filter by availability: keep `disponible_24h === 1` only.
- If no location available, show empty state with explanation.
- Tapping list item navigates to `DAEItem`.

**Implementation notes:**

- Follow bottom tab pattern from [`createBottomTabNavigator()`](src/scenes/AlertCur/Tabs.js:3).

**Acceptance criteria:**

- Drawer link opens `DAEList`.
- List is sorted by `distanceMeters`.
- Map tab renders markers.

**Likely files touched:**

- New: [`src/scenes/DAEList/index.js`](src/scenes/DAEList/index.js:1)
- New: [`src/scenes/DAEList/Tabs.js`](src/scenes/DAEList/Tabs.js:1)
- Possibly shared list row component

---

### Task 8 — Implement `DAEItem` screen with bottom tabs: Infos (default) + Go-to map (itinerary)

**Objective:** Create `DAEItem` detail view for a selected defib.

**Tabs:**

- `Infos`: name, address, access, availability badge
- `Carte`: show route from user to DAE, mimicking alert routing implementation in [`AlertCurMap`](src/scenes/AlertCurMap/index.js:170)

**Implementation notes:**

- Reuse route calculation patterns (OSRM URL building, polyline decode, step list components) from alert map.
- Route target is defib coordinates instead of alert coordinates.

**Acceptance criteria:**

- From any entrypoint (alert map marker or list), `DAEItem` shows correct defib.
- Itinerary works when online; offline behavior is a clear message (route unavailable offline).

**Likely files touched:**

- New: [`src/scenes/DAEItem/index.js`](src/scenes/DAEItem/index.js:1)
- New: [`src/scenes/DAEItem/Tabs.js`](src/scenes/DAEItem/Tabs.js:1)
- New: [`src/scenes/DAEItem/Map.js`](src/scenes/DAEItem/Map.js:1)

---

### Task 9 — Keyword detection while posting an alert + persistent DAE suggestion modal

**Objective:** Detect cardiac-related terms during alert posting and display a global modal that remains visible even after navigation.

**Detection requirements:**

- Keywords include: `cardiaque`, `cardiac` (typos), `coeur`, `malaise`, `inconscient`, `évanoui` etc.
- Should run locally/offline.

**Implementation approach (recommended):**

- Use fuzzy matching with `Fuse` (already used in [`findAlertTitle()`](src/finders/alertTitle.js:50)) or implement a lightweight normalization + substring/levenshtein.
- Trigger detection in the confirm submit flow, before/around navigation in [`onSubmit()`](src/scenes/SendAlertConfirm/useOnSubmit.js:32).
- Render modal at app root using `react-native-paper` [`Portal`](src/containers/SmsDisclaimerModel/index.js:37) inside [`LayoutProviders`](src/layout/LayoutProviders.js:51) so it persists across navigation.

**Modal UI:**

- Title/text: explain quickly why looking for a DAE matters.
- Two buttons:
  - `Chercher un défibrillateur` → navigate to `DAEList`
  - `Non merci` → dismiss

**Acceptance criteria:**

- Modal shows for matching terms even with no internet.
- Modal stays visible after redirect to current alert view.

**Likely files touched:**

- [`src/scenes/SendAlertConfirm/useOnSubmit.js`](src/scenes/SendAlertConfirm/useOnSubmit.js:1)
- New: [`src/containers/DAESuggestModal/index.js`](src/containers/DAESuggestModal/index.js:1)
- [`src/layout/LayoutProviders.js`](src/layout/LayoutProviders.js:30)
- Store from Task 3

---

### Task 10 — Verification checklist (manual) + minimal automated coverage

**Objective:** Provide a deterministic checklist and (where feasible) simple automated tests.

**Manual verification checklist:**

1) **Drawer**: DAE link visible, opens list.
2) **DAEList**:
   - permission granted → list populated, sorted
   - permission denied + last-known available → list uses last-known
   - permission denied + no last-known → empty state
3) **Alert Situation button**: enables overlay and opens alert map.
4) **Alert map**: DAE markers render; tap → DAEItem.
5) **DAEItem routing**: online route works; offline shows message.
6) **Keyword modal**:
   - trigger term in subject → modal shows
   - redirect to alert occurs and modal remains on top
   - CTA navigates to DAEList

**Acceptance criteria:**

- Checklist documented and reproducible.

**Likely files touched:**

- New: [`plans/DAE-manual-test-checklist.md`](plans/DAE-manual-test-checklist.md:1)
- Optional: e2e tests under [`e2e/`](e2e:1)

---

## Mermaid overview

```mermaid
flowchart TD
  A[User posts alert] --> B[Keyword detection]
  B -->|match| M[Show persistent DAE modal]
  B -->|no match| C[Navigate to AlertCur Situation]
  M --> C
  M -->|Chercher un defibrillateur| L[DAEList]
  M -->|Non merci| C
  C --> S[Button Afficher les defibrillateurs]
  S --> E[Enable overlay in store]
  E --> MAP[AlertCurMap]
  MAP -->|tap DAE marker| ITEM[DAEItem]
  L -->|tap list item| ITEM
```

