Nébula
GitHub

Engenharia

Contract

Documentação do artefato contract.yaml — estrutura OpenAPI, schemas, status codes, auth e como preencher a partir das entidades.

contract.mdMARKDOWNLeitura: 3 minSeções: 20

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.md e Docs/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çãoTemplate
API nova com múltiplos recursos, auth, paginação e componentes reutilizáveisTemplates/Full/contract.yaml
Feature com 1-3 endpoints em recurso já definidoTemplates/Quick/contract.yaml
Ambiguidade de schema ou status code surgiuMigrar 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ódigoQuando usar
200Operação bem-sucedida com corpo de resposta
201Recurso criado com sucesso
204Operação bem-sucedida sem corpo (ex.: DELETE)
400Dados inválidos ou malformados (BadRequest)
401Não autenticado ou token inválido (Unauthorized)
403Autenticado mas sem permissão (Forbidden)
404Recurso não encontrado (NotFound)
422Violação de regra de negócio (UnprocessableEntity)
429Rate limit excedido
500Erro interno do servidor

Endpoints obrigatórios em toda API

/health:
  get:
    security: []        # health não exige autenticação
    summary: "Health check da aplicacao"
    operationId: getHealth

components — reutilizáveis

securitySchemes — autenticação

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Aplicar globalmente:

security:
  - bearerAuth: []

Isentar endpoint específico:

/auth/login:
  post:
    security: []   # endpoint público

parameters — 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: string

responses — respostas de erro padronizadas

O framework define 4 respostas reutilizáveis:

components:
  responses:
    BadRequest:          # 400
    Unauthorized:        # 401
    NotFound:            # 404
    UnprocessableEntity: # 422

Todas 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 campo

schemas — 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-time

Separação obrigatória de schemas

SchemaQuando usar
ResourceResposta — representa o recurso completo
CreateResourceRequestRequest de criação — apenas campos write
UpdateResourceRequestRequest de atualização — todos opcionais
ResourceStatusEnum separado — referenciado por outros schemas
PaginatedResourceResponseListagem 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:

  1. info preenchido com título e versão reais
  2. servers com os ambientes do projeto
  3. /health presente sem autenticação
  4. Todo endpoint tem operationId único
  5. Todos os schemas com additionalProperties: false
  6. Request e Response são schemas separados por operação
  7. Respostas de erro (400, 401, 404, 422) reutilizam $ref para components/responses
  8. Enums em schemas separados — nunca inline
Atenção

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

ErroCorreção
additionalProperties ausenteAdicionar additionalProperties: false em todo schema de objeto
Schema único para request e responseSeparar: Resource (response), CreateResourceRequest, UpdateResourceRequest
operationId ausente ou duplicadoTodo endpoint precisa de operationId único em todo o contrato
Enum inline no schemaCriar schema separado (ResourceStatus) e referenciar com $ref
Respostas de erro duplicadasCentralizar em components/responses e referenciar com $ref
Status code errado422 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