Relacionamento Digitalcom o Cidadão
Parte X — Anexos Técnicos
Parte X — Anexos TécnicosCapítulo 71

Capítulo 71 — Contratos REST e OpenAPI

Este capítulo documenta os contratos REST da Plataforma de Relacionamento Digital com o Cidadão, apresentando a estrutura OpenAPI de cada grupo funcional, as convenções de contrato adotadas na plataforma, e os padrões qu…

71.1 Objetivo do Capítulo

Este capítulo documenta os contratos REST da Plataforma de Relacionamento Digital com o Cidadão, apresentando a estrutura OpenAPI de cada grupo funcional, as convenções de contrato adotadas na plataforma, e os padrões que garantem consistência, evolução controlada e interoperabilidade entre canais, serviços de domínio e sistemas externos.

O Capítulo 14 estabeleceu as diretrizes arquiteturais de APIs: classificação, padrões REST, paginação, idempotência, versionamento e ciclo de vida. Este capítulo é a materialização dessas diretrizes em contratos concretos — paths, métodos, headers, parâmetros, schemas de request/response e códigos de erro documentados por domínio.

Os contratos aqui descritos cobrem os 24 serviços de domínio definidos no Capítulo 12, organizados em grupos funcionais. Para cada grupo, são apresentados: estrutura do contrato OpenAPI, endpoints representativos com schemas detalhados, headers obrigatórios e opcionais, modelos de resposta padrão e mapeamento de erros. O catálogo completo de endpoints está registrado no repositório de contratos versionado da plataforma, referenciado no Capítulo 58.


71.2 Estrutura dos Contratos OpenAPI

71.2.1 Versão e Metadados

Todos os contratos adotam OpenAPI Specification 3.1.0. A estrutura raiz de cada arquivo de contrato segue o padrão:

openapi: "3.1.0"

info:
  title: "Request Service API"
  description: |
    API de gerenciamento do ciclo de vida das solicitações de serviços públicos.
    Classificação: Pública / Canal / Interna.
    Tenant-scoped: sim.
  version: "1.3.0"
  contact:
    name: "Plataforma de Relacionamento Digital com o Cidadão"
  license:
    name: "Uso restrito — PRODEMGE"

servers:
  - url: "https://api.{tenant}.plataforma.mg.gov.br/v1"
    description: "Produção — por tenant"
    variables:
      tenant:
        default: "default"
        description: "Identificador do tenant (slug do órgão)"
  - url: "https://api.staging.plataforma.mg.gov.br/v1"
    description: "Homologação"

tags:
  - name: "Solicitações"
    description: "Ciclo de vida das solicitações de serviços públicos"
  - name: "Protocolos"
    description: "Consulta pública por número de protocolo"

security:
  - BearerAuth: []

71.2.2 Componentes Reutilizáveis

Os contratos de todos os serviços referenciam um arquivo de componentes compartilhados (components.yaml) que define schemas, headers, responses e security schemes reutilizáveis. Isso elimina a duplicação de definições de erro, paginação, tenant context e schemas comuns entre os contratos dos 24 serviços.

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Token JWT emitido pelo IAM da plataforma após autenticação.
        Para cidadãos autenticados via GOV.BR, o token é emitido
        pela plataforma após vinculação da identidade federada.

  headers:
    X-Tenant-Id:
      description: "Identificador do tenant derivado da identidade autenticada. Não aceito como único fator de tenant."
      schema:
        type: string
        format: uuid
      required: true
    X-Correlation-Id:
      description: "Identificador de correlação para rastreamento distribuído."
      schema:
        type: string
      required: false
    Idempotency-Key:
      description: "UUID gerado pelo cliente para operações de criação idempotentes."
      schema:
        type: string
        format: uuid
      required: false

  schemas:
    ProblemDetails:
      type: object
      required: [type, title, status, code, correlationId]
      properties:
        type:
          type: string
          format: uri
          example: "https://platform.domain/problems/validation-error"
        title:
          type: string
          example: "Validation failed"
        status:
          type: integer
          example: 422
        code:
          type: string
          example: "VALIDATION_ERROR"
        correlationId:
          type: string
          example: "corr-a7f2-4b81-9c3d"
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              code:
                type: string
              message:
                type: string

    PagedResponse:
      type: object
      required: [items, page, size, totalElements, totalPages]
      properties:
        items:
          type: array
          items: {}
        page:
          type: integer
          minimum: 0
        size:
          type: integer
          minimum: 1
          maximum: 100
        totalElements:
          type: integer
        totalPages:
          type: integer

    CursorPagedResponse:
      type: object
      required: [items, hasMore]
      properties:
        items:
          type: array
          items: {}
        nextCursor:
          type: string
          description: "Opaco. O consumidor não interpreta ou constrói este valor."
        hasMore:
          type: boolean

  responses:
    400BadRequest:
      description: "Requisição malformada ou parâmetros inválidos."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    401Unauthorized:
      description: "Token ausente, expirado ou inválido."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    403Forbidden:
      description: "Autenticado mas sem permissão para esta operação."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    404NotFound:
      description: "Recurso não encontrado ou não acessível pelo tenant corrente."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    422UnprocessableContent:
      description: "Dados válidos sintaticamente mas inválidos semanticamente (regra de negócio)."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    429TooManyRequests:
      description: "Rate limit ou quota excedidos."
      headers:
        Retry-After:
          schema:
            type: integer
          description: "Segundos até que novas requisições sejam aceitas."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'
    500InternalServerError:
      description: "Erro interno não esperado. Registrado com correlationId."
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails'

71.2.3 Convenção de Content-Type

Requisições com body usam Content-Type: application/json. Respostas de sucesso retornam Content-Type: application/json. Respostas de erro retornam Content-Type: application/problem+json, conforme RFC 9457. Upload de documentos binários usa multipart/form-data com campo file tipado. APIs de streaming de IA retornam text/event-stream via Server-Sent Events.


71.3 Grupo Funcional: Identidade e Acesso

71.3.1 Identity Service — Autenticação e Usuários

paths:
  /auth/login:
    post:
      summary: "Autenticação local (usuários internos e cidadãos com cadastro local)"
      tags: [Autenticação]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [credential, password]
              properties:
                credential:
                  type: string
                  description: "CPF, e-mail ou login do usuário"
                password:
                  type: string
                  format: password
                  writeOnly: true
                tenantSlug:
                  type: string
                  description: "Slug do tenant para contexto de autenticação"
      responses:
        '200':
          description: "Autenticação bem-sucedida"
          content:
            application/json:
              schema:
                type: object
                properties:
                  accessToken:
                    type: string
                    description: "JWT de acesso"
                  tokenType:
                    type: string
                    enum: [Bearer]
                  expiresIn:
                    type: integer
                    description: "Segundos até expiração"
                  refreshToken:
                    type: string
                    description: "Token de renovação"
        '401':
          $ref: '#/components/responses/401Unauthorized'
        '429':
          $ref: '#/components/responses/429TooManyRequests'

  /auth/refresh:
    post:
      summary: "Renovação de token de acesso via refresh token"
      tags: [Autenticação]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [refreshToken]
              properties:
                refreshToken:
                  type: string
      responses:
        '200':
          description: "Tokens renovados"
        '401':
          $ref: '#/components/responses/401Unauthorized'

  /auth/logout:
    post:
      summary: "Encerramento de sessão e revogação de tokens"
      tags: [Autenticação]
      responses:
        '204':
          description: "Sessão encerrada"

  /auth/govbr/authorize:
    get:
      summary: "Início do fluxo OAuth 2.0 / OIDC com GOV.BR"
      tags: [Autenticação Federada]
      security: []
      parameters:
        - name: tenantSlug
          in: query
          required: true
          schema:
            type: string
        - name: redirectUri
          in: query
          required: true
          schema:
            type: string
            format: uri
      responses:
        '302':
          description: "Redirecionamento para GOV.BR"

  /auth/govbr/callback:
    get:
      summary: "Callback após autenticação no GOV.BR"
      tags: [Autenticação Federada]
      security: []
      parameters:
        - name: code
          in: query
          required: true
          schema:
            type: string
        - name: state
          in: query
          required: true
          schema:
            type: string
      responses:
        '302':
          description: "Redirecionamento para o canal com token da plataforma"

  /me:
    get:
      summary: "Perfil do usuário autenticado e permissões da sessão"
      tags: [Usuário]
      responses:
        '200':
          description: "Dados do usuário autenticado"
          content:
            application/json:
              schema:
                type: object
                properties:
                  userId:
                    type: string
                    format: uuid
                  name:
                    type: string
                  email:
                    type: string
                  tenantId:
                    type: string
                    format: uuid
                  roles:
                    type: array
                    items:
                      type: string
                  govbrLinked:
                    type: boolean
                    description: "Indica se a identidade GOV.BR está vinculada"

  /users:
    post:
      summary: "Criação de usuário interno (atendente, gestor, administrador)"
      tags: [Usuários]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateRequest'
      responses:
        '201':
          description: "Usuário criado"
          headers:
            Location:
              schema:
                type: string
                format: uri
        '400':
          $ref: '#/components/responses/400BadRequest'
        '409':
          description: "Credencial já registrada"

  /users/{userId}:
    get:
      summary: "Consulta de usuário por ID"
      tags: [Usuários]
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Dados do usuário"
        '404':
          $ref: '#/components/responses/404NotFound'

    patch:
      summary: "Atualização parcial de usuário"
      tags: [Usuários]
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                active:
                  type: boolean
      responses:
        '200':
          description: "Usuário atualizado"
        '404':
          $ref: '#/components/responses/404NotFound'

