nomadcode/packages/contracts/notes/flutter-core-api-candidates.md

18 KiB

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. 내부 통신 원칙

1.1 기본 표준

  • 설명: NomadCode 내부 런타임 간 신규 통신은 proto-socket을 기본 표준으로 사용한다.
  • 안정성 수준: 후보 (Candidate)
  • 적용 대상:
    • apps/clientservices/core
    • NomadCode Core ↔ 내부 control/runtime adapter
    • 향후 NomadCode가 직접 소유하는 MCP/action runtime 표면
  • 예외 대상:
    • health/readiness처럼 외부 운영 도구와 curl smoke가 직접 확인해야 하는 endpoint
    • Plane/Jira/Mattermost/IOP/OpenAI-compatible Responses/A2A처럼 외부 provider 또는 외부 실행 표면이 요구하는 native protocol
    • public callback/webhook
    • 단순 정적 조회처럼 proto-socket 연결 비용이 과한 read-only endpoint
  • 예외 기록 규칙: REST/HTTP를 새로 추가하거나 유지할 때는 이 문서 또는 관련 domain rule에 예외 사유를 남긴다.

1.2 proto-socket Semantic Envelope 후보

  • 설명: 아래 JSON은 wire schema가 아니라 proto-socket message가 가져야 할 의미 필드 후보다. 실제 source schema는 proto-socket 계약이 안정화되면 별도 schema로 승격한다.
  • Envelope Shape 후보:
    {
      "protocol_version": "nomadcode.proto-socket.v1",
      "id": "msg-uuid",
      "correlation_id": "request-or-flow-id",
      "type": "request",
      "channel": "task",
      "action": "task.list",
      "actor": {
        "kind": "client",
        "id": "apps/client"
      },
      "auth": {
        "scheme": "basic",
        "token_ref": "runtime-secret-ref"
      },
      "payload": {},
      "error": null,
      "meta": {
        "connection_id": "conn-id",
        "timestamp": "2026-05-30T00:00:00Z"
      }
    }
    
  • type 후보:
    • request: 요청 메시지
    • response: 요청 성공 응답
    • event: 구독 또는 서버 발행 이벤트
    • error: 요청 실패 또는 channel-level 오류
    • heartbeat: 연결 생존 확인
    • auth: 연결 인증 또는 인증 갱신
  • error 후보 필드:
    {
      "code": "task.not_found",
      "message": "task not found",
      "retryable": false,
      "details": {}
    }
    

1.3 REST Compatibility Map 후보

  • 설명: 현재 REST API는 proto-socket rail 구현 전까지의 호환 표면이다. task 관련 신규 내부 기능은 proto-socket channel을 우선한다.
현재 REST/HTTP 표면 proto-socket 후보 유지/전환 기준
GET /healthz 없음 Public 운영 health check로 REST 유지
GET /readyz system.ready event 또는 request 후보 DB readiness와 curl smoke 때문에 REST 유지, 내부 UI에는 proto-socket 상태 이벤트를 추가 가능
POST /api/tasks task.create request client-core 내부 호출은 proto-socket으로 전환, REST는 smoke/compat 유지
GET /api/tasks task.list request client-core 내부 조회는 proto-socket으로 전환, REST는 smoke/compat 유지
GET /api/tasks/{id} task.get request client-core 내부 조회는 proto-socket으로 전환, REST는 smoke/compat 유지
POST /api/tasks/{id}/enqueue task.enqueue request + task.status.changed event client-core 실행 요청과 상태 반영은 proto-socket으로 전환, REST는 smoke/compat 유지
POST /api/integrations/plane/tasks workitem.plane.import 후보 Plane API 자체는 외부 provider REST이며, 내부 호출 표면은 proto-socket으로 추가 가능

1.4 Core Endpoint 후보

  • 기본 경로: /proto-socket
  • 인증: 기존 Core Basic Auth middleware 적용
  • Wire message: 초기 구현은 google.protobuf.Struct semantic envelope를 사용한다.
  • Heartbeat: proto-socket 기본 heartbeat를 사용하며 Core 설정 기본값은 interval 30s, wait 10s다.

1.5 Task Channel Actions (구현됨)

  • 설명: services/core/internal/protosocket가 REST task API와 같은 의미를 task channel의 proto-socket action으로 제공한다. REST는 smoke/compat로 유지한다.
  • 안정성 수준: 후보 (Candidate)
  • 채널: task
  • 요청/응답 action 표:
