- Rename mobile app directory to client throughout the project - Restructure client app code into feature-based organization - Move code to src/features/workspaces/domain/presentation - Move services to src/integrations/ (mattermost, workspace, proto_socket) - Add app bootstrap and main entry point - Add push notification integration (Mattermost push client/host/plugin) - Add proto socket integration for real-time communication - Add integration tests for push and socket components - Archive old milestone: client-integration-standardization.md - Add new workflow core milestone: roadmap-driven-agent-ops-automation.md - Update agent-ops rules (project, core, mobile, contracts, workspace-ops) - Update roadmap files (ROADMAP.md, current.md, phase PHASE.md files) - Update bin scripts (build, dev, lint, test) - Add test environments documentation - Update contracts notes for Flutter Core API
226 lines
8.1 KiB
Markdown
226 lines
8.1 KiB
Markdown
# Flutter/Core API Contract Candidates
|
|
|
|
이 문서는 source schema가 아니라 Flutter-first 전환 중 공유 계약 후보를 모으는 compatibility note다.
|
|
실제 Go core 구현(`services/core`)과 향후 작성될 Flutter 클라이언트(`apps/client`) 간의 인터페이스 정합성을 보장하기 위한 임시 계약 후보이며, 단일 source-of-truth 스키마가 정의되기 전까지의 과도기적 스펙을 정의한다.
|
|
|
|
## API 안정성 레벨 정의
|
|
- **안정 (Stable)**: 인터페이스와 데이터 포맷이 고정되어 있어 즉시 연동에 사용할 수 있음.
|
|
- **후보 (Candidate)**: 연동 후보 스펙으로, 실연동 과정에서 필드가 추가되거나 변경될 수 있음.
|
|
|
|
---
|
|
|
|
## 1. 공통 및 인프라 API
|
|
|
|
### 1.1 `GET /healthz`
|
|
- **설명**: 서비스 헬스 체크.
|
|
- **인증**: 없음 (Public)
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Response Shape** (Status 200 OK):
|
|
```json
|
|
{
|
|
"status": "ok"
|
|
}
|
|
```
|
|
|
|
### 1.2 `GET /readyz`
|
|
- **설명**: 서비스 및 데이터베이스 준비 상태 체크.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Response Shape** (Status 200 OK):
|
|
```json
|
|
{
|
|
"status": "ready"
|
|
}
|
|
```
|
|
*(Status 503 Service Unavailable)*:
|
|
```json
|
|
{
|
|
"error": "database is not ready"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 태스크 관리 API (Tasks API)
|
|
|
|
### 2.1 `POST /api/tasks`
|
|
- **설명**: 새로운 태스크 생성.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Request Shape**:
|
|
```json
|
|
{
|
|
"title": "Task Title",
|
|
"source": "source_identifier",
|
|
"payload": {},
|
|
"metadata": {},
|
|
"external": {
|
|
"provider": "plane",
|
|
"id": "external-task-id",
|
|
"url": "https://...",
|
|
"metadata": {}
|
|
}
|
|
}
|
|
```
|
|
- **Response Shape** (Status 201 Created):
|
|
```json
|
|
{
|
|
"id": "task-uuid-string",
|
|
"status": "pending",
|
|
"external_provider": "plane",
|
|
"external_id": "external-task-id"
|
|
}
|
|
```
|
|
|
|
### 2.2 `GET /api/tasks`
|
|
- **설명**: 태스크 목록 조회.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Query Parameters**:
|
|
- `limit` (Optional, 기본값 20, 양의 정수)
|
|
- **Response Shape** (Status 200 OK):
|
|
```json
|
|
[
|
|
{
|
|
"id": "task-uuid-string",
|
|
"title": "Task Title",
|
|
"source": "source_identifier",
|
|
"status": "pending",
|
|
"payload": {},
|
|
"result": {},
|
|
"error": null,
|
|
"created_at": "2026-05-24T12:00:00Z",
|
|
"updated_at": "2026-05-24T12:00:00Z",
|
|
"external_provider": "plane",
|
|
"external_id": "external-task-id",
|
|
"external_url": "https://...",
|
|
"external_metadata": {},
|
|
"metadata": {}
|
|
}
|
|
]
|
|
```
|
|
|
|
### 2.3 `GET /api/tasks/{id}`
|
|
- **설명**: 단일 태스크 세부 정보 조회.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Response Shape** (Status 200 OK):
|
|
```json
|
|
{
|
|
"id": "task-uuid-string",
|
|
"title": "Task Title",
|
|
"source": "source_identifier",
|
|
"status": "pending",
|
|
"payload": {},
|
|
"result": {},
|
|
"error": null,
|
|
"created_at": "2026-05-24T12:00:00Z",
|
|
"updated_at": "2026-05-24T12:00:00Z",
|
|
"external_provider": "plane",
|
|
"external_id": "external-task-id",
|
|
"external_url": "https://...",
|
|
"external_metadata": {},
|
|
"metadata": {}
|
|
}
|
|
```
|
|
|
|
### 2.4 `POST /api/tasks/{id}/enqueue`
|
|
- **설명**: 태스크를 큐에 진입시켜 실행 대기 상태로 변경.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Response Shape** (Status 200 OK):
|
|
```json
|
|
{
|
|
"id": "task-uuid-string",
|
|
"status": "queued"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. 외부 연동 API (Integrations API)
|
|
|
|
### 3.1 `POST /api/integrations/plane/tasks`
|
|
- **설명**: Plane 워크아이템 정보를 기반으로 새로운 태스크 생성.
|
|
- **인증**: Basic Auth
|
|
- **안정성 수준**: 안정 (Stable)
|
|
- **Request Shape**:
|
|
```json
|
|
{
|
|
"workspace_slug": "my-workspace",
|
|
"project_id": "project-uuid-string",
|
|
"work_item_id": "work-item-id-string",
|
|
"state_id": "state-uuid-string",
|
|
"external_url": "https://...",
|
|
"comment": "Optional comment"
|
|
}
|
|
```
|
|
- **Response Shape** (Status 201 Created):
|
|
```json
|
|
{
|
|
"id": "task-uuid-string",
|
|
"status": "pending",
|
|
"external_provider": "plane",
|
|
"external_id": "work-item-id-string"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Workspace / Project Metadata 계약 후보
|
|
|
|
> [!IMPORTANT]
|
|
> **Workspace/Project Metadata 상태**: 현재 Go core 백엔드에 이와 관련한 별도의 Source-of-Truth 저장소나 전용 테이블 구조가 존재하지 않으며, API 명세 또한 완전히 확정되지 않았습니다. 아래는 Flutter 앱과 코어 간 향후 연동을 대비한 **계약 후보 필드 목록**입니다.
|
|
|
|
### 4.1 Workspace Metadata 후보 스펙
|
|
- **설명**: 에이전트 작업 공간(Workspace)에 대한 설정 및 상태 메타데이터.
|
|
- **후보 필드**:
|
|
- `workspace_id`: 작업 공간 고유 식별자 (UUID)
|
|
- `workspace_slug`: 작업 공간의 URL 친화적 식별자 (예: `nomadcode-dev`)
|
|
- `name`: 작업 공간 표시 이름 (예: `NomadCode Dev Workspace`)
|
|
- `owner_id`: 소유자 고유 식별자
|
|
- `created_at`: 생성 시각 (ISO 8601)
|
|
- `updated_at`: 최종 변경 시각 (ISO 8601)
|
|
- `status`: 현재 상태 (예: `active`, `archived`, `suspended`)
|
|
- `settings`: 작업 공간에 특화된 동적 설정 JSON 오브젝트 (예: 자동 스케줄링 옵션, 알림 채널 정보 등)
|
|
|
|
### 4.2 Project Metadata 후보 스펙
|
|
- **설명**: 작업 공간 내 세부 프로젝트(Project) 정보.
|
|
- **후보 필드**:
|
|
- `project_id`: 프로젝트 고유 식별자 (UUID)
|
|
- `workspace_id`: 해당 프로젝트가 속한 Workspace 식별자
|
|
- `name`: 프로젝트 표시 이름 (예: `Flutter client consolidation`)
|
|
- `description`: 프로젝트 세부 설명
|
|
- `provider`: 연동 플랫폼 식별자 (예: `plane`, `github`)
|
|
- `external_project_id`: 연동 플랫폼 측 프로젝트 ID
|
|
- `status`: 프로젝트 상태 (예: `active`, `paused`)
|
|
|
|
---
|
|
|
|
## 5. 클라이언트 Integration 설정 계약 후보
|
|
|
|
> [!IMPORTANT]
|
|
> 이 절은 `apps/client`의 integration boundary에서 host/plugin/transport 사이에 교환되는 설정값을 후보로 모은 것이다. 실제 source schema는 소비하는 core/client 경계가 안정화된 뒤로 미룬다.
|
|
> 관련 코드 경계: `apps/client/lib/src/integrations/proto_socket/` 와 `apps/client/lib/src/integrations/mattermost/`.
|
|
|
|
### 5.1 proto-socket Endpoint 설정 후보
|
|
- **설명**: `apps/client`가 proto-socket transport에 의존할 때 사용하는 연결/하트비트 설정. 현재 구현은 `proto_socket` Dart 패키지(local path)를 끌어 쓰며 bootstrap에서 자동 연결하지 않는다.
|
|
- **후보 필드**:
|
|
- `host`: 대상 서버 hostname
|
|
- `port`: TCP/WebSocket 포트 (기본은 `secure` 값에 따라 443 또는 80)
|
|
- `secure`: TLS 사용 여부 (boolean)
|
|
- `path`: WebSocket path (기본 `/`)
|
|
- `heartbeat_interval_seconds`: heartbeat 송신 주기 (기본 30)
|
|
- `heartbeat_wait_seconds`: heartbeat 응답 대기 한계 (기본 60)
|
|
- `enabled`: bootstrap 시 자동 연결 활성화 여부 (기본 false)
|
|
|
|
### 5.2 Mattermost Push Host 책임 경계 후보
|
|
- **설명**: Mattermost push 통합에서 `apps/client` host가 plugin adapter에게 위임/공급해야 하는 데이터와 콜백. plugin adapter는 platform 측 plugin singleton에 격리되어 있고, 그 외 코드는 모두 `MattermostPushClient` 인터페이스에만 의존한다.
|
|
- **호스트 소유 필드/콜백**:
|
|
- `server_url`: Mattermost 서버 base URL (auth 핸드오프, signing key 저장에 함께 사용)
|
|
- `auth_token`: 로그인 응답에서 받은 인증 토큰 (plugin의 `setAuthToken`으로 전달)
|
|
- `signing_key`: 서버 config의 `AsymmetricSigningPublicKey` (plugin의 `setSigningKey`로 전달)
|
|
- `device_token`: FCM 디바이스 토큰 (plugin의 `getDeviceToken` 및 `onDeviceTokenReady` 콜백으로 동기화)
|
|
- `on_navigate_to_channel(server_url, channel_id)`: notification open → 채널 라우팅 콜백
|
|
- `on_navigate_to_thread(server_url, root_id)`: notification open → CRT 스레드 라우팅 콜백
|
|
- `notification_stream`: app-level UI(snackbar 등) 소비를 위한 broadcast stream
|