71.4 Grupo Funcional: Tenant e Configuração

71.4.1 Tenant Service

paths:
  /tenants:
    get:
      summary: "Listagem de tenants (acesso administrativo global)"
      tags: [Tenants]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [ACTIVE, SUSPENDED, INACTIVE]
        - name: page
          in: query
          schema:
            type: integer
            default: 0
        - name: size
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: "Lista paginada de tenants"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PagedResponse'
                  - type: object
                    properties:
                      items:
                        type: array
                        items:
                          $ref: '#/components/schemas/TenantSummary'

    post:
      summary: "Criação de novo tenant"
      tags: [Tenants]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, slug, contactEmail]
              properties:
                name:
                  type: string
                  description: "Nome institucional do órgão"
                slug:
                  type: string
                  pattern: "^[a-z0-9-]+$"
                  description: "Identificador URL-friendly único"
                contactEmail:
                  type: string
                  format: email
                plan:
                  type: string
                  enum: [STARTER, STANDARD, ENTERPRISE]
      responses:
        '201':
          description: "Tenant criado"
          headers:
            Location:
              schema:
                type: string
                format: uri
        '409':
          description: "Slug já registrado"

  /tenants/{tenantId}:
    get:
      summary: "Detalhe do tenant"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Dados completos do tenant"

    patch:
      summary: "Atualização de configurações do tenant"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Tenant atualizado"

  /tenants/{tenantId}/activate:
    post:
      summary: "Ativação de tenant"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Tenant ativado"
        '409':
          description: "Tenant já ativo"

  /tenants/{tenantId}/suspend:
    post:
      summary: "Suspensão temporária de tenant"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: "Tenant suspenso"

  /tenants/{tenantId}/modules:
    get:
      summary: "Módulos habilitados para o tenant"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Lista de módulos e status de habilitação"
          content:
            application/json:
              schema:
                type: object
                properties:
                  modules:
                    type: array
                    items:
                      type: object
                      properties:
                        moduleId:
                          type: string
                        enabled:
                          type: boolean
                        enabledAt:
                          type: string
                          format: date-time

    put:
      summary: "Atualização dos módulos habilitados"
      tags: [Tenants]
      parameters:
        - name: tenantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                modules:
                  type: array
                  items:
                    type: object
                    properties:
                      moduleId:
                        type: string
                      enabled:
                        type: boolean
      responses:
        '200':
          description: "Módulos atualizados"

71.5.1 Citizen Service

paths:
  /citizens:
    post:
      summary: "Registro de cidadão com cadastro local"
      tags: [Cidadão]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [cpf, name, email]
              properties:
                cpf:
                  type: string
                  pattern: "^\\d{11}$"
                  description: "CPF sem formatação"
                name:
                  type: string
                email:
                  type: string
                  format: email
                birthDate:
                  type: string
                  format: date
                phone:
                  type: string
      responses:
        '201':
          description: "Cidadão registrado"
          headers:
            Location:
              schema:
                type: string
                format: uri
        '409':
          description: "CPF já registrado neste tenant"

  /citizens/{citizenId}:
    get:
      summary: "Dados do cidadão"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Dados básicos do cidadão"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Citizen'
        '404':
          $ref: '#/components/responses/404NotFound'

    patch:
      summary: "Atualização parcial do cadastro do cidadão"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                phone:
                  type: string
      responses:
        '200':
          description: "Cadastro atualizado"

  /citizens/{citizenId}/contacts:
    get:
      summary: "Contatos do cidadão (e-mails, telefones, canais de preferência)"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Lista de contatos"

    post:
      summary: "Adição de novo contato"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, value]
              properties:
                type:
                  type: string
                  enum: [EMAIL, PHONE, WHATSAPP]
                value:
                  type: string
                verified:
                  type: boolean
                  default: false
      responses:
        '201':
          description: "Contato adicionado"

  /citizens/{citizenId}/preferences:
    get:
      summary: "Preferências de comunicação e acessibilidade do cidadão"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Preferências do cidadão"

    put:
      summary: "Atualização completa das preferências"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                preferredChannel:
                  type: string
                  enum: [EMAIL, SMS, WHATSAPP, PUSH]
                language:
                  type: string
                  default: "pt-BR"
                accessibilityNeeds:
                  type: array
                  items:
                    type: string
                    enum: [VISUAL, AUDITORY, MOTOR, COGNITIVE]
      responses:
        '200':
          description: "Preferências atualizadas"

  /citizens/{citizenId}/360:
    get:
      summary: "Visão 360° do cidadão — composição por API, nunca por join de bancos"
      tags: [Cidadão]
      parameters:
        - name: citizenId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Visão consolidada do cidadão"
          content:
            application/json:
              schema:
                type: object
                properties:
                  citizen:
                    $ref: '#/components/schemas/Citizen'
                  recentRequests:
                    type: array
                    items:
                      $ref: '#/components/schemas/RequestSummary'
                  openInteractions:
                    type: array
                    items:
                      $ref: '#/components/schemas/InteractionSummary'
                  pendingAppointments:
                    type: array
                    items:
                      $ref: '#/components/schemas/AppointmentSummary'

71.5.2 Service Catalog Service

