# FlatRender V2 — Service Contracts

This directory defines all inter-service contracts. Services are loosely
coupled — they communicate via REST APIs (synchronous) and RabbitMQ
events (asynchronous). The browser connects to the Gateway over HTTPS +
WebSocket.

## Layout

```
contracts/
├── common/              # Reusable OpenAPI components (Error, Pagination, ...)
│   └── types.yaml
├── events/              # RabbitMQ event schemas (JSON Schema)
│   ├── README.md        # Event catalog with routing keys
│   ├── render.yaml
│   ├── node.yaml
│   ├── identity.yaml
│   ├── file.yaml
│   ├── tenant.yaml
│   └── notification.yaml
├── websocket/           # WebSocket message protocol
│   └── render-progress.md
└── rest/                # Per-service OpenAPI 3.0 specs
    ├── identity.openapi.yaml         # internal
    ├── content.openapi.yaml          # internal
    ├── studio.openapi.yaml           # internal
    ├── render.openapi.yaml           # internal
    ├── file.openapi.yaml             # internal
    ├── notification.openapi.yaml     # internal
    ├── node-agent.openapi.yaml       # called by render orchestrator
    ├── gateway-public.openapi.yaml   # what frontend uses
    └── reseller-api.openapi.yaml     # B2B API (api-key auth)
```

## Authentication

| Surface              | Auth                            | Carries                |
|----------------------|---------------------------------|------------------------|
| Gateway public API   | JWT (Bearer)                    | user_id, tenant_id     |
| Reseller API         | API key (X-API-Key + signature) | tenant_id, scopes      |
| Internal service API | Service token (mTLS in prod)    | service_name           |
| Node Agent API       | Shared secret (HMAC)            | orchestrator_signature |
| WebSocket            | JWT in query param `?token=...` | user_id, job_id        |

## Versioning

- REST: URL prefix `/v1/...`
- Events: routing key suffix `.v1`
- WebSocket: protocol negotiation header

## Conventions

- All IDs are UUID v4
- All timestamps ISO 8601 with timezone (`2026-05-27T10:15:00Z`)
- All money fields are `_minor` integers (rial / cent)
- All durations are seconds (numeric)
- All file sizes are bytes (integer)
- Pagination: `?page=1&page_size=20` returning `PaginatedResponse<T>`
- Errors: `{ "error": { "code", "message", "details", "trace_id" } }`
- Tenant context: `X-Tenant-Id` header on internal calls (JWT carries it on public)
