{"openapi":"3.1.0","info":{"title":"Royal Enfield REST API","description":"API REST para o ecossistema da Royal Enfield, gerenciando catálogo de motocicletas, variantes e cores, fichas técnicas, galeria de imagens, rede de concessionárias, agendamentos de test-ride e controle de usuários com autenticação em dois fatores (2FA) e JWT.","contact":{"name":"Vicente Alef - GitHub","url":"https://github.com/VicenteAlef"},"license":{"name":"MIT License","url":"https://opensource.org/licenses/MIT"},"version":"v1.0.0"},"externalDocs":{"description":"vicentedeveloper.com - Website","url":"https://vicentedeveloper.com"},"servers":[{"url":"http://api-re.vicentedeveloper.com.br","description":"Generated server url"}],"security":[{"Bearer Authentication":[]}],"tags":[{"name":"6. Galeria de Fotos","description":"Endpoints para gerenciamento do acervo de imagens e carrossel de fotos das motocicletas."},{"name":"7. Concessionárias","description":"Endpoints para consulta e gestão da rede de concessionárias autorizadas Royal Enfield."},{"name":"3. Motocicletas","description":"Catálogo de modelos Royal Enfield, criação, listagem com filtros, detalhes com ficha técnica, variantes e galeria, atualização e exclusão em cascata."},{"name":"4. Fichas Técnicas","description":"Endpoints para gerenciamento da ficha técnica detalhada (relação 1:1 com a motocicleta)."},{"name":"8. Agendamento de Test Rides","description":"Endpoints para solicitação pública, consulta com filtros, atualização de status e cancelamento de test rides."},{"name":"2. Gestão de Usuários (Admin)","description":"Endpoints administrativos para listagem paginada, filtros, alteração de papéis (RBAC) e exclusão de contas."},{"name":"5. Variantes e Cores","description":"Endpoints para gerenciamento de variantes de modelos, cores, preços e uploads de fotos."},{"name":"1. Autenticação e 2FA","description":"Endpoints para registro de usuários, login em duas etapas (2FA via e-mail), validação de OTP e emissão de JWT."}],"paths":{"/api/v1/variants/{id}/image":{"put":{"tags":["5. Variantes e Cores"],"summary":"Fazer upload ou substituir imagem da variante","description":"Envia uma nova foto para a variante, excluindo o arquivo físico antigo do disco local caso exista. Requer perfil USER ou ADMIN.","operationId":"uploadImage_1","parameters":[{"name":"id","in":"path","description":"UUID da variante","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Imagem enviada e URL atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"400":{"description":"Arquivo inválido ou extensão não suportada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"404":{"description":"Variante não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}},"post":{"tags":["5. Variantes e Cores"],"summary":"Fazer upload ou substituir imagem da variante","description":"Envia uma nova foto para a variante, excluindo o arquivo físico antigo do disco local caso exista. Requer perfil USER ou ADMIN.","operationId":"uploadImage","parameters":[{"name":"id","in":"path","description":"UUID da variante","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Imagem enviada e URL atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"400":{"description":"Arquivo inválido ou extensão não suportada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"404":{"description":"Variante não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}}},"/api/v1/variants/{id}":{"get":{"tags":["5. Variantes e Cores"],"summary":"Obter variante por ID","description":"Retorna os detalhes de uma variante a partir do seu identificador único.","operationId":"getById","parameters":[{"name":"id","in":"path","description":"UUID da variante","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Variante encontrada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"404":{"description":"Variante não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}},"put":{"tags":["5. Variantes e Cores"],"summary":"Atualizar dados da variante","description":"Atualiza os dados de uma variante existente. Requer perfil USER ou ADMIN.","operationId":"update","parameters":[{"name":"id","in":"path","description":"UUID da variante","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantRequest"}}},"required":true},"responses":{"200":{"description":"Variante atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"400":{"description":"Dados da variante inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"404":{"description":"Variante não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}},"delete":{"tags":["5. Variantes e Cores"],"summary":"Excluir variante","description":"Remove a variante do banco de dados e apaga o arquivo físico de imagem do disco local. Requer perfil USER ou ADMIN.","operationId":"delete","parameters":[{"name":"id","in":"path","description":"UUID da variante","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Variante excluída com sucesso."},"404":{"description":"Variante não encontrada."},"403":{"description":"Acesso negado."}}}},"/api/v1/motorcycles/{motorcycleId}/technical-spec":{"get":{"tags":["4. Fichas Técnicas"],"summary":"Obter ficha técnica da motocicleta","description":"Retorna os dados de motor, potência, torque, peso, capacidade do tanque, transmissão e freios da motocicleta.","operationId":"getByMotorcycleId","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Ficha técnica encontrada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}},"404":{"description":"Ficha técnica ou motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}}}},"put":{"tags":["4. Fichas Técnicas"],"summary":"Criar ou atualizar ficha técnica (Upsert)","description":"Salva ou atualiza a ficha técnica vinculada à motocicleta. Requer perfil USER ou ADMIN.","operationId":"createOrUpdate","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TechnicalSpecRequest"}}},"required":true},"responses":{"200":{"description":"Ficha técnica criada ou atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}},"400":{"description":"Dados da ficha técnica inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TechnicalSpecResponse"}}}}}},"delete":{"tags":["4. Fichas Técnicas"],"summary":"Remover ficha técnica","description":"Exclui o registro de ficha técnica associado à motocicleta. Requer perfil USER ou ADMIN.","operationId":"delete_1","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Ficha técnica removida com sucesso."},"404":{"description":"Motocicleta ou ficha técnica não encontrada."},"403":{"description":"Acesso negado."}}}},"/api/v1/motorcycles/{id}":{"get":{"tags":["3. Motocicletas"],"summary":"Obter detalhes da motocicleta por ID","description":"Retorna as informações completas da moto incluindo ficha técnica, lista de variantes/cores e galeria de fotos.","operationId":"getById_1","parameters":[{"name":"id","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Detalhes da motocicleta recuperados com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}}}},"put":{"tags":["3. Motocicletas"],"summary":"Atualizar dados da motocicleta","description":"Atualiza dados cadastrais básicos de um modelo. Requer perfil USER ou ADMIN.","operationId":"update_1","parameters":[{"name":"id","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MotorcycleUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Motocicleta atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"400":{"description":"Dados de atualização inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}}}},"delete":{"tags":["3. Motocicletas"],"summary":"Excluir motocicleta","description":"Exclui a motocicleta em cascata (ficha técnica, variantes, galeria) e remove fisicamente todos os arquivos de imagem associados. Requer perfil USER ou ADMIN.","operationId":"delete_2","parameters":[{"name":"id","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Motocicleta e mídias associadas excluídas com sucesso."},"404":{"description":"Motocicleta não encontrada."},"403":{"description":"Acesso negado."}}}},"/api/v1/gallery/{id}":{"put":{"tags":["6. Galeria de Fotos"],"summary":"Atualizar imagem ou legenda da galeria","description":"Atualiza a legenda, ordem ou substitui a foto física da galeria. Requer perfil USER ou ADMIN.","operationId":"updateImage","parameters":[{"name":"id","in":"path","description":"UUID do item da galeria","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"caption","in":"query","description":"Nova legenda","required":false,"schema":{"type":"string"}},{"name":"displayOrder","in":"query","description":"Nova ordem de exibição","required":false,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Item da galeria atualizado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"404":{"description":"Item da galeria não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}}}},"delete":{"tags":["6. Galeria de Fotos"],"summary":"Remover imagem da galeria","description":"Exclui a foto da galeria e remove o arquivo físico correspondente do disco. Requer perfil USER ou ADMIN.","operationId":"deleteImage","parameters":[{"name":"id","in":"path","description":"UUID do item da galeria","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Foto removida com sucesso."},"404":{"description":"Item da galeria não encontrado."},"403":{"description":"Acesso negado."}}}},"/api/v1/dealerships/{id}":{"get":{"tags":["7. Concessionárias"],"summary":"Obter concessionária por ID","description":"Retorna os detalhes de uma concessionária específica a partir de seu identificador UUID.","operationId":"getById_2","parameters":[{"name":"id","in":"path","description":"UUID da concessionária","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Concessionária encontrada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"404":{"description":"Concessionária não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}}}},"put":{"tags":["7. Concessionárias"],"summary":"Atualizar concessionária","description":"Atualiza endereço, contatos ou nome de uma concessionária. Requer perfil USER ou ADMIN.","operationId":"update_2","parameters":[{"name":"id","in":"path","description":"UUID da concessionária","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealershipUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Concessionária atualizada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"400":{"description":"Dados informados inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"404":{"description":"Concessionária não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}}}},"delete":{"tags":["7. Concessionárias"],"summary":"Excluir concessionária","description":"Remove uma concessionária do sistema. Requer perfil USER ou ADMIN.","operationId":"delete_3","parameters":[{"name":"id","in":"path","description":"UUID da concessionária","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Concessionária removida com sucesso."},"404":{"description":"Concessionária não encontrada."},"403":{"description":"Acesso negado."}}}},"/api/v1/test-rides":{"get":{"tags":["8. Agendamento de Test Rides"],"summary":"Listar agendamentos de test ride (Paginado com Filtros)","description":"Retorna lista de agendamentos com filtros opcionais por concessionária, moto, status, e-mail do cliente e intervalo de datas. Requer autenticação (VISITOR, USER, ADMIN).","operationId":"list","parameters":[{"name":"dealershipId","in":"query","description":"UUID da concessionária","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"motorcycleId","in":"query","description":"UUID da motocicleta","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","description":"Status do agendamento (PENDING, CONFIRMED, COMPLETED, CANCELLED)","required":false,"schema":{"type":"string","enum":["PENDING","CONFIRMED","COMPLETED","CANCELLED"]}},{"name":"customerEmail","in":"query","description":"E-mail do cliente","required":false,"schema":{"type":"string"}},{"name":"startDate","in":"query","description":"Data de início (ISO-8601)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","description":"Data de fim (ISO-8601)","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","description":"Zero-based page index (0..N)","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"size","in":"query","description":"The size of the page to be returned","required":false,"schema":{"type":"integer","default":10,"minimum":1}},{"name":"sort","in":"query","description":"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.","required":false,"schema":{"type":"array","default":["preferredDate,ASC"],"items":{"type":"string"}}}],"responses":{"200":{"description":"Lista de agendamentos retornada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageTestRideResponse"}}}},"403":{"description":"Acesso não autorizado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageTestRideResponse"}}}}}},"post":{"tags":["8. Agendamento de Test Rides"],"summary":"Solicitar agendamento de test ride","description":"Endpoint público para solicitação de agendamento de test ride com validação de data futura e integridade da concessionária e moto.","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRideCreateRequest"}}},"required":true},"responses":{"201":{"description":"Agendamento registrado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"400":{"description":"Dados do agendamento inválidos ou data no passado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"404":{"description":"Motocicleta, variante ou concessionária não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}}}}},"/api/v1/motorcycles":{"get":{"tags":["3. Motocicletas"],"summary":"Listar motocicletas (Paginado com Filtros)","description":"Retorna o catálogo público de motocicletas com paginação e filtros opcionais por família, status ativo e busca textual.","operationId":"list_1","parameters":[{"name":"family","in":"query","description":"Filtrar por família (ex: Cruiser, Classic, Roadster, Adventure)","required":false,"schema":{"type":"string"}},{"name":"active","in":"query","description":"Filtrar por status ativo (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"query","in":"query","description":"Busca textual no nome do modelo","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Zero-based page index (0..N)","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"size","in":"query","description":"The size of the page to be returned","required":false,"schema":{"type":"integer","default":10,"minimum":1}},{"name":"sort","in":"query","description":"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.","required":false,"schema":{"type":"array","default":["modelName,ASC"],"items":{"type":"string"}}}],"responses":{"200":{"description":"Catálogo de motocicletas retornado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageMotorcycleSummaryResponse"}}}}}},"post":{"tags":["3. Motocicletas"],"summary":"Criar nova motocicleta","description":"Cadastra um modelo base de motocicleta com ficha técnica inicial opcional. Requer perfil USER ou ADMIN.","operationId":"create_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MotorcycleCreateRequest"}}},"required":true},"responses":{"201":{"description":"Motocicleta criada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"400":{"description":"Dados da motocicleta inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleDetailResponse"}}}}}}},"/api/v1/motorcycles/{motorcycleId}/variants":{"get":{"tags":["5. Variantes e Cores"],"summary":"Listar variantes de uma motocicleta","description":"Retorna as variantes e opções de cores de um determinado modelo de moto.","operationId":"listByMotorcycle","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"activeOnly","in":"query","description":"Filtrar apenas variantes ativas","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Lista de variantes retornada com sucesso.","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}}},"post":{"tags":["5. Variantes e Cores"],"summary":"Criar variante via JSON","description":"Cadastra uma variante (versão/cor) para uma motocicleta sem envio inicial de arquivo de imagem. Requer perfil USER ou ADMIN.","operationId":"createMultipart","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MotorcycleVariantRequest"},"image":{"type":"string","format":"binary"}},"required":["data"]}},"application/json":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantRequest"}}},"required":true},"responses":{"201":{"description":"Variante criada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"400":{"description":"Dados da variante inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}}}}}}},"/api/v1/motorcycles/{motorcycleId}/gallery":{"get":{"tags":["6. Galeria de Fotos"],"summary":"Listar galeria de fotos de uma motocicleta","description":"Retorna todas as imagens cadastradas para a moto, ordenadas pelo campo displayOrder.","operationId":"listGallery","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Galeria de fotos retornada com sucesso.","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}}}}},"post":{"tags":["6. Galeria de Fotos"],"summary":"Adicionar imagem na galeria via upload físico","description":"Faz upload de um arquivo de foto para a galeria da motocicleta, salvando localmente. Requer perfil USER ou ADMIN.","operationId":"addImageFile","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"caption","in":"query","description":"Legenda da imagem","required":false,"schema":{"type":"string"}},{"name":"displayOrder","in":"query","description":"Ordem de exibição no carrossel","required":false,"schema":{"type":"integer","format":"int32","default":0}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"Imagem adicionada à galeria com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"400":{"description":"Formato de arquivo inválido.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}}}}},"/api/v1/motorcycles/{motorcycleId}/gallery/url":{"post":{"tags":["6. Galeria de Fotos"],"summary":"Adicionar imagem na galeria via URL externa","description":"Registra uma URL de imagem externa para a galeria da motocicleta. Requer perfil USER ou ADMIN.","operationId":"addImageUrl","parameters":[{"name":"motorcycleId","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryRequest"}}},"required":true},"responses":{"201":{"description":"Imagem registrada na galeria com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"400":{"description":"Dados da requisição inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}}}}}}},"/api/v1/dealerships":{"get":{"tags":["7. Concessionárias"],"summary":"Listar concessionárias (Paginado com Filtros)","description":"Retorna lista paginada de concessionárias com opções de filtro por estado (UF), cidade e busca textual.","operationId":"list_2","parameters":[{"name":"state","in":"query","description":"Sigla do estado (ex: SP, RJ, MG)","required":false,"schema":{"type":"string"}},{"name":"city","in":"query","description":"Nome da cidade","required":false,"schema":{"type":"string"}},{"name":"query","in":"query","description":"Busca textual por nome ou endereço","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Zero-based page index (0..N)","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"size","in":"query","description":"The size of the page to be returned","required":false,"schema":{"type":"integer","default":10,"minimum":1}},{"name":"sort","in":"query","description":"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.","required":false,"schema":{"type":"array","default":["name,ASC"],"items":{"type":"string"}}}],"responses":{"200":{"description":"Lista de concessionárias retornada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDealershipResponse"}}}}}},"post":{"tags":["7. Concessionárias"],"summary":"Cadastrar concessionária","description":"Cadastra uma nova concessionária na base de dados. Requer perfil USER ou ADMIN.","operationId":"create_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealershipCreateRequest"}}},"required":true},"responses":{"201":{"description":"Concessionária cadastrada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"400":{"description":"Dados da concessionária inválidos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DealershipResponse"}}}}}}},"/api/v1/auth/verify-2fa":{"post":{"tags":["1. Autenticação e 2FA"],"summary":"Validar código 2FA e emitir JWT (2º Fator)","description":"Valida o código OTP de 6 dígitos enviado por e-mail e emite o token JWT para autenticação.","operationId":"verify2Fa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verify2FaRequest"}}},"required":true},"responses":{"200":{"description":"Autenticação concluída com sucesso e token JWT emitido.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Código 2FA expirado, inválido ou já utilizado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/v1/auth/register":{"post":{"tags":["1. Autenticação e 2FA"],"summary":"Registrar novo usuário","description":"Cria um novo usuário na plataforma com role padrão VISITOR e dispara e-mail de notificação para administradores.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"201":{"description":"Usuário cadastrado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"400":{"description":"Dados de entrada inválidos ou e-mail já cadastrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}}}},"/api/v1/auth/login":{"post":{"tags":["1. Autenticação e 2FA"],"summary":"Iniciar fluxo de login (1º Fator)","description":"Valida credenciais (e-mail e senha) e despacha um código OTP de 6 dígitos para o e-mail cadastrado.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Credenciais válidas e código 2FA enviado por e-mail.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LoginStepResponse"}}}},"401":{"description":"E-mail ou senha incorretos.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/LoginStepResponse"}}}}}}},"/api/v1/users/{id}/role":{"patch":{"tags":["2. Gestão de Usuários (Admin)"],"summary":"Atualizar cargo (Role) do usuário","description":"Permite alterar a role de um usuário entre VISITOR, USER e ADMIN. Requer ROLE_ADMIN.","operationId":"updateRole","parameters":[{"name":"id","in":"path","description":"UUID do usuário","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRoleRequest"}}},"required":true},"responses":{"200":{"description":"Cargo atualizado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"400":{"description":"Role informada inválida.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"Usuário não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"403":{"description":"Acesso negado (requer perfil ADMIN).","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}}}},"/api/v1/test-rides/{id}/status":{"patch":{"tags":["8. Agendamento de Test Rides"],"summary":"Atualizar status do agendamento","description":"Permite alterar o status do agendamento (PENDING, CONFIRMED, COMPLETED, CANCELLED). Requer perfil USER ou ADMIN.","operationId":"updateStatus","parameters":[{"name":"id","in":"path","description":"UUID do agendamento","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRideStatusUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Status atualizado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"400":{"description":"Status inválido.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"404":{"description":"Agendamento não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}}}}},"/api/v1/test-rides/{id}/cancel":{"patch":{"tags":["8. Agendamento de Test Rides"],"summary":"Cancelar agendamento de test ride","description":"Cancela o agendamento alterando o status para CANCELLED. Requer perfil USER ou ADMIN.","operationId":"cancel","parameters":[{"name":"id","in":"path","description":"UUID do agendamento","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Agendamento cancelado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"404":{"description":"Agendamento não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}}}}},"/api/v1/motorcycles/{id}/toggle-status":{"patch":{"tags":["3. Motocicletas"],"summary":"Ativar / Desativar motocicleta","description":"Alterna o status ativo/inativo da motocicleta no catálogo. Requer perfil USER ou ADMIN.","operationId":"toggleStatus","parameters":[{"name":"id","in":"path","description":"UUID da motocicleta","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Status alterado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleSummaryResponse"}}}},"404":{"description":"Motocicleta não encontrada.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleSummaryResponse"}}}},"403":{"description":"Acesso negado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MotorcycleSummaryResponse"}}}}}}},"/api/v1/users":{"get":{"tags":["2. Gestão de Usuários (Admin)"],"summary":"Listar usuários (Paginado com Filtros)","description":"Retorna lista paginada de usuários cadastrados com suporte a busca textual, filtro de cargo e filtro de usuários inativos (nunca acessaram). Requer ROLE_ADMIN.","operationId":"list_3","parameters":[{"name":"neverAccessed","in":"query","description":"Filtrar por usuários que nunca efetuaram login","required":false,"schema":{"type":"boolean"}},{"name":"role","in":"query","description":"Filtrar por cargo (VISITOR, USER, ADMIN)","required":false,"schema":{"type":"string","enum":["ROLE_VISITOR","ROLE_USER","ROLE_ADMIN"]}},{"name":"query","in":"query","description":"Busca textual por nome ou e-mail","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Zero-based page index (0..N)","required":false,"schema":{"type":"integer","default":0,"minimum":0}},{"name":"size","in":"query","description":"The size of the page to be returned","required":false,"schema":{"type":"integer","default":10,"minimum":1}},{"name":"sort","in":"query","description":"Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.","required":false,"schema":{"type":"array","default":["createdAt,DESC"],"items":{"type":"string"}}}],"responses":{"200":{"description":"Lista de usuários retornada com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageUserResponse"}}}},"403":{"description":"Acesso negado (requer perfil ADMIN).","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageUserResponse"}}}}}}},"/api/v1/users/{id}":{"get":{"tags":["2. Gestão de Usuários (Admin)"],"summary":"Obter usuário por ID","description":"Retorna dados completos de um usuário a partir do seu UUID. Requer ROLE_ADMIN.","operationId":"getById_3","parameters":[{"name":"id","in":"path","description":"UUID do usuário","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Usuário encontrado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"Usuário não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"403":{"description":"Acesso negado (requer perfil ADMIN).","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}}},"delete":{"tags":["2. Gestão de Usuários (Admin)"],"summary":"Excluir usuário","description":"Remove um usuário do sistema. Requer ROLE_ADMIN.","operationId":"delete_4","parameters":[{"name":"id","in":"path","description":"UUID do usuário","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Usuário excluído com sucesso."},"404":{"description":"Usuário não encontrado."},"403":{"description":"Acesso negado (requer perfil ADMIN)."}}}},"/api/v1/test-rides/{id}":{"get":{"tags":["8. Agendamento de Test Rides"],"summary":"Obter agendamento por ID","description":"Retorna dados completos de um agendamento de test ride. Requer autenticação.","operationId":"getById_4","parameters":[{"name":"id","in":"path","description":"UUID do agendamento","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Agendamento encontrado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"404":{"description":"Agendamento não encontrado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}},"403":{"description":"Acesso não autorizado.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TestRideResponse"}}}}}},"delete":{"tags":["8. Agendamento de Test Rides"],"summary":"Excluir agendamento de test ride","description":"Remove um agendamento do banco de dados. Requer perfil USER ou ADMIN.","operationId":"delete_5","parameters":[{"name":"id","in":"path","description":"UUID do agendamento","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Agendamento removido com sucesso."},"404":{"description":"Agendamento não encontrado."},"403":{"description":"Acesso negado."}}}},"/api/v1/auth/me":{"get":{"tags":["1. Autenticação e 2FA"],"summary":"Obter dados do usuário autenticado","description":"Retorna os detalhes e permissões do usuário logado baseado no token JWT informado no cabeçalho.","operationId":"getCurrentUser","responses":{"200":{"description":"Perfil do usuário recuperado com sucesso.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"403":{"description":"Acesso não autorizado / token ausente ou inválido.","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}}}}},"components":{"schemas":{"MotorcycleVariantResponse":{"type":"object","description":"Dados detalhados de uma variante/cor da motocicleta","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único da variante","example":"11111111-2222-3333-4444-555555555555"},"motorcycleId":{"type":"string","format":"uuid","description":"UUID da motocicleta pai","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"variantName":{"type":"string","description":"Nome da versão/variante","example":"Astral"},"colorName":{"type":"string","description":"Nome da cor","example":"Astral Black"},"hexColorCode":{"type":"string","description":"Código hexadecimal da cor","example":"#0A0A0A"},"price":{"type":"number","description":"Preço da variante","example":33990.0},"imageUrl":{"type":"string","description":"URL da imagem da variante","example":"/uploads/variants/astral-black.webp"},"includedAccessories":{"type":"string","description":"Acessórios e acabamentos exclusivos inclusos","example":"Espelhos clássicos, rodas de liga leve"},"active":{"type":"boolean","description":"Status de disponibilidade da variante","example":true},"createdAt":{"type":"string","format":"date-time","description":"Data de cadastro","example":"2026-08-28T19:54:16Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-28T19:54:16Z"}}},"MotorcycleVariantRequest":{"type":"object","description":"Dados para cadastro ou atualização de variante/cor da motocicleta","properties":{"variantName":{"type":"string","description":"Nome da variante","example":"Interstellar","maxLength":100,"minLength":0},"colorName":{"type":"string","description":"Nome da cor","example":"Interstellar Grey","maxLength":100,"minLength":0},"hexColorCode":{"type":"string","description":"Código hexadecimal da cor","example":"#6E7072","maxLength":10,"minLength":0},"price":{"type":"number","description":"Preço da variante","example":34990.0},"imageUrl":{"type":"string","description":"URL da imagem da variante (caso já hospedada)","example":"/uploads/variants/interstellar-grey.webp","maxLength":255,"minLength":0},"includedAccessories":{"type":"string","description":"Acessórios e acabamentos exclusivos inclusos","example":"Pintura em dois tons, detalhes pretos"},"active":{"type":"boolean","description":"Status de disponibilidade da variante","example":true}},"required":["colorName","price","variantName"]},"TechnicalSpecRequest":{"type":"object","description":"Dados da ficha técnica da motocicleta","properties":{"powerHp":{"type":"string","description":"Potência máxima e rotação","example":47,"maxLength":50,"minLength":0},"torqueNm":{"type":"string","description":"Torque máximo e rotação","example":52.3,"maxLength":50,"minLength":0},"weightKg":{"type":"number","description":"Peso em ordem de marcha (kg)","example":241.0},"fuelCapacityL":{"type":"number","description":"Capacidade do tanque de combustível (Litros)","example":15.7},"seatHeightMm":{"type":"integer","format":"int32","description":"Altura do assento em milímetros","example":740},"transmission":{"type":"string","description":"Tipo de transmissão / câmbio","example":6,"maxLength":50,"minLength":0},"frontBrake":{"type":"string","description":"Especificação do freio dianteiro","example":"Disco único de 320mm com ABS de canal duplo","maxLength":100,"minLength":0},"rearBrake":{"type":"string","description":"Especificação do freio traseiro","example":"Disco único de 300mm com ABS de canal duplo","maxLength":100,"minLength":0},"coolingSystem":{"type":"string","description":"Sistema de arrefecimento do motor","example":"Ar e radiador de óleo","maxLength":50,"minLength":0}}},"TechnicalSpecResponse":{"type":"object","description":"Ficha técnica completa da motocicleta","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único da ficha técnica","example":"e4a2d890-1c23-4b56-7890-abcdef123456"},"powerHp":{"type":"string","description":"Potência máxima do motor","example":47},"torqueNm":{"type":"string","description":"Torque máximo do motor","example":52.3},"weightKg":{"type":"number","description":"Peso em ordem de marcha (kg)","example":241.0},"fuelCapacityL":{"type":"number","description":"Capacidade do tanque (Litros)","example":15.7},"seatHeightMm":{"type":"integer","format":"int32","description":"Altura do assento em milímetros","example":740},"transmission":{"type":"string","description":"Transmissão","example":6},"frontBrake":{"type":"string","description":"Freio dianteiro","example":"Disco único de 320mm com ABS de canal duplo"},"rearBrake":{"type":"string","description":"Freio traseiro","example":"Disco único de 300mm com ABS de canal duplo"},"coolingSystem":{"type":"string","description":"Sistema de refrigeração","example":"Ar e radiador de óleo"},"createdAt":{"type":"string","format":"date-time","description":"Data de cadastro","example":"2026-08-28T19:54:16Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-28T19:54:16Z"}}},"MotorcycleUpdateRequest":{"type":"object","description":"Dados para atualização de uma motocicleta","properties":{"modelName":{"type":"string","description":"Nome do modelo da motocicleta","example":"Super Meteor 650 Twin","maxLength":100,"minLength":0},"family":{"type":"string","description":"Família ou categoria da moto","example":"Cruiser","maxLength":50,"minLength":0},"engineCc":{"type":"integer","format":"int32","description":"Cilindrada do motor em cc","example":648},"startingPrice":{"type":"number","description":"Preço inicial sugerido","example":34990.0},"description":{"type":"string","description":"Descrição detalhada do modelo","example":"Cruiser topo de linha da Royal Enfield atualizada."},"active":{"type":"boolean","description":"Status de visibilidade no catálogo","example":true}},"required":["engineCc","family","modelName","startingPrice"]},"MotorcycleDetailResponse":{"type":"object","description":"Detalhes completos da motocicleta incluindo ficha técnica, variantes e galeria","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único da motocicleta","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"modelName":{"type":"string","description":"Nome do modelo","example":"Super Meteor 650"},"family":{"type":"string","description":"Família da moto","example":"Cruiser"},"engineCc":{"type":"integer","format":"int32","description":"Cilindrada em cc","example":648},"startingPrice":{"type":"number","description":"Preço inicial a partir de","example":33990.0},"description":{"type":"string","description":"Descrição da motocicleta","example":"Cruiser premium com motor bicilíndrico paralelo de 648cc."},"active":{"type":"boolean","description":"Status de visibilidade no catálogo","example":true},"technicalSpec":{"$ref":"#/components/schemas/TechnicalSpecResponse","description":"Ficha técnica detalhada da motocicleta"},"variants":{"type":"array","description":"Lista de variantes e cores disponíveis","items":{"$ref":"#/components/schemas/MotorcycleVariantResponse"}},"gallery":{"type":"array","description":"Galeria de imagens e carrossel","items":{"$ref":"#/components/schemas/MotorcycleGalleryResponse"}},"createdAt":{"type":"string","format":"date-time","description":"Data de cadastro","example":"2026-08-28T19:54:16Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-28T19:54:16Z"}}},"MotorcycleGalleryResponse":{"type":"object","description":"Dados de uma imagem na galeria da motocicleta","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único do item da galeria","example":"99999999-8888-7777-6666-555555555555"},"motorcycleId":{"type":"string","format":"uuid","description":"UUID da motocicleta associada","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"imageUrl":{"type":"string","description":"URL da imagem","example":"/uploads/gallery/front-view.jpg"},"caption":{"type":"string","description":"Legenda descritiva da imagem","example":"Vista Frontal"},"displayOrder":{"type":"integer","format":"int32","description":"Ordem de exibição no carrossel","example":1},"createdAt":{"type":"string","format":"date-time","description":"Data de envio da imagem","example":"2026-08-28T19:54:16Z"}}},"DealershipUpdateRequest":{"type":"object","description":"Dados para atualização de uma concessionária","properties":{"name":{"type":"string","description":"Nome da concessionária","example":"Royal Enfield Moema Premium","maxLength":100,"minLength":0},"city":{"type":"string","description":"Cidade da concessionária","example":"São Paulo","maxLength":50,"minLength":0},"state":{"type":"string","description":"Sigla da unidade federativa (UF)","example":"SP","maxLength":2,"minLength":2,"pattern":"^[A-Za-z]{2}$"},"address":{"type":"string","description":"Endereço completo","example":"Av. Ibirapuera, 2907 - Moema","maxLength":200,"minLength":0},"phone":{"type":"string","description":"Telefone de contato","example":"(11) 5051-9999","maxLength":20,"minLength":0},"email":{"type":"string","description":"E-mail de contato da loja","example":"contato.moema@royalenfield.com.br","maxLength":100,"minLength":0}},"required":["address","city","name","state"]},"DealershipResponse":{"type":"object","description":"Dados detalhados de uma concessionária Royal Enfield","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único da concessionária","example":"11111111-2222-3333-4444-555555555555"},"name":{"type":"string","description":"Nome da loja","example":"Royal Enfield Moema"},"city":{"type":"string","description":"Cidade","example":"São Paulo"},"state":{"type":"string","description":"Estado / UF","example":"SP"},"address":{"type":"string","description":"Endereço completo","example":"Av. Ibirapuera, 2907 - Moema"},"phone":{"type":"string","description":"Telefone de contato","example":"(11) 5051-0000"},"email":{"type":"string","description":"E-mail de contato","example":"moema@royalenfield.com.br"},"createdAt":{"type":"string","format":"date-time","description":"Data de cadastro","example":"2026-08-31T19:30:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-31T19:30:00Z"}}},"TestRideCreateRequest":{"type":"object","description":"Dados para solicitação de agendamento de test ride","properties":{"customerName":{"type":"string","description":"Nome completo do interessado","example":"Carlos Silva","maxLength":100,"minLength":0},"customerEmail":{"type":"string","description":"E-mail de contato do cliente","example":"carlos.silva@email.com","maxLength":100,"minLength":0},"customerPhone":{"type":"string","description":"Telefone ou WhatsApp do cliente","example":"(11) 98765-4321","maxLength":20,"minLength":0},"preferredDate":{"type":"string","format":"date-time","description":"Data e hora desejadas para o test ride (formato ISO-8601)","example":"2026-09-15T14:30:00Z"},"motorcycleId":{"type":"string","format":"uuid","description":"UUID da motocicleta desejada","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"variantId":{"type":"string","format":"uuid","description":"UUID da variante/cor específica desejada (opcional)","example":"11111111-2222-3333-4444-555555555555"},"dealershipId":{"type":"string","format":"uuid","description":"UUID da concessionária onde será realizado o test ride","example":"11111111-2222-3333-4444-555555555555"}},"required":["customerEmail","customerName","customerPhone","dealershipId","motorcycleId","preferredDate"]},"MotorcycleSummary":{"type":"object","description":"Resumo da motocicleta no agendamento de test ride","properties":{"id":{"type":"string","format":"uuid","description":"UUID da moto","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"modelName":{"type":"string","description":"Modelo","example":"Super Meteor 650"},"family":{"type":"string","description":"Família","example":"Cruiser"},"engineCc":{"type":"integer","format":"int32","description":"Cilindrada","example":648}}},"TestRideResponse":{"type":"object","description":"Dados detalhados do agendamento de test ride","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único do agendamento","example":"99999999-aaaa-bbbb-cccc-dddddddddddd"},"customerName":{"type":"string","description":"Nome do cliente","example":"Carlos Silva"},"customerEmail":{"type":"string","description":"E-mail do cliente","example":"carlos.silva@email.com"},"customerPhone":{"type":"string","description":"Telefone do cliente","example":"(11) 98765-4321"},"preferredDate":{"type":"string","format":"date-time","description":"Data e hora agendadas","example":"2026-09-15T14:30:00Z"},"status":{"type":"string","description":"Status do agendamento","enum":["PENDING","CONFIRMED","COMPLETED","CANCELLED"],"example":"PENDING"},"motorcycle":{"$ref":"#/components/schemas/MotorcycleSummary","description":"Resumo da motocicleta selecionada"},"variant":{"$ref":"#/components/schemas/VariantSummary","description":"Resumo da variante/cor selecionada (se houver)"},"dealership":{"$ref":"#/components/schemas/DealershipResponse","description":"Dados da concessionária do agendamento"},"createdAt":{"type":"string","format":"date-time","description":"Data de solicitação","example":"2026-08-31T19:30:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-31T19:30:00Z"}}},"VariantSummary":{"type":"object","description":"Resumo da variante no agendamento de test ride","properties":{"id":{"type":"string","format":"uuid","description":"UUID da variante","example":"11111111-2222-3333-4444-555555555555"},"variantName":{"type":"string","description":"Nome da variante","example":"Astral"},"colorName":{"type":"string","description":"Nome da cor","example":"Astral Black"},"imageUrl":{"type":"string","description":"URL da foto da variante","example":"/uploads/variants/astral-black.webp"}}},"MotorcycleCreateRequest":{"type":"object","description":"Dados para cadastro de uma nova motocicleta","properties":{"modelName":{"type":"string","description":"Nome do modelo da motocicleta","example":"Super Meteor 650","maxLength":100,"minLength":0},"family":{"type":"string","description":"Família ou categoria da moto","example":"Cruiser","maxLength":50,"minLength":0},"engineCc":{"type":"integer","format":"int32","description":"Cilindrada do motor em cc","example":648},"startingPrice":{"type":"number","description":"Preço inicial sugerido","example":33990.0},"description":{"type":"string","description":"Descrição detalhada do modelo","example":"Cruiser premium com motor bicilíndrico paralelo de 648cc."},"active":{"type":"boolean","default":"true","description":"Status de visibilidade no catálogo","example":true},"technicalSpec":{"$ref":"#/components/schemas/TechnicalSpecRequest","description":"Ficha técnica inicial opcional da motocicleta"}},"required":["engineCc","family","modelName","startingPrice"]},"MotorcycleGalleryRequest":{"type":"object","description":"Dados para cadastro de foto na galeria da motocicleta","properties":{"imageUrl":{"type":"string","description":"URL da imagem (usado para links externos)","example":"https://external-cdn.com/super-meteor-lifestyle.jpg","maxLength":255,"minLength":0},"caption":{"type":"string","description":"Legenda da imagem","example":"Painel de Instrumentos Digital","maxLength":150,"minLength":0},"displayOrder":{"type":"integer","format":"int32","default":"0","description":"Ordem de exibição no carrossel","example":1}}},"DealershipCreateRequest":{"type":"object","description":"Dados para cadastro de uma nova concessionária","properties":{"name":{"type":"string","description":"Nome da concessionária","example":"Royal Enfield Moema","maxLength":100,"minLength":0},"city":{"type":"string","description":"Cidade da concessionária","example":"São Paulo","maxLength":50,"minLength":0},"state":{"type":"string","description":"Sigla da unidade federativa (UF)","example":"SP","maxLength":2,"minLength":2,"pattern":"^[A-Za-z]{2}$"},"address":{"type":"string","description":"Endereço completo","example":"Av. Ibirapuera, 2907 - Moema","maxLength":200,"minLength":0},"phone":{"type":"string","description":"Telefone de contato","example":"(11) 5051-0000","maxLength":20,"minLength":0},"email":{"type":"string","description":"E-mail de contato da loja","example":"moema@royalenfield.com.br","maxLength":100,"minLength":0}},"required":["address","city","name","state"]},"Verify2FaRequest":{"type":"object","description":"Dados para validação do código 2FA e emissão do JWT","properties":{"email":{"type":"string","description":"E-mail do usuário em processo de autenticação","example":"admin@royalenfield.com.br"},"code":{"type":"string","description":"Código numérico de 6 dígitos recebido por e-mail","example":123456,"pattern":"^\\d{6}$"}},"required":["code","email"]},"AuthResponse":{"type":"object","description":"Dados de autenticação bem-sucedida contendo o token JWT","properties":{"token":{"type":"string","description":"Token de acesso JWT emitido","example":"eyJhbGciOiJIUzI1NiJ9..."},"tokenType":{"type":"string","description":"Tipo do token","example":"Bearer"},"expiresIn":{"type":"integer","format":"int64","description":"Tempo de expiração do token em milissegundos","example":86400000},"user":{"$ref":"#/components/schemas/UserResponse","description":"Dados do usuário autenticado"}}},"UserResponse":{"type":"object","description":"Dados de representação de um usuário","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único do usuário","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Nome do usuário","example":"Carlos Silva"},"email":{"type":"string","description":"E-mail cadastrado","example":"carlos.silva@email.com"},"role":{"type":"string","description":"Perfil de acesso / cargo (Role)","enum":["ROLE_VISITOR","ROLE_USER","ROLE_ADMIN"],"example":"VISITOR"},"lastLoginAt":{"type":"string","format":"date-time","description":"Data e hora do último login realizado","example":"2026-09-07T10:30:00Z"},"createdAt":{"type":"string","format":"date-time","description":"Data de criação da conta","example":"2026-09-07T08:00:00Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última modificação","example":"2026-09-07T08:00:00Z"}}},"RegisterRequest":{"type":"object","description":"Dados para cadastro de um novo usuário","properties":{"name":{"type":"string","description":"Nome completo do usuário","example":"Carlos Silva","maxLength":100,"minLength":0},"email":{"type":"string","description":"Endereço de e-mail único","example":"carlos.silva@email.com","maxLength":100,"minLength":0},"password":{"type":"string","description":"Senha de acesso (mínimo 6 caracteres)","example":"Segredo@123","maxLength":100,"minLength":6}},"required":["email","name","password"]},"LoginRequest":{"type":"object","description":"Dados para início do fluxo de autenticação","properties":{"email":{"type":"string","description":"E-mail cadastrado do usuário","example":"admin@royalenfield.com.br"},"password":{"type":"string","description":"Senha de acesso","example":"Admin@123456"}},"required":["email","password"]},"LoginStepResponse":{"type":"object","description":"Resposta da primeira etapa de login (despacho do 2FA)","properties":{"requires2FA":{"type":"boolean","description":"Indica que o segundo fator de autenticação é obrigatório","example":true},"email":{"type":"string","description":"E-mail de destino do código OTP","example":"admin@royalenfield.com.br"},"message":{"type":"string","description":"Mensagem orientativa","example":"A 6-digit verification code has been sent to your email."}}},"UpdateUserRoleRequest":{"type":"object","description":"Dados para atualização de permissões do usuário","properties":{"role":{"type":"string","description":"Novo papel do usuário","enum":["ROLE_VISITOR","ROLE_USER","ROLE_ADMIN"],"example":"USER"}},"required":["role"]},"TestRideStatusUpdateRequest":{"type":"object","description":"Dados para atualização de status do agendamento de test ride","properties":{"status":{"type":"string","description":"Novo status do agendamento","enum":["PENDING","CONFIRMED","COMPLETED","CANCELLED"],"example":"CONFIRMED"}},"required":["status"]},"MotorcycleSummaryResponse":{"type":"object","description":"Resumo dos dados da motocicleta para listagem","properties":{"id":{"type":"string","format":"uuid","description":"Identificador único da motocicleta","example":"ad7f150a-516c-49d2-b72c-53d077045994"},"modelName":{"type":"string","description":"Nome do modelo","example":"Super Meteor 650"},"family":{"type":"string","description":"Família da moto","example":"Cruiser"},"engineCc":{"type":"integer","format":"int32","description":"Cilindrada em cc","example":648},"startingPrice":{"type":"number","description":"Preço inicial a partir de","example":33990.0},"description":{"type":"string","description":"Descrição da motocicleta","example":"Cruiser premium com motor bicilíndrico paralelo de 648cc."},"active":{"type":"boolean","description":"Status de visibilidade no catálogo","example":true},"mainImageUrl":{"type":"string","description":"URL da imagem principal/destaque","example":"/uploads/variants/celestial-red.webp"},"variantCount":{"type":"integer","format":"int32","description":"Total de variantes e cores cadastradas","example":3},"createdAt":{"type":"string","format":"date-time","description":"Data de cadastro","example":"2026-08-28T19:54:16Z"},"updatedAt":{"type":"string","format":"date-time","description":"Data da última atualização","example":"2026-08-28T19:54:16Z"}}},"PageUserResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/UserResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"PageableObject":{"type":"object","properties":{"unpaged":{"type":"boolean"},"pageNumber":{"type":"integer","format":"int32"},"paged":{"type":"boolean"},"pageSize":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int64"},"sort":{"$ref":"#/components/schemas/SortObject"}}},"SortObject":{"type":"object","properties":{"unsorted":{"type":"boolean"},"sorted":{"type":"boolean"},"empty":{"type":"boolean"}}},"PageTestRideResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/TestRideResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"PageMotorcycleSummaryResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/MotorcycleSummaryResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}},"PageDealershipResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"numberOfElements":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/DealershipResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"empty":{"type":"boolean"}}}},"securitySchemes":{"Bearer Authentication":{"type":"http","description":"Insira o token JWT gerado após a autenticação (sem a palavra 'Bearer ', apenas o token).","name":"Bearer Authentication","scheme":"bearer","bearerFormat":"JWT"}}}}