paths:
  /services:
    get:
      summary: "Catálogo de serviços públicos do tenant"
      tags: [Catálogo]
      security: []
      parameters:
        - name: categoryId
          in: query
          schema:
            type: string
        - name: channel
          in: query
          schema:
            type: string
            enum: [WEB, MOBILE, PRESENTIAL]
        - name: q
          in: query
          description: "Busca textual no nome e descrição"
          schema:
            type: string
        - name: page
          in: query
          schema:
            type: integer
            default: 0
        - name: size
          in: query
          schema:
            type: integer
            default: 20
            maximum: 50
      responses:
        '200':
          description: "Catálogo paginado de serviços"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PagedResponse'

    post:
      summary: "Criação de serviço público"
      tags: [Catálogo]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ServiceCreateRequest'
      responses:
        '201':
          description: "Serviço criado em rascunho"
          headers:
            Location:
              schema:
                type: string
                format: uri

  /services/{serviceId}:
    get:
      summary: "Detalhe de serviço público"
      tags: [Catálogo]
      security: []
      parameters:
        - name: serviceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Dados completos do serviço"

    patch:
      summary: "Atualização de dados do serviço (sem publicar nova versão)"
      tags: [Catálogo]
      parameters:
        - name: serviceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Serviço atualizado"

  /services/{serviceId}/publish:
    post:
      summary: "Publicação do serviço — torna-o disponível ao cidadão"
      tags: [Catálogo]
      parameters:
        - name: serviceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Serviço publicado"
        '409':
          description: "Serviço sem versão aprovada ou já publicado"

  /services/{serviceId}/suspend:
    post:
      summary: "Suspensão temporária do serviço"
      tags: [Catálogo]
      parameters:
        - name: serviceId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Serviço suspenso"

  /service-categories:
    get:
      summary: "Categorias de serviços do tenant"
      tags: [Catálogo]
      security: []
      responses:
        '200':
          description: "Árvore de categorias"

71.6 Grupo Funcional: Solicitações e Formulários

71.6.1 Request Service

O Request Service é o serviço central da plataforma. Seu contrato define o ciclo completo de uma solicitação de serviço público.

paths:
  /requests:
    get:
      summary: "Listagem de solicitações do cidadão autenticado"
      tags: [Solicitações]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [DRAFT, SUBMITTED, IN_PROGRESS, PENDING_COMPLEMENT,
                   COMPLETED, REJECTED, CANCELLED]
        - name: serviceId
          in: query
          schema:
            type: string
            format: uuid
        - name: createdFrom
          in: query
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          schema:
            type: string
            format: date-time
        - name: page
          in: query
          schema:
            type: integer
            default: 0
        - name: size
          in: query
          schema:
            type: integer
            default: 20
            maximum: 50
      responses:
        '200':
          description: "Solicitações paginadas"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PagedResponse'
                  - type: object
                    properties:
                      items:
                        type: array
                        items:
                          $ref: '#/components/schemas/RequestSummary'

    post:
      summary: "Criação de rascunho de solicitação"
      tags: [Solicitações]
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [serviceId, serviceVersion, formId, formVersion]
              properties:
                serviceId:
                  type: string
                  format: uuid
                serviceVersion:
                  type: string
                  description: "Versão do serviço no momento da criação"
                formId:
                  type: string
                  format: uuid
                formVersion:
                  type: string
                  description: "Versão do formulário — preservada para validação posterior"
                channel:
                  type: string
                  enum: [WEB, MOBILE, PRESENTIAL, PHONE]
      responses:
        '201':
          description: "Rascunho criado"
          headers:
            Location:
              schema:
                type: string
                format: uri
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Request'
        '400':
          $ref: '#/components/responses/400BadRequest'

  /requests/{requestId}:
    get:
      summary: "Detalhe da solicitação"
      tags: [Solicitações]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Solicitação completa com histórico de status"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Request'
        '404':
          $ref: '#/components/responses/404NotFound'

    patch:
      summary: "Atualização de dados do formulário (rascunho)"
      tags: [Solicitações]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: If-Match
          in: header
          required: false
          schema:
            type: string
          description: "ETag para controle de concorrência otimista"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                formData:
                  type: object
                  description: "Dados do formulário em estrutura livre definida pelo schema do formulário"
                  additionalProperties: true
      responses:
        '200':
          description: "Dados atualizados"
          headers:
            ETag:
              schema:
                type: string
        '412':
          description: "ETag não corresponde — conflito de concorrência"
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'

  /requests/{requestId}/submit:
    post:
      summary: "Submissão da solicitação — transição de DRAFT para SUBMITTED"
      tags: [Solicitações]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Solicitação submetida — protocolo gerado"
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                    format: uuid
                  protocolNumber:
                    type: string
                    description: "Número de protocolo único"
                  status:
                    type: string
                    enum: [SUBMITTED]
                  submittedAt:
                    type: string
                    format: date-time
        '409':
          description: "Solicitação já submetida"
        '422':
          description: "Formulário incompleto ou documentos obrigatórios ausentes"
          $ref: '#/components/responses/422UnprocessableContent'

  /requests/{requestId}/cancel:
    post:
      summary: "Cancelamento de solicitação pelo cidadão"
      tags: [Solicitações]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: "Solicitação cancelada"
        '409':
          description: "Status atual não permite cancelamento pelo cidadão"

  /requests/{requestId}/complement:
    post:
      summary: "Envio de complementação solicitada pelo atendente"
      tags: [Solicitações]
      parameters:
        - name: requestId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [complementData]
              properties:
                complementData:
                  type: object
                  additionalProperties: true
                message:
                  type: string
      responses:
        '200':
          description: "Complementação registrada"
        '409':
          description: "Solicitação não está aguardando complementação"

  /protocols/{protocolNumber}:
    get:
      summary: "Consulta pública de solicitação por protocolo"
      tags: [Protocolos]
      security: []
      parameters:
        - name: protocolNumber
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: "Situação da solicitação acessível publicamente"
          content:
            application/json:
              schema:
                type: object
                properties:
                  protocolNumber:
                    type: string
                  status:
                    type: string
                  serviceName:
                    type: string
                  submittedAt:
                    type: string
                    format: date-time
                  estimatedCompletionDate:
                    type: string
                    format: date
                  lastUpdate:
                    type: string
                    format: date-time
        '404':
          $ref: '#/components/responses/404NotFound'

71.6.2 Schemas Centrais do Request Service

components:
  schemas:
    Request:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
        protocolNumber:
          type: string
          nullable: true
          description: "Nulo até a submissão"
        tenantId:
          type: string
          format: uuid
        citizenId:
          type: string
          format: uuid
        serviceId:
          type: string
          format: uuid
        serviceVersion:
          type: string
        formId:
          type: string
          format: uuid
        formVersion:
          type: string
        status:
          type: string
          enum: [DRAFT, SUBMITTED, IN_PROGRESS, PENDING_COMPLEMENT,
                 COMPLETED, REJECTED, CANCELLED]
        channel:
          type: string
          enum: [WEB, MOBILE, PRESENTIAL, PHONE]
        formData:
          type: object
          additionalProperties: true
        documents:
          type: array
          items:
            $ref: '#/components/schemas/RequestDocumentRef'
        statusHistory:
          type: array
          items:
            $ref: '#/components/schemas/StatusHistoryEntry'
        createdAt:
          type: string
          format: date-time
        submittedAt:
          type: string
          format: date-time
          nullable: true
        updatedAt:
          type: string
          format: date-time

    RequestSummary:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
        protocolNumber:
          type: string
          nullable: true
        serviceName:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    StatusHistoryEntry:
      type: object
      properties:
        status:
          type: string
        transitionedAt:
          type: string
          format: date-time
        actor:
          type: string
          description: "ID do usuário ou 'SYSTEM'"
        note:
          type: string
          nullable: true

    RequestDocumentRef:
      type: object
      properties:
        documentId:
          type: string
          format: uuid
        role:
          type: string
          description: "Papel do documento na solicitação (ex: RG_FRENTE, COMPROVANTE_RESIDENCIA)"
        uploadedAt:
          type: string
          format: date-time

71.7 Grupo Funcional: Workflow e Tarefas

71.7.1 Workflow Service

