# Contract: Chat Message Stream (SSE) — with conversation scope

**Feature**: `004-chat-conversations` (extends `003-chat-streaming`)  
**Version**: API v1  
**Consumer**: `ChatFront/src/app/core/services/chat-api.service.ts`  
**Producer**: `ChatController::messageStream` → `ChatConversationStreamService`

## Endpoint

| Method | Path | Auth |
|--------|------|------|
| `POST` | `/api/v1/chat/conversations/{conversationId}/message/stream` | `Authorization: Bearer {jwt}` |

**Not for attachments.** Use `POST /api/v1/chat/conversations/{conversationId}/message` (multipart) for PDF/JPG.

## Request

**Headers**:

```
Authorization: Bearer {access_token}
Content-Type: application/json
Accept: text/event-stream
```

**Body**:

```json
{
  "message": "¿Y cuántos contratos?"
}
```

| Field | Type | Required | Validation |
|-------|------|----------|------------|
| `message` | string | yes | Non-empty after trim |

**Path**:

| Param | Validation |
|-------|------------|
| `conversationId` | Integer; MUST belong to authenticated user |

## Response

Unchanged from `003-chat-streaming` — SSE events `status`, `chunk`, `done`, `error`.

**Additional rule (FR-005)**: Server MUST load conversation history only for `{conversationId}` when building LLM context.

### `done` event

```json
{
  "type": "done",
  "assistant_id": 42,
  "content": "Texto completo.",
  "conversation_id": 12
}
```

Optional `conversation_id` in `done` helps client confirm thread (v1 optional field).

## Error HTTP (non-SSE)

| Status | When |
|--------|------|
| `401` | Unauthorized |
| `404` | Unknown or foreign `conversationId` |
| `422` | Empty message / domain error before stream |

## Deprecated endpoint

| Method | Path | Status |
|--------|------|--------|
| `POST` | `/api/v1/chat/message/stream` | Deprecated — uses user's latest conversation |

## Frontend usage

```typescript
streamConversationMessage(
  conversationId: number,
  message: string,
  handlers: ChatStreamHandlers,
): AbortController
```

Store `assistant_active_conversation_id` in `sessionStorage` when switching threads.

## FR Traceability

| Requirement | Contract element |
|-------------|------------------|
| FR-005 | History scoped to path `conversationId` |
| FR-006 | Context window applied server-side |
| FR-011 | Stream under conversation resource |