action request payload response type response payload
task.create POST /api/tasks JSON shape (title, source, payload, metadata?, external?) response { "id", "status", "external_provider", "external_id", "task": { …full task } }
task.list { "limit": 20 } (생략 시 0 전달, 기본 20/최대 100 bounding은 core workflow service가 담당) response { "tasks": [ { …full task } ] }
task.get { "id": "task-id" } response { "task": { …full task } }
task.enqueue { "id": "task-id" } response { "id", "status": "queued", "task": { …full task } }
  • task status event (서버 발행):
action type channel payload
task.status.changed event task { "id", "type": "task.running|task.completed|task.failed|task.canceled", "status", "title", "message" }
  • scheduler가 내는 모든 task lifecycle event(running/completed/failed/canceled)가 notification fanout을 통해 broadcast된다. completed event의 Mattermost 알림 동작은 그대로 유지된다.

  • error envelope code 표 (type: "error"):

code 의미 retryable REST 대응 status
task.invalid_input 잘못된 task 입력(ErrInvalidTaskInput) false 400
task.conflict 현재 상태에서 enqueue 불가(ErrTaskCannotBeEnqueued) false 409
task.not_found task 없음(pgx.ErrNoRows) false 404
task.invalid_payload envelope payload 디코드 실패 false (REST 없음)
internal.error 그 외 내부 오류 true 500
UNSUPPORTED_ACTION dispatcher에 등록되지 않은 action false (REST 없음)

1.6 Diagnostics 필드 후보

  • 설명: proto-socket 로그와 클라이언트 디버그 표면에서 연결과 메시지 흐름을 추적하기 위한 공통 diagnostics 필드 후보다. 확정 schema가 아니라 Core/Client 구현을 맞추기 위한 compatibility note로만 사용한다.
  • 안정성 수준: 후보 (Candidate)
  • 최소 공통 필드:
필드 위치 필수성 소비자 책임
connection_id envelope meta.connection_id, Core log attribute, Client debug surface 연결이 확립된 response/event/error에서 가능하면 포함 Core는 연결별 안정 식별자를 부여하고, Client는 표시/필터링에만 사용한다.
protocol_version envelope top-level, Core log attribute, Client debug surface 모든 proto-socket envelope에 포함 Core와 Client는 지원하지 않는 version을 compatibility 문제로 보고하되, secret이나 payload 원문을 함께 출력하지 않는다.
channel envelope top-level, Core log attribute, Client debug surface request/response/event/error에서 포함 dispatcher와 Client debug surface는 channel name을 그대로 노출하되 business payload를 함께 노출하지 않는다.
action envelope top-level, Core log attribute, Client debug surface request/response/event/error에서 포함 request 흐름과 최근 event/error를 추적하는 용도로만 사용한다.
error.code / error_code envelope error.code, Core log attribute, Client debug surface error envelope에서 포함, 성공 envelope에서는 생략 또는 null Core는 error code를 안정적인 문자열로 기록하고, Client는 최근 오류 요약에만 사용한다.
timestamp envelope meta.timestamp, Core log timestamp, Client debug surface Core가 발행하는 response/event/error에서 가능하면 포함 소비자는 시간 정렬과 최근 상태 표시에 사용하고 clock 차이를 프로토콜 오류로 단정하지 않는다.
  • Core log attributes: connection_id, protocol_version, channel, action, error_code, timestamp를 structured log attribute로 남긴다. error가 없으면 error_code는 생략하거나 null로 둔다.
  • Envelope meta: response/event/error는 가능한 경우 meta.connection_id, meta.timestamp를 포함하고, top-level protocol_version, channel, action과 함께 diagnostics 기준으로 소비된다.
  • Client debug surface: 연결 상태, connection id, protocol version, 최근 channel/action/error code/timestamp만 표시한다.
  • 노출 금지: auth token, Basic Auth header, secret, token_ref가 가리키는 실제 값, payload/result 원문, 외부 provider credential은 Core log와 Client debug surface에 기록하거나 표시하지 않는다.