paths:
  /process-instances:
    get:
      summary: "Listagem de instâncias de processo"
      tags: [Workflow]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [ACTIVE, SUSPENDED, COMPLETED, CANCELLED]
        - name: requestId
          in: query
          schema:
            type: string
            format: uuid
        - name: page
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: "Instâncias de processo paginadas"

    post:
      summary: "Criação de instância de processo (início de workflow)"
      tags: [Workflow]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [processDefinitionKey, variables]
              properties:
                processDefinitionKey:
                  type: string
                  description: "Chave da definição de processo no BPM Engine"
                requestId:
                  type: string
                  format: uuid
                tenantId:
                  type: string
                  format: uuid
                variables:
                  type: object
                  additionalProperties: true
      responses:
        '201':
          description: "Instância de processo criada"

  /process-instances/{instanceId}:
    get:
      summary: "Detalhe de instância de processo"
      tags: [Workflow]
      parameters:
        - name: instanceId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: "Estado atual da instância"

  /process-instances/{instanceId}/cancel:
    post:
      summary: "Cancelamento de instância de processo"
      tags: [Workflow]
      parameters:
        - name: instanceId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: "Instância cancelada"

  /process-definitions:
    get:
      summary: "Definições de processo disponíveis para o tenant"
      tags: [Workflow]
      responses:
        '200':
          description: "Lista de definições de processo"

  /process-definitions/{key}/deploy:
    post:
      summary: "Deploy de nova versão de definição de processo (BPMN)"
      tags: [Workflow]
      parameters:
        - name: key
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [bpmnFile]
              properties:
                bpmnFile:
                  type: string
                  format: binary
                  description: "Arquivo BPMN 2.0"
      responses:
        '201':
          description: "Definição implantada"

71.7.2 Task Service

paths:
  /tasks:
    get:
      summary: "Tarefas disponíveis para o usuário autenticado"
      tags: [Tarefas]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [CREATED, CLAIMED, IN_PROGRESS, COMPLETED, CANCELLED]
        - name: assignee
          in: query
          schema:
            type: string
            description: "UUID do usuário ou 'me' para tarefas do usuário autenticado"
        - name: priority
          in: query
          schema:
            type: string
            enum: [LOW, MEDIUM, HIGH, URGENT]
        - name: dueBefore
          in: query
          schema:
            type: string
            format: date-time
        - name: cursor
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 50
      responses:
        '200':
          description: "Tarefas (paginação por cursor)"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/CursorPagedResponse'

  /tasks/{taskId}:
    get:
      summary: "Detalhe de tarefa"
      tags: [Tarefas]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Dados completos da tarefa"

  /tasks/{taskId}/claim:
    post:
      summary: "Assumir tarefa"
      tags: [Tarefas]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Tarefa assumida"
        '409':
          description: "Tarefa já assumida por outro usuário"

  /tasks/{taskId}/unclaim:
    post:
      summary: "Devolver tarefa ao pool"
      tags: [Tarefas]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Tarefa devolvida ao pool"

  /tasks/{taskId}/complete:
    post:
      summary: "Conclusão de tarefa com variáveis de saída"
      tags: [Tarefas]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                variables:
                  type: object
                  additionalProperties: true
                  description: "Variáveis de processo atualizadas pela tarefa"
                comment:
                  type: string
      responses:
        '200':
          description: "Tarefa concluída — workflow prossegue"
        '409':
          description: "Tarefa não está em estado concluível"

  /tasks/{taskId}/delegate:
    post:
      summary: "Delegação de tarefa para outro usuário"
      tags: [Tarefas]
      parameters:
        - name: taskId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [targetUserId]
              properties:
                targetUserId:
                  type: string
                  format: uuid
                reason:
                  type: string
      responses:
        '200':
          description: "Tarefa delegada"

71.8 Grupo Funcional: CRM e Comunicação

71.8.1 CRM Service

paths:
  /interactions:
    get:
      summary: "Histórico de interações do tenant"
      tags: [CRM]
      parameters:
        - name: citizenId
          in: query
          schema:
            type: string
            format: uuid
        - name: channel
          in: query
          schema:
            type: string
            enum: [PORTAL, MOBILE, PHONE, EMAIL, WHATSAPP, PRESENTIAL]
        - name: status
          in: query
          schema:
            type: string
            enum: [OPEN, PENDING, RESOLVED, CLOSED]
        - name: cursor
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
            maximum: 100
      responses:
        '200':
          description: "Interações (paginação por cursor)"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/CursorPagedResponse'

    post:
      summary: "Abertura de nova interação"
      tags: [CRM]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [citizenId, channel, subject]
              properties:
                citizenId:
                  type: string
                  format: uuid
                channel:
                  type: string
                  enum: [PORTAL, MOBILE, PHONE, EMAIL, WHATSAPP, PRESENTIAL]
                subject:
                  type: string
                requestId:
                  type: string
                  format: uuid
                  nullable: true
                  description: "Solicitação relacionada, se houver"
      responses:
        '201':
          description: "Interação aberta"
          headers:
            Location:
              schema:
                type: string
                format: uri

  /interactions/{interactionId}:
    get:
      summary: "Detalhe da interação com histórico de mensagens"
      tags: [CRM]
      parameters:
        - name: interactionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Interação completa"

  /interactions/{interactionId}/messages:
    post:
      summary: "Envio de mensagem na interação"
      tags: [CRM]
      parameters:
        - name: interactionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content]
              properties:
                content:
                  type: string
                  maxLength: 5000
                attachments:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: "IDs de documentos previamente enviados"
      responses:
        '201':
          description: "Mensagem registrada"

  /interactions/{interactionId}/close:
    post:
      summary: "Encerramento de interação"
      tags: [CRM]
      parameters:
        - name: interactionId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                resolution:
                  type: string
                closureReason:
                  type: string
                  enum: [RESOLVED, UNRESOLVED, CITIZEN_ABANDONED, DUPLICATE]
      responses:
        '200':
          description: "Interação encerrada"

71.8.2 Communication Service

paths:
  /communications:
    post:
      summary: "Envio de comunicação para cidadão (e-mail, SMS, WhatsApp, push)"
      tags: [Comunicação]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [citizenId, templateId, channel]
              properties:
                citizenId:
                  type: string
                  format: uuid
                templateId:
                  type: string
                  format: uuid
                templateVersion:
                  type: string
                channel:
                  type: string
                  enum: [EMAIL, SMS, WHATSAPP, PUSH]
                variables:
                  type: object
                  additionalProperties: true
                  description: "Variáveis de substituição no template"
                scheduledAt:
                  type: string
                  format: date-time
                  nullable: true
                  description: "Nulo para envio imediato"
      responses:
        '202':
          description: "Comunicação aceita para envio"
          content:
            application/json:
              schema:
                type: object
                properties:
                  communicationId:
                    type: string
                    format: uuid
                  status:
                    type: string
                    enum: [QUEUED, SCHEDULED]

  /communications/{communicationId}:
    get:
      summary: "Situação de envio de comunicação"
      tags: [Comunicação]
      parameters:
        - name: communicationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Status de entrega"
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum: [QUEUED, SCHEDULED, SENDING, DELIVERED, BOUNCED, FAILED]
                  sentAt:
                    type: string
                    format: date-time
                    nullable: true
                  deliveredAt:
                    type: string
                    format: date-time
                    nullable: true
                  failureReason:
                    type: string
                    nullable: true

  /templates:
    get:
      summary: "Templates de comunicação do tenant"
      tags: [Comunicação]
      responses:
        '200':
          description: "Lista de templates"

    post:
      summary: "Criação de template de comunicação"
      tags: [Comunicação]
      responses:
        '201':
          description: "Template criado"

  /templates/{templateId}/versions:
    post:
      summary: "Publicação de nova versão de template"
      tags: [Comunicação]
      parameters:
        - name: templateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [channel, subject, body]
              properties:
                channel:
                  type: string
                  enum: [EMAIL, SMS, WHATSAPP, PUSH]
                subject:
                  type: string
                  nullable: true
                  description: "Obrigatório para e-mail"
                body:
                  type: string
                  description: "Conteúdo com variáveis em sintaxe {{variavel}}"
                variables:
                  type: array
                  items:
                    type: string
                  description: "Lista das variáveis esperadas no template"
      responses:
        '201':
          description: "Versão de template publicada"

71.9 Grupo Funcional: Documentos e Agendamentos

