Contract é o contrato oficial da API do projeto em formato OpenAPI 3.1.0. Define endpoints, autenticação, payloads, schemas, status codes e padrões de erro de forma estruturada e consumível por ferramentas (Swagger UI, Redoc, Postman, geração de código, testes de contrato).
Fase: 4 — Design de Sistema
Pré-requisito: Docs/architecture.md · Docs/entities.md aprovados
Template: Templates/Full/contract.yaml ou Templates/Quick/contract.yaml
Artefato oficial: Docs/contract.yaml
Próximo artefato: Docs/structure.md · Docs/plan.md
Quando criar ou revisar
- Após aprovação de
Docs/architecture.mdeDocs/entities.md - Novo endpoint identificado em user story ou flow
- Mudança de schema de entidade que afeta a API
- Novo padrão de erro necessário
- Mudança de autenticação ou segurança
Full vs Quick
| Situação | Template |
|---|---|
| API nova com múltiplos recursos, auth, paginação e componentes reutilizáveis | Templates/Full/contract.yaml |
| Feature com 1-3 endpoints em recurso já definido | Templates/Quick/contract.yaml |
| Ambiguidade de schema ou status code surgiu | Migrar para Full na task em que surgiu |
Estrutura do arquivo OpenAPI 3.1.0
O template Full tem 5 seções de primeiro nível:
openapi: 3.1.0
info: # identificação e metadados
servers: # ambientes (prod, staging, local)
tags: # agrupamento de endpoints
security: # auth global
paths: # endpoints
components: # reutilizáveis (schemas, parameters, responses, securitySchemes)info — identificação
info:
title: "[Nome da API]"
version: "1.0.0"
summary: "Contrato oficial da API do projeto."
description: |
Descrição completa do propósito e contexto da API.
contact:
name: "[Responsável]"servers — ambientes
O template registra os 3 ambientes padrão:
servers:
- url: "https://api.exemplo.com"
description: "Producao"
- url: "https://staging-api.exemplo.com"
description: "Staging"
- url: "http://localhost:3000"
description: "Local"tags — agrupamento
tags:
- name: System
description: "Saude e disponibilidade"
- name: Auth
description: "Autenticacao e sessao"
- name: Resource
description: "Operacoes CRUD do recurso principal"paths — endpoints
Padrão de endpoint completo
/resources/{resourceId}:
patch:
tags: [Resource]
summary: "Descrição curta da operação"
operationId: "updateResource" # obrigatório — único no contrato
parameters:
- $ref: "#/components/parameters/ResourceIdParam"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateResourceRequest"
responses:
"200":
description: "Recurso atualizado com sucesso"
content:
application/json:
schema:
$ref: "#/components/schemas/Resource"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"Status codes padrão do framework
| Código | Quando usar |
|---|---|
200 | Operação bem-sucedida com corpo de resposta |
201 | Recurso criado com sucesso |
204 | Operação bem-sucedida sem corpo (ex.: DELETE) |
400 | Dados inválidos ou malformados (BadRequest) |
401 | Não autenticado ou token inválido (Unauthorized) |
403 | Autenticado mas sem permissão (Forbidden) |
404 | Recurso não encontrado (NotFound) |
422 | Violação de regra de negócio (UnprocessableEntity) |
429 | Rate limit excedido |
500 | Erro interno do servidor |
Endpoints obrigatórios em toda API
/health:
get:
security: [] # health não exige autenticação
summary: "Health check da aplicacao"
operationId: getHealthcomponents — reutilizáveis
securitySchemes — autenticação
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWTAplicar globalmente:
security:
- bearerAuth: []Isentar endpoint específico:
/auth/login:
post:
security: [] # endpoint públicoparameters — parâmetros reutilizáveis
components:
parameters:
PageParam:
name: page
in: query
required: false
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
ResourceIdParam:
name: resourceId
in: path
required: true
schema:
type: stringresponses — respostas de erro padronizadas
O framework define 4 respostas reutilizáveis:
components:
responses:
BadRequest: # 400
Unauthorized: # 401
NotFound: # 404
UnprocessableEntity: # 422Todas usam o schema ErrorResponse:
ErrorResponse:
type: object
additionalProperties: false
required: [code, message, details]
properties:
code:
type: string # "BAD_REQUEST" | "NOT_FOUND" | "BUSINESS_RULE_VIOLATION"
message:
type: string # mensagem legível
details:
type: array # lista de erros de validação por camposchemas — estrutura dos dados
Regras obrigatórias para todo schema
NomeDoSchema:
type: object
additionalProperties: false # obrigatório — rejeita campos extras
required: [id, name, ...] # campos obrigatórios explícitos
properties:
id:
type: string
name:
type: string
minLength: 1
maxLength: 120
status:
$ref: "#/components/schemas/ResourceStatus" # enum separado
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-timeSeparação obrigatória de schemas
| Schema | Quando usar |
|---|---|
Resource | Resposta — representa o recurso completo |
CreateResourceRequest | Request de criação — apenas campos write |
UpdateResourceRequest | Request de atualização — todos opcionais |
ResourceStatus | Enum separado — referenciado por outros schemas |
PaginatedResourceResponse | Listagem com data[] + meta (PaginationMeta) |
Paginação padrão
PaginationMeta:
type: object
additionalProperties: false
required: [page, limit, total, totalPages]
properties:
page: { type: integer }
limit: { type: integer }
total: { type: integer }
totalPages: { type: integer }
PaginatedResourceResponse:
type: object
additionalProperties: false
required: [data, meta]
properties:
data:
type: array
items:
$ref: "#/components/schemas/Resource"
meta:
$ref: "#/components/schemas/PaginationMeta"Autenticação — Login e sessão
LoginRequest:
required: [email, password]
properties:
email: { type: string, format: email }
password: { type: string, minLength: 8 }
LoginResponse:
required: [accessToken, refreshToken, user]
properties:
accessToken: { type: string }
refreshToken: { type: string }
user:
$ref: "#/components/schemas/AuthenticatedUser"
AuthenticatedUser:
required: [id, name, email, role]
properties:
id: { type: string }
name: { type: string }
email: { type: string, format: email }
role: { type: string }Prompt para gerar com agente
Atue como SystemAgent.
Objetivo: criar Docs/contract.yaml com base em Docs/entities.md e Docs/architecture.md
Carregue contexto base:
- GUIDE.md
- Skills/contracts.md
- Templates/Full/contract.yaml
- Docs/entities.md
- Docs/architecture.md
- Docs/user-stories.md
Preencha o contract.yaml seguindo OpenAPI 3.1.0.
Para cada entidade central do domínio: criar grupo de endpoints (GET lista, POST, GET detalhe, PATCH, DELETE).
Definir schemas separados para Resource, CreateRequest, UpdateRequest e ListResponse.
Usar $ref em todos os schemas, parameters e responses reutilizáveis.
Todo endpoint precisa de operationId único.
Usar additionalProperties: false em todos os schemas de objeto.
Registrar responses de erro padronizadas em components/responses.Definição de pronto
O contract está pronto quando:
infopreenchido com título e versão reaisserverscom os ambientes do projeto/healthpresente sem autenticação- Todo endpoint tem
operationIdúnico - Todos os schemas com
additionalProperties: false - Request e Response são schemas separados por operação
- Respostas de erro (400, 401, 404, 422) reutilizam
$refpara components/responses - Enums em schemas separados — nunca inline
Contrato sem additionalProperties: false nos schemas aceita silenciosamente campos não documentados — isso gera divergência entre o que a API aceita e o que o contrato descreve. Todo schema de objeto deve ter essa propriedade definida explicitamente.
Erros comuns
| Erro | Correção |
|---|---|
additionalProperties ausente | Adicionar additionalProperties: false em todo schema de objeto |
| Schema único para request e response | Separar: Resource (response), CreateResourceRequest, UpdateResourceRequest |
operationId ausente ou duplicado | Todo endpoint precisa de operationId único em todo o contrato |
| Enum inline no schema | Criar schema separado (ResourceStatus) e referenciar com $ref |
| Respostas de erro duplicadas | Centralizar em components/responses e referenciar com $ref |
| Status code errado | 422 para violação de negócio — não 400 |
Relação com outros artefatos
Docs/entities.md (aprovado) → schemas derivados dos atributos
Docs/architecture.md (aprovado) → módulos determinam agrupamento por tag
↓
Docs/contract.yaml → define a superfície da API
↓
Implementação backend → controladores implementam o contrato
Testes de integração → validam conformidade com o contrato
Docs/structure.md → organização de pastas reflete os módulos do contrato