Appearance
Keryx alert data classification and local storage
Approved: 25 August 2026
This document is the P1-05 production data-classification, retention, and local-storage policy for Keryx for SafeCall. It inventories QR, alert, native, notification, and support data; classifies sensitivity and roles; and records approved launch controls for SharedPreferences storage and full lock-screen previews.
It does not claim that encrypted platform storage, redacted lock-screen builders, privacy policy pages, or store forms exist. Implementation of later hardening and disclosure text remains other work items.
Purpose and non-goals
Purpose
- Inventory data that crosses QR, device storage, OS notifications, native prefs, and support channels.
- Classify sensitivity and controller/processor roles for honest privacy and store disclosures.
- Approve retention, deletion, tombstones, backups, lock-screen exposure, device-loss, and diagnostic redaction for launch.
- Feed #99– #101 and related support work.
Non-goals
- Changing Dart stores, OS notification builders, or backup entitlements.
- Moving secrets to Keychain / EncryptedSharedPreferences for this work item.
- Publishing privacy/terms pages or filling Apple/Play forms.
- Implementing ntfy token revoke UX (owned by P1-02 implementation and #120/ #121).
- Adding an analytics or crash SDK (prohibited at launch by P0-05).
Approved decisions
- Owner and approver: Thomas Minitsios, 25 August 2026.
- Lock-screen preview: full OS notification title + body for launch; policies and store forms must disclose lock-screen exposure.
- Storage protection: SharedPreferences is acceptable for local config (including future
subscribe_auth), pause flag, and alert history for launch. Platform secure storage is not a launch blocker. Treatsubscribe_authas a secret in documentation and support even while prefs-backed. - Visible retention: latest 200 active + archived messages.
- Tombstones: up to 500 deleted tombstones to suppress ntfy-cache reintroduction; not a user-visible archive.
Roles
| Role | Party | Scope |
|---|---|---|
| App publisher / product controller for the app binary and store listings | sourcectl | App design, store privacy answers, in-app processing on device as shipped |
| Hosted alert transport processor | Client deployer of the ntfy host (and any APNs/FCM upstream they configure) | Message cache, ACL, upstream wakes; see #119 |
| SafeCall platform operator | Contracted SafeCall deployment operator | Alert generation and publish path; publish token custody |
| Device / local copy controller | SafeCall administrator who installs and provisions Keryx on their device | Local config, history, OS notifications, device backups, reset |
Ordinary administrators do not configure ntfy topics; they select friendly categories and scan a QR on their own device.
Data inventory and classification
Sensitivity scale: Secret (credential), High (operational alert or subscribe capability), Medium (transport/debug metadata), Low (non-identifying flags).
| Data | Sensitivity | Purpose | Storage today / target | Retention | Backup exposure | Notes |
|---|---|---|---|---|---|---|
QR payload / local config (ntfy_server_url, topics, labels, created_at, debug_access) | High | Provision subscribe path and UI labels | SharedPreferences keryx_config | Until reset/uninstall or replace QR | May enter OS device backup | v1 today; v2 adds secret below |
subscribe_auth / token_id (v2) | Secret / Medium | Authenticated subscribe; support correlation | SharedPreferences with config (launch-approved) | Until reset/uninstall or revoke+replace | May enter OS device backup | Never show in ordinary or debug UI; revoke is offboarding |
| Topic names | High | Routing; may enable guessing on open hosts | Config, history, debug UI if enabled | With config/history | Backup with prefs | Prefer friendly labels in ordinary UI |
| Friendly labels | Medium | Administrator-facing category names | Config | With config | Backup with prefs | |
| Alert title / body | High | Deliver SafeCall alert; may include device name, MAC, operational or location-like content | SharedPreferences history; OS notification UI | Latest 200 visible; then drop | Backup with prefs; lock-screen visible | Full lock-screen preview approved |
| Raw ntfy JSON | High | Dedupe, debug, tag/priority recovery | SharedPreferences with message record | With visible message or until tombstone overflow | Backup with prefs | Debug UI only when debug_access |
| Tags / priority / timestamps / message id | Medium–High | Display, sort, poll since | History + native last-message ids | With history / subscription prefs | Backup with prefs | |
| Tombstones / dedupe keys | Medium | Prevent deleted alerts from returning via cache poll | SharedPreferences (deleted status) | Cap 500 | Backup with prefs | Not user-visible archive |
| Pause flag | Low | Suppress notifications while configured | SharedPreferences keryx_paused | Until changed/reset | Backup with prefs | |
| Parsed alert condition state / known devices | High | Authoritative category cards and per-device controls | SharedPreferences alert-state store | Until reset/new QR; bounded to known alert subjects | Backup with prefs | Contains the same device identifiers and summaries already present in alert bodies |
| Category and per-device notification policy | Medium | Local rolling-window suppression | SharedPreferences policy store plus native policy snapshot | Until changed/reset/new QR | Backup with prefs | Suppression never removes the underlying alert from history/state |
| Native last-notified timestamps and message dedupe ids | Medium | Apply policy consistently during background delivery | Vendored plugin preferences | Bounded/pruned; until reset/unsubscribe | Platform-dependent | Native mutable delivery state is separate from the Dart-owned policy |
| Native Android subscription prefs (URL, topics, auth, last ids) | Secret–High | Plugin subscribe/restart | Vendored plugin SharedPreferences / device-protected context | Until clear/unsubscribe | May backup with app data | Align with P1-02/P1-03 implementation |
| APNs / FCM device tokens (when implemented) | Secret | Wake registration on client ntfy | Per iOS / Android designs | Until delete/reset | Platform-dependent | Not sent to SafeCall HTTP APIs |
| OS lock-screen notification content | High | Immediate administrator awareness | OS notification shade / lock screen | Until dismissed or OS clears | N/A (ephemeral UI) | Full title+body approved; disclose |
| Debug diagnostics | Medium–High | Restricted troubleshooting | In-app detail when debug_access | Session / stored message lifetime | Screenshots risk | No secrets; minimize in tickets |
| Support tickets / intake | High if payloads attached | Field diagnosis | External support channel | Per SafeCall support process | N/A | Redact secrets; minimize raw JSON (#132) |
| Analytics / crash SDK identifiers | — | — | Not collected at launch | — | — | P0-05 |
Approved launch controls
Storage protection
- SharedPreferences for Flutter config and notification history is approved for launch, including future storage of
subscribe_authin that config blob. - Documentation and support must still call
subscribe_autha secret. - Optional later migration to Keychain / EncryptedSharedPreferences is a deferred improvement, not a launch requirement under this approval.
Lock-screen and OS notifications
- Full title and body (including emoji tags where shown) may appear on the lock screen and notification shade.
- #99– #101 must disclose that alert content can appear on a locked device.
- Redacted lock-screen previews are not required for launch.
Retention, delete, and reset
| Control | Launch rule |
|---|---|
| Visible messages | Cap at latest 200 active + archived combined (current NotificationStore.maxMessages) |
| Tombstones | Cap at 500 deleted records; purpose is cache-poll suppression only |
| Per-item delete / delete-all archived | Local only; creates tombstones as implemented today |
| Reset App | Clears local config, history, parsed condition state, policy, and native delivery state; does not revoke ntfy subscribe token |
| Offboarding | Require revoke by token_id on the ntfy host, then local reset/uninstall (P1-02, #120/#121) |
Device backups
- Accept default OS backup behavior of app preferences for launch.
- Disclose that backups may contain alert history, topic metadata, and config secrets (including
subscribe_authafter v2). - Excluding prefs from backup or encrypting backup contents is a later improvement, not a launch blocker.
Device loss and replacement
- A holder of a lost/stolen provisioned device can read local history and may continue receiving alerts until the subscribe token is revoked and the device is wiped or reset.
- Replacement: mint a new QR/token, revoke the old token, then reset or uninstall the old device when available.
- Local reset alone is not sufficient offboarding (threat model A7/A10).
Diagnostic redaction
- Ordinary Active/Archive/detail UI: message and received time; no
subscribe_auth, no APNs/FCM tokens, no publish credentials. debug_accessQR may show topic names, ntfy ids, tags, priority, and raw JSON; still must not showsubscribe_auth.- Support intake (#132) and privacy copy (#99): redact secrets; avoid pasting full raw payloads unless necessary and time-bounded.
Mapping to threat model
| Abuse case | How this policy treats it |
|---|---|
| A7 device loss | Documents local exposure; offboarding requires P1-02 revoke + wipe |
| A8 debug overexposure | Limits secrets in debug; debug_access remains restricted |
| A9 log leakage | No analytics SDK; support redaction process |
| A10 offboarding | Local reset insufficient; revoke required |
Residual A7/A10 risk remains until revoke UX and deployer ACL are live.
Explicit non-claims
Closing #98 approves this policy. It does not:
- move secrets to platform secure storage;
- change lock-screen notification builders;
- implement token revoke or offboarding UI;
- publish privacy/terms URLs or complete Apple/Play forms;
- claim alert bodies never contain personal or location-like data.
Implementation and disclosure handoffs
| Work | Owner |
|---|---|
| Privacy, terms, and support commitments matching this inventory | #99 — DRAFT package in legal/; live publish remains #107 |
| Apple privacy / encryption / nutrition answers | #100 |
| Play Data Safety and related declarations | #101 |
| Safety claims if lock-screen exposure matters operationally | #103 |
| Device-loss, reset, and offboarding administrator guidance | #120, #121 |
| Support intake redaction | #132 |
| Optional secure-storage hardening | Deferred; not launch-required |
v2 subscribe_auth stored in prefs | Later P1-02 implementation; follows this storage approval |
Review record
- Status: approved as the P1-05 data classification and local-storage policy.
- Date: 25 August 2026.
- Approver: Thomas Minitsios under the P0-05 RACI.
- Depends on: P1-01 threat model, P1-02 provisioning protocol.
- Evidence sources:
keryx/lib/services/notification_store.dart,keryx/lib/services/keryx_config_store.dart,keryx/lib/models/ntfy_message.dart,keryx/lib/screens/notification_detail_screen.dart,keryx/lib/screens/home_screen.dart, vendored Android notification/prefs paths,docs/gtm/keryx/threat-model.md.