71.9.1 Document Service

paths:
  /documents:
    post:
      summary: "Upload de documento"
      tags: [Documentos]
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, documentType]
              properties:
                file:
                  type: string
                  format: binary
                  description: "Arquivo binário (PDF, JPEG, PNG)"
                documentType:
                  type: string
                  description: "Tipo de documento conforme catálogo do tenant"
                requestId:
                  type: string
                  format: uuid
                  nullable: true
                  description: "Solicitação à qual o documento será associado"
                citizenId:
                  type: string
                  format: uuid
                description:
                  type: string
            encoding:
              file:
                contentType: application/pdf, image/jpeg, image/png
      responses:
        '201':
          description: "Documento armazenado"
          content:
            application/json:
              schema:
                type: object
                properties:
                  documentId:
                    type: string
                    format: uuid
                  fileName:
                    type: string
                  mimeType:
                    type: string
                  sizeBytes:
                    type: integer
                  uploadedAt:
                    type: string
                    format: date-time
        '413':
          description: "Arquivo excede o tamanho máximo permitido"

  /documents/{documentId}:
    get:
      summary: "Metadados do documento"
      tags: [Documentos]
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Metadados do documento"
        '404':
          $ref: '#/components/responses/404NotFound'

    delete:
      summary: "Exclusão de documento (restrita a rascunhos e documentos não submetidos)"
      tags: [Documentos]
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: "Documento excluído"
        '409':
          description: "Documento vinculado a solicitação submetida — exclusão não permitida"

  /documents/{documentId}/download:
    get:
      summary: "Download do arquivo do documento"
      tags: [Documentos]
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Arquivo binário do documento"
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
          headers:
            Content-Disposition:
              schema:
                type: string
              description: "attachment; filename=\"nome-do-arquivo.pdf\""
            Content-Type:
              schema:
                type: string

  /documents/{documentId}/classify:
    post:
      summary: "Classificação manual ou reclassificação de documento"
      tags: [Documentos]
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [documentType]
              properties:
                documentType:
                  type: string
                classification:
                  type: string
                  enum: [PUBLIC, INTERNAL, CONFIDENTIAL, RESTRICTED]
      responses:
        '200':
          description: "Documento classificado"

  /documents/{documentId}/versions:
    get:
      summary: "Histórico de versões do documento"
      tags: [Documentos]
      parameters:
        - name: documentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Versões do documento"

71.9.2 Scheduling Service

paths:
  /agendas:
    get:
      summary: "Agendas de atendimento disponíveis"
      tags: [Agendamentos]
      parameters:
        - name: serviceId
          in: query
          schema:
            type: string
            format: uuid
        - name: locationId
          in: query
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Agendas disponíveis"

    post:
      summary: "Criação de agenda de atendimento"
      tags: [Agendamentos]
      responses:
        '201':
          description: "Agenda criada"

  /agendas/{agendaId}/availability:
    get:
      summary: "Disponibilidade de horários em uma agenda"
      tags: [Agendamentos]
      parameters:
        - name: agendaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: date
          in: query
          required: true
          schema:
            type: string
            format: date
          description: "Data para consulta de disponibilidade"
      responses:
        '200':
          description: "Horários disponíveis"
          content:
            application/json:
              schema:
                type: object
                properties:
                  date:
                    type: string
                    format: date
                  slots:
                    type: array
                    items:
                      type: object
                      properties:
                        slotId:
                          type: string
                          format: uuid
                        startTime:
                          type: string
                          format: date-time
                        endTime:
                          type: string
                          format: date-time
                        available:
                          type: boolean

  /appointments:
    post:
      summary: "Agendamento de horário"
      tags: [Agendamentos]
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [agendaId, slotId, citizenId]
              properties:
                agendaId:
                  type: string
                  format: uuid
                slotId:
                  type: string
                  format: uuid
                citizenId:
                  type: string
                  format: uuid
                requestId:
                  type: string
                  format: uuid
                  nullable: true
                notes:
                  type: string
      responses:
        '201':
          description: "Agendamento confirmado"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Appointment'
        '409':
          description: "Horário já ocupado — outro cidadão confirmou antes"

  /appointments/{appointmentId}:
    get:
      summary: "Detalhe do agendamento"
      tags: [Agendamentos]
      parameters:
        - name: appointmentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Agendamento"

  /appointments/{appointmentId}/reschedule:
    post:
      summary: "Reagendamento"
      tags: [Agendamentos]
      parameters:
        - name: appointmentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [newSlotId]
              properties:
                newSlotId:
                  type: string
                  format: uuid
                reason:
                  type: string
      responses:
        '200':
          description: "Reagendamento confirmado"

  /appointments/{appointmentId}/cancel:
    post:
      summary: "Cancelamento de agendamento"
      tags: [Agendamentos]
      parameters:
        - name: appointmentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: "Agendamento cancelado"

71.10 Grupo Funcional: Ouvidoria e Satisfação

71.10.1 Ombudsman Service

paths:
  /manifestations:
    get:
      summary: "Listagem de manifestações"
      tags: [Ouvidoria]
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [RECLAMACAO, DENUNCIA, SUGESTAO, ELOGIO, SOLICITACAO, PEDIDO_INFORMACAO]
        - name: status
          in: query
          schema:
            type: string
            enum: [REGISTERED, TRIAGED, FORWARDED, PENDING_COMPLEMENT, RESPONDED, CLOSED]
        - name: page
          in: query
          schema:
            type: integer
        - name: size
          in: query
          schema:
            type: integer
            maximum: 50
      responses:
        '200':
          description: "Manifestações paginadas"

    post:
      summary: "Registro de manifestação de ouvidoria"
      tags: [Ouvidoria]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, subject, description]
              properties:
                type:
                  type: string
                  enum: [RECLAMACAO, DENUNCIA, SUGESTAO, ELOGIO, SOLICITACAO, PEDIDO_INFORMACAO]
                subject:
                  type: string
                description:
                  type: string
                anonymous:
                  type: boolean
                  default: false
                  description: "Manifestação anônima — identidade não registrada"
                documents:
                  type: array
                  items:
                    type: string
                    format: uuid
      responses:
        '201':
          description: "Manifestação registrada"

  /manifestations/{manifestationId}:
    get:
      summary: "Detalhe da manifestação"
      tags: [Ouvidoria]
      parameters:
        - name: manifestationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Manifestação completa"

  /manifestations/{manifestationId}/forward:
    post:
      summary: "Encaminhamento para setor responsável"
      tags: [Ouvidoria]
      parameters:
        - name: manifestationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [targetSectorId]
              properties:
                targetSectorId:
                  type: string
                  format: uuid
                forwardingNote:
                  type: string
      responses:
        '200':
          description: "Manifestação encaminhada"

  /manifestations/{manifestationId}/respond:
    post:
      summary: "Resposta à manifestação"
      tags: [Ouvidoria]
      parameters:
        - name: manifestationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [response]
              properties:
                response:
                  type: string
                internalNote:
                  type: string
                  description: "Nota interna não visível ao cidadão"
      responses:
        '200':
          description: "Resposta registrada"

  /manifestations/{manifestationId}/close:
    post:
      summary: "Encerramento da manifestação"
      tags: [Ouvidoria]
      parameters:
        - name: manifestationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Manifestação encerrada"

71.10.2 Satisfaction Service

