# Mobile Delivery

Cheqi uses push notifications as opaque work hints. The durable encrypted
generation queue is the source of truth.

```mermaid
flowchart TD
    A[Encrypted generation job committed] --> B[Durable push outbox]
    B --> C[APNs or FCM work hint]
    C --> D[Targeted job fetch]
    D --> E[Decrypt and generate locally]
    E --> F[Persist local receipt]
    F --> G[Submit downstream ciphertext if elected]
    G --> H[Acknowledge device completion]
    C -. missed, delayed, or offline .-> I[Foreground queue sync]
    I --> D
```

## Push contract

Receipt and credit-note hints use this versioned payload:

```json
{
  "eventType": "RECEIPT_GENERATION_AVAILABLE",
  "eventVersion": 1,
  "jobId": "opaque UUID",
  "documentType": "RECEIPT"
}
```

`documentType` may also be `CREDIT_NOTE`. The payload contains no receipt line
items, totals, encrypted generation body, generated document, customer payment
identifier, or reusable recipient identifier.

On receipt, the app fetches only the assigned job using the opaque `jobId` and
its authenticated device ID. Duplicate and out-of-order hints are safe because
the server claim and local generation state are idempotent.

## Durable backend behavior

The generation job and push-outbox rows are committed transactionally. A
background dispatcher retries temporary APNs or FCM failures with exponential
backoff. Multiple backend instances lock due rows so only one dispatcher sends
a given outbox entry at a time.

An invalid provider token permanently fails that device's outbox entry and is
removed from active use. An APNs or FCM success only means the provider accepted
the hint; it is not proof that the phone generated the receipt.

## iOS

Cheqi sends one APNs alert notification with `content-available: 1`, immediate
priority, and push type `alert`. The visible notification remains the primary
delivery class, while `content-available` gives the containing app a
best-effort background execution window for the targeted fetch.

Cheqi does not send a second pure-silent notification for the same job. Silent
background pushes are low priority, may be throttled, and would duplicate the
same fetch without creating a delivery guarantee.

The iOS target must have:

- the Push Notifications capability
- Background Modes enabled with **Remote notifications** selected
- the correct APNs entitlement and environment for the installed build


APNs token registration is independent from permission to display alerts. The
app registers for a device token at launch even when visible notifications are
off. Cheqi explains the notification benefit once; it does not repeatedly show
the system permission prompt. If permission is disabled, Profile shows a
passive status and a link to the app's system settings.

iOS background execution remains best-effort. The system may delay or end the
window, and it normally does not relaunch the containing app after the user
explicitly force-quits it. Opening or foregrounding Cheqi runs the authoritative
queue sync and catches up missed work.

The existing Cheqi notification extension displays receipt notification
content. It is not a Notification Service Extension and is not responsible for
decrypting or storing generation jobs before the main app runs.

## Android

Cheqi sends a high-priority FCM data message. A data message reaches
`FirebaseMessagingService.onMessageReceived` while the app is backgrounded;
using an FCM notification payload here would allow the system tray to bypass
the app's processing code.

The service:

1. validates the versioned work hint
2. posts the visible notification when Android allows it
3. enqueues one unique expedited WorkManager job for the generation-job ID
4. waits for network access
5. fetches and processes the assigned job through the existing idempotent
receipt pipeline


On Android 13 and later, `POST_NOTIFICATIONS` controls whether Cheqi can display
the notification. It does not grant access to the durable receipt queue and is
not the acknowledgement mechanism. Background execution can still be delayed
by device battery policies, and FCM may deprioritize sustained high-priority
traffic that does not result in user-visible notifications. Foreground sync is
therefore still required.

If FCM reports deleted messages, Cheqi schedules a full authoritative sync.

## Notification permission behavior

Notifications matter because they make receipts timely and visible, but
permission is not a data-delivery guarantee.

- Ask only after explaining the benefit in context.
- Record that the explanation was shown so logout or device re-registration
does not repeat it.
- Keep token registration active independently from visible-alert permission.
- When permission is off, show a passive status and settings link instead of
repeatedly prompting.
- Always process the durable queue when the app becomes active.


## Reliability guarantees

- Push is a hint; the encrypted queue is authoritative.
- Provider acceptance is not device completion.
- Repeated hints and retries are safe.
- Each owner device independently generates and stores its own CHEQI receipt.
- Exactly one leased device performs downstream fan-out.
- Receipt contents remain encrypted until the assigned device decrypts them.
- Foreground synchronization repairs missed, collapsed, throttled, offline, and
force-quit delivery.


## Production verification

Before promoting this flow, test physical devices in the APNs/FCM environment
used by the release build:

1. Confirm the device token is registered after login and survives normal
account reset/re-registration behavior.
2. Background the app without force-quitting it and submit an encrypted receipt.
3. Confirm the outbox sends one hint and the device performs the targeted fetch.
4. Confirm local generation, durable persistence, downstream delivery, and
acknowledgement complete exactly once.
5. Repeat with visible notification permission disabled.
6. Repeat while offline, then restore connectivity and verify catch-up.
7. Force-quit iOS, submit a receipt, reopen Cheqi, and verify foreground sync
catches it up.
8. Test token rotation and an invalid-token response in the release provider
environment.


Do not treat a successful backend `202` or an APNs/FCM acceptance log as the end
of this test. The final evidence is the generated local receipt and completed
durable job.