Doc status: Latest (rolling). See Versions.
This page tracks planned features, UX improvements, and known issues that are documented but not yet implemented. Items are grouped by priority and labelled with their category.
Known Issues
Re-login still prompts for invite code when membership exists
bug ux high
Current behaviour: When a user with an existing UID, active license, and group membership signs back in (e.g. after clearing app data or reinstalling), the app still presents the "Enter invite code" screen — even though the server already knows their group association.
Expected behaviour: The app should detect the existing membership via GET /v1/me/membership and restore the user directly into their group without requiring an invite code.
Context: The recovery endpoint already exists and works (added in v1.0.0). The mobile post-login flow calls it, but currently falls through to the invite-code screen if local state is empty — it should instead use the API response to skip the invite step entirely.
Affected versions: v1.0.0, v1.0.1
Alert notifications are silent and do not persist
bug critical high
Current behaviour: When an alert is triggered, recipients receive a standard push notification with default message-tone priority. On silent/DND mode the notification makes no sound. The notification text is generic ("Neighbourhood — alert triggered nearby") with no address detail. Once the notification is dismissed or the app is opened, the alert disappears entirely — there is no in-app record of it.
Expected behaviour:
- Critical / alarm-level sound — Alert notifications must behave like a "Find My Phone" alarm: full-volume, bypass silent/DND, persist audibly until the user unlocks the phone and acknowledges. On iOS this requires the Critical Alerts entitlement. On Android this requires an alarm-priority notification channel with
IMPORTANCE_MAX/fullScreenIntent. - Address detail in payload — The decrypted address text should be displayed in the notification body (encrypted in transit, decrypted on-device before display).
- In-app persistence — The alert message and timestamp must persist in the app's alert list in plaintext until a manager clears/resolves the incident from the admin dashboard. Users should be able to re-read the alert at any time.
Affected versions: v1.0.0, v1.0.1
Planned Features
"Join a different group" button
feature ux medium
Add an in-app option (accessible from Settings or the group info screen) that allows a user to leave their current group and join a different one by entering a new invite code.
Acceptance criteria:
- Button visible in Settings / group info area
- Tapping it confirms the action ("You will leave [group name]. Continue?")
- On confirm, clears local group state and prompts for a new invite code
- Server-side: updates the user's
groupIdto the new group, cleans up old crypto keys
Multi-group membership
feature future
Allow users to be members of more than one neighbourhood group simultaneously.
Scope:
- User can hold memberships in multiple groups
- Group switcher UI in the app (e.g. tab or dropdown)
- Alerts are scoped to the currently-active group (or optionally all groups)
- Each group has independent admin controls (pause/ban per group)
- Crypto keys are per-group (each group has its own KEM key pair)
Considerations:
- Data model change: user doc
groupId: string→groupIds: string[](or a subcollection) - Push notification routing: fan-out must target the correct group's members
- License model: does each group need its own license, or does one license cover multi-group?
- UX: keep it simple — avoid overwhelming users who only need one group
Dependencies: "Join a different group" should ship first as a stepping stone.
Incident lifecycle (acknowledge / close) — partially implemented ✅
feature future
Delivered (admin side):
- Admin can resolve an incident from the admin dashboard with optional resolution note
- Resolution sends FCM push notification to the group confirming resolution
- Incidents tab in admin dashboard shows all incidents across managed groups with status filter
- Incident detail modal with full note timeline, add-note form, and resolve action
- Incident notes support visibility levels: public (all managers), manager only, super admin only
- API:
POST /v1/admin/groups/:gid/incidents/:iid/resolve,GET/POST .../notes
Still planned:
- Member "I'm aware" acknowledgement (mobile app)
- In-app incident history screen (mobile app)
- Strict permissions: only the original reporter or an admin can close
Admin audit log UI ✅
feature high — Implemented in v0.7.0
Full audit log surfaced in the admin dashboard with role-based scoping.
Delivered:
- Super admin view: All events across all groups — create_group, set_member_status, broadcast, trigger_incident, set_user_role, grant_license, revoke_license, add_incident_note, resolve_incident
- Manager view: Only events for their own group(s)
- Filterable by action, email, group (text search)
- Action-colour-coded table with 100-row pagination
- API:
GET /v1/admin/auditwith role-based scoping
iOS Critical Alerts entitlement
feature critical high
Why: Standard iOS push notifications respect silent mode and Do Not Disturb. For a neighbourhood emergency alert system this is unacceptable — alerts must sound at full volume regardless of device settings.
Apple Critical Alerts:
- Requires a special entitlement granted by Apple (not available by default)
- Application via Apple entitlement request form
- Must demonstrate the app serves a genuine safety/health/security purpose
- Once approved, the provisioning profile is updated and the app can send notifications with
{ "sound": { "critical": 1, "volume": 1.0 } }in the APNs payload - Critical Alerts bypass Do Not Disturb, silent mode, and Focus modes
- A dedicated UI toggle in iOS Settings allows users to disable Critical Alerts per-app (Apple requirement)
Action items:
- Submit the entitlement request to Apple with justification (neighbourhood emergency safety system)
- Update the FCM payload builder in the API to include the critical alert sound payload when the entitlement is approved
- Update the iOS notification channel / category configuration in the Expo config
- Test on a physical device in DND mode
Android alarm-priority notifications
feature critical high
Why: Android respects DND for standard notification channels. Emergency alerts need to bypass this.
Android approach:
- Create a notification channel with
IMPORTANCE_HIGHorIMPORTANCE_MAX(alarm level) - Set the channel to bypass DND:
setBypassDnd(true)(requiresACCESS_NOTIFICATION_POLICYpermission) - Use
fullScreenIntentto wake the device and show an interstitial alert activity - Use a custom alarm sound (looping) that plays until the user interacts
- On Android 14+, check
canUseFullScreenIntent()and request permission if needed - Configure via
expo-notificationschannel settings or a custom config plugin
Action items:
- Create a dedicated "Emergency Alert" notification channel in the Expo config with alarm-level importance
- Add
ACCESS_NOTIFICATION_POLICYto AndroidManifest.xml via config plugin - Implement a full-screen intent activity that shows the alert and plays alarm sound
- Test on physical device in DND mode
Alert persistence and incident lifecycle
feature high
Alerts must persist in-app until explicitly cleared by a manager.
Scope:
- When an alert is received, write it to local storage (AsyncStorage / SQLite) with: message, timestamp, sender, group, status (
active/resolved) - Display an "Active Alerts" list in the app — visible on the home/main screen
- Alert remains in the list with
activestatus until a manager resolves it from the admin dashboard - When resolved, a push notification is sent to the group: "Alert resolved by [manager]"
- App updates the local alert status to
resolved(greyed out, moved to history) - Admin dashboard: "Resolve Alert" button per active incident
Dependencies: Admin audit log (to record who resolved and when)
Completed (v1.0.1+)
Incident management & audit log (admin)
feature high — Implemented in v0.7.0
Full incident management with ticketing, notes with visibility levels, resolution workflow, and comprehensive audit logging. See entries above for details.
Notification listener crash on Android
bug critical — Fixed in v1.0.1
Notifications.removeNotificationSubscription() was removed in expo-notifications 0.32.x. The useEffect cleanup called this undefined function, causing a crash loop after Google Sign-In. Fixed by switching to subscription.remove().
Reinstall recovery
feature — Fixed in v1.0.0
Server now persists groupId on the user document. New GET /v1/me/membership endpoint allows the app to recover group state after a reinstall without requiring the user to re-enter an invite code (server-side recovery works; see known issue above for the remaining client-side gap).