paths:
  /feedback:
    get:
      summary: "Listagem de avaliações recebidas"
      tags: [Satisfação]
      parameters:
        - name: serviceId
          in: query
          schema:
            type: string
            format: uuid
        - name: channel
          in: query
          schema:
            type: string
        - name: ratingFrom
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 5
        - name: ratingTo
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 5
        - name: page
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: "Avaliações paginadas"

    post:
      summary: "Submissão de avaliação pelo cidadão"
      tags: [Satisfação]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rating, context]
              properties:
                rating:
                  type: integer
                  minimum: 1
                  maximum: 5
                comment:
                  type: string
                  maxLength: 1000
                context:
                  type: object
                  required: [type]
                  properties:
                    type:
                      type: string
                      enum: [REQUEST, INTERACTION, APPOINTMENT, SERVICE]
                    referenceId:
                      type: string
                      format: uuid
                channel:
                  type: string
      responses:
        '201':
          description: "Avaliação registrada"

  /feedback/summary:
    get:
      summary: "Consolidação de indicadores de satisfação"
      tags: [Satisfação]
      parameters:
        - name: serviceId
          in: query
          schema:
            type: string
            format: uuid
        - name: period
          in: query
          schema:
            type: string
            enum: [7D, 30D, 90D, 12M]
            default: 30D
      responses:
        '200':
          description: "Indicadores consolidados"
          content:
            application/json:
              schema:
                type: object
                properties:
                  averageRating:
                    type: number
                    format: float
                    minimum: 1
                    maximum: 5
                  totalResponses:
                    type: integer
                  nps:
                    type: number
                    description: "Net Promoter Score calculado"
                  distribution:
                    type: object
                    properties:
                      rating1:
                        type: integer
                      rating2:
                        type: integer
                      rating3:
                        type: integer
                      rating4:
                        type: integer
                      rating5:
                        type: integer
                  period:
                    type: object
                    properties:
                      from:
                        type: string
                        format: date
                      to:
                        type: string
                        format: date

71.11 Grupo Funcional: Analytics e IA

71.11.1 Analytics Service

paths:
  /dashboards:
    get:
      summary: "Dashboards disponíveis para o perfil do usuário"
      tags: [Analytics]
      responses:
        '200':
          description: "Lista de dashboards"

  /dashboards/{dashboardId}/data:
    get:
      summary: "Dados do dashboard para renderização"
      tags: [Analytics]
      parameters:
        - name: dashboardId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: period
          in: query
          schema:
            type: string
            enum: [TODAY, 7D, 30D, 90D, 12M, CUSTOM]
        - name: from
          in: query
          schema:
            type: string
            format: date
        - name: to
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: "Conjuntos de dados para os widgets do dashboard"

  /metrics/{domain}:
    get:
      summary: "Métricas operacionais por domínio"
      tags: [Analytics]
      parameters:
        - name: domain
          in: path
          required: true
          schema:
            type: string
            enum: [requests, interactions, ombudsman, appointments, communications, satisfaction]
        - name: period
          in: query
          schema:
            type: string
            enum: [7D, 30D, 90D, 12M]
            default: 30D
      responses:
        '200':
          description: "Métricas do domínio selecionado"

  /reports:
    get:
      summary: "Relatórios disponíveis e agendados"
      tags: [Analytics]
      responses:
        '200':
          description: "Lista de relatórios"

  /reports/export:
    post:
      summary: "Exportação de relatório"
      tags: [Analytics]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reportType, period, format]
              properties:
                reportType:
                  type: string
                period:
                  type: object
                  properties:
                    from:
                      type: string
                      format: date
                    to:
                      type: string
                      format: date
                format:
                  type: string
                  enum: [CSV, XLSX, PDF]
                filters:
                  type: object
                  additionalProperties: true
      responses:
        '202':
          description: "Exportação em processamento"
          content:
            application/json:
              schema:
                type: object
                properties:
                  exportId:
                    type: string
                    format: uuid
                  estimatedReadyAt:
                    type: string
                    format: date-time

71.11.2 AI Gateway — Contratos de IA

paths:
  /ai/chat:
    post:
      summary: "Envio de mensagem ao assistente de IA do tenant"
      tags: [IA]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [message]
              properties:
                message:
                  type: string
                  maxLength: 4096
                conversationId:
                  type: string
                  format: uuid
                  nullable: true
                  description: "Nulo para nova conversa"
                stream:
                  type: boolean
                  default: false
                  description: "true para resposta via Server-Sent Events"
                context:
                  type: object
                  properties:
                    requestId:
                      type: string
                      format: uuid
                    serviceId:
                      type: string
                      format: uuid
      responses:
        '200':
          description: "Resposta da IA (modo síncrono)"
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversationId:
                    type: string
                    format: uuid
                  messageId:
                    type: string
                    format: uuid
                  content:
                    type: string
                  model:
                    type: string
                    description: "Modelo utilizado — abstraído pelo AI Gateway"
                  tokensUsed:
                    type: integer
            text/event-stream:
              schema:
                type: string
                description: |
                  Server-Sent Events para modo streaming.
                  Eventos: data: {delta}, data: [DONE]

  /ai/search:
    post:
      summary: "Busca semântica na base de conhecimento do tenant"
      tags: [IA]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query:
                  type: string
                  maxLength: 512
                knowledgeBaseId:
                  type: string
                  format: uuid
                  nullable: true
                topK:
                  type: integer
                  minimum: 1
                  maximum: 20
                  default: 5
      responses:
        '200':
          description: "Resultados da busca semântica"
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        documentId:
                          type: string
                        chunk:
                          type: string
                        score:
                          type: number
                          format: float
                        metadata:
                          type: object
                          additionalProperties: true

  /ai/classify:
    post:
      summary: "Classificação de texto por modelo de IA"
      tags: [IA]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text, classificationTask]
              properties:
                text:
                  type: string
                classificationTask:
                  type: string
                  enum: [MANIFESTATION_TYPE, SENTIMENT, PRIORITY, SERVICE_CATEGORY]
      responses:
        '200':
          description: "Resultado da classificação"
          content:
            application/json:
              schema:
                type: object
                properties:
                  label:
                    type: string
                  confidence:
                    type: number
                    format: float
                  alternatives:
                    type: array
                    items:
                      type: object
                      properties:
                        label:
                          type: string
                        confidence:
                          type: number

  /ai/knowledge-bases:
    get:
      summary: "Bases de conhecimento do tenant"
      tags: [IA]
      responses:
        '200':
          description: "Lista de bases de conhecimento"

    post:
      summary: "Criação de base de conhecimento"
      tags: [IA]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                description:
                  type: string
      responses:
        '201':
          description: "Base criada"

  /ai/knowledge-bases/{knowledgeBaseId}/documents:
    post:
      summary: "Indexação de documento na base de conhecimento"
      tags: [IA]
      parameters:
        - name: knowledgeBaseId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                title:
                  type: string
                metadata:
                  type: string
                  description: "JSON com metadados do documento"
      responses:
        '202':
          description: "Documento aceito para indexação"

71.12 Contratos de Webhooks

A plataforma expõe mecanismo de webhooks para notificação de eventos a sistemas externos autorizados. O contrato de webhook é simétrico ao catálogo de eventos do Capítulo 72.

paths:
  /webhooks:
    get:
      summary: "Endpoints de webhook configurados pelo tenant"
      tags: [Webhooks]
      responses:
        '200':
          description: "Lista de webhooks"

    post:
      summary: "Registro de endpoint de webhook"
      tags: [Webhooks]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [targetUrl, events, signingSecret]
              properties:
                targetUrl:
                  type: string
                  format: uri
                  description: "Endpoint HTTPS do sistema receptor"
                events:
                  type: array
                  items:
                    type: string
                  description: "Eventos subscritos (ex: request.submitted.v1)"
                signingSecret:
                  type: string
                  writeOnly: true
                  description: "Segredo para assinatura HMAC-SHA256 do payload"
                active:
                  type: boolean
                  default: true
      responses:
        '201':
          description: "Webhook registrado"

  /webhooks/{webhookId}:
    delete:
      summary: "Remoção de webhook"
      tags: [Webhooks]
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: "Webhook removido"

  /webhooks/{webhookId}/test:
    post:
      summary: "Disparo de evento de teste"
      tags: [Webhooks]
      parameters:
        - name: webhookId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: "Payload de teste enviado"
          content:
            application/json:
              schema:
                type: object
                properties:
                  httpStatus:
                    type: integer
                  responseTimeMs:
                    type: integer
                  success:
                    type: boolean

