chore: update .gitignore, README, and add agent-ops roadmap
This commit is contained in:
parent
41e450744a
commit
196a7162ee
19 changed files with 1349 additions and 160 deletions
76
.gitignore
vendored
76
.gitignore
vendored
|
|
@ -1,9 +1,16 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
# OS and editor noise
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
*.tmp
|
||||
*.log
|
||||
|
||||
# Compiled artifacts
|
||||
*.class
|
||||
*.pyc
|
||||
|
||||
# Tool caches
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
|
|
@ -12,7 +19,7 @@
|
|||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
# IntelliJ / Android Studio
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
|
@ -23,14 +30,65 @@ migrate_working_dir/
|
|||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Flutter / Dart / Pub
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
/build/
|
||||
/coverage/
|
||||
.pub-cache/
|
||||
.pub/
|
||||
**/build/
|
||||
coverage/
|
||||
|
||||
# Flutter generated native files
|
||||
**/Flutter/.last_build_id
|
||||
**/Flutter/Generated.xcconfig
|
||||
**/Flutter/ephemeral/
|
||||
**/Flutter/flutter_export_environment.sh
|
||||
**/.symlinks/
|
||||
|
||||
# Android / Gradle
|
||||
**/.gradle/
|
||||
**/.kotlin/
|
||||
**/.cxx/
|
||||
**/.externalNativeBuild/
|
||||
**/captures/
|
||||
**/local.properties
|
||||
**/app/debug/
|
||||
**/app/profile/
|
||||
**/app/release/
|
||||
|
||||
# Android signing and local Firebase configuration
|
||||
key.properties
|
||||
**/*.jks
|
||||
**/*.keystore
|
||||
**/google-services.json
|
||||
!**/google-services.example.json
|
||||
|
||||
# iOS / macOS / CocoaPods / Xcode
|
||||
**/Pods/
|
||||
**/DerivedData/
|
||||
**/xcuserdata/
|
||||
**/*.xcuserstate
|
||||
**/.generated/
|
||||
**/Flutter/App.framework
|
||||
**/Flutter/Flutter.framework
|
||||
**/Flutter/Flutter.podspec
|
||||
**/Flutter/app.flx
|
||||
**/Flutter/app.zip
|
||||
**/Flutter/flutter_assets/
|
||||
ServiceDefinitions.json
|
||||
**/GoogleService-Info.plist
|
||||
!**/GoogleService-Info.example.plist
|
||||
|
||||
# Local environment files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.*.example
|
||||
|
||||
# Agent-Ops Private Rules
|
||||
agent-ops/rules/private/
|
||||
|
|
|
|||
368
README.md
368
README.md
|
|
@ -1,172 +1,256 @@
|
|||
# mattermost_push_plugin
|
||||
|
||||
An Android-first Flutter plugin for receiving Mattermost push notifications, displaying system notifications, handling tap events, processing inline replies, delivering ACKs, and securely storing device tokens, authentication tokens, and signing keys.
|
||||
Android-first Flutter plugin for Mattermost push notifications.
|
||||
|
||||
---
|
||||
The plugin owns the push-notification domain that should not be duplicated in
|
||||
each consuming app: native FCM handling, notification display, notification tap
|
||||
events, inline replies, dismiss handling, ACK delivery, device-token storage,
|
||||
auth-token storage, and Mattermost signing-key storage.
|
||||
|
||||
## Support Matrix
|
||||
## Platform Status
|
||||
|
||||
| Platform | Support Status | Native Features Implemented |
|
||||
|---|---|---|
|
||||
| **Android** | **Full (Production Ready)** | Kotlin, Native FCM Service, Room DB, JJWT Verification, OkHttp ACK Client, Notification Builder, Inline Reply Receiver, Dismiss Receiver |
|
||||
| **iOS** | No-op Scaffold (Stub) | Future roadmap milestone |
|
||||
| **macOS** | No-op Scaffold (Stub) | Future roadmap milestone |
|
||||
| Platform | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| Android | Production target | Native FCM service, Room storage, JJWT verification, OkHttp ACK client, notification builder, inline reply receiver, dismiss receiver |
|
||||
| iOS | Stub | Plugin scaffold exists, behavior is not implemented yet |
|
||||
| macOS | Stub | Plugin scaffold exists, behavior is not implemented yet |
|
||||
|
||||
---
|
||||
|
||||
## Core Responsibilities
|
||||
|
||||
This plugin isolates the Mattermost push notification domain logic from the host application.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Mattermost Server] -->|Secure JWT Push| B(Plugin Native FCM Service)
|
||||
B -->|1. Signature Verification JJWT| C{Valid?}
|
||||
C -->|Yes| D[2. Store & Build Notification]
|
||||
C -->|No| E[Drop Push]
|
||||
D -->|3. OkHttp ACK API| A
|
||||
D -->|4. Display System Notification| F(Android Status Bar)
|
||||
F -->|Tap Notification| G[5. Method Channel Opened Event]
|
||||
F -->|Inline Reply| H[6. Broadcast Reply Receiver]
|
||||
H -->|Deliver via OkHttp| A
|
||||
G -->|Flutter Stream| I(Host App Navigation)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Public Dart API Reference
|
||||
|
||||
Get the singleton instance via `MattermostPushPlugin.instance`.
|
||||
|
||||
### 1. Initialization
|
||||
|
||||
Initialize the plugin channel subscriptions, listen to token refreshes, and request notification permissions:
|
||||
|
||||
```dart
|
||||
import 'package:mattermost_push_plugin/mattermost_push_plugin.dart';
|
||||
|
||||
await MattermostPushPlugin.instance.initialize();
|
||||
```
|
||||
|
||||
### 2. Streams & Callbacks
|
||||
|
||||
Set up listeners and navigation callbacks inside your app initialization flow:
|
||||
|
||||
```dart
|
||||
// 1. Listen to raw native notification events (Message, Clear, Session, etc.)
|
||||
MattermostPushPlugin.instance.onNotification.listen((data) {
|
||||
print("Raw push received: $data");
|
||||
});
|
||||
|
||||
// 2. Listen to user interaction (notification tap) events
|
||||
MattermostPushPlugin.instance.onNotificationOpened.listen((event) {
|
||||
print("Notification clicked! Channel: ${event.channelId}, Root: ${event.rootId}");
|
||||
});
|
||||
|
||||
// 3. Register navigation handlers (automatically triggered by onNotificationOpened)
|
||||
MattermostPushPlugin.instance.onNavigateToChannel = (String serverUrl, String channelId) {
|
||||
// Navigate the app to the specific channel
|
||||
};
|
||||
|
||||
MattermostPushPlugin.instance.onNavigateToThread = (String serverUrl, String rootId) {
|
||||
// Navigate the app to the specific CRT thread
|
||||
};
|
||||
|
||||
// 4. Triggered when the device token is registered/refreshed
|
||||
MattermostPushPlugin.instance.onDeviceTokenReady = (String deviceToken) {
|
||||
// e.g. "android_rn-v2:YOUR_FCM_TOKEN"
|
||||
// Send this token to the Mattermost server for token registration
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Credential & Signing Key Storing
|
||||
|
||||
Securely write server-specific secrets to native persistent storage. These are required by the native service to decrypt and verify the authenticity of push messages.
|
||||
|
||||
```dart
|
||||
// Save authenticating token for HTTP ACK requests
|
||||
await MattermostPushPlugin.instance.setAuthToken(
|
||||
"https://mattermost.example.com",
|
||||
"YOUR_USER_AUTH_TOKEN",
|
||||
identifier: "user_session_id", // optional
|
||||
);
|
||||
|
||||
// Save public signing key for verification
|
||||
await MattermostPushPlugin.instance.setSigningKey(
|
||||
"https://mattermost.example.com",
|
||||
"YOUR_SERVER_PUBLIC_SIGNING_KEY",
|
||||
);
|
||||
|
||||
// Clear token on logout
|
||||
await MattermostPushPlugin.instance.clearAuthToken("https://mattermost.example.com");
|
||||
|
||||
// Fetch the formatted device token
|
||||
String? token = await MattermostPushPlugin.instance.getDeviceToken();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Host App Integration & Responsibilities
|
||||
|
||||
The host application (`apps/mobile`) acts as the consumer of the plugin and is responsible for:
|
||||
|
||||
1. **Firebase Configuration**: Include the `google-services.json` in `android/app/` and initialize Firebase in the Dart main block.
|
||||
2. **Authentication Flow**: Call `setAuthToken` and `setSigningKey` on successful Mattermost login, and `clearAuthToken` on logout.
|
||||
3. **App Navigation**: Implement `onNavigateToChannel` and `onNavigateToThread` callbacks to route users inside the Flutter UI.
|
||||
4. **FCM Token Registration**: Send the formatted token received in `onDeviceTokenReady` to the Mattermost server.
|
||||
|
||||
### Firebase Messaging Manifest Collision Guard
|
||||
This plugin implements a custom Android FCM service (`MattermostFirebaseMessagingService`) that consumes incoming FCM payloads. To prevent manifest merge collisions with the standard Flutter `firebase_messaging` library, the plugin's `AndroidManifest.xml` disables the generic Flutter Firebase service via `tools:node="remove"`.
|
||||
Ensure that the host app does not redeclare duplicate FCM services unless explicitly configured to do so.
|
||||
|
||||
---
|
||||
|
||||
## Test Harness Strategy
|
||||
|
||||
This repository keeps the plugin and its independent consumer test app together:
|
||||
## Repository Layout
|
||||
|
||||
```text
|
||||
mattermost-push-plugin/
|
||||
lib/ # Public Dart API and Flutter-facing behavior
|
||||
android/ # Android native plugin implementation
|
||||
ios/ # iOS plugin scaffold
|
||||
macos/ # macOS plugin scaffold
|
||||
test/ # Dart unit tests for the plugin contract
|
||||
example/ # Thin Flutter app used as the integration test harness
|
||||
test/ # Widget tests for the harness app
|
||||
integration_test/ # Device/emulator integration tests
|
||||
```
|
||||
|
||||
The `example/` app is the official place to validate plugin integration without coupling this package to any consuming product app. Consumer apps should only test their own wiring, such as calling initialization, storing credentials, and connecting navigation callbacks.
|
||||
The `example/` app is the official independent consumer app for this repository.
|
||||
Use it to validate plugin integration without coupling tests to any real product
|
||||
app. Consuming apps should only test their own wiring, such as initialization,
|
||||
credential handoff, and navigation callbacks.
|
||||
|
||||
Recommended verification layers:
|
||||
## How It Works
|
||||
|
||||
1. `flutter test` from the repository root for Dart API behavior, event parsing, callback routing, and token formatting.
|
||||
2. `flutter test` from `example/` for the test harness app.
|
||||
3. Android unit tests from `example/android` for native payload, storage, signing, and ACK behavior.
|
||||
4. `flutter test integration_test` from `example/` on a device or emulator for plugin registration, method/event channels, notification-open routing, and manifest integration.
|
||||
5. Manual smoke tests for true Firebase FCM delivery and real Mattermost server ACK flows, because those depend on external infrastructure.
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Mattermost Server] -->|Secure JWT Push| B(Android FCM Service)
|
||||
B -->|Verify signing key| C{Valid?}
|
||||
C -->|Yes| D[Store payload and build notification]
|
||||
C -->|No| E[Drop push]
|
||||
D -->|Send ACK| A
|
||||
D -->|Display notification| F(Android status bar)
|
||||
F -->|Tap| G[Flutter opened event]
|
||||
F -->|Inline reply| H[Reply receiver]
|
||||
H -->|Send reply| A
|
||||
G -->|Stream and callbacks| I(Host app navigation)
|
||||
```
|
||||
|
||||
Recommended local commands:
|
||||
## Host App Responsibilities
|
||||
|
||||
The plugin isolates push handling, but the host application still owns app-level
|
||||
integration:
|
||||
|
||||
1. Configure Firebase for the host app, including `google-services.json` under
|
||||
`android/app/`.
|
||||
2. Initialize Firebase as required by the host app before push registration.
|
||||
3. Call `MattermostPushPlugin.instance.initialize()` during app startup.
|
||||
4. Save auth tokens and signing keys after login.
|
||||
5. Clear auth tokens on logout.
|
||||
6. Send the formatted device token to the Mattermost server.
|
||||
7. Connect notification-open callbacks to the host app router.
|
||||
|
||||
## Installation
|
||||
|
||||
For local development or another app in the same workspace, use a path
|
||||
dependency:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
mattermost_push_plugin:
|
||||
path: ../mattermost-push-plugin
|
||||
```
|
||||
|
||||
For a private Git dependency, point the consuming app at the repository and pin
|
||||
the branch, tag, or commit according to your release process.
|
||||
|
||||
## Dart Usage
|
||||
|
||||
Import the public API:
|
||||
|
||||
```dart
|
||||
import 'package:mattermost_push_plugin/mattermost_push_plugin.dart';
|
||||
```
|
||||
|
||||
Initialize the plugin:
|
||||
|
||||
```dart
|
||||
await MattermostPushPlugin.instance.initialize();
|
||||
```
|
||||
|
||||
Listen to raw notification events:
|
||||
|
||||
```dart
|
||||
MattermostPushPlugin.instance.onNotification.listen((data) {
|
||||
// data includes the native payload plus a push type.
|
||||
});
|
||||
```
|
||||
|
||||
Listen to notification-open events:
|
||||
|
||||
```dart
|
||||
MattermostPushPlugin.instance.onNotificationOpened.listen((event) {
|
||||
final serverUrl = event.serverUrl;
|
||||
final channelId = event.channelId;
|
||||
final rootId = event.rootId;
|
||||
});
|
||||
```
|
||||
|
||||
Register navigation callbacks:
|
||||
|
||||
```dart
|
||||
MattermostPushPlugin.instance.onNavigateToChannel = (
|
||||
String serverUrl,
|
||||
String channelId,
|
||||
) {
|
||||
// Navigate to the channel in the host app.
|
||||
};
|
||||
|
||||
MattermostPushPlugin.instance.onNavigateToThread = (
|
||||
String serverUrl,
|
||||
String rootId,
|
||||
) {
|
||||
// Navigate to the CRT thread in the host app.
|
||||
};
|
||||
```
|
||||
|
||||
Handle device-token registration:
|
||||
|
||||
```dart
|
||||
MattermostPushPlugin.instance.onDeviceTokenReady = (String deviceToken) {
|
||||
// Example format: android_rn-v2:YOUR_FCM_TOKEN
|
||||
// Send this token to the Mattermost server.
|
||||
};
|
||||
```
|
||||
|
||||
Store credentials and signing keys:
|
||||
|
||||
```dart
|
||||
await MattermostPushPlugin.instance.setAuthToken(
|
||||
'https://mattermost.example.com',
|
||||
'USER_AUTH_TOKEN',
|
||||
identifier: 'user_session_id',
|
||||
);
|
||||
|
||||
await MattermostPushPlugin.instance.setSigningKey(
|
||||
'https://mattermost.example.com',
|
||||
'SERVER_PUBLIC_SIGNING_KEY',
|
||||
);
|
||||
|
||||
await MattermostPushPlugin.instance.clearAuthToken(
|
||||
'https://mattermost.example.com',
|
||||
);
|
||||
|
||||
final token = await MattermostPushPlugin.instance.getDeviceToken();
|
||||
```
|
||||
|
||||
## Event Types
|
||||
|
||||
The Dart API currently recognizes these native event types:
|
||||
|
||||
| Type | Meaning |
|
||||
| --- | --- |
|
||||
| `message` | A Mattermost message notification |
|
||||
| `clear` | Notification clear or dismiss event |
|
||||
| `session` | Session-related event |
|
||||
| `token_refresh` | Device-token refresh event |
|
||||
| `opened` | User opened a notification |
|
||||
|
||||
`NotificationOpenedEvent` parses `server_url`, `channel_id`, `root_id`, and
|
||||
`is_crt_enabled`. If CRT is enabled and `root_id` is present, the plugin calls
|
||||
`onNavigateToThread`; otherwise it calls `onNavigateToChannel` when a channel is
|
||||
available.
|
||||
|
||||
## Android Notes
|
||||
|
||||
The Android manifest declares the plugin's own
|
||||
`MattermostFirebaseMessagingService` and removes the default FlutterFire
|
||||
messaging components with `tools:node="remove"`. This avoids duplicate FCM
|
||||
service registration when the host app also depends on `firebase_messaging`.
|
||||
|
||||
Host apps should not redeclare duplicate FCM services unless they intentionally
|
||||
coordinate that behavior with this plugin.
|
||||
|
||||
Android Gradle tests require a configured Android SDK through `ANDROID_HOME` or
|
||||
`example/android/local.properties`.
|
||||
|
||||
## Development Commands
|
||||
|
||||
Run Dart analysis and unit tests from the repository root:
|
||||
|
||||
```sh
|
||||
flutter analyze
|
||||
flutter test
|
||||
(cd example && flutter analyze && flutter test)
|
||||
(cd example/android && ./gradlew testDebugUnitTest)
|
||||
```
|
||||
|
||||
Android Gradle tests require a configured Android SDK via `ANDROID_HOME` or `example/android/local.properties`.
|
||||
Run harness-app checks:
|
||||
|
||||
---
|
||||
```sh
|
||||
cd example
|
||||
flutter analyze
|
||||
flutter test
|
||||
flutter test integration_test
|
||||
```
|
||||
|
||||
## Verification & Manual Smoke Testing Checklist
|
||||
Run Android native unit tests:
|
||||
|
||||
Since full end-to-end FCM flows cannot be automated in headless test runners, verify functionality manually using the following checklist:
|
||||
```sh
|
||||
cd example/android
|
||||
./gradlew testDebugUnitTest
|
||||
```
|
||||
|
||||
- [ ] **FCM Payload Receipt**: Verify that sending an FCM notification payload targeting the host application successfully wakes up `MattermostFirebaseMessagingService`.
|
||||
- [ ] **Signature Verification**: Ensure that a valid push payload signed by the Mattermost server's private key compiles and passes the native JJWT verification using the stored signing key.
|
||||
- [ ] **Notification Display**: Verify the system notification builds with the correct title, message, avatar (if supplied), and CRT threading hierarchy.
|
||||
- [ ] **ACK Delivery**: Verify the plugin sends a HTTP `POST` receipt delivery ACK back to the Mattermost server and logs a `200 OK` or `201 Created` response.
|
||||
- [ ] **Notification Tap & Route**: Tap the system notification and verify the host app launches/resumes, triggers the `onNotificationOpened` stream, and executes the designated navigation callback.
|
||||
- [ ] **Inline Reply Action**: Click "Reply" directly on the system notification. Type a reply, press send, and verify the native broadcast receiver intercepts the text, writes it to the local Room database, and sends it via HTTP to the Mattermost API.
|
||||
- [ ] **Notification Dismiss (Clear)**: Swipe away or dismiss a notification and verify the `NotificationDismissService` is triggered, clearing the corresponding notification records natively.
|
||||
- [ ] **Token Storage & Generation**: Ensure the generated token has the correct `android_rn-v2:` prefix and is saved securely in the device's native database/shared preferences.
|
||||
## Test Strategy
|
||||
|
||||
Use the repository tests as the source of truth for plugin behavior:
|
||||
|
||||
1. Root `test/` covers Dart API behavior, event parsing, callback routing, and
|
||||
device-token formatting.
|
||||
2. `android/src/test/` should cover native payload parsing, signing-key lookup,
|
||||
local storage, notification behavior, and ACK request behavior.
|
||||
3. `example/test/` covers the thin Flutter harness app.
|
||||
4. `example/integration_test/` should cover real plugin registration,
|
||||
method-channel behavior, event-channel behavior, notification-open routing,
|
||||
and manifest integration on a device or emulator.
|
||||
5. Manual smoke tests cover true Firebase FCM delivery and real Mattermost ACK
|
||||
flows because they depend on external infrastructure.
|
||||
|
||||
## Manual Smoke Checklist
|
||||
|
||||
Use this checklist before promoting a plugin change to a consuming app:
|
||||
|
||||
- [ ] FCM payload wakes `MattermostFirebaseMessagingService`.
|
||||
- [ ] Valid Mattermost push payload passes signing-key verification.
|
||||
- [ ] Invalid or unsigned payload is dropped.
|
||||
- [ ] System notification displays the expected title, message, avatar, and CRT
|
||||
threading behavior.
|
||||
- [ ] ACK request is sent to the Mattermost server and receives a successful
|
||||
response.
|
||||
- [ ] Tapping a notification launches or resumes the app and emits
|
||||
`onNotificationOpened`.
|
||||
- [ ] Channel notifications call `onNavigateToChannel`.
|
||||
- [ ] CRT thread notifications call `onNavigateToThread`.
|
||||
- [ ] Inline reply action sends the reply through the native receiver.
|
||||
- [ ] Dismiss action clears native notification records as expected.
|
||||
- [ ] Device token is stored with the `android_rn-v2:` prefix.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- Android is the only implemented runtime target.
|
||||
- iOS and macOS are scaffolded but no-op.
|
||||
- Full FCM delivery cannot be reliably automated in a headless test runner.
|
||||
- The `example/` app is intentionally small and should not grow into a product
|
||||
app.
|
||||
|
|
|
|||
47
agent-ops/roadmap/ROADMAP.md
Normal file
47
agent-ops/roadmap/ROADMAP.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# 로드맵
|
||||
|
||||
## 전체 목표
|
||||
|
||||
여러 Flutter 프로젝트에서 공통으로 사용할 수 있는 Mattermost 알림 기반 플러그인을 만든다. 이 플러그인은 소비 프로젝트의 인증, 라우팅, UI에 과도하게 결합되지 않으면서 Android push runtime을 안정적으로 제공하고, 자체 `example/` 테스트 하네스와 자동/수동 검증 체계로 기능 신뢰도를 유지한다.
|
||||
|
||||
## Phase 흐름
|
||||
|
||||
위에서 아래로 진행된 순서와 예정 흐름을 나타낸다.
|
||||
완료된 Phase도 로드맵에서 제거하지 않고, archive의 Phase 문서로 연결한다.
|
||||
검토중 또는 진행중 Phase는 계획 Phase보다 위에 두어, 아래로 갈수록 미래 계획에 가까워지게 정렬한다.
|
||||
|
||||
- [진행중] 검증 기반 정착
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
- 요약: 플러그인 목적, 독립 테스트 하네스, 품질 게이트를 명확히 해서 소비 프로젝트 의존 없이 검증 가능한 기반을 만든다.
|
||||
- [계획] Android 런타임 신뢰도 강화
|
||||
- 경로: `agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md`
|
||||
- 요약: Android push 수신, 저장, 알림 표시, ACK, inline reply 경로를 단위 테스트와 통합 테스트로 신뢰할 수 있게 만든다.
|
||||
- [계획] 소비 프로젝트 도입 안정화
|
||||
- 경로: `agent-ops/roadmap/phase/consumer-adoption/PHASE.md`
|
||||
- 요약: 여러 프로젝트가 같은 플러그인을 예측 가능하게 설치, 설정, 업그레이드할 수 있는 도입 계약을 정리한다.
|
||||
- [계획] 플랫폼 확장 판단
|
||||
- 경로: `agent-ops/roadmap/phase/platform-expansion/PHASE.md`
|
||||
- 요약: 현재 stub 상태인 iOS/macOS를 어떤 수준까지 지원할지 결정하고, 확장 시 필요한 parity 기준을 정의한다.
|
||||
|
||||
## 로딩 정책
|
||||
|
||||
- 일반 작업에서는 `agent-ops/roadmap/ROADMAP.md`를 매번 읽지 않는다.
|
||||
- 기능 추가, 구조 변경, 스킬 추가/수정, 문서 구조 변경 작업을 수행할 때는 `agent-ops/roadmap/current.md`를 먼저 읽는다.
|
||||
- `current.md`는 현재 작업 위치가 아니라 활성 Phase와 활성 Milestone 후보 목록이다.
|
||||
- `current.md`에는 개인별 현재 작업 위치나 완료 상태를 기록하지 않는다.
|
||||
- `current.md`의 활성 Phase는 `agent-ops/roadmap/phase/<phase-slug>/PHASE.md`를 가리킨다.
|
||||
- `current.md`의 활성 Milestone은 `agent-ops/roadmap/phase/<phase-slug>/milestones/<milestone-slug>.md`를 가리킨다.
|
||||
- `current.md`는 `agent-ops/roadmap/archive/**` 경로를 활성 항목으로 포함하지 않는다.
|
||||
- 요청 내용, 현재 브랜치, 변경 파일, 관련 코드 경로를 보고 가장 관련 있는 활성 Phase와 Milestone 문서를 같은 세션에서 1회 읽는다.
|
||||
- 활성 Phase 또는 Milestone 밖의 작업이면 이 문서의 Phase 흐름을 확인하고 사용자에게 진행 또는 전환 여부를 확인한다.
|
||||
- 이 문서는 로드맵 생성/갱신, Phase 전환, Phase 추가/수정, 전체 구조 변경 요청이 있을 때만 읽는다.
|
||||
- 상세 작업과 완료 기준은 각 Milestone 문서의 `필수 기능`, `완료 기준`으로 관리한다.
|
||||
- 모든 필수 작업과 완료 기준이 충족된 Milestone은 먼저 `[검토중]`으로 두고, 사용자 완료 확인과 archive 승인을 받은 뒤 `[완료]`로 전환한다.
|
||||
- 완료된 Phase는 `agent-ops/roadmap/archive/phase/<phase-slug>/PHASE.md`로 이동하고, 하위 Milestone도 같은 archive Phase scaffold 아래에 둔다.
|
||||
- 진행중 Phase 안에서 완료된 Milestone은 활성 Phase 문서에 짧은 링크를 남기고, 상세 문서는 `agent-ops/roadmap/archive/phase/<phase-slug>/milestones/`로 이동한다.
|
||||
- archive `PHASE.md`는 Phase 자체가 완료 또는 폐기될 때만 만들며, 진행중 Phase의 완료 Milestone만 archive된 경우 archive Phase 디렉터리에 `milestones/`만 있을 수 있다.
|
||||
- `agent-ops/roadmap/archive/**`는 일반 작업에서 읽지 않는다. 과거 완료 내용, 완료 근거, 복원, 비교가 필요한 경우에만 `ROADMAP.md` 또는 `PHASE.md`의 archive 링크를 따라가서 읽는다.
|
||||
- 아카이브된 Phase/Milestone 문서는 최신 템플릿이나 스킬 규약에 맞춰 재포맷하지 않는다.
|
||||
- 선택된 Milestone의 `구현 잠금` 섹션이 없거나 상태가 `잠금`이면 코드 구현, `agent-task` 구현 계획 생성, 세부 API/파일 구조 확정을 시작하기 전에 현재 요청에 직접 영향을 주는 `결정 필요` 항목만 확인한다.
|
||||
- 현재 요청과 직접 관련 없는 미정 항목은 잠금 상태로 남겨도 되며, 기존 구조/도메인 rule/플랫폼 관례로 정할 수 있는 작업은 표준선으로 기록하고 진행할 수 있다.
|
||||
- Milestone 전체에서 사용자만 결정할 항목이 더 이상 없고 에이전트가 표준선에 따라 실행하면 되는 상태라면 `구현 잠금` 상태를 `해제`로 둔다.
|
||||
32
agent-ops/roadmap/current.md
Normal file
32
agent-ops/roadmap/current.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# 현재 로드맵 컨텍스트
|
||||
|
||||
## 활성 Phase
|
||||
|
||||
- [진행중] 검증 기반 정착
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
|
||||
## 활성 Milestone
|
||||
|
||||
- [진행중] 프로젝트 운영 계약 정리
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/project-operating-contract.md`
|
||||
- [진행중] 독립 테스트 하네스 정착
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/self-contained-test-harness.md`
|
||||
- [계획] 품질 게이트 자동화
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/quality-gates.md`
|
||||
|
||||
## 선택 규칙
|
||||
|
||||
- 이 문서는 활성 Phase와 활성 Milestone 후보 목록이며, 개인별 현재 작업 위치나 완료 상태를 기록하지 않는다.
|
||||
- 활성 Phase는 `agent-ops/roadmap/phase/<phase-slug>/PHASE.md`를 가리킨다.
|
||||
- 활성 Milestone은 `agent-ops/roadmap/phase/<phase-slug>/milestones/<milestone-slug>.md`를 가리킨다.
|
||||
- 활성 항목은 아카이브 경로를 포함하지 않는다.
|
||||
- `[검토중]` 항목은 사용자 완료 확인 전까지 활성 항목으로 남길 수 있다.
|
||||
- `[완료]` 또는 `[폐기]` 항목은 archive 링크를 남긴 뒤 활성 항목에서 제거한다.
|
||||
- 요청 내용, 현재 브랜치, 변경 파일, 관련 코드 경로를 보고 가장 관련 있는 Phase와 Milestone을 선택하고 같은 세션에서 1회 읽는다.
|
||||
- 활성 Phase 또는 Milestone 둘 이상에 걸치면 필요한 문서를 모두 읽고 작업 범위를 좁힌다.
|
||||
- 활성 범위 밖의 작업이면 `agent-ops/roadmap/ROADMAP.md`의 Phase 흐름을 확인하고 사용자에게 진행 또는 전환 여부를 확인한다.
|
||||
- 완료된 과거 내용이 필요할 때만 `ROADMAP.md` 또는 `PHASE.md`에 있는 archive 링크를 따라가서 읽는다.
|
||||
- 선택된 Milestone의 `구현 잠금` 섹션이 없거나 상태가 `잠금`이면 구현이나 구현 계획을 시작하기 전에 현재 요청에 직접 영향을 주는 `결정 필요` 항목만 확인한다. 관련 결정이 없고 표준선으로 처리 가능하면 잠금을 유지한 채 진행할 수 있으며, Milestone 전체에서 사용자만 결정할 항목이 더 이상 없을 때만 `구현 잠금` 상태를 `해제`로 둔다.
|
||||
30
agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md
Normal file
30
agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Phase: Android 런타임 신뢰도 강화
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 목표
|
||||
|
||||
Android push runtime의 핵심 경로를 기능별로 검증 가능하게 만든다. FCM payload 처리, 서명 검증, 로컬 저장, notification action, ACK/reply 네트워크 흐름을 소비 프로젝트 없이도 재현하고 확인할 수 있게 한다.
|
||||
|
||||
## Milestone 흐름
|
||||
|
||||
완료된 Milestone은 archive 경로를 가리키고, 검토중, 진행중, 계획 또는 보류 Milestone은 이 Phase 하위 `milestones/` 경로를 가리킨다.
|
||||
완료, 검토중, 진행중, 계획 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
|
||||
|
||||
- [계획] Native 단위 테스트 확장
|
||||
- 경로: `agent-ops/roadmap/phase/android-runtime-confidence/milestones/native-unit-coverage.md`
|
||||
- 요약: Android helper와 plugin method contract에 대한 단위 테스트 기반을 넓힌다.
|
||||
- [계획] 알림 액션 흐름 검증
|
||||
- 경로: `agent-ops/roadmap/phase/android-runtime-confidence/milestones/notification-flow-verification.md`
|
||||
- 요약: notification display, tap, dismiss, inline reply 경로의 검증 방법을 만든다.
|
||||
- [계획] ACK와 네트워크 회복성 검증
|
||||
- 경로: `agent-ops/roadmap/phase/android-runtime-confidence/milestones/ack-network-resilience.md`
|
||||
- 요약: Mattermost ACK/reply 요청 생성, 실패 처리, 재시도 또는 fallback 정책을 검증한다.
|
||||
|
||||
## Phase 경계
|
||||
|
||||
- Android 구현 신뢰도에 집중하며, iOS/macOS parity는 다루지 않는다.
|
||||
- 실제 Firebase와 실제 Mattermost 서버에 의존하는 검증은 manual smoke 또는 선택형 integration으로 분리한다.
|
||||
- public Dart API 변경이 필요하면 `검증 기반 정착` Phase의 계약 문서와 테스트도 함께 갱신한다.
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# Milestone: ACK와 네트워크 회복성 검증
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
Mattermost ACK와 inline reply delivery가 예측 가능한 요청을 만들고 실패 상황을 안전하게 처리하도록 검증한다. 네트워크 의존 로직은 mock server 또는 fake client로 분리해 소비 프로젝트 없이 확인할 수 있게 한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 잠금
|
||||
- 결정 필요: 아래 체크리스트
|
||||
- [ ] ACK 실패 시 retry, drop, local queue 중 어떤 정책을 우선할지 결정한다
|
||||
- [ ] inline reply 실패 시 사용자에게 표시할 책임이 plugin인지 소비 앱인지 결정한다
|
||||
|
||||
## 범위
|
||||
|
||||
- ACK request 생성과 auth token 사용 검증
|
||||
- reply delivery request 생성 검증
|
||||
- network failure, auth failure, server error 처리 기준 정의
|
||||
- fake HTTP client 또는 mock server 기반 테스트 추가
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [ack] ACK 전송 계약
|
||||
|
||||
Mattermost 서버로 보내는 receipt ACK 경로를 검증한다.
|
||||
|
||||
- [ ] [request-shape] ACK URL, method, header, body shape를 테스트한다
|
||||
- [ ] [auth] 저장된 auth token 사용 여부를 테스트한다
|
||||
- [ ] [success] 200/201 성공 응답 처리 기준을 테스트한다
|
||||
|
||||
### Epic: [failure] 실패 처리
|
||||
|
||||
네트워크 실패가 plugin runtime을 불안정하게 만들지 않도록 한다.
|
||||
|
||||
- [ ] [network-error] timeout 또는 connection failure 처리 기준을 테스트한다
|
||||
- [ ] [auth-error] 401/403 처리 기준을 정리한다
|
||||
- [ ] [server-error] 5xx 응답 처리 기준을 정리한다
|
||||
|
||||
### Epic: [reply] Inline Reply Delivery
|
||||
|
||||
Inline reply 요청 흐름의 입력과 실패 경계를 명확히 한다.
|
||||
|
||||
- [ ] [reply-request] reply text와 context가 Mattermost API 요청으로 변환되는지 테스트한다
|
||||
- [ ] [reply-failure] reply 실패 시 저장, 재시도, 노출 정책을 결정된 기준대로 구현한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] ACK 요청 생성이 네트워크 없이 테스트된다
|
||||
- [ ] 성공과 실패 응답 처리 기준이 테스트 또는 문서로 명확하다
|
||||
- [ ] inline reply delivery 실패 정책이 결정되고 구현에 반영되어 있다
|
||||
- [ ] 외부 Mattermost 서버 없이 기본 네트워크 로직을 검증할 수 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 소비 앱의 사용자-facing error UI
|
||||
- Mattermost 서버 자체 동작 검증
|
||||
- 장기 offline queue 제품 정책 확정 전 대규모 queue 구현
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `android/src/main/java/**`, `android/src/main/kotlin/**`, `android/src/test/**`
|
||||
- 표준선(선택): HTTP 테스트는 fake client 또는 mock server를 사용하고 실제 서버에 의존하지 않는다
|
||||
- 선행 작업: Native 단위 테스트 확장
|
||||
- 후속 작업: 소비 프로젝트 도입 안정화
|
||||
- 확인 필요: ACK 실패 정책, inline reply 실패 책임 경계
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# Milestone: Native 단위 테스트 확장
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
Android native runtime의 핵심 helper와 method contract를 단위 테스트로 검증한다. 단순 platform version boilerplate 테스트를 넘어 payload, token, signing key, storage, helper behavior를 변경 위험에 맞게 확인한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- Android plugin method call contract 테스트
|
||||
- payload parsing과 fallback 기준 테스트
|
||||
- token/signing key 저장과 조회 테스트
|
||||
- Room 또는 helper 계층의 테스트 가능성 개선
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [method-contract] Method Channel 계약
|
||||
|
||||
Flutter Dart API가 호출하는 native method의 입력/출력 계약을 검증한다.
|
||||
|
||||
- [ ] [save-token] `saveDeviceToken` 입력 검증과 저장 호출을 테스트한다
|
||||
- [ ] [get-token] `getDeviceToken` 반환 계약을 테스트한다
|
||||
- [ ] [auth-token] `setAuthToken`과 `clearAuthToken` 계약을 테스트한다
|
||||
- [ ] [signing-key] `setSigningKey` 저장 계약을 테스트한다
|
||||
|
||||
### Epic: [payload] Payload 처리
|
||||
|
||||
Mattermost push payload key와 fallback 규칙을 안정적으로 유지한다.
|
||||
|
||||
- [ ] [intent-payload] intent extras가 opened event payload로 변환되는지 테스트한다
|
||||
- [ ] [snake-case] `server_url`, `channel_id`, `root_id`, `is_crt_enabled` key 호환을 유지한다
|
||||
- [ ] [missing-server] `server_url` 누락 시 fallback 정책을 테스트한다
|
||||
|
||||
### Epic: [storage] 저장 계층
|
||||
|
||||
테스트하기 어려운 저장 경로를 작게 분리한다.
|
||||
|
||||
- [ ] [db-boundary] Room/DatabaseHelper 테스트 경계를 정리한다
|
||||
- [ ] [prefs-boundary] SharedPreferences signing key 저장 경계를 테스트한다
|
||||
- [ ] [test-fixtures] native unit test fixture를 추가한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] Android native test가 platform version boilerplate 이상의 plugin 계약을 검증한다
|
||||
- [ ] token, auth token, signing key 경로가 테스트로 보호된다
|
||||
- [ ] payload key 변경 시 테스트가 실패할 수 있다
|
||||
- [ ] Android unit test 실행 방법이 문서와 일치한다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 FCM 수신 E2E
|
||||
- 실제 Mattermost 서버 ACK
|
||||
- iOS/macOS native 테스트
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `android/src/main/**`, `android/src/test/**`, `example/android/**`
|
||||
- 표준선(선택): native unit test는 외부 Firebase/Mattermost 네트워크 없이 deterministic하게 유지한다
|
||||
- 선행 작업: 품질 게이트 자동화
|
||||
- 후속 작업: 알림 액션 흐름 검증, ACK와 네트워크 회복성 검증
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
# Milestone: 알림 액션 흐름 검증
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/android-runtime-confidence/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
Mattermost notification display, tap, dismiss, inline reply 흐름을 테스트 가능한 단위로 나눈다. 실제 system notification과 사용자의 상호작용이 필요한 부분은 manual smoke와 emulator integration으로 분리한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- notification builder 입력과 output contract 검증
|
||||
- notification tap event가 Dart opened stream으로 전달되는 경로 검증
|
||||
- dismiss receiver와 inline reply receiver 경로 검증
|
||||
- manual smoke checklist와 자동 테스트 경계 정리
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [display] Notification 표시
|
||||
|
||||
NotificationHelper가 Mattermost payload를 기대한 알림 형태로 구성하는지 확인한다.
|
||||
|
||||
- [ ] [title-message] title과 message 표시 계약을 테스트한다
|
||||
- [ ] [threading] CRT/thread 관련 grouping 기준을 테스트한다
|
||||
- [ ] [avatar] avatar 또는 fallback icon 처리를 테스트한다
|
||||
|
||||
### Epic: [interaction] 사용자 상호작용
|
||||
|
||||
Tap, dismiss, inline reply를 event 또는 native action으로 연결한다.
|
||||
|
||||
- [ ] [tap-opened] notification tap이 opened event로 이어지는 경로를 검증한다
|
||||
- [ ] [dismiss] dismiss receiver가 native record 정리 경로를 호출하는지 검증한다
|
||||
- [ ] [inline-reply] inline reply text가 reply delivery 경로로 전달되는지 검증한다
|
||||
|
||||
### Epic: [manual] 수동 검증 경계
|
||||
|
||||
자동화가 어려운 system UI 상호작용을 명확한 수동 절차로 남긴다.
|
||||
|
||||
- [ ] [checklist] README manual smoke checklist를 실제 runtime 경로와 맞춘다
|
||||
- [ ] [logs] 수동 검증 중 확인할 log 또는 observable signal을 정리한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] notification 생성 로직이 payload fixture로 검증된다
|
||||
- [ ] tap opened event 경로가 example 또는 native test에서 확인된다
|
||||
- [ ] inline reply와 dismiss 경로가 최소 하나 이상의 자동 테스트 또는 명확한 manual smoke로 보호된다
|
||||
- [ ] 자동화 불가능한 항목이 문서에 분리되어 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 Mattermost 서버 reply 성공 보장
|
||||
- 앱별 navigation UI 검증
|
||||
- iOS/macOS notification 구현
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `android/src/main/kotlin/**`, `android/src/main/java/**`, `example/integration_test/**`, `README.md`
|
||||
- 표준선(선택): system UI 의존 테스트는 flaky하면 manual smoke 또는 선택형 emulator job으로 둔다
|
||||
- 선행 작업: Native 단위 테스트 확장
|
||||
- 후속 작업: ACK와 네트워크 회복성 검증
|
||||
- 확인 필요: 없음
|
||||
27
agent-ops/roadmap/phase/consumer-adoption/PHASE.md
Normal file
27
agent-ops/roadmap/phase/consumer-adoption/PHASE.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Phase: 소비 프로젝트 도입 안정화
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 목표
|
||||
|
||||
여러 소비 프로젝트가 같은 플러그인을 반복해서 안전하게 도입하고 업그레이드할 수 있게 한다. 설치 방식, host app 책임, 릴리스 기준, breaking change 처리 기준을 명확히 한다.
|
||||
|
||||
## Milestone 흐름
|
||||
|
||||
완료된 Milestone은 archive 경로를 가리키고, 검토중, 진행중, 계획 또는 보류 Milestone은 이 Phase 하위 `milestones/` 경로를 가리킨다.
|
||||
완료, 검토중, 진행중, 계획 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
|
||||
|
||||
- [계획] 통합 계약 문서화
|
||||
- 경로: `agent-ops/roadmap/phase/consumer-adoption/milestones/integration-contract.md`
|
||||
- 요약: 소비 프로젝트가 지켜야 할 Firebase, 인증, signing key, navigation, token registration 계약을 문서화한다.
|
||||
- [계획] 릴리스와 소비 방식 정리
|
||||
- 경로: `agent-ops/roadmap/phase/consumer-adoption/milestones/release-consumption-workflow.md`
|
||||
- 요약: 여러 프로젝트가 안정적으로 가져다 쓸 버전 관리, 배포, 변경 로그, 업그레이드 절차를 정한다.
|
||||
|
||||
## Phase 경계
|
||||
|
||||
- 소비 프로젝트의 비즈니스 로직, 화면 구성, 세부 인증 구현은 플러그인 repository에 포함하지 않는다.
|
||||
- 도입 가이드는 공통 계약에 집중하고, 프로젝트별 예외는 소비 프로젝트 쪽 문서로 남긴다.
|
||||
- 배포 채널과 버전 정책은 사용자 결정이 필요한 영역으로 남겨둔다.
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# Milestone: 통합 계약 문서화
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/consumer-adoption/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
소비 프로젝트가 이 플러그인을 도입할 때 반드시 지켜야 하는 계약을 정리한다. Firebase 설정, auth token 저장, signing key 저장, device token 등록, notification navigation callback 연결 책임을 plugin과 host app 사이에서 명확히 나눈다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- host app integration guide 작성
|
||||
- Firebase/manifest 설정 주의사항 정리
|
||||
- 인증과 signing key lifecycle 문서화
|
||||
- notification opened event와 navigation callback contract 정리
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [host-contract] Host App 책임
|
||||
|
||||
소비 프로젝트가 구현해야 하는 영역을 명확히 한다.
|
||||
|
||||
- [ ] [firebase] Firebase 설정과 초기화 책임을 문서화한다
|
||||
- [ ] [auth] login/logout 시 auth token 저장과 clear 흐름을 문서화한다
|
||||
- [ ] [signing] server signing key 저장 흐름을 문서화한다
|
||||
- [ ] [device-token] `android_rn-v2:` device token 등록 책임을 문서화한다
|
||||
|
||||
### Epic: [navigation] Navigation 계약
|
||||
|
||||
알림 tap 이벤트를 소비 앱 라우팅으로 연결하는 기준을 정한다.
|
||||
|
||||
- [ ] [channel] channel notification callback 계약을 문서화한다
|
||||
- [ ] [thread] CRT thread notification callback 계약을 문서화한다
|
||||
- [ ] [payload] host app이 기대할 수 있는 payload key를 문서화한다
|
||||
|
||||
### Epic: [compatibility] 호환성 주의사항
|
||||
|
||||
소비 프로젝트에서 충돌하기 쉬운 설정을 미리 드러낸다.
|
||||
|
||||
- [ ] [manifest] `firebase_messaging` service 제거 설정의 의미를 문서화한다
|
||||
- [ ] [multi-server] 여러 Mattermost server 사용 시 identifier/fallback 기준을 문서화한다
|
||||
- [ ] [android-only] Android-first 제약과 iOS/macOS stub 상태를 문서화한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] 새 소비 프로젝트가 README만 보고 기본 integration 순서를 이해할 수 있다
|
||||
- [ ] 소비 프로젝트가 구현할 책임과 plugin이 제공할 책임이 분리되어 있다
|
||||
- [ ] payload key와 token format이 문서에 명시되어 있다
|
||||
- [ ] Android FCM service 충돌 가능성과 대응 기준이 문서화되어 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 프로젝트별 onboarding 문서 작성
|
||||
- 소비 앱 내부 라우터 구현
|
||||
- 소비 앱 인증 API 구현
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `README.md`, `example/README.md`, `lib/**`, `android/src/main/AndroidManifest.xml`
|
||||
- 표준선(선택): plugin 문서는 공통 계약만 설명하고, 프로젝트별 예외는 소비 프로젝트 문서에 둔다
|
||||
- 선행 작업: 검증 기반 정착, Android 런타임 신뢰도 강화
|
||||
- 후속 작업: 릴리스와 소비 방식 정리
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# Milestone: 릴리스와 소비 방식 정리
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/consumer-adoption/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
여러 소비 프로젝트가 같은 플러그인을 안정적으로 가져다 쓰고 업그레이드할 수 있게 한다. versioning, changelog, dependency pinning, release validation 기준을 정한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 잠금
|
||||
- 결정 필요: 아래 체크리스트
|
||||
- [ ] 배포 방식을 private Git dependency, private pub registry, mono workspace 중 무엇으로 운영할지 결정한다
|
||||
- [ ] versioning 정책을 SemVer 기반으로 둘지 내부 release tag 기준으로 둘지 결정한다
|
||||
|
||||
## 범위
|
||||
|
||||
- 소비 프로젝트 dependency 지정 방식 정리
|
||||
- version/tag/changelog 기준 정의
|
||||
- breaking change 기준과 migration note 작성 규칙 정의
|
||||
- release 전 필수 검증 체크리스트 정의
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [versioning] 버전 정책
|
||||
|
||||
소비 프로젝트가 어떤 단위를 pin해야 하는지 정한다.
|
||||
|
||||
- [ ] [semver] version bump 기준을 정리한다
|
||||
- [ ] [tags] release tag naming 기준을 정리한다
|
||||
- [ ] [breaking] breaking change 판정 기준을 정리한다
|
||||
|
||||
### Epic: [release] 릴리스 검증
|
||||
|
||||
릴리스 전에 통과해야 하는 검증 단계를 정의한다.
|
||||
|
||||
- [ ] [checklist] release validation checklist를 만든다
|
||||
- [ ] [changelog] CHANGELOG 작성 기준을 정리한다
|
||||
- [ ] [consumer-smoke] 대표 소비 프로젝트에서 확인할 최소 smoke 범위를 정리한다
|
||||
|
||||
### Epic: [consumption] 소비 방식
|
||||
|
||||
여러 프로젝트가 같은 artifact를 안정적으로 참조하게 한다.
|
||||
|
||||
- [ ] [dependency] Git 또는 registry dependency 예시를 문서화한다
|
||||
- [ ] [pinning] branch, tag, commit pinning 권장 기준을 정리한다
|
||||
- [ ] [upgrade] 업그레이드 절차와 rollback 기준을 정리한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] 소비 프로젝트가 어떤 dependency source와 version을 사용할지 결정되어 있다
|
||||
- [ ] 릴리스 전 필수 검증 기준이 문서화되어 있다
|
||||
- [ ] breaking change와 migration note 기준이 있다
|
||||
- [ ] `CHANGELOG.md` 운영 방식이 정해져 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 private registry 인프라 구축
|
||||
- 소비 프로젝트 전체 migration 수행
|
||||
- 자동 배포 secret 구성
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `pubspec.yaml`, `CHANGELOG.md`, `README.md`, `.github/**`
|
||||
- 표준선(선택): 배포 채널이 결정되기 전에는 Git tag와 changelog 중심의 보수적 운영을 가정한다
|
||||
- 선행 작업: 통합 계약 문서화
|
||||
- 후속 작업: 플랫폼 확장 판단
|
||||
- 확인 필요: 배포 방식, versioning 정책
|
||||
27
agent-ops/roadmap/phase/platform-expansion/PHASE.md
Normal file
27
agent-ops/roadmap/phase/platform-expansion/PHASE.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Phase: 플랫폼 확장 판단
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 목표
|
||||
|
||||
현재 scaffold 상태인 iOS와 macOS 지원 범위를 명확히 결정한다. Android 전용 플러그인으로 안정화할지, Apple platform도 단계적으로 runtime parity를 맞출지 판단하고 필요한 기준을 문서화한다.
|
||||
|
||||
## Milestone 흐름
|
||||
|
||||
완료된 Milestone은 archive 경로를 가리키고, 검토중, 진행중, 계획 또는 보류 Milestone은 이 Phase 하위 `milestones/` 경로를 가리킨다.
|
||||
완료, 검토중, 진행중, 계획 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
|
||||
|
||||
- [계획] Apple 플랫폼 지원 결정
|
||||
- 경로: `agent-ops/roadmap/phase/platform-expansion/milestones/apple-platform-decision.md`
|
||||
- 요약: iOS/macOS를 stub으로 유지할지, 제한 지원할지, Android와 parity를 맞출지 결정한다.
|
||||
- [계획] Apple 런타임 parity 기준
|
||||
- 경로: `agent-ops/roadmap/phase/platform-expansion/milestones/apple-runtime-parity.md`
|
||||
- 요약: Apple platform 구현을 시작할 경우 필요한 API, native capability, 테스트 기준을 정의한다.
|
||||
|
||||
## Phase 경계
|
||||
|
||||
- 이 Phase는 Android 안정화 이후에 진행하는 미래 계획으로 둔다.
|
||||
- iOS/macOS에서 구현되지 않은 기능을 Dart public API가 성공한 것처럼 보이게 만들지 않는다.
|
||||
- Apple platform 범위는 제품 요구와 운영 비용을 함께 보고 결정한다.
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
# Milestone: Apple 플랫폼 지원 결정
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/platform-expansion/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
iOS와 macOS를 현재처럼 stub으로 유지할지, 제한 지원할지, Android와 기능 parity를 맞출지 결정한다. 지원 수준을 결정하지 않은 상태에서 public API가 Apple platform에서도 완전 동작한다고 오해되지 않게 한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 잠금
|
||||
- 결정 필요: 아래 체크리스트
|
||||
- [ ] iOS 지원이 실제 소비 프로젝트 요구사항인지 결정한다
|
||||
- [ ] macOS 지원이 실제 소비 프로젝트 요구사항인지 결정한다
|
||||
- [ ] Apple platform에서 push notification, signing, ACK, reply 중 어떤 기능 범위를 우선할지 결정한다
|
||||
|
||||
## 범위
|
||||
|
||||
- 현재 iOS/macOS scaffold 상태 점검
|
||||
- Apple platform support matrix 정리
|
||||
- Android-only 제약의 public documentation 보강
|
||||
- 구현 시작 전 요구사항과 운영 비용 판단
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [decision] 지원 수준 결정
|
||||
|
||||
Apple platform을 어떤 수준으로 다룰지 결정한다.
|
||||
|
||||
- [ ] [ios-need] iOS 지원 필요성을 확인한다
|
||||
- [ ] [macos-need] macOS 지원 필요성을 확인한다
|
||||
- [ ] [support-level] stub, limited, parity 중 지원 수준을 결정한다
|
||||
|
||||
### Epic: [docs] 제약 문서화
|
||||
|
||||
결정 전후로 소비 프로젝트가 platform 상태를 오해하지 않게 한다.
|
||||
|
||||
- [ ] [matrix] README platform status를 최신 결정과 맞춘다
|
||||
- [ ] [api-behavior] unsupported platform에서 public API가 보이는 동작을 문서화한다
|
||||
- [ ] [risk] Apple platform 미지원으로 인한 소비 프로젝트 위험을 정리한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] iOS 지원 여부와 범위가 결정되어 있다
|
||||
- [ ] macOS 지원 여부와 범위가 결정되어 있다
|
||||
- [ ] README와 roadmap에 Apple platform 상태가 일관되게 표현되어 있다
|
||||
- [ ] 결정된 지원 수준에 따라 후속 Milestone이 유지, 수정, 또는 폐기된다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- Apple native push runtime 구현
|
||||
- APNs 인증서 또는 provisioning 설정
|
||||
- Android runtime 변경
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `ios/**`, `macos/**`, `README.md`, `pubspec.yaml`
|
||||
- 표준선(선택): 결정 전까지 iOS/macOS는 명시적인 stub으로 유지한다
|
||||
- 선행 작업: 소비 프로젝트 도입 안정화
|
||||
- 후속 작업: Apple 런타임 parity 기준
|
||||
- 확인 필요: iOS/macOS 실제 지원 요구와 우선순위
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
# Milestone: Apple 런타임 parity 기준
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/platform-expansion/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
Apple platform 구현을 시작하기로 결정된 경우 필요한 capability와 테스트 기준을 정의한다. Android와 동일해야 하는 계약과 Apple platform 특성 때문에 다르게 가야 하는 계약을 구분한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 잠금
|
||||
- 결정 필요: 아래 체크리스트
|
||||
- [ ] Apple 플랫폼 지원 결정 Milestone에서 limited 또는 parity 지원이 승인되어야 한다
|
||||
- [ ] APNs 기반 push와 Mattermost payload 처리 범위를 결정해야 한다
|
||||
|
||||
## 범위
|
||||
|
||||
- iOS/macOS native runtime capability mapping
|
||||
- Dart API platform behavior 기준
|
||||
- APNs, notification tap, ACK, token registration 테스트 기준
|
||||
- Apple platform에서 불가능하거나 다르게 처리해야 하는 기능 식별
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [capability] Capability Mapping
|
||||
|
||||
Android runtime 기능을 Apple platform 기준으로 재분류한다.
|
||||
|
||||
- [ ] [push] APNs 수신과 payload 처리 가능 범위를 정의한다
|
||||
- [ ] [token] device token format과 registration 기준을 정의한다
|
||||
- [ ] [notification] notification display와 tap handling 기준을 정의한다
|
||||
- [ ] [ack] ACK delivery 가능 범위를 정의한다
|
||||
- [ ] [reply] inline reply 가능 여부와 대체 정책을 정의한다
|
||||
|
||||
### Epic: [tests] 테스트 기준
|
||||
|
||||
Apple platform 구현을 검증할 방법을 정한다.
|
||||
|
||||
- [ ] [unit] Swift unit test 범위를 정한다
|
||||
- [ ] [integration] Flutter integration test 범위를 정한다
|
||||
- [ ] [manual] 실제 APNs가 필요한 manual smoke 범위를 정한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] Apple platform 기능별 parity 여부가 표로 정리되어 있다
|
||||
- [ ] Dart API가 platform별로 어떤 동작을 보장하는지 문서화되어 있다
|
||||
- [ ] Apple runtime 구현 전 필요한 테스트 기준이 명확하다
|
||||
- [ ] 지원하지 않을 기능은 unsupported behavior로 명확히 표현되어 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 Apple runtime 구현
|
||||
- APNs 인증 인프라 구축
|
||||
- Android API breaking change
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `ios/**`, `macos/**`, `lib/**`, `example/ios/**`, `example/macos/**`
|
||||
- 표준선(선택): Android의 public Dart API contract를 기준으로 삼되 Apple platform 특성상 다른 동작은 명시적으로 문서화한다
|
||||
- 선행 작업: Apple 플랫폼 지원 결정
|
||||
- 후속 작업: 없음
|
||||
- 확인 필요: Apple platform 지원 승인, APNs 처리 범위
|
||||
30
agent-ops/roadmap/phase/validation-foundation/PHASE.md
Normal file
30
agent-ops/roadmap/phase/validation-foundation/PHASE.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Phase: 검증 기반 정착
|
||||
|
||||
## 상태
|
||||
|
||||
[진행중]
|
||||
|
||||
## 목표
|
||||
|
||||
플러그인의 목적과 책임 경계를 문서와 테스트 구조로 고정한다. 소비 프로젝트에 의존하지 않고 `example/` 앱과 repository 자체 검증만으로 공통 알림 기능의 기본 품질을 확인할 수 있게 만든다.
|
||||
|
||||
## Milestone 흐름
|
||||
|
||||
완료된 Milestone은 archive 경로를 가리키고, 검토중, 진행중, 계획 또는 보류 Milestone은 이 Phase 하위 `milestones/` 경로를 가리킨다.
|
||||
완료, 검토중, 진행중, 계획 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다.
|
||||
|
||||
- [진행중] 프로젝트 운영 계약 정리
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/project-operating-contract.md`
|
||||
- 요약: 플러그인의 목적, repo 구조, 소비 프로젝트와의 책임 경계를 문서와 규칙으로 정리한다.
|
||||
- [진행중] 독립 테스트 하네스 정착
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/self-contained-test-harness.md`
|
||||
- 요약: `example/` 앱을 실제 소비 앱 대신 사용하는 얇은 통합 테스트 환경으로 정착시킨다.
|
||||
- [계획] 품질 게이트 자동화
|
||||
- 경로: `agent-ops/roadmap/phase/validation-foundation/milestones/quality-gates.md`
|
||||
- 요약: 분석, 단위 테스트, Android 테스트, integration test를 반복 가능한 명령과 CI 기준으로 묶는다.
|
||||
|
||||
## Phase 경계
|
||||
|
||||
- 이 Phase는 프로젝트 운영과 검증 기반을 다루며, Android runtime 기능 자체의 깊은 리팩터링은 다음 Phase에서 다룬다.
|
||||
- 소비 프로젝트별 UI, 인증 플로우, 라우팅 구현은 이 repository의 책임으로 끌어오지 않는다.
|
||||
- `example/`은 테스트 하네스로 유지하며 제품 앱처럼 비대해지지 않게 한다.
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# Milestone: 프로젝트 운영 계약 정리
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
이 프로젝트가 여러 소비 프로젝트의 공통 알림 기반이 된다는 목적을 문서와 규칙으로 명확히 한다. 플러그인 repository와 소비 프로젝트 사이의 책임 경계를 고정하고, 이후 작업자가 같은 기준으로 판단할 수 있게 한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[진행중]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- 루트 README의 프로젝트 목적, 사용 방식, 검증 전략 정리
|
||||
- `example/` 테스트 하네스 목적 문서화
|
||||
- build output, IDE 설정, generated 파일 제외 기준 정리
|
||||
- agent-ops 프로젝트 규칙과 로드맵의 책임 경계 정렬
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [docs] 프로젝트 목적 문서화
|
||||
|
||||
공유 플러그인으로서의 목적과 소비 프로젝트의 책임 경계를 문서화한다.
|
||||
|
||||
- [ ] [root-readme] 루트 README에 프로젝트 목표, host app 책임, Android 주의사항, 제한사항을 정리한다
|
||||
- [ ] [example-readme] `example/README.md`에 테스트 하네스 목적과 유지 규칙을 정리한다
|
||||
- [ ] [smoke-checklist] 수동 smoke checklist가 FCM, 알림, ACK, reply, dismiss 경로를 포함하게 한다
|
||||
|
||||
### Epic: [repo-hygiene] Repository 운영 기준
|
||||
|
||||
반복 작업 중 생성물이 source control에 섞이지 않게 한다.
|
||||
|
||||
- [ ] [gitignore] Flutter, Android, iOS/macOS, Firebase, local env 생성물을 `.gitignore`에 반영한다
|
||||
- [ ] [tracked-noise] 이미 추적 중인 파일과 새로 ignore되는 파일의 경계를 확인한다
|
||||
- [ ] [rules-align] 프로젝트 규칙과 README의 책임 경계가 충돌하지 않게 맞춘다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] README에서 이 repository의 목적이 "공통 Mattermost 알림 플러그인"으로 읽힌다
|
||||
- [ ] 소비 프로젝트와 plugin repository의 책임 경계가 문서에 분리되어 있다
|
||||
- [ ] `example/`이 독립 테스트 하네스라는 점이 문서에 명시되어 있다
|
||||
- [ ] `.gitignore`가 Flutter plugin, Android, iOS/macOS, Firebase 로컬 설정을 포함한다
|
||||
- [ ] 새 문서가 기존 코드의 실제 API와 충돌하지 않는다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 Android runtime 동작 변경
|
||||
- CI workflow 추가
|
||||
- 소비 프로젝트별 통합 문서 작성
|
||||
- 배포 채널 결정
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `README.md`, `example/README.md`, `.gitignore`, `agent-ops/rules/project/rules.md`
|
||||
- 표준선(선택): Flutter plugin은 root package와 `example/` host app 구조를 유지한다
|
||||
- 선행 작업: 없음
|
||||
- 후속 작업: 독립 테스트 하네스 정착, 품질 게이트 자동화
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
# Milestone: 품질 게이트 자동화
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
반복 가능한 로컬 명령과 CI 기준으로 플러그인 변경의 기본 품질을 확인한다. Dart 분석, root unit test, example test, Android unit test, integration test를 변경 범위에 맞춰 실행할 수 있게 한다.
|
||||
|
||||
## 상태
|
||||
|
||||
[계획]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 잠금
|
||||
- 결정 필요: 아래 체크리스트
|
||||
- [ ] CI provider를 GitHub Actions로 둘지, 다른 내부 CI를 사용할지 결정한다
|
||||
- [ ] Android emulator 기반 integration test를 PR 필수로 둘지, nightly/manual로 둘지 결정한다
|
||||
|
||||
## 범위
|
||||
|
||||
- 로컬 검증 명령 표준화
|
||||
- CI workflow 또는 내부 자동화 기준 정의
|
||||
- Android SDK/Firebase 설정이 필요한 테스트의 실행 조건 분리
|
||||
- 실패 시 어떤 레이어를 먼저 확인할지 문서화
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [local-checks] 로컬 검증 명령
|
||||
|
||||
개발자가 같은 명령으로 기본 품질을 확인하게 한다.
|
||||
|
||||
- [ ] [root-analyze] root `flutter analyze` 기준을 유지한다
|
||||
- [ ] [root-test] root `flutter test` 기준을 유지한다
|
||||
- [ ] [example-checks] example `flutter analyze`와 `flutter test` 기준을 유지한다
|
||||
- [ ] [android-test] Android unit test 실행 전제와 명령을 정리한다
|
||||
|
||||
### Epic: [ci] 자동 품질 게이트
|
||||
|
||||
반복 가능한 CI 게이트를 만든다.
|
||||
|
||||
- [ ] [workflow] 선택된 CI provider에 분석과 단위 테스트 workflow를 추가한다
|
||||
- [ ] [android-sdk] Android unit test가 필요한 SDK 설정을 문서화하거나 자동화한다
|
||||
- [ ] [optional-integration] emulator/integration test를 필수 또는 선택 job으로 분리한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] 문서에 있는 로컬 명령이 실제 repository 구조와 맞는다
|
||||
- [ ] 기본 PR 검증에서 root 분석과 root test가 실행된다
|
||||
- [ ] example 분석과 test가 기본 검증 범위에 포함된다
|
||||
- [ ] Android SDK가 없을 때 실패 원인이 명확하게 드러난다
|
||||
- [ ] 외부 Firebase/Mattermost 의존 테스트가 기본 PR 검증을 불안정하게 만들지 않는다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 Firebase 프로젝트 secret 관리 체계 확정
|
||||
- 릴리스 자동 배포
|
||||
- Android runtime 기능 리팩터링
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `.github/**`, `README.md`, `example/README.md`, `android/**`, `example/android/**`
|
||||
- 표준선(선택): 외부 서비스가 필요한 검증은 기본 PR gate가 아니라 선택형 job 또는 manual smoke로 둔다
|
||||
- 선행 작업: 프로젝트 운영 계약 정리, 독립 테스트 하네스 정착
|
||||
- 후속 작업: Android 런타임 신뢰도 강화
|
||||
- 확인 필요: CI provider와 emulator job 정책
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
# Milestone: 독립 테스트 하네스 정착
|
||||
|
||||
## 위치
|
||||
|
||||
- Roadmap: `agent-ops/roadmap/ROADMAP.md`
|
||||
- Phase: `agent-ops/roadmap/phase/validation-foundation/PHASE.md`
|
||||
|
||||
## 목표
|
||||
|
||||
소비 프로젝트에 의존하지 않고 플러그인 통합을 검증할 수 있도록 `example/` 앱을 얇은 실제 host app으로 정착시킨다. `example/`은 제품 앱이 아니라 method channel, event channel, manifest merge, notification-open routing을 확인하는 테스트 하네스가 된다.
|
||||
|
||||
## 상태
|
||||
|
||||
[진행중]
|
||||
|
||||
## 구현 잠금
|
||||
|
||||
- 상태: 해제
|
||||
- 결정 필요: 없음
|
||||
|
||||
## 범위
|
||||
|
||||
- `example/` 앱의 테스트 하네스 역할 정리
|
||||
- `example/test`와 `example/integration_test`의 검증 책임 분리
|
||||
- 실제 Firebase FCM이 필요한 테스트와 deterministic test control의 경계 정의
|
||||
- plugin root test와 example integration test 사이의 중복 방지
|
||||
|
||||
## 필수 기능
|
||||
|
||||
### Epic: [harness-ui] 얇은 Host App
|
||||
|
||||
통합 검증에 필요한 최소 UI와 callback 관찰 지점을 제공한다.
|
||||
|
||||
- [ ] [observable-state] device token, notification event, opened event를 확인할 수 있는 최소 상태 표시를 제공한다
|
||||
- [ ] [callback-hooks] channel/thread navigation callback이 호출되는지 관찰할 수 있게 한다
|
||||
- [ ] [no-product-logic] 제품 인증, 실제 라우팅, 프로젝트별 UI를 포함하지 않는다
|
||||
|
||||
### Epic: [integration-tests] Integration Test 기반
|
||||
|
||||
디바이스 또는 emulator에서 플러그인 연결을 확인하는 테스트를 둔다.
|
||||
|
||||
- [ ] [plugin-registration] example app에서 plugin registration이 정상 동작하는지 확인한다
|
||||
- [ ] [method-channel] Dart에서 native method channel 호출을 검증한다
|
||||
- [ ] [event-channel] native event를 Dart stream으로 전달하는 흐름을 검증한다
|
||||
- [ ] [opened-routing] notification opened payload가 channel/thread callback으로 연결되는지 검증한다
|
||||
|
||||
### Epic: [test-controls] 재현 가능한 테스트 제어
|
||||
|
||||
외부 FCM 없이도 핵심 경로를 재현할 수 있는 테스트 방식을 마련한다.
|
||||
|
||||
- [ ] [fake-payload] test/debug 전용 push payload 주입 방식을 설계한다
|
||||
- [ ] [manual-boundary] 실제 FCM과 Mattermost server가 필요한 항목은 manual smoke로 분리한다
|
||||
- [ ] [docs] 하네스 실행 명령과 전제 조건을 문서화한다
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- [ ] `example/` 앱만으로 plugin registration과 기본 channel 계약을 확인할 수 있다
|
||||
- [ ] `example/integration_test`가 singleton 접근 이상의 통합 경로를 검증한다
|
||||
- [ ] 실제 FCM이 없어도 테스트 가능한 경로와 수동 smoke 경로가 분리되어 있다
|
||||
- [ ] 소비 프로젝트 없이 새 plugin 변경의 기본 위험을 확인할 수 있다
|
||||
|
||||
## 완료 리뷰
|
||||
|
||||
- 상태: 없음
|
||||
- 요청일: 없음
|
||||
- 완료 근거: 없음
|
||||
- 리뷰 필요:
|
||||
- [ ] 사용자가 완료 결과를 확인했다
|
||||
- [ ] archive 이동을 승인했다
|
||||
- 리뷰 코멘트: 없음
|
||||
|
||||
## 범위 제외
|
||||
|
||||
- 실제 Mattermost 인증 플로우 구현
|
||||
- 소비 앱의 production navigation 구현
|
||||
- 외부 Firebase 프로젝트를 CI 필수 조건으로 만드는 일
|
||||
|
||||
## 작업 컨텍스트
|
||||
|
||||
- 관련 경로: `example/lib/**`, `example/test/**`, `example/integration_test/**`, `lib/**`, `android/src/main/**`
|
||||
- 표준선(선택): `example/`은 Flutter plugin 표준 host app으로 유지하고, 테스트용 기능은 제품 기능처럼 확장하지 않는다
|
||||
- 선행 작업: 프로젝트 운영 계약 정리
|
||||
- 후속 작업: 품질 게이트 자동화, Android 런타임 신뢰도 강화
|
||||
- 확인 필요: 없음
|
||||
|
|
@ -1,26 +1,56 @@
|
|||
# mattermost_push_plugin_example
|
||||
|
||||
Thin Flutter app for exercising `mattermost_push_plugin` in isolation from any
|
||||
Thin Flutter app for exercising `mattermost_push_plugin` independently from any
|
||||
real consuming product app.
|
||||
|
||||
## Purpose
|
||||
|
||||
This app is the repository's integration test harness. Keep it small and focused
|
||||
on the plugin contract:
|
||||
on proving the plugin contract:
|
||||
|
||||
- plugin registration in a real Flutter application
|
||||
- method channel and event channel behavior
|
||||
- method-channel calls from Dart to the native plugin
|
||||
- event-channel delivery from native code to Dart
|
||||
- notification-open routing callbacks
|
||||
- Android manifest merge behavior
|
||||
- manual smoke testing for Firebase FCM and Mattermost ACK flows
|
||||
- manual Firebase FCM and Mattermost ACK smoke testing
|
||||
|
||||
Product-specific UI, authentication, and navigation should stay in consuming
|
||||
apps. This app should only include the minimum surface needed to prove the
|
||||
plugin works independently.
|
||||
Product-specific UI, authentication flows, and navigation should stay in
|
||||
consuming apps. This app should only include the minimum surface needed to prove
|
||||
that the plugin works in isolation.
|
||||
|
||||
## Structure
|
||||
|
||||
```text
|
||||
example/
|
||||
lib/ # Small harness UI
|
||||
test/ # Widget tests for the harness
|
||||
integration_test/ # Device/emulator plugin integration tests
|
||||
android/ # Android app used to host the plugin
|
||||
ios/ # iOS host scaffold
|
||||
macos/ # macOS host scaffold
|
||||
```
|
||||
|
||||
## Running The App
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```sh
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
Run on a connected device or emulator:
|
||||
|
||||
```sh
|
||||
flutter run
|
||||
```
|
||||
|
||||
For Android FCM smoke testing, make sure the Android app has the required
|
||||
Firebase configuration, including `android/app/google-services.json`.
|
||||
|
||||
## Verification
|
||||
|
||||
Run these checks from this directory:
|
||||
Run checks from this directory:
|
||||
|
||||
```sh
|
||||
flutter analyze
|
||||
|
|
@ -34,5 +64,13 @@ Run Android native unit tests from `example/android`:
|
|||
./gradlew testDebugUnitTest
|
||||
```
|
||||
|
||||
Android Gradle tests require a configured Android SDK via `ANDROID_HOME` or
|
||||
Android Gradle tests require a configured Android SDK through `ANDROID_HOME` or
|
||||
`example/android/local.properties`.
|
||||
|
||||
## Maintenance Rules
|
||||
|
||||
- Keep the app thin.
|
||||
- Prefer deterministic test controls over product-like UI.
|
||||
- Do not add consuming-app business logic here.
|
||||
- Add integration tests here when a plugin behavior needs a real Flutter host.
|
||||
- Keep manual FCM and Mattermost server checks documented in the root README.
|
||||
|
|
|
|||
Loading…
Reference in a new issue