This commit is contained in:
Daniel Arantes Loverde
2026-02-15 08:18:06 -03:00
parent d7b8b1864a
commit 0f5ad4c268
35 changed files with 4090 additions and 309 deletions

View File

@@ -75,7 +75,8 @@ Used when interacting with a specific store (Catalog, Checkout).
```
**Fluxo:**
- Passo 1: enviar `email` + `phoneNumber` para receber código por email.<OTP>`.
- Passo 1: enviar `email` + `phoneNumber` para receber código por email.
- Passo 2: enviar `email` + `phoneNumber` e o OTP no header `Authorization: Bearer <OTP>`.
**Response:**
@@ -115,14 +116,16 @@ Used when interacting with a specific store (Catalog, Checkout).
"phoneNumber": "+5511999999999",
"favorites": ["store_abc...", "store_xyz..."],
"address_book": [],
"behavioral_stats": {
"total_orders": 5,
"avg_ticket_size": 45.00
}
"verified": true,
"biometricsEnabled": false,
"createdAt": "2026-01-21T22:37:56.472Z",
"updatedAt": "2026-02-13T19:00:00.000Z"
}
}
```
**Campos internos não retornados para o app:** `keyHash`, `strongHash`, `source`, `isShadow`, `profile_metrics`, `behavioral_stats`, `otpHash`, `otpHashParams`, `otpExpiresAt`.
### 4. Update Profile
**POST** `/api/customer/:id`
@@ -137,14 +140,56 @@ Used when interacting with a specific store (Catalog, Checkout).
{
"name": "Daniel A. Loverde", // Fields to update
"phoneNumber": "+5511988888888",
"biometricsEnabled": true
"biometricsEnabled": true,
"address_book": [
{
"label": "Casa",
"type": "residential",
"address": "Avenida das Andorinhas",
"number": "477",
"neighborhood": "Jardim Andorinhas",
"city": "Campinas",
"state": "SP",
"zipCode": "13101-400",
"country": "Brasil",
"complement": "Apto 78",
"lat_long": [-22.9064, -47.0616]
}
]
}
```
**Regra de coordenadas (`address_book.lat_long`):**
- Se existir `zipCode` válido e houver cache do CEP no Atomenta (`/api/public/cep/:cep`) para o mesmo usuário, a API valida o ponto enviado.
- Se não houver cache local, o Atomenta consulta a AwesomeAPI e atualiza o cache antes de validar.
- Se `lat_long` estiver ausente/inválido, a API preenche com as coordenadas do CEP cacheado.
- Se a distância entre `lat_long` enviado e o ponto do CEP for maior que `1.5 km`, a API substitui `lat_long` pelo ponto do CEP cacheado.
- Objetivo: evitar discrepâncias grandes entre endereço e coordenada salva no perfil.
---
## 🏠 App Home Screen
### List Categories
**GET** `/api/public/categories`
**Headers:**
- `Accept: application/json`
**Response:**
```json
{
"error": false,
"result": [
{ "id": "all", "name": "Todas", "icon": "🏪" },
{ "id": "lanches", "name": "Lanches", "icon": "🍔" },
{ "id": "pizza", "name": "Pizza", "icon": "🍕" }
]
}
```
### List Stores (Smart Listing)
**GET** `/api/app/stores`
@@ -244,7 +289,7 @@ Lists stores based on user location, filtered by distance.
### 2. Full Store Info
**GET** `/api/store/:storeId/info`
Returns detailed info including operating hours and accepted payment methods.
Retorna versão pública para app (sem dados administrativos/financeiros da loja).
**Response:**
@@ -254,30 +299,29 @@ Returns detailed info including operating hours and accepted payment methods.
"code": "STORE_INFO_RETRIEVED",
"result": {
"isOpen": true,
"statusLabel": "Aberto",
"fantasyName": "Mc Donalds",
"specialty": "Lanches",
"minOrder": 15,
"deliveryTime": "30-45 min",
"logo": "https://...",
"cover": "https://...",
"paymentMethods": {
"paymentOnDelivery": true,
"paymentOnPickup": true,
"acceptCash": true,
"acceptPix": true,
"acceptCreditCard": true, // Resumo Geral
"acceptDebitCard": true, // Resumo Geral
"brands": {
"credit": {
"visa": true,
"master": true,
"elo": true,
"amex": false,
"hipercard": false
},
"debit": {
"visa": true,
"master": true,
"elo": true
}
}
"acceptPix": true
},
"openingHours": { ... },
"address": { ... }
"openingHours": { "...": "..." },
"address": {
"street": "Rua X",
"neighborhood": "Centro",
"city": "Campinas",
"state": "SP",
"zipcode": "13000-000",
"latitude": -22.9,
"longitude": -47.0
}
}
}
```
@@ -285,7 +329,7 @@ Returns detailed info including operating hours and accepted payment methods.
### 3. Product Catalog
**GET** `/api/store/:storeId/catalog`
Returns categories with their respective products.
Retorna categorias com produtos, incluindo diferenciação explícita de pizza.
**Response:**
@@ -294,15 +338,45 @@ Returns categories with their respective products.
"error": false,
"result": [
{
"id": "cat_1...",
"name": "Burgers",
"id": "cat_lanches",
"name": "Lanches",
"isPizzaCategory": false,
"products": [
{
"id": "prod_1...",
"name": "Big Mac",
"price": 25.90,
"image": "https://...",
"addonGroups": [...]
"id": "prod_xburger",
"type": "prepared",
"name": "X-Burger",
"description": "Pão, carne e queijo",
"image": "/uploads/products/xburger.jpg",
"price": "25.00",
"addons": "yes",
"addonGroups": []
}
]
},
{
"id": "cat_pizzas",
"name": "Pizzas",
"isPizzaCategory": true,
"pizzaConfig": {
"sizes": [{ "id": "broto", "name": "Broto", "slices": 4, "maxFlavors": 1 }],
"doughs": [{ "id": "tradicional", "name": "Tradicional", "active": true }],
"crusts": [{ "id": "catupiry", "name": "Catupiry", "active": true, "priceModifier": "10.00" }]
},
"products": [
{
"id": "prod_pizza_calabresa",
"type": "pizza",
"name": "Pizza Calabresa",
"description": "Molho, mussarela e calabresa",
"image": "/uploads/products/pizza-calabresa.jpg",
"price": "0.00",
"pizzaPrices": {
"broto": "35.00",
"grande": "55.00"
},
"addons": "yes",
"addonGroups": []
}
]
}
@@ -310,7 +384,59 @@ Returns categories with their respective products.
}
```
### 4. Create Order (Checkout)
**Como identificar pizza no app:**
- Produto pizza: `products[].type === "pizza"`.
- Configuração de montagem/preço por tamanho: `category.isPizzaCategory === true` + `category.pizzaConfig` + `product.pizzaPrices`.
### 4. Validate Delivery Address (Checkout)
**POST** `/api/store/:storeId/delivery/validate-address`
Use este endpoint ao trocar endereço na tela de pagamento para validar cobertura antes de finalizar.
**Body:**
```json
{
"address": {
"street": "Avenida das Andorinhas",
"number": "477",
"neighborhood": "Jardim Andorinhas",
"city": "Campinas",
"state": "SP",
"zip": "13101-400",
"lat": -22.918,
"lng": -47.01813
}
}
```
**Resposta Exemplo:**
```json
{
"error": false,
"code": "DELIVERY_ADDRESS_VALIDATED",
"result": {
"deliveryAllowed": true,
"reasonCode": "DELIVERY_ALLOWED",
"reasonMessage": "Endereço válido para entrega",
"deliveryMode": "KM",
"distance": 1.3,
"deliveryFee": 8,
"deliveryTime": "35 min",
"sameCity": false,
"matchedKmRange": { "from": 1, "to": 2, "price": 8, "time": 35 },
"matchedNeighborhood": null
}
}
```
**Regras de validação:**
- `KM`: valida distância até o limite da última faixa + tolerância de `0.5 km`.
- `NEIGHBORHOOD`: reprova se cidade do endereço for diferente da cidade da loja.
- `NEIGHBORHOOD`: aprova se bairro configurado bater, ou se for mesma cidade (fallback).
### 5. Create Order (Checkout)
**POST** `/api/store/:storeId/orders`
**Body:**
@@ -330,9 +456,17 @@ Returns categories with their respective products.
"items": [
{
"productId": "prod_123",
"name": "X-Burger",
"qty": 2,
"price": 25.00,
"addons": []
"addons": [
{
"addonId": "addon_egg",
"name": "Ovo",
"price": 2.50,
"qty": 2
}
]
}
],
"total": 50.00,
@@ -346,6 +480,12 @@ Returns categories with their respective products.
}
```
**Regras para `items[].addons`:**
- `qty` do adicional é aceito no backend (ex.: `2 ovos`).
- Se `qty` não for enviado ou vier inválido, a API assume `1`.
- `qty` mínimo efetivo é `1`.
**Response:**
```json
@@ -354,8 +494,74 @@ Returns categories with their respective products.
"code": "ORDER_CREATED",
"result": {
"id": "ord_987...",
"status": "created",
"paymentPayload": "https://www.asaas.com/i/..." // Link para pagamento (Pix/Boleto)
"shortId": "1234",
"status": "PAYMENT_PENDING",
"paymentStatus": "PENDING",
"paymentMethod": "PIX",
"paymentPayload": {
"copyPaste": "000201010212...",
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
"expirationDate": "2026-02-14T22:30:00.000Z"
},
"payment": {
"method": "PIX",
"status": "PENDING",
"pix": {
"copyPaste": "000201010212...",
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
"expirationDate": "2026-02-14T22:30:00.000Z"
}
}
}
}
```
**Observação de segurança:** o Atomenta não retorna mais links de checkout/fatura do Asaas no payload de criação do pedido.
### 6. Realtime de Status do Pedido (Socket.IO)
Use este canal para acompanhar mudança de status do pedido em tempo real (sem depender de push notification).
**Socket Endpoint:**
- `ws://<host>:<port>/socket.io/` (em produção, usar `wss://` se houver TLS no balanceador)
**Auth no handshake:**
- Enviar o JWT do customer em `auth.token` (mesmo token do `Authorization: Bearer ...` das APIs HTTP).
**Exemplo de conexão (conceitual):**
```json
{
"auth": {
"token": "Bearer <Users_JWT_Token>"
}
}
```
**Eventos recebidos pelo app:**
- `order_update`: enviado quando o pedido muda (pagamento aprovado, aceito pela loja, saiu para entrega, concluído, cancelado).
**Payload típico de `order_update`:**
```json
{
"id": "ord_987...",
"shortId": "1234",
"storeId": "store_123...",
"userId": "cust_uuid...",
"status": "CONFIRMED",
"paymentStatus": "CONFIRMED",
"updatedAt": "2026-02-15T20:10:00.000Z"
}
```
### 7. Fallback oficial (Polling)
Se o socket cair, o app deve continuar consultando o status até estado final.
**Endpoint:**
- `GET /api/public/orders/:orderId`
**Sugestão de estratégia:**
- primeiros 60s: a cada `3s`
- próximos 2min: a cada `5s`
- depois: a cada `10s`
- parar em status final (`COMPLETED`, `CANCELED`, `REFUNDED`) ou ao sair da tela.