Payload padrão de webhook:

{
  "webhookId": "uuid",
  "eventType": "request.submitted.v1",
  "occurredAt": "2026-07-17T14:30:00Z",
  "tenantId": "uuid",
  "payload": {
    "requestId": "uuid",
    "protocolNumber": "2026-00123456",
    "serviceId": "uuid"
  },
  "signature": "sha256=hmac-assinatura-hex"
}

A assinatura usa HMAC-SHA256 sobre o corpo bruto do payload. O receptor deve validar a assinatura antes de processar o evento. Webhooks sem resposta 2xx em até 30 segundos são reenviados com backoff exponencial até 5 tentativas.


71.13 Convenções Transversais de Contrato

71.13.1 Headers Obrigatórios em Toda Requisição Autenticada

HeaderTipoGerado porPropósito
Authorization: Bearer {token}AutenticaçãoClienteToken JWT de sessão
X-Tenant-IdContextoGatewayDerivado do token — não aceito do cliente como único fator
X-Correlation-IdRastreamentoGatewayPropagado ao longo de toda a cadeia
X-Request-IdRastreamentoGatewayIdentificador único da requisição HTTP
traceparentTelemetriaGatewayW3C Trace Context para rastreamento distribuído

71.13.2 Headers de Resposta Padrão

HeaderPresente emPropósito
LocationPOST 201URL do recurso criado
ETagGET com versionamentoVersão do recurso para controle de concorrência
SunsetAPIs depreciadasData de remoção da versão
Retry-After429Segundos até próxima tentativa
X-Correlation-IdTodas as respostasRastreabilidade na resposta

71.13.3 Campos Proibidos em Respostas

Independentemente do que o consumidor solicita, os contratos garantem que as seguintes informações nunca aparecem em respostas de API:

  • Stack trace Java ou qualquer outra linguagem
  • Nome de classe interna, método, caminho de arquivo ou linha de código
  • Query SQL ou nome de tabela
  • URL interna de serviço
  • Credencial, chave de API, segredo ou token
  • Payload completo de outro tenant
  • Dados pessoais sensíveis em endpoints que não os requerem explicitamente

71.13.4 Matriz de Paginação por Tipo de API

Tipo de ListagemEstratégiaParâmetrosResposta
Listagens administrativas com totalOffsetpage, size (max 100)PagedResponse com totalElements
Feeds, histórico, grandes volumesCursorcursor, limit (max 100)CursorPagedResponse com nextCursor
Busca com relevânciaCursor + scorecursor, limit, qItens com campo score
ExportaçõesAssíncronaJob ID + polling202 Accepted + endpoint de status

71.13.5 Tenant Isolation por Contrato

Nenhum endpoint retorna ou aceita dados de tenant diferente do tenant derivado da identidade autenticada. Essa garantia é aplicada em duas camadas: o API Gateway bloqueia requisições sem token válido e extrai o tenant do token; o serviço de domínio filtra todos os acessos ao banco de dados pelo tenantId extraído do Tenant Context — nunca pelo tenantId da query string ou body do cliente.


71.14 Catálogo de Contratos por Serviço

A tabela a seguir consolida todos os contratos OpenAPI da plataforma com localização, versão e classificação.

ServiçoArquivo de ContratoVersãoClassificaçãoEstratégia
Identity Serviceidentity-service-api.yaml1.2.0Pública + CanalDesign First
Tenant Servicetenant-service-api.yaml1.1.0AdministrativaDesign First
Citizen Servicecitizen-service-api.yaml1.3.0Pública + CanalDesign First
Service Catalog Servicecatalog-service-api.yaml1.2.0Pública + CanalDesign First
Forms Serviceforms-service-api.yaml1.1.0Canal + InternaDesign First
Request Servicerequest-service-api.yaml2.0.0Pública + CanalDesign First
Workflow Serviceworkflow-service-api.yaml1.0.0Interna + AdministrativaCode First governado
Task Servicetask-service-api.yaml1.1.0Canal + InternaDesign First
CRM Servicecrm-service-api.yaml1.2.0Canal + InternaDesign First
Communication Servicecommunication-service-api.yaml1.1.0Canal + InternaCode First governado
Document Servicedocument-service-api.yaml1.3.0Pública + CanalDesign First
Scheduling Servicescheduling-service-api.yaml1.1.0Pública + CanalDesign First
Ombudsman Serviceombudsman-service-api.yaml1.0.0Pública + CanalDesign First
Satisfaction Servicesatisfaction-service-api.yaml1.0.0Pública + CanalDesign First
Segmentation Servicesegmentation-service-api.yaml1.0.0Administrativa + InternaCode First governado
Campaign Servicecampaign-service-api.yaml1.0.0AdministrativaCode First governado
Analytics Serviceanalytics-service-api.yaml1.1.0Canal + AdministrativaDesign First
Data Quality Servicedata-quality-service-api.yaml1.0.0AdministrativaCode First governado
AI Gatewayai-gateway-api.yaml1.2.0Canal + InternaDesign First
AI Specialized Serviceai-specialized-api.yaml1.0.0InternaCode First governado
Integration Serviceintegration-service-api.yaml1.1.0IntegraçãoDesign First
Configuration Serviceconfiguration-service-api.yaml1.0.0AdministrativaCode First governado
Audit Serviceaudit-service-api.yaml1.0.0AdministrativaDesign First
Webhookswebhooks-api.yaml1.0.0AdministrativaDesign First

Os arquivos de contrato são armazenados no repositório platform-api-contracts/ sob controle de versão Git, com pull request obrigatório para alterações em contratos classificados como Design First. O pipeline de CI valida a compatibilidade de cada pull request contra a versão anterior do contrato usando ferramentas de diff semântico de OpenAPI.


71.15 Governança de Evolução dos Contratos

71.15.1 Compatibilidade e Breaking Changes

A regra de compatibilidade segue o Capítulo 14: mudanças compatíveis não requerem nova versão de URI; mudanças incompatíveis exigem nova versão e período de convivência. O pipeline detecta automaticamente mudanças incompatíveis usando análise de diff de schema OpenAPI e bloqueia o merge quando identifica:

  • remoção de campo presente em respostas anteriores
  • mudança de tipo de campo existente
  • adição de campo obrigatório em request body
  • mudança de código HTTP de sucesso
  • remoção de endpoint ou método HTTP

71.15.2 Período de Deprecação

Contratos depreciados publicam o header Sunset com a data de remoção planejada. O portal de APIs exibe avisos de deprecação para desenvolvedores. Tenants integrados diretamente às APIs recebem comunicação formal conforme a política de descontinuação definida no Capítulo 55.

Sunset: Tue, 31 Mar 2027 00:00:00 GMT
Deprecation: Sat, 01 Oct 2026 00:00:00 GMT
Link: <https://api.plataforma.mg.gov.br/v2/requests>; rel="successor-version"

71.15.3 Testes de Contrato no Pipeline

Cada serviço de domínio mantém testes de contrato automatizados que verificam se a implementação Java/Spring Boot está em conformidade com o arquivo OpenAPI correspondente. A abordagem é Pact-compatible para APIs de integração crítica: o consumidor define suas expectativas em um pact file; o produtor verifica sua implementação contra esse pact no pipeline de CI. Qualquer divergência entre contrato e implementação falha o pipeline antes do merge, garantindo que contratos e código nunca divirjam silenciosamente.


71.16 Riscos e Mitigações

