⚙️ Tecnologias e Arquitetura
🗓 Informações Gerais
- Nome do Projeto: Plataforma Web com Frontend Estático e API em Lightsail
- Tech Lead: Jonathan Alves
- Data de Entrada na Área: 25/08/2025
- Data Estimada de Conclusão: 30/09/2025
Checklist de Entrada e Saída
✅ Checklist de Entrada
- Documento de Visão de Produto validado
📤 Checklist de Saída
- Stack definida e aprovada
- Diagrama de arquitetura completo
- Plano de implantação claro
- Documento validado com o time de Desenvolvimento
Stack Tecnológica
Frontend
- Framework: React + Vite
- Linguagem: TypeScript
- UI/Estilo: Tailwind CSS
- Ferramentas: ESLint, Prettier
- Hospedagem: Amazon S3 (static website) + CloudFront (CDN)
- Domínio: Route 53 + ACM (certificado SSL)
Justificativa: Build estático rápido e econômico via S3; distribuição global com baixa latência via CloudFront; domínio e SSL gerenciados pela AWS.
Backend
- Linguagem: TypeScript
- Framework: Nest.js
- Execução: Amazon Lightsail (instância ou Lightsail Containers)
- ORM: Prisma
- Autenticação: JWT (Access + Refresh token)
- Upload de Arquivos: Amazon S3
Justificativa: NestJS oferece arquitetura modular, validação e DI. Lightsail simplifica custo/gestão mantendo acesso ao ecossistema AWS.
Banco de Dados
- Tipo: Relacional
- Tecnologia: PostgreSQL gerenciado no Amazon Lightsail
Justificativa: Instância gerenciada com snapshots automáticos, menor custo/complexidade que RDS para este porte.
Outras Tecnologias
- Cache: N/A (futuro: ElastiCache/Redis)
- Monitoramento: CloudWatch Logs + Sentry
- Testes: N/A (futuro)
Arquitetura da Solução
Visão Geral
Aplicação SPA hospedada no S3 e servida globalmente pelo CloudFront. Usuário acessa app.seu-dominio.com (CloudFront), que chama a API api.seu-dominio.com hospedada em Lightsail. A API acessa PostgreSQL gerenciado do Lightsail em sub-rede privada.
Componentes Principais
- Frontend (S3 + CloudFront): Entrega de assets estáticos/SPA
- API (Lightsail): NestJS; autenticação JWT; integração com S3 e banco
- Banco de Dados (Lightsail PostgreSQL): Dados transacionais; snapshots automáticos
- DNS (Route 53): Zonas hospedadas e registros
- Certificados (ACM): TLS para CloudFront
Ambiente de Desenvolvimento
# Banco local
docker compose up -d db
# Backend
npm run start:dev
# Frontend
npm run dev
Considerações de Segurança
Políticas de CORS
- Permitir apenas
https://app.seu-dominio.com - Métodos: GET/POST/PUT/PATCH/DELETE
- Credenciais desabilitadas por padrão
Proteção de Dados
- Em trânsito: HTTPS via CloudFront/ACM; TLS 1.2+
- Em repouso: Criptografia S3 e banco habilitada
Autenticação e Autorização
- JWT com expiração curta (access token)
- Refresh token opcional
- Senhas com bcrypt
- Roles/guards no NestJS
Rede e Acesso
- Banco não exposto à Internet
- Security groups com portas mínimas
- 443/80 para CloudFront; 443/22 restrito para API
🗂️ MODELAGEM DE DADOS
USUÁRIOS
Empresa Parceira
CREATE TABLE companies (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
cnpj VARCHAR(14) UNIQUE NOT NULL,
logo VARCHAR(500),
description TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Consultor de Investimento
CREATE TABLE consultants (
id SERIAL PRIMARY KEY,
company_id INTEGER REFERENCES companies(id),
name VARCHAR(255) NOT NULL,
identification_number VARCHAR(50) NOT NULL,
rg VARCHAR(20) NOT NULL,
cpf VARCHAR(11) UNIQUE NOT NULL,
cargo VARCHAR(100),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Cliente Final
CREATE TABLE clients (
id SERIAL PRIMARY KEY,
consultant_id INTEGER REFERENCES consultants(id),
name VARCHAR(255) NOT NULL,
rg VARCHAR(20) NOT NULL,
cpf VARCHAR(11) UNIQUE NOT NULL,
estado_civil VARCHAR(50),
cep VARCHAR(8),
endereco TEXT,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Especialista
CREATE TABLE specialists (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
rg VARCHAR(20) NOT NULL,
cpf VARCHAR(11) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
especialidade ENUM('carros', 'barcos', 'aeronaves') NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Admin
CREATE TABLE admins (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
PRODUTOS
Carros
CREATE TABLE cars (
id SERIAL PRIMARY KEY,
specialist_id INTEGER REFERENCES specialists(id),
marca VARCHAR(100) NOT NULL,
modelo VARCHAR(100) NOT NULL,
valor DECIMAL(15,2) NOT NULL,
estado ENUM('novo', 'seminovo', 'colecao') NOT NULL,
ano INTEGER NOT NULL,
descricao TEXT,
cor VARCHAR(50),
km INTEGER,
cambio VARCHAR(50),
combustivel VARCHAR(50),
tipo_categoria ENUM('SUV', 'sedan', 'coupe', 'conversivel', 'esportivo', 'supercarro'),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Barcos
CREATE TABLE boats (
id SERIAL PRIMARY KEY,
specialist_id INTEGER REFERENCES specialists(id),
marca VARCHAR(100) NOT NULL,
modelo VARCHAR(100) NOT NULL,
valor DECIMAL(15,2) NOT NULL,
ano INTEGER NOT NULL,
fabricante VARCHAR(100),
tamanho VARCHAR(50),
estilo VARCHAR(100),
combustivel VARCHAR(50),
motor VARCHAR(100),
ano_motor INTEGER,
descricao_completa TEXT,
acessorios TEXT,
estado ENUM('novo', 'seminovo', 'colecao') NOT NULL,
tipo_embarcacao ENUM('iate', 'lancha', 'catamara', 'veleiro', 'jet_boat', 'outro'),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Aeronaves
CREATE TABLE aircraft (
id SERIAL PRIMARY KEY,
specialist_id INTEGER REFERENCES specialists(id),
categoria VARCHAR(100),
ano INTEGER NOT NULL,
marca VARCHAR(100) NOT NULL,
modelo VARCHAR(100) NOT NULL,
assentos INTEGER,
estado ENUM('novo', 'seminovo', 'colecao') NOT NULL,
descricao TEXT,
valor DECIMAL(15,2) NOT NULL,
tipo_aeronave ENUM('VLJ', 'executivo_medio', 'intercontinental', 'turbohelice', 'helicoptero'),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Imagens dos Produtos
CREATE TABLE product_images (
id SERIAL PRIMARY KEY,
product_id INTEGER NOT NULL,
product_type ENUM('car', 'boat', 'aircraft') NOT NULL,
image_url VARCHAR(500) NOT NULL,
is_primary BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
);
PROCESSOS
Processos de Negociação
CREATE TABLE processes (
id SERIAL PRIMARY KEY,
client_id INTEGER REFERENCES clients(id),
specialist_id INTEGER REFERENCES specialists(id),
product_id INTEGER NOT NULL,
product_type ENUM('car', 'boat', 'aircraft') NOT NULL,
status ENUM('agendamento', 'negociacao', 'documentacao', 'concluido') DEFAULT 'agendamento',
notes TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Documentos
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
process_id INTEGER REFERENCES processes(id),
file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(500) NOT NULL,
file_type VARCHAR(50),
uploaded_by INTEGER NOT NULL,
uploaded_by_type ENUM('client', 'specialist') NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
Agendamentos
CREATE TABLE appointments (
id SERIAL PRIMARY KEY,
client_id INTEGER REFERENCES clients(id),
specialist_id INTEGER REFERENCES specialists(id),
product_id INTEGER NOT NULL,
product_type ENUM('car', 'boat', 'aircraft') NOT NULL,
date DATE NOT NULL,
time TIME NOT NULL,
status ENUM('scheduled', 'completed', 'cancelled') DEFAULT 'scheduled',
notes TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
GUIAS DE INTERESSE
Carros
CREATE TABLE car_interests (
id SERIAL PRIMARY KEY,
client_id INTEGER REFERENCES clients(id),
uso_principal VARCHAR(100),
preferencia_foco VARCHAR(100),
faixa_valor VARCHAR(50),
status VARCHAR(50),
marca_preferida VARCHAR(100),
modelo_preferido VARCHAR(100),
perfil_veiculo VARCHAR(100),
blindagem BOOLEAN,
carroceria VARCHAR(100),
fator_importante TEXT,
recursos_indispensaveis TEXT,
estilo_viagem VARCHAR(100),
mensagem_imagem TEXT,
prazo_aquisicao VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Barcos
CREATE TABLE boat_interests (
id SERIAL PRIMARY KEY,
client_id INTEGER REFERENCES clients(id),
uso_principal ENUM('lazer', 'cruzeiros', 'pesca', 'eventos', 'colecao_investimento'),
preferencia_foco ENUM('conforto', 'performance', 'equilibrio'),
faixa_valor ENUM('ate_500k', '500k_1M', 'acima_1M'),
status ENUM('nova', 'seminova', 'colecao_raridade'),
marca_preferida VARCHAR(100),
modelo_preferido VARCHAR(100),
tipo_embarcacao ENUM('iate', 'lancha', 'catamara', 'veleiro', 'jet_boat', 'outro'),
tamanho_embarcacao ENUM('ate_30_pes', '30_50_pes', 'acima_50_pes'),
motor ENUM('diesel', 'gasolina', 'eletrico_hibrido'),
capacidade_pessoas ENUM('1_4', '5_8', 'mais_8'),
cabine_pernoite ENUM('day_boat', '1_2_cabines', 'mais_2_cabines'),
experiencia_navegacao ENUM('nenhuma', 'basica', 'medio_porte', 'iates_grandes'),
operacao_embarcacao ENUM('pessoal', 'com_auxilio', 'apenas_crew_capitao'),
marina_preferencia ENUM('possui', 'precisa_indicacao', 'nao_prioridade'),
recursos_indispensaveis TEXT,
prazo_aquisicao ENUM('imediato', 'curto', 'medio', 'longo'),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Aeronaves
CREATE TABLE aircraft_interests (
id SERIAL PRIMARY KEY,
client_id INTEGER REFERENCES clients(id),
uso_principal ENUM('corporativo', 'lazer', 'turismo', 'transporte_familia', 'colecao_investimento'),
preferencia_foco ENUM('conforto_luxo', 'performance', 'equilibrio'),
faixa_valor ENUM('ate_5M', '5_20M', 'acima_20M'),
status ENUM('nova', 'seminova', 'colecao_raridade'),
marca_preferida VARCHAR(100),
modelo_preferido VARCHAR(100),
tipo_aeronave ENUM('VLJ', 'executivo', 'intercontinental', 'turbohelice', 'helicoptero', 'outro'),
alcance_autonomia ENUM('curta', 'media', 'longa'),
capacidade_passageiros ENUM('ate_4', '5_8', 'mais_8'),
experiencia_voo ENUM('nenhuma', 'aeronaves_leves', 'executivos_turbohelices', 'grandes_intercontinentais'),
operacao_aeronave ENUM('pilotar_pessoalmente', 'com_auxilio', 'apenas_crew_piloto'),
hangar_preferencia ENUM('possui', 'precisa_indicacao', 'nao_prioridade'),
configuracao_cabine ENUM('executiva', 'passageiros_familia', 'outra'),
recursos_indispensaveis TEXT,
prazo_aquisicao ENUM('imediato', 'curto', 'medio', 'longo'),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
🔌 API - ROTAS E ENDPOINTS
PADRÕES GERAIS DA API
Formato Base das Respostas
Todas as respostas da API seguem o padrão:
Sucesso:
{
"success": true,
"message": "Descrição da operação",
"data": { /* dados retornados */ },
"meta": { /* metadados quando aplicável */ }
}
Erro:
{
"success": false,
"error": {
"code": 400,
"message": "Descrição do erro",
"details": { /* detalhes específicos do erro */ },
"timestamp": "2024-10-08T14:30:00Z"
}
}
Paginação
Todas as rotas que retornam listas suportam paginação:
Query Params:
page(integer, default: 1) - Página atuallimit(integer, default: 20, max: 100) - Itens por páginasort(string) - Campo para ordenaçãoorder(string: 'asc'|'desc', default: 'desc') - Direção da ordenação
Resposta Paginada:
{
"success": true,
"message": "Lista recuperada com sucesso",
"data": [...],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 150,
"total_pages": 8,
"has_next": true,
"has_prev": false
}
}
}
AUTENTICAÇÃO
POST /api/auth/login
Descrição: Autentica usuário no sistema
Acesso: Público
Request:
{
"email": "user@email.com",
"password": "senha123"
}
Responses:
- 200 - Login realizado com sucesso:
{
"success": true,
"message": "Login realizado com sucesso",
"data": {
"token": "jwt_token_here",
"refresh_token": "refresh_token_here",
"expires_in": 3600,
"user": {
"id": 1,
"name": "Nome do Usuário",
"email": "user@email.com",
"user_type": "client",
"company_id": 1,
"created_at": "2024-10-08T14:30:00Z"
}
}
}
- 400 - Dados inválidos:
{
"success": false,
"error": {
"code": 400,
"message": "Dados inválidos",
"details": {
"email": ["O campo email é obrigatório"],
"password": ["O campo senha é obrigatório"]
}
}
}
- 401 - Credenciais inválidas:
{
"success": false,
"error": {
"code": 401,
"message": "Email ou senha incorretos"
}
}
- 429 - Rate limit excedido:
{
"success": false,
"error": {
"code": 429,
"message": "Muitas tentativas de login. Tente novamente em 15 minutos"
}
}
POST /api/auth/register/client
Descrição: Registra novo cliente no sistema
Acesso: Público
Request:
{
"name": "Nome do Cliente",
"email": "cliente@email.com",
"password": "senha123",
"rg": "12.345.678-9",
"cpf": "12345678901",
"estado_civil": "solteiro",
"cep": "01234567",
"endereco": "Rua das Flores, 123",
"consultant_id": 1
}
Responses:
- 201 - Conta criada com sucesso:
{
"success": true,
"message": "Conta criada com sucesso",
"data": {
"user": {
"id": 1,
"name": "Nome do Cliente",
"email": "cliente@email.com",
"user_type": "client",
"created_at": "2024-10-08T14:30:00Z"
}
}
}
- 409 - Email ou CPF já cadastrados:
{
"success": false,
"error": {
"code": 409,
"message": "Email ou CPF já cadastrados no sistema"
}
}
- 422 - Erro de validação:
{
"success": false,
"error": {
"code": 422,
"message": "Dados inválidos",
"details": {
"cpf": ["CPF inválido"],
"password": ["Senha deve ter pelo menos 6 caracteres"]
}
}
}
POST /api/auth/logout
Descrição: Invalida token do usuário
Acesso: Usuário autenticado
Responses:
- 200 - Logout realizado:
{
"success": true,
"message": "Logout realizado com sucesso"
}
- 401 - Token inválido:
{
"success": false,
"error": {
"code": 401,
"message": "Token inválido ou expirado"
}
}
POST /api/auth/refresh
Descrição: Renova token de acesso
Acesso: Usuário autenticado
Request:
{
"refresh_token": "refresh_token_here"
}
Responses:
- 200 - Token renovado:
{
"success": true,
"message": "Token renovado com sucesso",
"data": {
"token": "new_jwt_token",
"expires_in": 3600
}
}
- 401 - Token expirado:
{
"success": false,
"error": {
"code": 401,
"message": "Refresh token inválido ou expirado"
}
}
PRODUTOS - CARROS
GET /api/cars
Descrição: Lista todos os carros com filtros e paginação
Acesso: Todos usuários logados
Query Parameters:
Filtros de Busca:
- search (string) - Busca textual em marca, modelo e descrição
- marca (string) - Nome da marca
- modelo (string) - Nome do modelo
- ano_min (integer) - Ano mínimo
- ano_max (integer) - Ano máximo
- preco_min (decimal) - Preço mínimo
- preco_max (decimal) - Preço máximo
- estado (enum: 'novo'|'seminovo'|'colecao')
- tipo_categoria (enum: 'SUV'|'sedan'|'coupe'|'conversivel'|'esportivo'|'supercarro')
- cor (string) - Cor do veículo
- km_max (integer) - Quilometragem máxima
- cambio (enum: 'manual'|'automatico'|'cvt')
- combustivel (enum: 'gasolina'|'alcool'|'flex'|'diesel'|'eletrico'|'hibrido')
Paginação e Ordenação:
- page (integer, default: 1)
- limit (integer, default: 20, max: 100)
- sort (enum: 'valor'|'ano'|'km'|'created_at', default: 'created_at')
- order (enum: 'asc'|'desc', default: 'desc')
Responses:
- 200 - Lista recuperada com sucesso:
{
"success": true,
"message": "Carros listados com sucesso",
"data": [
{
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00,
"estado": "novo",
"ano": 2024,
"cor": "Rosso Corsa",
"km": 0,
"cambio": "automatico",
"combustivel": "gasolina",
"tipo_categoria": "esportivo",
"descricao": "Supercarro italiano com motor V8 biturbo",
"specialist": {
"id": 1,
"name": "João Silva",
"email": "joao@specialist.com"
},
"images": [
{
"id": 1,
"image_url": "https://bucket.s3.com/car-1-front.jpg",
"is_primary": true
}
],
"created_at": "2024-10-08T14:30:00Z",
"updated_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 45,
"total_pages": 3,
"has_next": true,
"has_prev": false
},
"filters": {
"total_without_filters": 120,
"applied_filters": ["marca", "preco_min"]
}
}
}
- 400 - Parâmetros inválidos:
{
"success": false,
"error": {
"code": 400,
"message": "Parâmetros de consulta inválidos",
"details": {
"ano_min": ["Deve ser um número inteiro"],
"preco_max": ["Deve ser maior que preco_min"]
}
}
}
GET /api/cars/:id
Descrição: Obtém detalhes de um carro específico
Acesso: Todos usuários logados
Responses:
- 200 - Carro encontrado:
{
"success": true,
"message": "Carro encontrado",
"data": {
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00,
"estado": "novo",
"ano": 2024,
"descricao": "Supercarro italiano com motor V8 biturbo de 720cv",
"cor": "Rosso Corsa",
"km": 0,
"cambio": "automatico",
"combustivel": "gasolina",
"tipo_categoria": "esportivo",
"specialist": {
"id": 1,
"name": "João Silva",
"email": "joao@specialist.com",
"especialidade": "carros"
},
"images": [
{
"id": 1,
"image_url": "https://bucket.s3.com/car-1-front.jpg",
"is_primary": true
},
{
"id": 2,
"image_url": "https://bucket.s3.com/car-1-interior.jpg",
"is_primary": false
}
],
"created_at": "2024-10-08T14:30:00Z",
"updated_at": "2024-10-08T14:30:00Z"
}
}
- 404 - Carro não encontrado:
{
"success": false,
"error": {
"code": 404,
"message": "Carro não encontrado"
}
}
POST /api/cars
Descrição: Cria novo carro no catálogo
Acesso: Especialista (carros), Admin
Request:
{
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00,
"estado": "novo",
"ano": 2024,
"descricao": "Supercarro italiano com motor V8 biturbo",
"cor": "Rosso Corsa",
"km": 0,
"cambio": "automatico",
"combustivel": "gasolina",
"tipo_categoria": "esportivo"
}
Responses:
- 201 - Carro criado com sucesso:
{
"success": true,
"message": "Carro cadastrado com sucesso",
"data": {
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo",
/* ... outros campos ... */
"created_at": "2024-10-08T14:30:00Z"
}
}
- 403 - Sem permissão:
{
"success": false,
"error": {
"code": 403,
"message": "Acesso negado. Apenas especialistas em carros podem criar carros"
}
}
PUT /api/cars/:id
Descrição: Atualiza dados de um carro
Acesso: Especialista owner, Admin
Responses:
- 200 - Carro atualizado:
{
"success": true,
"message": "Carro atualizado com sucesso",
"data": {
"id": 1,
/* ... dados atualizados ... */
"updated_at": "2024-10-08T15:00:00Z"
}
}
DELETE /api/cars/:id
Descrição: Remove carro do catálogo
Acesso: Especialista owner, Admin
Responses:
- 204 - Carro removido:
{
"success": true,
"message": "Carro removido com sucesso"
}
- 409 - Conflito:
{
"success": false,
"error": {
"code": 409,
"message": "Não é possível remover carro com processos ativos"
}
}
PRODUTOS - BARCOS
GET /api/boats
Descrição: Lista todos os barcos com filtros e paginação
Acesso: Todos usuários logados
Query Parameters:
Filtros Específicos de Barcos:
- tipo_embarcacao (enum: 'iate'|'lancha'|'catamara'|'veleiro'|'jet_boat'|'outro')
- tamanho (enum: 'ate_30_pes'|'30_50_pes'|'acima_50_pes')
- fabricante (string)
- combustivel (enum: 'diesel'|'gasolina'|'eletrico'|'hibrido')
- motor (string)
Filtros Comuns:
- search, marca, modelo, ano_min, ano_max, preco_min, preco_max, estado
- page, limit, sort, order
Responses:
- 200 - Lista de barcos:
{
"success": true,
"message": "Barcos listados com sucesso",
"data": [
{
"id": 1,
"marca": "Azimut",
"modelo": "Grande 32M",
"valor": 8500000.00,
"estado": "novo",
"ano": 2024,
"fabricante": "Azimut Yachts",
"tamanho": "acima_50_pes",
"estilo": "Motor Yacht",
"combustivel": "diesel",
"motor": "Caterpillar C32 ACERT",
"ano_motor": 2024,
"tipo_embarcacao": "iate",
"descricao_completa": "Iate de luxo com acabamento em madeira italiana",
"acessorios": "Ar condicionado, sistema de navegação GPS, som premium",
"specialist": {
"id": 2,
"name": "Marina Santos",
"especialidade": "barcos"
},
"images": [
{
"id": 3,
"image_url": "https://bucket.s3.com/boat-1-exterior.jpg",
"is_primary": true
}
],
"created_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 28,
"total_pages": 2,
"has_next": true,
"has_prev": false
}
}
}
PRODUTOS - AERONAVES
GET /api/aircraft
Descrição: Lista todas as aeronaves com filtros e paginação
Acesso: Todos usuários logados
Query Parameters:
Filtros Específicos de Aeronaves:
- categoria (string)
- tipo_aeronave (enum: 'VLJ'|'executivo_medio'|'intercontinental'|'turbohelice'|'helicoptero')
- assentos_min (integer)
- assentos_max (integer)
Filtros Comuns:
- search, marca, modelo, ano_min, ano_max, preco_min, preco_max, estado
- page, limit, sort, order
Responses:
- 200 - Lista de aeronaves:
{
"success": true,
"message": "Aeronaves listadas com sucesso",
"data": [
{
"id": 1,
"categoria": "Jato Executivo",
"ano": 2023,
"marca": "Embraer",
"modelo": "Phenom 300E",
"assentos": 8,
"estado": "seminovo",
"descricao": "Jato executivo médio com alcance intercontinental",
"valor": 15000000.00,
"tipo_aeronave": "executivo_medio",
"specialist": {
"id": 3,
"name": "Carlos Aviation",
"especialidade": "aeronaves"
},
"images": [
{
"id": 5,
"image_url": "https://bucket.s3.com/aircraft-1-exterior.jpg",
"is_primary": true
}
],
"created_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 15,
"total_pages": 1,
"has_next": false,
"has_prev": false
}
}
}
PROCESSOS DE NEGOCIAÇÃO
GET /api/processes
Descrição: Lista processos de negociação conforme permissões do usuário
Acesso: Conforme hierarquia de permissões
Regras de Acesso:
- Admin: Todos os processos
- Especialista: Apenas seus processos
- Consultor: Processos dos seus clientes
- Cliente: Apenas seus processos
Query Parameters:
Filtros:
- status (enum: 'agendamento'|'negociacao'|'documentacao'|'concluido')
- product_type (enum: 'car'|'boat'|'aircraft')
- client_id (integer) - apenas Admin/Consultor
- specialist_id (integer) - apenas Admin
- date_from (date: YYYY-MM-DD)
- date_to (date: YYYY-MM-DD)
- search (string) - nome do cliente ou produto
Paginação:
- page, limit, sort ('created_at'|'updated_at'|'status'), order
Responses:
- 200 - Lista de processos:
{
"success": true,
"message": "Processos listados com sucesso",
"data": [
{
"id": 1,
"status": "negociacao",
"product_type": "car",
"client": {
"id": 1,
"name": "João Cliente",
"email": "joao@email.com"
},
"specialist": {
"id": 1,
"name": "Maria Especialista",
"especialidade": "carros"
},
"product": {
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00
},
"notes": "Cliente demonstrou interesse em test drive",
"documents_count": 3,
"last_activity": "2024-10-08T10:30:00Z",
"created_at": "2024-10-05T14:30:00Z",
"updated_at": "2024-10-08T10:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 12,
"total_pages": 1,
"has_next": false,
"has_prev": false
},
"summary": {
"by_status": {
"agendamento": 2,
"negociacao": 5,
"documentacao": 3,
"concluido": 2
}
}
}
}
- 403 - Sem permissão:
{
"success": false,
"error": {
"code": 403,
"message": "Acesso negado. Você não tem permissão para visualizar estes processos"
}
}
POST /api/processes
Descrição: Cria novo processo de negociação
Acesso: Consultor (seus clientes), Admin
Request:
{
"client_id": 1,
"product_id": 1,
"product_type": "car",
"specialist_id": 1,
"notes": "Cliente interessado em test drive"
}
Responses:
- 201 - Processo criado:
{
"success": true,
"message": "Processo criado com sucesso",
"data": {
"id": 1,
"status": "agendamento",
"product_type": "car",
"client": {
"id": 1,
"name": "João Cliente"
},
"specialist": {
"id": 1,
"name": "Maria Especialista"
},
"product": {
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo"
},
"notes": "Cliente interessado em test drive",
"created_at": "2024-10-08T14:30:00Z"
}
}
- 404 - Recurso não encontrado:
{
"success": false,
"error": {
"code": 404,
"message": "Cliente, produto ou especialista não encontrado"
}
}
- 409 - Processo já existe:
{
"success": false,
"error": {
"code": 409,
"message": "Já existe um processo ativo para este cliente e produto"
}
}
PUT /api/processes/:id/status
Descrição: Atualiza status do processo
Acesso: Especialista owner, Admin
Request:
{
"status": "documentacao",
"notes": "Documentos enviados para análise"
}
Responses:
- 200 - Status atualizado:
{
"success": true,
"message": "Status do processo atualizado com sucesso",
"data": {
"id": 1,
"status": "documentacao",
"notes": "Documentos enviados para análise",
"updated_at": "2024-10-08T15:00:00Z",
"status_history": [
{
"status": "agendamento",
"changed_at": "2024-10-05T14:30:00Z"
},
{
"status": "negociacao",
"changed_at": "2024-10-07T10:00:00Z"
},
{
"status": "documentacao",
"changed_at": "2024-10-08T15:00:00Z"
}
]
}
}
AGENDAMENTOS
GET /api/appointments
Descrição: Lista agendamentos conforme permissões do usuário
Acesso: Conforme hierarquia de permissões
Query Parameters:
Filtros:
- status (enum: 'scheduled'|'completed'|'cancelled')
- date_from (date: YYYY-MM-DD)
- date_to (date: YYYY-MM-DD)
- client_id (integer) - conforme permissão
- specialist_id (integer) - conforme permissão
- product_type (enum: 'car'|'boat'|'aircraft')
Paginação:
- page, limit, sort ('date'|'time'|'created_at'), order
Responses:
- 200 - Lista de agendamentos:
{
"success": true,
"message": "Agendamentos listados com sucesso",
"data": [
{
"id": 1,
"date": "2024-10-10",
"time": "14:00:00",
"status": "scheduled",
"notes": "Test drive do Ferrari F8",
"client": {
"id": 1,
"name": "João Cliente",
"email": "joao@email.com"
},
"specialist": {
"id": 1,
"name": "Maria Especialista",
"especialidade": "carros"
},
"product": {
"id": 1,
"product_type": "car",
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00
},
"created_at": "2024-10-08T14:30:00Z",
"updated_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 8,
"total_pages": 1,
"has_next": false,
"has_prev": false
},
"summary": {
"upcoming": 5,
"completed": 2,
"cancelled": 1
}
}
}
POST /api/appointments
Descrição: Cria novo agendamento
Acesso: Cliente, Consultor, Especialista
Request:
{
"client_id": 1,
"specialist_id": 1,
"product_id": 1,
"product_type": "car",
"date": "2024-10-10",
"time": "14:00",
"notes": "Test drive do Ferrari F8"
}
Responses:
- 201 - Agendamento criado:
{
"success": true,
"message": "Agendamento criado com sucesso",
"data": {
"id": 1,
"date": "2024-10-10",
"time": "14:00:00",
"status": "scheduled",
"notes": "Test drive do Ferrari F8",
"client": {
"id": 1,
"name": "João Cliente"
},
"specialist": {
"id": 1,
"name": "Maria Especialista"
},
"product": {
"id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo"
},
"created_at": "2024-10-08T14:30:00Z"
}
}
- 409 - Conflito de horário:
{
"success": false,
"error": {
"code": 409,
"message": "Especialista já possui agendamento neste horário",
"details": {
"conflicting_appointment": {
"id": 2,
"date": "2024-10-10",
"time": "14:00:00",
"client": "Outro Cliente"
},
"suggested_times": [
"15:00:00",
"16:00:00",
"17:00:00"
]
}
}
}
- 422 - Erro de validação:
{
"success": false,
"error": {
"code": 422,
"message": "Dados inválidos",
"details": {
"date": ["Data deve ser futura"],
"time": ["Horário deve estar entre 08:00 e 18:00"]
}
}
}
PUT /api/appointments/:id/status
Descrição: Atualiza status do agendamento
Acesso: Participantes do agendamento, Admin
Request:
{
"status": "completed",
"notes": "Test drive realizado com sucesso"
}
Responses:
- 200 - Status atualizado:
{
"success": true,
"message": "Agendamento atualizado com sucesso",
"data": {
"id": 1,
"status": "completed",
"notes": "Test drive realizado com sucesso",
"completed_at": "2024-10-10T15:30:00Z",
"updated_at": "2024-10-10T15:30:00Z"
}
}
GUIAS DE INTERESSE
GET /api/interests/car
Descrição: Lista guias de interesse em carros
Acesso: Cliente (próprio), Consultor (seus clientes), Admin
Query Parameters:
Filtros:
- client_id (integer) - obrigatório para Consultor/Admin
- faixa_valor (string)
- marca_preferida (string)
- prazo_aquisicao (string)
- uso_principal (string)
Paginação: page, limit, sort, order
Responses:
- 200 - Lista de interesses:
{
"success": true,
"message": "Guias de interesse listados com sucesso",
"data": [
{
"id": 1,
"client": {
"id": 1,
"name": "João Cliente"
},
"uso_principal": "lazer",
"preferencia_foco": "conforto",
"faixa_valor": "1M_5M",
"status": "novo",
"marca_preferida": "Ferrari",
"modelo_preferido": "F8 Tributo",
"perfil_veiculo": "esportivo",
"blindagem": false,
"carroceria": "coupe",
"fator_importante": "Performance e design",
"recursos_indispensaveis": "Ar condicionado, som premium",
"estilo_viagem": "urbano",
"mensagem_imagem": "Procuro um supercarro para uso no fim de semana",
"prazo_aquisicao": "curto",
"created_at": "2024-10-08T14:30:00Z",
"updated_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 5,
"total_pages": 1,
"has_next": false,
"has_prev": false
}
}
}
POST /api/interests/car
Descrição: Cria novo guia de interesse em carros
Acesso: Cliente (próprio), Consultor (seus clientes)
Request:
{
"client_id": 1,
"uso_principal": "lazer",
"preferencia_foco": "conforto",
"faixa_valor": "1M_5M",
"status": "novo",
"marca_preferida": "Ferrari",
"modelo_preferido": "F8 Tributo",
"perfil_veiculo": "esportivo",
"blindagem": false,
"carroceria": "coupe",
"fator_importante": "Performance e design",
"recursos_indispensaveis": "Ar condicionado, som premium",
"estilo_viagem": "urbano",
"mensagem_imagem": "Procuro um supercarro para uso no fim de semana",
"prazo_aquisicao": "curto"
}
Responses:
- 201 - Interesse criado:
{
"success": true,
"message": "Guia de interesse criado com sucesso",
"data": {
"id": 1,
/* ... dados do interesse ... */
"created_at": "2024-10-08T14:30:00Z"
}
}
- 409 - Interesse já existe:
{
"success": false,
"error": {
"code": 409,
"message": "Cliente já possui um guia de interesse ativo para carros"
}
}
GET /api/interests/boat
Descrição: Lista guias de interesse em barcos
Estrutura similar ao endpoint de carros, com campos específicos de barcos
POST /api/interests/boat
Request com campos específicos de barcos:
{
"client_id": 1,
"uso_principal": "lazer",
"preferencia_foco": "conforto",
"faixa_valor": "500k_1M",
"status": "nova",
"marca_preferida": "Azimut",
"tipo_embarcacao": "iate",
"tamanho_embarcacao": "30_50_pes",
"motor": "diesel",
"capacidade_pessoas": "5_8",
"cabine_pernoite": "1_2_cabines",
"experiencia_navegacao": "medio_porte",
"operacao_embarcacao": "com_auxilio",
"marina_preferencia": "precisa_indicacao",
"recursos_indispensaveis": "GPS, ar condicionado",
"prazo_aquisicao": "medio"
}
GET /api/interests/aircraft
Descrição: Lista guias de interesse em aeronaves
Estrutura similar aos demais endpoints
POST /api/interests/aircraft
Request com campos específicos de aeronaves:
{
"client_id": 1,
"uso_principal": "corporativo",
"preferencia_foco": "performance",
"faixa_valor": "5_20M",
"status": "seminova",
"marca_preferida": "Embraer",
"tipo_aeronave": "executivo",
"alcance_autonomia": "media",
"capacidade_passageiros": "5_8",
"experiencia_voo": "executivos_turbohelices",
"operacao_aeronave": "apenas_crew_piloto",
"hangar_preferencia": "precisa_indicacao",
"configuracao_cabine": "executiva",
"recursos_indispensaveis": "Internet, entretenimento",
"prazo_aquisicao": "medio"
}
DOCUMENTOS
GET /api/processes/:id/documents
Descrição: Lista documentos de um processo específico
Acesso: Participantes do processo, Admin
Query Parameters:
Filtros:
- file_type (string) - Tipo do arquivo (pdf, jpg, png, etc.)
- uploaded_by_type (enum: 'client'|'specialist')
Paginação: page, limit, sort ('created_at'|'file_name'), order
Responses:
- 200 - Lista de documentos:
{
"success": true,
"message": "Documentos listados com sucesso",
"data": [
{
"id": 1,
"file_name": "contrato_compra_venda.pdf",
"file_type": "pdf",
"file_size": 1024000,
"uploaded_by": {
"id": 1,
"name": "João Cliente",
"type": "client"
},
"process": {
"id": 1,
"status": "documentacao"
},
"created_at": "2024-10-08T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 3,
"total_pages": 1,
"has_next": false,
"has_prev": false
},
"summary": {
"total_size": 3072000,
"by_type": {
"pdf": 2,
"jpg": 1
}
}
}
}
POST /api/documents
Descrição: Faz upload de documento para um processo
Acesso: Cliente (próprios processos), Especialista (seus processos)
Content-Type: multipart/form-data
Request:
FormData:
- file: [arquivo]
- process_id: 1
- description: "Contrato assinado"
Responses:
- 201 - Documento enviado:
{
"success": true,
"message": "Documento enviado com sucesso",
"data": {
"id": 1,
"file_name": "contrato_compra_venda.pdf",
"file_path": "documents/process_1/contrato_compra_venda.pdf",
"file_type": "pdf",
"file_size": 1024000,
"description": "Contrato assinado",
"process_id": 1,
"uploaded_by": {
"id": 1,
"name": "João Cliente",
"type": "client"
},
"created_at": "2024-10-08T14:30:00Z"
}
}
- 413 - Arquivo muito grande:
{
"success": false,
"error": {
"code": 413,
"message": "Arquivo muito grande. Tamanho máximo: 10MB"
}
}
- 415 - Tipo não suportado:
{
"success": false,
"error": {
"code": 415,
"message": "Tipo de arquivo não suportado",
"details": {
"supported_types": ["pdf", "doc", "docx", "jpg", "png", "gif"]
}
}
}
GET /api/documents/:id/download
Descrição: Baixa arquivo do documento
Acesso: Participantes do processo, Admin
Responses:
- 200 - Arquivo baixado:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="contrato_compra_venda.pdf"
[binary content]
- 404 - Documento não encontrado:
{
"success": false,
"error": {
"code": 404,
"message": "Documento não encontrado"
}
}
DELETE /api/documents/:id
Descrição: Remove documento do sistema
Acesso: Usuário que fez upload, Admin
Responses:
- 204 - Documento removido:
{
"success": true,
"message": "Documento removido com sucesso"
}
- 403 - Sem permissão:
{
"success": false,
"error": {
"code": 403,
"message": "Apenas o autor do documento pode removê-lo"
}
}
DASHBOARD E ESTATÍSTICAS
GET /api/dashboard/stats
Descrição: Obtém estatísticas do dashboard conforme tipo de usuário
Acesso: Usuário logado
Responses por tipo de usuário:
Cliente:
{
"success": true,
"message": "Estatísticas do dashboard",
"data": {
"active_processes": 2,
"completed_processes": 1,
"upcoming_appointments": 1,
"interests_created": 3,
"favorite_products": 5,
"recent_activities": [
{
"type": "process_update",
"message": "Processo #123 atualizado para 'documentacao'",
"date": "2024-10-08T10:30:00Z"
},
{
"type": "appointment_scheduled",
"message": "Agendamento marcado para 10/10/2024",
"date": "2024-10-07T15:00:00Z"
}
],
"process_timeline": [
{
"month": "2024-08",
"started": 1,
"completed": 0
},
{
"month": "2024-09",
"started": 1,
"completed": 1
}
]
}
}
Consultor:
{
"success": true,
"message": "Estatísticas do dashboard",
"data": {
"total_clients": 15,
"active_processes": 8,
"completed_processes": 12,
"conversion_rate": 69,
"monthly_revenue": 1250000.00,
"upcoming_appointments": 4,
"client_satisfaction": 4.8,
"monthly_processes": [
{ "month": "2024-07", "started": 3, "completed": 5 },
{ "month": "2024-08", "started": 5, "completed": 2 },
{ "month": "2024-09", "started": 2, "completed": 8 },
{ "month": "2024-10", "started": 8, "completed": 1 }
],
"top_products": [
{
"product_type": "car",
"marca": "Ferrari",
"interest_count": 12
},
{
"product_type": "boat",
"marca": "Azimut",
"interest_count": 8
}
]
}
}
Especialista:
{
"success": true,
"message": "Estatísticas do dashboard",
"data": {
"active_processes": 12,
"products_listed": 45,
"completed_sales": 8,
"pending_documentation": 3,
"upcoming_appointments": 6,
"average_sale_time": 45,
"total_revenue": 28500000.00,
"monthly_sales": [
{ "month": "2024-07", "count": 2, "value": 5700000.00 },
{ "month": "2024-08", "count": 4, "value": 11400000.00 },
{ "month": "2024-09", "count": 1, "value": 2850000.00 },
{ "month": "2024-10", "count": 5, "value": 14250000.00 }
],
"product_performance": [
{
"product_id": 1,
"marca": "Ferrari",
"modelo": "F8 Tributo",
"views": 156,
"interests": 12,
"appointments": 5
}
]
}
}
Admin:
{
"success": true,
"message": "Estatísticas do dashboard",
"data": {
"total_users": 150,
"total_products": 89,
"active_processes": 45,
"total_revenue": 89500000.00,
"monthly_revenue": [
{ "month": "2024-07", "value": 15000000.00 },
{ "month": "2024-08", "value": 28000000.00 },
{ "month": "2024-09", "value": 19000000.00 },
{ "month": "2024-10", "value": 35000000.00 }
],
"conversion_rates": {
"carros": 68,
"barcos": 72,
"aeronaves": 59
},
"user_activity": {
"daily_active": 45,
"weekly_active": 89,
"monthly_active": 134
},
"popular_categories": [
{ "category": "carros", "count": 45, "percentage": 50.6 },
{ "category": "barcos", "count": 28, "percentage": 31.5 },
{ "category": "aeronaves", "count": 16, "percentage": 17.9 }
],
"system_health": {
"uptime": 99.9,
"response_time": 245,
"error_rate": 0.1
}
}
}
ESTOQUE E INVENTÁRIO
GET /api/inventory
Descrição: Lista produtos do inventário com status de disponibilidade
Acesso: Especialista (seus produtos), Admin
Query Parameters:
Filtros:
- status (enum: 'disponivel'|'reservado'|'vendido')
- product_type (enum: 'car'|'boat'|'aircraft')
- specialist_id (integer) - apenas Admin
- date_from (date) - Data de cadastro
- date_to (date) - Data de cadastro
Paginação: page, limit, sort ('created_at'|'valor'|'status'), order
Responses:
- 200 - Lista do inventário:
{
"success": true,
"message": "Inventário listado com sucesso",
"data": [
{
"id": 1,
"product_type": "car",
"marca": "Ferrari",
"modelo": "F8 Tributo",
"valor": 2850000.00,
"status": "disponivel",
"days_in_inventory": 45,
"interest_count": 12,
"appointment_count": 5,
"process_count": 2,
"specialist": {
"id": 1,
"name": "Maria Especialista"
},
"last_activity": "2024-10-07T16:30:00Z",
"created_at": "2024-08-24T14:30:00Z"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 45,
"total_pages": 3,
"has_next": true,
"has_prev": false
},
"summary": {
"by_status": {
"disponivel": 35,
"reservado": 7,
"vendido": 3
},
"total_value": 128750000.00,
"average_days_in_inventory": 67
}
}
}
PUT /api/products/:id/status
Descrição: Atualiza status de disponibilidade do produto
Acesso: Especialista owner, Admin
Request:
{
"status": "reservado",
"notes": "Produto reservado para cliente João"
}
Responses:
- 200 - Status atualizado:
{
"success": true,
"message": "Status do produto atualizado com sucesso",
"data": {
"id": 1,
"status": "reservado",
"notes": "Produto reservado para cliente João",
"updated_at": "2024-10-08T15:30:00Z",
"status_history": [
{
"status": "disponivel",
"changed_at": "2024-08-24T14:30:00Z"
},
{
"status": "reservado",
"changed_at": "2024-10-08T15:30:00Z",
"notes": "Produto reservado para cliente João"
}
]
}
}
🔐 REGRAS DE ACESSO
Hierarquia de Permissões
- Admin: Acesso total ao sistema
- Especialista: Apenas produtos/processos da sua especialidade
- Consultor: Apenas seus clientes e processos relacionados
- Cliente: Apenas seus próprios dados e processos
- Empresa: Apenas dados dos seus consultores
Controle de Acesso por Recurso
Produtos
- Visualizar: Todos usuários logados
- Criar/Editar: Especialista da área + Admin
- Excluir: Especialista owner + Admin
Processos
- Visualizar: Participantes do processo + Admin
- Criar: Consultor (seus clientes) + Admin
- Atualizar status: Especialista owner + Admin
Documentos
- Upload: Cliente/Especialista do processo
- Download: Participantes do processo + Admin
- Excluir: Usuário que fez upload + Admin
Agendamentos
- Criar: Cliente, Consultor, Especialista
- Visualizar: Participantes do agendamento + Admin
- Cancelar: Participantes + Admin
📊 CÓDIGOS DE STATUS HTTP
Autenticação e Autorização
401- Token não fornecido ou inválido403- Token válido mas sem permissão para o recurso429- Rate limit excedido
Validação e Dados
400- Requisição malformada ou parâmetros inválidos404- Recurso não encontrado409- Conflito (duplicação, regra de negócio violada)422- Erro de validação dos dados
Sucesso
200- Requisição bem-sucedida201- Recurso criado com sucesso204- Recurso removido (sem conteúdo)
Servidor
500- Erro interno do servidor503- Serviço temporariamente indisponível
Upload de Arquivos
413- Arquivo muito grande415- Tipo de arquivo não suportado
Formato de Resposta de Erro
{
"error": {
"code": 422,
"message": "Dados de validação inválidos",
"details": {
"email": ["O campo email é obrigatório"],
"cpf": ["CPF já cadastrado no sistema"]
}
}
}