nexo/docs/linux-notification-test-guide.md
toki ee2e79b334 docs: Linux 알림 테스트 가이드 및 evidence 템플릿 추가, Windows/Linux 선행 정리 아카이브
- Windows 및 Linux 알림 선행 정리 마일스톤을 아카이브로 이동
- iOS 알림 테스트 마일스톤을 활성 milestone로 변경
- Linux 알림 테스트 가이드 및 smoke evidence 템플릿 추가
- Flutter Test Linux fixture 파일 추가 (open_channel, open_thread)
2026-06-02 10:50:27 +09:00

169 lines
8.4 KiB
Markdown

# Linux Notification Test Guide
Last verified: 2026-06-02
This guide fixes the preflight contract for Linux notification work before a
Linux test machine, distribution, desktop environment, notification daemon, or
real OS notification UI evidence is available.
Do not commit private host values, device tokens, auth tokens, signing keys,
runtime endpoints, user names, channel names, desktop session details that
identify a private machine, or private package repository values into tracked
docs. Use placeholders in examples and keep credential files in approved local
or secret-store locations.
## Current Repository State
- `packages/messaging_flutter/pubspec.yaml` does not currently register a
Linux plugin platform.
- There is no `packages/messaging_flutter/linux/` plugin scaffold and no
`apps/flutter-test/linux/` host scaffold in the current repository.
- Dart already expects native notification and action channels:
`com.tokilabs.nexo.messaging/notifications` and
`com.tokilabs.nexo.messaging/notification_actions`.
- The Linux bridge is therefore not implemented yet. Until it exists, local
routing can only be tested through Dart unit tests or a future debug injection
bridge.
- Local routing fixtures live under `apps/flutter-test/linux/Fixtures/*.json`.
The first useful Linux smoke target is:
1. Add a Linux plugin platform registration and generated host scaffold in a
controlled implementation plan.
2. Register the expected EventChannel and MethodChannel in the Linux plugin.
3. Implement a debug-only local injection path compatible with
`debugSendNativeEvent`.
4. Choose a notification API path and runtime dependency strategy for the smoke.
5. Map notification daemon action data or portal activation data into the Dart
`NotificationOpenedEvent` contract.
6. Collect display, click/open routing, lifecycle, and known ACK, dismiss, and
inline reply gap evidence.
## Platform Registration Contract
Do not add a partial Linux platform entry without the matching source and host
scaffold. A future implementation plan should update these together:
```yaml
flutter:
plugin:
platforms:
linux:
pluginClass: NexoMessagingPlugin
```
Expected source/host areas for that plan:
- `packages/messaging_flutter/linux/` for the Linux plugin implementation.
- `apps/flutter-test/linux/` for the test host scaffold generated by Flutter.
- `packages/messaging_flutter/pubspec.yaml` for platform registration.
- `apps/flutter-test/README.md` and package docs for smoke instructions.
The current preflight milestone documents this contract only. It does not claim
Linux runtime support.
## Minimum Bridge Contract
The Dart SDK expects the Linux native side to preserve these channel names:
| Channel | Name | Direction | Minimum Linux behavior |
|---|---|---|---|
| EventChannel | `com.tokilabs.nexo.messaging/notifications` | native to Dart | Emit codec-safe maps for notification, open, token, clear, session, and future action-failure events. |
| MethodChannel | `com.tokilabs.nexo.messaging/notification_actions` | Dart to native | Accept SDK action methods used by Dart without crashing the host app. |
Minimum methods for the action channel:
| Method | Minimum preflight result | Production expectation |
|---|---|---|
| `debugSendNativeEvent` | Validate the argument is a map and emit it on the EventChannel. | Debug/test-only injection path. |
| `saveDeviceToken` | Accept and store or no-op a formatted token string without logging secrets. | Store the Linux server-registration token once the platform token source is chosen. |
| `getDeviceToken` | Return the last stored formatted token or null. | Return the current formatted Linux server-registration token. |
| `setAuthToken` | Validate required string arguments and no-op. | Persist token for ACK/reply work only after storage rules are designed. |
| `clearAuthToken` | Validate `serverUrl` and no-op. | Clear persisted token for the server. |
| `setSigningKey` | Validate required string arguments and no-op without persistence. | Persist the signing key only after secure storage rules are designed. |
Fallback boundaries:
- Missing bridge methods should return the Flutter Linux equivalent of "not
implemented", not a successful placeholder.
- Token, auth, signing-key, ACK, dismiss, and inline reply persistence are not
implied by this preflight milestone.
- Real notification display and activation handling belong to `Linux 알림 테스트`
unless a smaller bridge implementation plan explicitly handles them first.
## Notification API Matrix
| Candidate | Environment fit | Strength | Preflight constraint |
|---|---|---|---|
| D-Bus `org.freedesktop.Notifications` | Common desktop notification daemon path | Broad support across GNOME, KDE, XFCE, and other desktops | Action callbacks and capabilities vary by daemon and session. |
| XDG Desktop Portal notifications | Flatpak/sandbox-friendly desktops | Better fit for portal-mediated desktop environments | Portal availability and notification support vary by distribution and session. |
| libnotify wrapper | Thin client around the freedesktop notification spec | Simple display smoke for common desktops | Callback/action support still depends on the underlying daemon. |
| Local debug injection only | No daemon, package, or desktop requirement | Deterministic EventChannel/opened-routing verification | Does not prove OS display or activation. |
Preflight default: use local debug injection for contract tests, and defer the
D-Bus vs desktop portal vs libnotify runtime decision to the `Linux 알림 테스트`
milestone or a dedicated implementation plan.
## Runtime Dependency Boundaries
Future Linux notification implementation should record the runtime assumptions
before claiming smoke support:
- Distribution and version, such as Ubuntu, Fedora, Debian, or another target.
- Desktop environment and session type, such as GNOME/KDE/XFCE and X11/Wayland.
- Notification daemon or portal availability.
- Required build packages and runtime libraries.
- Whether action callbacks are supported by the chosen daemon or portal path.
Tracked docs should keep these as sanitized evidence fields, not private machine
configuration dumps.
## Payload Mapping
Linux notification action data maps into Dart using the same stable keys as the
Android, iOS, macOS, and Windows contracts:
| Payload key | Dart event field | Notes |
|---|---|---|
| `type` | `type` | Use `message` for visible message notifications and `opened` for direct open events. |
| `server_url` | `server_url` | Required before host navigation callbacks can run. |
| `server_id` | `server_id` | Diagnostic and future server URL fallback input. |
| `channel_id` | `channel_id` | Drives `onNavigateToChannel` when thread routing is not selected. |
| `root_id` | `root_id` | Drives `onNavigateToThread` when CRT is enabled. |
| `is_crt_enabled` | `is_crt_enabled` | Accept boolean `true`, string `"true"`, or string `"1"`. |
| `ack_id` | `ack_id` | Preserve for future ACK evidence; do not invent ACK behavior. |
| `post_id` | `post_id` | Preserve for notification identity and future ACK/display evidence. |
| `userInteraction` | `userInteraction` | Set to `true` when a click/open path caused the event. |
Routing expectation:
- Channel fixture: `server_url` and `channel_id` are present, `root_id` is empty
and `is_crt_enabled` is false, so Dart calls `onNavigateToChannel`.
- Thread fixture: `server_url` and `root_id` are present and
`is_crt_enabled` is true, so Dart calls `onNavigateToThread`.
## Local Fixtures
Use the fixture files as sanitized payloads for a future debug injection method
or for manual D-Bus/portal action data construction during smoke testing:
- `apps/flutter-test/linux/Fixtures/open_channel.json`
- `apps/flutter-test/linux/Fixtures/open_thread.json`
The fixtures intentionally use `https://example.invalid` and smoke IDs. Replace
private runtime values only in local run notes or sanitized evidence.
## Evidence
Use [`linux-notification-smoke-evidence-template.md`](linux-notification-smoke-evidence-template.md)
for Linux runs. Preflight evidence should explicitly separate:
- distribution, desktop environment, session, and daemon or portal state
- visible display state
- click/open routing result
- app lifecycle state
- ACK, dismiss, and inline reply implementation gaps
Until the scaffold, bridge, and real OS smoke exist, a valid preflight result
may be "not implemented yet" with a concrete follow-up plan, rather than a
failed runtime claim.