RiscoConsequênciaMitigação
Contrato desatualizado em relação à implementaçãoConsumidores codificam comportamento não documentadoTestes de contrato no pipeline; falha em caso de divergência
Breaking change sem versionamento de URICanais quebram após deployAnálise automática de diff no pipeline; bloqueio de merge
Schema com campo obrigatório adicionado silenciosamenteClientes antigos falham na serializaçãoPipeline de compatibilidade; período de deprecação obrigatório
Tenant Context extraído do bodyAcesso cruzado entre órgãosTenant Context extraído exclusivamente do token pelo Gateway
Dados pessoais em logs de APIVazamento de informação pessoal (LGPD)Mascaramento automático no middleware de logging; PII identificado no schema
Contrato de IA sem isolamento de quotaTenant consome quota de outroQuotas por tenant aplicadas no AI Gateway, não apenas no API Gateway externo
Versionamento inconsistente entre serviçosDificuldade de coordenação de mudançasConvenção única (/api/v{N}/) aplicada por linting no pipeline

71.17 Decisões Arquiteturais

ADRTema
ADR-086REST Guideline corporativo — verbos, URLs, JSON, datas
ADR-087Convenção JSON e padrão de datas (camelCase, ISO 8601 UTC)
ADR-088Estratégia de versionamento de APIs (URI, período de deprecação)
ADR-089Problem Details RFC 9457 — formato estendido com correlationId
ADR-090Estratégia de paginação por tipo de API (offset vs cursor)
ADR-091Idempotency-Key — implementação e retenção
ADR-092ETag e controle de concorrência otimista
ADR-093OpenAPI como contrato — Design First vs. Code First por categoria
ADR-094Tenant Context em HTTP — extração do token, não do header do cliente
ADR-106Webhooks — política, assinatura HMAC-SHA256 e reentrega
ADR-107Streaming de IA — SSE via text/event-stream por canal
ADR-108Contratos das capacidades de IA no AI Gateway

71.18 Rastreabilidade com Requisitos

Bloco 5 — Integração e Interoperabilidade (Anexo III):

  • Item 5.1 — Integração com sistemas internos e externos via APIs: todos os 24 serviços de domínio expõem contratos OpenAPI documentados neste capítulo; o padrão REST com versionamento por URI é aplicado uniformemente.
  • Item 5.3 — Gestão de APIs (versionamento e monitoramento): ciclo de vida de contrato com estados Proposed → Retired documentados no catálogo; header Sunset para deprecações; pipeline de compatibilidade como controle automatizado.
  • Item 5.6 — Uso de padrões de interoperabilidade: OpenAPI 3.1.0 como especificação de contrato; RFC 9457 para erros; W3C Trace Context para rastreamento; OAuth 2.0 / JWT para autenticação.

Bloco 6 — Infraestrutura, Segurança e Governança (Anexo III):

  • Item 6.5 — Rastreabilidade e auditoria: correlationId em toda resposta; X-Request-Id e traceparent propagados; PII mascarado em logs de API.

Capacidades (Anexo IV):

  • Item 1.2 — Integração de sistemas por APIs: catálogo de 24 contratos OpenAPI versionados; Design First para APIs de alto impacto; testes de contrato automatizados no pipeline.
  • Item 2.1 — Arquitetura multi-tenant: Tenant Context extraído do token em todos os contratos; filtro de tenant obrigatório validado por contrato e por implementação.

71.19 Próximo Capítulo

O Capítulo 72 — Eventos e Tópicos de Mensageria — documenta os contratos assíncronos da plataforma: o catálogo completo de eventos por domínio, as definições AsyncAPI dos tópicos RabbitMQ, os schemas de payload de cada evento, as políticas de DLQ e reentrega, e a rastreabilidade entre eventos publicados e consumidos pelos 24 serviços de domínio.


71.20 Controle de Versão

CampoValor
DocumentoDocumento Mestre — Plataforma de Relacionamento Digital com o Cidadão
Capítulo71 — Contratos REST e OpenAPI
Versão1.0
SituaçãoConcluído
Última atualização17/07/2026

71.21 Rastreabilidade PRODEMGE

Edital CP 001/2026:

  • Item 3.3 — Grupos de características técnicas: APIs REST documentadas em OpenAPI como padrão de interoperabilidade da plataforma.

Plano de Negócio (Anexo I):

  • Seção 3.3 — Características Técnicas: plataforma interoperável com APIs documentadas e integrada ao ecossistema governamental.
  • Seção 5 — Propriedade intelectual e custódia: contratos versionados em repositório sob custódia PRODEMGE conforme Capítulo 58.

Funcionalidades (Anexo III) — impacto na pontuação de 60%:

  • Bloco 5, Item 5.1 — Integração com sistemas internos e externos via APIs: 24 contratos OpenAPI documentados neste capítulo.
  • Bloco 5, Item 5.3 — Gestão de APIs (versionamento e monitoramento): ciclo de vida de contrato com análise automática de compatibilidade.
  • Bloco 5, Item 5.6 — Uso de padrões de interoperabilidade: OpenAPI 3.1.0, RFC 9457, W3C Trace Context.
  • Bloco 6, Item 6.5 — Rastreabilidade e auditoria: correlationId rastreável em toda resposta de API.

Capacidades (Anexo IV) — impacto na pontuação de 30%:

  • Bloco 1, Item 1.2 — Integração de sistemas por APIs: catálogo de 24 contratos versionados com testes automatizados de conformidade.
  • Bloco 2, Item 2.1 — Arquitetura multi-tenant: Tenant Context por contrato, validado em duas camadas.

Esclarecimentos pertinentes:

  • Madrona Advogados, 08/07/2026 — Documentação funcional confirmada: especificações de API, contratos OpenAPI, schemas e exemplos são evidências aceitas para fins de qualificação técnica.
  • WideLabs, 09/07/2026 — Evidências por links acessíveis publicamente são aceitas; os arquivos de contrato OpenAPI referenciados neste capítulo são acessíveis no repositório público da plataforma.

Erratas:

  • Errata nº 002 — Não aplicável a este capítulo.

Nesta página

71.1 Objetivo do Capítulo71.2 Estrutura dos Contratos OpenAPI71.2.1 Versão e Metadados71.2.2 Componentes Reutilizáveis71.2.3 Convenção de Content-Type71.3 Grupo Funcional: Identidade e Acesso71.3.1 Identity Service — Autenticação e Usuários71.4 Grupo Funcional: Tenant e Configuração71.4.1 Tenant Service71.5 Grupo Funcional: Cidadão e Catálogo71.5.1 Citizen Service71.5.2 Service Catalog Service71.6 Grupo Funcional: Solicitações e Formulários71.6.1 Request Service71.6.2 Schemas Centrais do Request Service71.7 Grupo Funcional: Workflow e Tarefas71.7.1 Workflow Service71.7.2 Task Service71.8 Grupo Funcional: CRM e Comunicação71.8.1 CRM Service71.8.2 Communication Service71.9 Grupo Funcional: Documentos e Agendamentos71.9.1 Document Service71.9.2 Scheduling Service71.10 Grupo Funcional: Ouvidoria e Satisfação71.10.1 Ombudsman Service71.10.2 Satisfaction Service71.11 Grupo Funcional: Analytics e IA71.11.1 Analytics Service71.11.2 AI Gateway — Contratos de IA71.12 Contratos de Webhooks71.13 Convenções Transversais de Contrato71.13.1 Headers Obrigatórios em Toda Requisição Autenticada71.13.2 Headers de Resposta Padrão71.13.3 Campos Proibidos em Respostas71.13.4 Matriz de Paginação por Tipo de API71.13.5 Tenant Isolation por Contrato71.14 Catálogo de Contratos por Serviço71.15 Governança de Evolução dos Contratos71.15.1 Compatibilidade e Breaking Changes71.15.2 Período de Deprecação71.15.3 Testes de Contrato no Pipeline71.16 Riscos e Mitigações71.17 Decisões Arquiteturais71.18 Rastreabilidade com Requisitos71.19 Próximo Capítulo71.20 Controle de Versão71.21 Rastreabilidade PRODEMGE