1.7 새 내부 통신 추가 운영 체크

  • 신규 apps/clientservices/core 또는 내부 runtime 간 통신은 먼저 proto-socket channel/action으로 표현 가능한지 확인한다.
  • REST/HTTP를 새로 추가하거나 유지해야 하면 health/readiness, 외부 provider 호환 API, 운영 smoke/curl, public callback, 단순 정적 조회 중 어느 예외인지 이 문서 또는 관련 domain rule에 기록한다.
  • 새 channel/action은 envelope의 protocol_version, type, channel, action, correlation_id, payload, error.retryable 의미를 이 문서에 추가한다.
  • 클라이언트가 소비하는 request/response/event shape는 구현 전에 후보 표와 테스트 fixture 기준을 남긴다.
  • Core 구현은 기존 REST smoke/compat 표면을 제거하지 않고, 내부 UI/런타임 호출만 proto-socket 우선 경로로 전환한다.
  • 검증은 최소한 channel/action dispatch, auth boundary, error envelope, event broadcast 또는 reconnect 영향 중 해당되는 항목을 테스트로 고정한다.

2. 공통 및 인프라 API

2.1 GET /healthz

  • 설명: 서비스 헬스 체크.
  • 인증: 없음 (Public)
  • 안정성 수준: 안정 (Stable)
  • Response Shape (Status 200 OK):
    {
      "status": "ok"
    }
    

2.2 GET /readyz

  • 설명: 서비스 및 데이터베이스 준비 상태 체크.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Response Shape (Status 200 OK):
    {
      "status": "ready"
    }
    
    (Status 503 Service Unavailable):
    {
      "error": "database is not ready"
    }
    

3. 태스크 관리 API (Tasks API)

3.1 POST /api/tasks

  • 설명: 새로운 태스크 생성.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Request Shape:
    {
      "title": "Task Title",
      "source": "source_identifier",
      "payload": {},
      "metadata": {},
      "external": {
        "provider": "plane",
        "id": "external-task-id",
        "url": "https://...",
        "metadata": {}
      }
    }
    
  • Response Shape (Status 201 Created):
    {
      "id": "task-uuid-string",
      "status": "pending",
      "external_provider": "plane",
      "external_id": "external-task-id"
    }
    

3.2 GET /api/tasks

  • 설명: 태스크 목록 조회.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Query Parameters:
    • limit (Optional, 기본값 20, 양의 정수)
  • Response Shape (Status 200 OK):
    [
      {
        "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": {}
      }
    ]
    

3.3 GET /api/tasks/{id}

  • 설명: 단일 태스크 세부 정보 조회.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Response Shape (Status 200 OK):
    {
      "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": {}
    }
    

3.4 POST /api/tasks/{id}/enqueue

  • 설명: 태스크를 큐에 진입시켜 실행 대기 상태로 변경.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Response Shape (Status 200 OK):
    {
      "id": "task-uuid-string",
      "status": "queued"
    }
    

4. 외부 연동 API (Integrations API)

4.1 POST /api/integrations/plane/tasks

  • 설명: Plane 워크아이템 정보를 기반으로 새로운 태스크 생성.
  • 인증: Basic Auth
  • 안정성 수준: 안정 (Stable)
  • Request Shape:
    {
      "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):
    {
      "id": "task-uuid-string",
      "status": "pending",
      "external_provider": "plane",
      "external_id": "work-item-id-string"
    }
    

5. Workspace / Project Metadata 계약 후보

Important

Workspace/Project Metadata 상태: 현재 Go core 백엔드에 이와 관련한 별도의 Source-of-Truth 저장소나 전용 테이블 구조가 존재하지 않으며, API 명세 또한 완전히 확정되지 않았습니다. 아래는 Flutter 앱과 코어 간 향후 연동을 대비한 계약 후보 필드 목록입니다.

5.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 오브젝트 (예: 자동 스케줄링 옵션, 알림 채널 정보 등)

5.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)

6. 클라이언트 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/.

6.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)

6.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 저장에 함께 사용)
    • server_identifier: 선택 필드. FCM payload의 server_idserver_url로 역해석해야 하는 multi-server host에서 plugin의 setAuthToken(..., identifier:)로 함께 전달
    • auth_token: 로그인 응답에서 받은 인증 토큰 (plugin의 setAuthToken으로 전달)
    • signing_key: 서버 config의 AsymmetricSigningPublicKey (plugin의 setSigningKey로 전달)
    • device_token: FCM 디바이스 토큰 (plugin의 getDeviceTokenonDeviceTokenReady 콜백으로 동기화)
    • 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