Skip to content

Repository files navigation

API REST — Gestão de Propostas

API versionada em /api/v1 para gestão de clientes e propostas, com idempotência, optimistic lock, auditoria e exclusão lógica.

Stack: Slim 4, PHP-DI, Eloquent (Illuminate Database), SQLite, PHPUnit.

Pré-requisitos

  • PHP 8.2+
  • Composer
  • Extensões PHP: pdo_sqlite, json, mbstring

Instalação

cd TestePratico
composer install
copy .env.example .env   # Windows
# cp .env.example .env   # Linux/macOS
php database/migrate.php
php database/seed.php

Executar localmente

php -S localhost:8080 -t public

Base URL: http://localhost:8080/api/v1

Testes

vendor/bin/phpunit

Cobertura obrigatória:

  • Transição válida e inválida de status
  • Idempotência (Idempotency-Key)
  • Conflito de versão (optimistic lock)
  • Busca com filtros e paginação

Padrão de erros

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Dados inválidos",
    "details": [{ "field": "documento", "message": "CPF inválido" }]
  }
}

Códigos: VALIDATION_ERROR (422), NOT_FOUND (404), CONFLICT (409), VERSION_CONFLICT (409), IDEMPOTENCY_CONFLICT (409), UNPROCESSABLE (422).

Headers

Header Uso
Content-Type: application/json Corpo JSON
Idempotency-Key Obrigatório em POST /propostas e POST /propostas/{id}/submit
X-Actor Identificador do ator (ex: user:123). Default: system

Endpoints

Clientes

POST /api/v1/clientes

curl -X POST http://localhost:8080/api/v1/clientes \
  -H "Content-Type: application/json" \
  -d "{\"nome\":\"João Silva\",\"email\":\"joao@example.com\",\"documento\":\"529.982.247-25\"}"

GET /api/v1/clientes/{id}

curl http://localhost:8080/api/v1/clientes/1

Propostas

POST /api/v1/propostas (requer Idempotency-Key)

curl -X POST http://localhost:8080/api/v1/propostas \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "X-Actor: user:1" \
  -d "{\"cliente_id\":1,\"produto\":\"Plano Pro\",\"valor_mensal\":199.90,\"origem\":\"API\"}"

PATCH /api/v1/propostas/{id} (somente status DRAFT, exige versao)

curl -X PATCH http://localhost:8080/api/v1/propostas/1 \
  -H "Content-Type: application/json" \
  -d "{\"versao\":1,\"produto\":\"Plano Enterprise\",\"valor_mensal\":299.90}"

POST /api/v1/propostas/{id}/submit (requer Idempotency-Key)

curl -X POST http://localhost:8080/api/v1/propostas/1/submit \
  -H "Idempotency-Key: 660e8400-e29b-41d4-a716-446655440001"

POST /api/v1/propostas/{id}/approve

curl -X POST http://localhost:8080/api/v1/propostas/1/approve \
  -H "Content-Type: application/json" \
  -d "{\"actor\":\"user:admin\"}"

POST /api/v1/propostas/{id}/reject

curl -X POST http://localhost:8080/api/v1/propostas/1/reject

POST /api/v1/propostas/{id}/cancel (soft delete + auditoria)

curl -X POST http://localhost:8080/api/v1/propostas/1/cancel

GET /api/v1/propostas/{id}

curl http://localhost:8080/api/v1/propostas/1

GET /api/v1/propostas (filtros e paginação obrigatórios)

Query params: page, per_page, status, cliente_id, origem, produto, valor_min, valor_max, created_from, created_to, sort, order

curl "http://localhost:8080/api/v1/propostas?status=DRAFT&per_page=10&page=1&sort=created_at&order=desc"

GET /api/v1/propostas/{id}/auditoria

curl "http://localhost:8080/api/v1/propostas/1/auditoria?page=1&per_page=15"

Regras de negócio

Fluxo de status

DRAFT → submit → SUBMITTED → approve → APPROVED
                            → reject  → REJECTED
DRAFT/SUBMITTED → cancel → CANCELED (+ exclusão lógica)

Estados finais (APPROVED, REJECTED, CANCELED) são imutáveis.

Idempotência

POST /propostas e POST /propostas/{id}/submit exigem header Idempotency-Key. Requisições repetidas com a mesma chave e mesmo payload retornam a resposta original sem duplicar registros.

Optimistic lock

Campo versao incrementado a cada mutação. Envie a versão atual no PATCH ou no body das transições. Conflito retorna 409 VERSION_CONFLICT.

Auditoria

Eventos: CREATED, UPDATED_FIELDS, STATUS_CHANGED, DELETED_LOGICAL. Registrados automaticamente em mudanças de status ou campos sensíveis (produto, valor_mensal, cliente_id).

Estrutura do projeto

src/
  Application/Services/   # Regras de negócio
  Domain/                 # Enums, máquina de estados, validadores
  Http/Actions/           # Controllers
  Http/Middleware/        # Erros, JSON, idempotência
  Infrastructure/         # Models e repositories
database/migrations/      # Schema SQLite
tests/Feature/            # Testes de integração
tests/Unit/               # Testes unitários

Decisões arquiteturais

  1. Slim 4 — framework leve, ideal para API REST sem overhead de MVC completo.
  2. Eloquent standalone — migrations, relations e eager loading sem instalar Laravel inteiro.
  3. SQLite — zero configuração para execução local e testes em memória.
  4. Idempotência via middleware — centraliza lógica e persiste resposta para replay seguro.
  5. PropostaStatusMachine — transições de status em único ponto, facilitando testes e manutenção.

About

Uma API REST desenvolvida como solução para um desafio técnico da TSTech no processo seletivo para a vaga de Desenvolvedor Full Stack. O projeto foi construído utilizando Slim Framework 4, Composer e recursos nativos do PHP, priorizando uma arquitetura simples, organizada e de fácil manutenção.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages