Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a89251d7e0 | ||
|
|
4567ae4786 |
No files matched your search
@@ -1,539 +1,109 @@
|
|||||||
# NutriScan
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|
<img src="assets/readme/hero.svg" width="100%" alt="NutriScan: busca de alimentos no Open Food Facts por código de barras ou nome, mostrando um produto com Nutri-Score D e NOVA grupo 4">
|
||||||
|
|
||||||
**Plataforma completa de informações nutricionais alimentares**
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
_Descubra o que a comunidade alimentar sabe sobre seus alimentos_
|
[Notas da API Open Food Facts](docs/openFoodFacts.md) · [Issues](https://git.evandro.dev.br/evandro/nutriscan/issues)
|
||||||
|
|
||||||
[](https://nextjs.org/)
|
|
||||||
[](https://www.typescriptlang.org/)
|
|
||||||
[](https://www.prisma.io/)
|
|
||||||
[](https://tailwindcss.com/)
|
|
||||||
[](https://world.openfoodfacts.org/)
|
|
||||||
|
|
||||||
[](https://nutriscan.evandro.dev.br)
|
|
||||||
[](https://github.com/evandrodevbr/lista-compras/issues)
|
|
||||||
[](https://github.com/evandrodevbr/lista-compras/issues)
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## 📋 Índice
|
O cache JSON do servidor vem no repositório (`data/products-cache.json`) com produtos reais do Open Food Facts. Contado por Nutri-Score, num clone novo e sem instalar nada:
|
||||||
|
|
||||||
- [Sobre o Projeto](#-sobre-o-projeto)
|
```console
|
||||||
- [Demonstração Visual](#-demonstração-visual)
|
$ node -e "const p = Object.values(require('./data/products-cache.json').products); const g = {}; for (const x of p) g[x.nutrition_grades] = (g[x.nutrition_grades] || 0) + 1; console.log(p.length, g)"
|
||||||
- [Funcionalidades](#-funcionalidades)
|
232 { e: 26, unknown: 167, d: 24, c: 9, a: 2, b: 4 }
|
||||||
- [Stack Tecnológica](#-stack-tecnológica)
|
|
||||||
- [Arquitetura](#-arquitetura)
|
|
||||||
- [Instalação e Setup](#-instalação-e-setup)
|
|
||||||
- [API e Integrações](#-api-e-integrações)
|
|
||||||
- [Database Schema](#-database-schema)
|
|
||||||
- [Performance e Otimizações](#-performance-e-otimizações)
|
|
||||||
- [Deployment](#-deployment)
|
|
||||||
- [Scripts Disponíveis](#-scripts-disponíveis)
|
|
||||||
- [Contribuindo](#-contribuindo)
|
|
||||||
- [Licença](#-licença)
|
|
||||||
- [Contato](#-contato)
|
|
||||||
- [Agradecimentos](#-agradecimentos)
|
|
||||||
|
|
||||||
## 🚀 Sobre o Projeto
|
|
||||||
|
|
||||||
**NutriScan** é uma plataforma web moderna que democratiza o acesso a informações nutricionais transparentes e confiáveis. Desenvolvida com foco na experiência do usuário e performance, a aplicação conecta consumidores conscientes à maior base de dados colaborativa de alimentos do mundo.
|
|
||||||
|
|
||||||
### 🎯 Missão
|
|
||||||
|
|
||||||
Empoderar usuários com dados nutricionais precisos e abrangentes para tomada de decisões alimentares mais conscientes através de uma plataforma intuitiva, rápida e confiável.
|
|
||||||
|
|
||||||
### ⭐ Diferenciais
|
|
||||||
|
|
||||||
- **Dados Colaborativos**: Acesso a milhões de produtos da maior base de dados open source do mundo
|
|
||||||
- **Filtros Avançados**: Sistema sofisticado de busca e filtros para descoberta precisa de produtos
|
|
||||||
- **Classificações de Saúde**: Nutri-Score e NOVA group para avaliação rápida da qualidade
|
|
||||||
- **Atualizações em Tempo Real**: Sincronização de dados ao vivo e resultados instantâneos
|
|
||||||
- **Arquitetura Moderna**: Desenvolvida com tecnologias de ponta e foco em performance
|
|
||||||
|
|
||||||
### 📊 Estatísticas
|
|
||||||
|
|
||||||
| Métrica | Valor |
|
|
||||||
| ------------------- | ----- |
|
|
||||||
| Produtos no banco | 2M+ |
|
|
||||||
| Países cobertos | 100+ |
|
|
||||||
| Disponibilidade | 24/7 |
|
|
||||||
| Dados colaborativos | Sim |
|
|
||||||
|
|
||||||
## 📱 Demonstração Visual
|
|
||||||
|
|
||||||
> **Nota**: Screenshots serão adicionados em breve mostrando as principais funcionalidades da aplicação.
|
|
||||||
|
|
||||||
### Principais Telas
|
|
||||||
|
|
||||||
- **Página Inicial**: Interface de busca com hero section e barra de pesquisa
|
|
||||||
- **Resultados**: Lista de produtos com filtros avançados e ordenação
|
|
||||||
- **Detalhes do Produto**: Informações nutricionais completas e classificações
|
|
||||||
- **Lista de Compras**: Gerenciamento de produtos com quantidades e status
|
|
||||||
- **Modos de Tema**: Visualização em tema claro e escuro
|
|
||||||
|
|
||||||
## ✨ Funcionalidades
|
|
||||||
|
|
||||||
### 🔍 Sistema de Busca Inteligente
|
|
||||||
|
|
||||||
O NutriScan oferece múltiplas formas de encontrar produtos alimentícios:
|
|
||||||
|
|
||||||
- **Busca por Código de Barras**: Reconhecimento automático de códigos de 8-13 dígitos
|
|
||||||
- **Busca por Nome/Marca**: Pesquisa textual inteligente com sugestões
|
|
||||||
- **Detecção Automática**: Sistema que identifica o tipo de busca automaticamente
|
|
||||||
- **Geolocalização**: Priorização de produtos locais baseada na localização do usuário
|
|
||||||
- **API Proxy**: Chamadas seguras através de rotas Next.js para evitar problemas de CORS
|
|
||||||
|
|
||||||
### 💾 Sistema de Cache Avançado
|
|
||||||
|
|
||||||
Sistema multi-camada de cache para performance otimizada:
|
|
||||||
|
|
||||||
- **Cache localStorage**: Armazenamento local com TTL configurável
|
|
||||||
- **Cache de Buscas**: Armazenamento completo de buscas com filtros aplicados
|
|
||||||
- **Cache JSON**: 218 produtos pré-carregados para uso offline
|
|
||||||
- **Modo Cache-Only**: Funcionamento completo sem conexão com internet
|
|
||||||
- **Sincronização Inteligente**: Atualização automática de dados quando online
|
|
||||||
- **Estatísticas de Storage**: Monitoramento de uso de armazenamento
|
|
||||||
|
|
||||||
### 🎛️ Filtros e Ordenação
|
|
||||||
|
|
||||||
Sistema robusto de filtros para descoberta precisa:
|
|
||||||
|
|
||||||
#### Classificações de Saúde
|
|
||||||
|
|
||||||
- **Nutri-Score**: Filtro por classificação A-E (muito bom a muito ruim)
|
|
||||||
- **NOVA Group**: Filtro por nível de processamento 1-4 (não processado a ultraprocessado)
|
|
||||||
|
|
||||||
#### Filtros de Produto
|
|
||||||
|
|
||||||
- **Categorias**: Filtro por tipo de alimento (bebidas, laticínios, snacks, etc.)
|
|
||||||
- **Marcas**: Filtro por fabricante
|
|
||||||
- **Alérgenos**: Identificação e filtro por substâncias alergênicas
|
|
||||||
- **Aditivos**: Filtro por aditivos alimentares e conservantes
|
|
||||||
|
|
||||||
#### Filtros Nutricionais
|
|
||||||
|
|
||||||
- **Ranges Personalizados**: Filtros por valores nutricionais (calorias, gorduras, açúcares, etc.)
|
|
||||||
- **12 Opções de Ordenação**: Por relevância, nutrição, nome, marca, valores nutricionais, etc.
|
|
||||||
|
|
||||||
### 🛒 Listas de Compras Colaborativas
|
|
||||||
|
|
||||||
Sistema completo de gerenciamento de compras:
|
|
||||||
|
|
||||||
- **Múltiplas Listas**: Criação e gerenciamento de várias listas de compras
|
|
||||||
- **Produtos Detalhados**: Adição com quantidade, unidade e observações
|
|
||||||
- **Status de Compra**: Marcação de itens como comprados
|
|
||||||
- **Sincronização**: Persistência via Prisma + SQLite
|
|
||||||
- **Compartilhamento**: Compartilhamento de listas via ID único
|
|
||||||
|
|
||||||
### 🎨 Interface e Experiência do Usuário
|
|
||||||
|
|
||||||
Design moderno e acessível:
|
|
||||||
|
|
||||||
- **Design Responsivo**: Mobile-first com adaptação para todos os dispositivos
|
|
||||||
- **Temas**: Modo claro e escuro com persistência de preferência
|
|
||||||
- **Animações**: Transições suaves com Framer Motion
|
|
||||||
- **Acessibilidade**: Componentes Radix UI com suporte completo a leitores de tela
|
|
||||||
- **Estados de Loading**: Skeletons e indicadores de carregamento
|
|
||||||
- **Paginação Otimizada**: Carregamento eficiente de grandes listas
|
|
||||||
- **Imagens Otimizadas**: Lazy loading e otimização automática
|
|
||||||
|
|
||||||
## 🛠 Stack Tecnológica
|
|
||||||
|
|
||||||
### Framework Principal
|
|
||||||
|
|
||||||
- **[Next.js 14.2.18](https://nextjs.org/)** - React framework com App Router e Server Actions
|
|
||||||
- **[TypeScript 5.7.2](https://www.typescriptlang.org/)** - JavaScript tipado para maior confiabilidade
|
|
||||||
- **[React 18.3.1](https://react.dev/)** - Biblioteca de interface moderna com recursos concorrentes
|
|
||||||
|
|
||||||
### Banco de Dados e ORM
|
|
||||||
|
|
||||||
- **[Prisma 5.22.0](https://www.prisma.io/)** - ORM type-safe para gerenciamento de dados
|
|
||||||
- **[SQLite](https://www.sqlite.org/)** - Banco de dados leve e serverless
|
|
||||||
|
|
||||||
### Estilização e UI
|
|
||||||
|
|
||||||
- **[Tailwind CSS 3.4.15](https://tailwindcss.com/)** - Framework CSS utility-first
|
|
||||||
- **[shadcn/ui](https://ui.shadcn.com/)** - Biblioteca de componentes reutilizáveis
|
|
||||||
- **[Radix UI](https://www.radix-ui.com/)** - Primitivos acessíveis não estilizados
|
|
||||||
- **[Lucide Icons 0.460.0](https://lucide.dev/)** - Ícones bonitos e customizáveis
|
|
||||||
- **[Framer Motion 11.12.0](https://www.framer.com/motion/)** - Biblioteca de animações
|
|
||||||
|
|
||||||
### APIs Externas
|
|
||||||
|
|
||||||
- **[Open Food Facts](https://world.openfoodfacts.org/)** - Base de dados global de produtos alimentícios
|
|
||||||
- **Geolocation API** - Recomendações baseadas em localização
|
|
||||||
|
|
||||||
### Ferramentas de Desenvolvimento
|
|
||||||
|
|
||||||
- **[ESLint 8.57.1](https://eslint.org/)** - Linting e formatação de código
|
|
||||||
- **[PostCSS 8.4.49](https://postcss.org/)** - Processamento de CSS
|
|
||||||
- **[pnpm](https://pnpm.io/)** - Gerenciador de pacotes eficiente
|
|
||||||
|
|
||||||
## 🏗 Arquitetura
|
|
||||||
|
|
||||||
### Estrutura do App Router
|
|
||||||
|
|
||||||
```
|
|
||||||
app/
|
|
||||||
├── actions.ts # Server Actions para mutações de dados
|
|
||||||
├── api/ # Rotas de API para proxies de serviços externos
|
|
||||||
│ ├── cache/sync/ # Sincronização de cache
|
|
||||||
│ ├── location/ # Serviços de geolocalização
|
|
||||||
│ ├── products/[barcode]/ # Proxy de busca de produto
|
|
||||||
│ ├── search/ # Proxy de busca Open Food Facts
|
|
||||||
│ └── storage-stats/ # Estatísticas de armazenamento
|
|
||||||
├── components/ # Componentes específicos de funcionalidades
|
|
||||||
│ ├── landing/ # Seções da página inicial
|
|
||||||
│ └── [componentes diversos] # Componentes reutilizáveis
|
|
||||||
├── lista/[id]/ # Páginas de lista de compras
|
|
||||||
├── produto/[barcode]/ # Páginas de detalhes do produto
|
|
||||||
├── resultados/ # Página de resultados de busca
|
|
||||||
└── layout.tsx # Layout raiz
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fluxo de Dados
|
## O que é
|
||||||
|
|
||||||
1. **Requisições de Busca**: Entrada do usuário → Rota de API → API Open Food Facts → Resposta
|
NutriScan é um app web em Next.js para buscar produtos alimentícios no [Open Food Facts](https://world.openfoodfacts.org/) e montar listas de compras. A entrada é detectada sozinha: 8 a 13 dígitos viram busca por código de barras; o resto, busca por nome ou marca.
|
||||||
2. **Gerenciamento de Listas**: Ações do usuário → Server Actions → Prisma → Banco de dados
|
|
||||||
3. **Atualizações em Tempo Real**: Server Actions → Banco de dados → Revalidação → Atualização da UI
|
|
||||||
|
|
||||||
### Sistema de Cache
|
Páginas: `/` (landing), `/resultados`, `/produto/[barcode]`, `/lista/[id]` e `/sobre`.
|
||||||
|
|
||||||
```mermaid
|
| Recurso | O que faz |
|
||||||
graph TD
|
|---|---|
|
||||||
A[Usuário] --> B[Interface]
|
| **Filtros** | Nutri-Score A–E, grupos NOVA 1–4, categorias, marcas, alérgenos e aditivos (incluir/excluir, ou "sem aditivos"), faixas por 100 g de energia, gordura, carboidratos, proteínas, açúcares, fibras e sódio, e países |
|
||||||
B --> C{Cache Local?}
|
| **12 critérios de ordenação** | Relevância, Nutri-Score, nome, marca, energia, gordura, açúcares, completude, com imagem, com dados nutricionais, Eco-Score e grupo NOVA, em ordem crescente ou decrescente |
|
||||||
C -->|Sim| D[Retornar Dados]
|
| **País por IP** | A rota `/api/location` descobre o país do visitante e a busca prioriza produtos dele; o resultado fica 7 dias no `localStorage`, com Brasil como fallback |
|
||||||
C -->|Não| E[API Route]
|
| **Listas de compras** | Várias listas acessíveis por ID em `/lista/[id]`; cada item tem nome, quantidade, unidade e status de comprado, persistidos com Prisma + SQLite |
|
||||||
E --> F[Open Food Facts API]
|
| **Interface** | Tema claro/escuro, componentes shadcn/ui sobre Radix UI, animações com Framer Motion, skeletons, paginação e manifest de PWA |
|
||||||
F --> G[Salvar no Cache]
|
|
||||||
G --> D
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚦 Instalação e Setup
|
## Por que usar
|
||||||
|
|
||||||
### Pré-requisitos
|
- **Menos chamadas ao Open Food Facts.** A busca passa por dois caches antes da API: `localStorage` no navegador (TTL padrão de 1 hora) e o cache JSON no servidor. Tudo que vem da API é gravado no cache JSON.
|
||||||
|
- **Funciona sem a API.** No modo cache-only o servidor responde só com o cache JSON, sem consultar o Open Food Facts.
|
||||||
|
- **Filtros combinados**: Nutri-Score, NOVA, alérgenos, aditivos e faixas de nutrientes ao mesmo tempo, com 12 ordenações.
|
||||||
|
|
||||||
- **Node.js** 18.0 ou superior
|
Quando não usar: se você precisa publicar o app ou usá-lo comercialmente (a licença só permite uso pessoal em localhost), ler código de barras pela câmera (a entrada é digitada ou colada) ou esperar Nutri-Score em cada produto (no cache acima, 167 de 232 produtos vieram sem nota).
|
||||||
- **pnpm** 8.0 ou superior (gerenciador de pacotes recomendado)
|
|
||||||
|
|
||||||
### Instalação Passo a Passo
|
## Como funciona
|
||||||
|
|
||||||
1. **Clone o repositório**
|
1. O navegador procura a busca no `localStorage` (`lib/cacheManager.ts`, `hooks/useSearchCache.ts`).
|
||||||
|
2. Se não achar, chama as rotas Next.js `/api/search` e `/api/products/[barcode]`.
|
||||||
|
3. As rotas consultam o cache JSON do servidor (`lib/jsonCacheManager.ts`, `data/products-cache.json`).
|
||||||
|
4. Fora do modo cache-only, o que falta vem do Open Food Facts (`lib/openFoodFactsApi.ts`: timeout de 8 s, 200 ms entre páginas, até 1000 produtos por página) e é gravado no cache JSON. `POST /api/cache/sync` também grava produtos enviados pelo cliente.
|
||||||
|
5. As listas de compras usam Server Actions (`app/actions.ts`) sobre Prisma + SQLite: modelos `Lista` e `Produtos` em `prisma/schema.prisma`.
|
||||||
|
|
||||||
```bash
|
## Início rápido
|
||||||
git clone https://github.com/evandrodevbr/lista-compras.git
|
|
||||||
cd lista-compras
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Instale as dependências**
|
Requisitos: Node.js 18+ (o deploy usa `nodejs_18`) e pnpm (o deploy fixa `[email protected]`).
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm install
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Configure as variáveis de ambiente**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env.local
|
|
||||||
```
|
|
||||||
|
|
||||||
Configure as seguintes variáveis:
|
|
||||||
|
|
||||||
```env
|
|
||||||
DATABASE_URL="file:./prisma/db/database.sqlite"
|
|
||||||
NEXT_PUBLIC_SITE_URL="http://localhost:3000"
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Inicialize o banco de dados**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm db:generate
|
|
||||||
pnpm db:migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Inicie o servidor de desenvolvimento**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
6. **Abra seu navegador**
|
|
||||||
Navegue para [http://localhost:3000](http://localhost:3000)
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
|
|
||||||
**Problema**: Erro de conexão com banco de dados
|
|
||||||
|
|
||||||
- **Solução**: Verifique se o arquivo `database.sqlite` existe em `prisma/db/`
|
|
||||||
|
|
||||||
**Problema**: Erro de build do Prisma
|
|
||||||
|
|
||||||
- **Solução**: Execute `pnpm db:generate` antes do build
|
|
||||||
|
|
||||||
**Problema**: Dependências não instaladas
|
|
||||||
|
|
||||||
- **Solução**: Use `pnpm install --no-frozen-lockfile`
|
|
||||||
|
|
||||||
## 🔌 API e Integrações
|
|
||||||
|
|
||||||
### Integração Open Food Facts
|
|
||||||
|
|
||||||
O NutriScan integra com a API Open Food Facts através de um wrapper customizado (`lib/openFoodFactsApi.ts`) que fornece:
|
|
||||||
|
|
||||||
- **Busca de Produtos**: Pesquisa por nome, marca ou categoria
|
|
||||||
- **Lookup por Código de Barras**: Busca direta usando códigos de barras
|
|
||||||
- **Filtros Avançados**: Filtros por notas nutricionais, alérgenos, aditivos e mais
|
|
||||||
- **Cache**: Estratégia de cache inteligente para melhor performance
|
|
||||||
- **Tratamento de Erros**: Tratamento abrangente de erros e mecanismos de fallback
|
|
||||||
|
|
||||||
### Endpoints Disponíveis
|
|
||||||
|
|
||||||
| Endpoint | Descrição | Método |
|
|
||||||
| ------------------------- | ----------------------------- | ------ |
|
|
||||||
| `/api/search` | Busca de produtos | GET |
|
|
||||||
| `/api/products/[barcode]` | Busca de produto específico | GET |
|
|
||||||
| `/api/location` | Serviços de geolocalização | GET |
|
|
||||||
| `/api/cache/sync` | Sincronização de cache | POST |
|
|
||||||
| `/api/storage-stats` | Estatísticas de armazenamento | GET |
|
|
||||||
|
|
||||||
### Rate Limits e Cache
|
|
||||||
|
|
||||||
- **Resultados de Busca**: Cache de 1 hora para reduzir chamadas à API
|
|
||||||
- **Detalhes de Produto**: Cache de 24 horas para produtos frequentemente acessados
|
|
||||||
- **Opções de Filtro**: Cache de 1 semana para dados estáticos como categorias e marcas
|
|
||||||
|
|
||||||
## 🗄 Database Schema
|
|
||||||
|
|
||||||
### Schema Prisma
|
|
||||||
|
|
||||||
```prisma
|
|
||||||
model Lista {
|
|
||||||
id String @id
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
produtos Produtos[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model Produtos {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
nome String
|
|
||||||
qtd Float
|
|
||||||
tipoUN String
|
|
||||||
comprado Boolean @default(false)
|
|
||||||
listaId String @default("default")
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
lista Lista @relation(fields: [listaId], references: [id])
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Características Principais
|
|
||||||
|
|
||||||
- **Estrutura Simples**: Fácil de entender e manter
|
|
||||||
- **Listas Flexíveis**: Suporte para múltiplas listas de compras
|
|
||||||
- **Rastreamento de Produtos**: Gerenciamento de quantidade e unidade
|
|
||||||
- **Rastreamento de Status**: Status de compra para cada item
|
|
||||||
- **Timestamps**: Rastreamento automático de criação e atualização
|
|
||||||
|
|
||||||
## ⚡ Performance e Otimizações
|
|
||||||
|
|
||||||
### Estratégia de Cache Multi-Camada
|
|
||||||
|
|
||||||
1. **Cache de Busca**: Armazenamento local de resultados de busca
|
|
||||||
2. **Cache de Produtos**: Cache JSON de produtos populares
|
|
||||||
3. **Cache de Imagens**: Lazy loading e otimização automática
|
|
||||||
4. **Cache de API**: Cache de respostas da API Open Food Facts
|
|
||||||
|
|
||||||
### Otimizações de Performance
|
|
||||||
|
|
||||||
- **Lazy Loading**: Carregamento sob demanda de imagens e componentes
|
|
||||||
- **Code Splitting**: Divisão automática de código por rota
|
|
||||||
- **Otimização de Bundle**: Minificação e tree-shaking automáticos
|
|
||||||
- **Server Actions**: Atualizações de dados sem recarregamento de página
|
|
||||||
- **Image Optimization**: Otimização automática de imagens com Next.js
|
|
||||||
|
|
||||||
### Métricas de Performance
|
|
||||||
|
|
||||||
- **First Load JS**: ~87.3 kB compartilhado
|
|
||||||
- **Build Time**: Otimizado com Prisma e Next.js
|
|
||||||
- **Cache Hit Rate**: Monitorado via storage stats API
|
|
||||||
|
|
||||||
## 🚀 Deployment
|
|
||||||
|
|
||||||
### Configuração Dokploy
|
|
||||||
|
|
||||||
O projeto inclui configuração para deployment via Dokploy (`dokploy.yaml`):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
build:
|
|
||||||
pre_build:
|
|
||||||
- npm install -g pnpm@latest
|
|
||||||
- export PNPM_HOME="/root/.local/share/pnpm"
|
|
||||||
- export PATH="$PNPM_HOME:$PATH"
|
|
||||||
steps:
|
|
||||||
- name: Verify pnpm
|
|
||||||
run: which pnpm && pnpm --version
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --no-frozen-lockfile
|
|
||||||
- name: Generate Prisma Client
|
|
||||||
run: pnpx prisma generate
|
|
||||||
- name: Build application
|
|
||||||
run: pnpm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuração Nixpacks
|
|
||||||
|
|
||||||
Configuração alternativa para deployment (`nixpacks.toml`):
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[phases.setup]
|
|
||||||
nixPkgs = ['nodejs_18', 'openssl']
|
|
||||||
cmds = [
|
|
||||||
'npm install -g pnpm@latest',
|
|
||||||
'npm install -g prisma'
|
|
||||||
]
|
|
||||||
|
|
||||||
[phases.install]
|
|
||||||
cmds = [
|
|
||||||
'npx pnpm install --no-frozen-lockfile',
|
|
||||||
'mkdir -p prisma',
|
|
||||||
'touch prisma/dev.db',
|
|
||||||
'chmod -R 777 prisma'
|
|
||||||
]
|
|
||||||
|
|
||||||
[phases.build]
|
|
||||||
cmds = [
|
|
||||||
'mkdir -p node_modules/.prisma',
|
|
||||||
'mkdir -p .next',
|
|
||||||
'chmod -R 777 node_modules/.prisma node_modules/.bin .next prisma',
|
|
||||||
'npx prisma generate',
|
|
||||||
'npx prisma db push --accept-data-loss',
|
|
||||||
'npx pnpm run build'
|
|
||||||
]
|
|
||||||
|
|
||||||
[start]
|
|
||||||
cmd = 'npx pnpm start'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Checklist de Deployment
|
|
||||||
|
|
||||||
- [ ] Configurar variáveis de ambiente
|
|
||||||
- [ ] Executar migrações do banco de dados
|
|
||||||
- [ ] Gerar Prisma Client
|
|
||||||
- [ ] Build da aplicação
|
|
||||||
- [ ] Configurar domínio e SSL
|
|
||||||
- [ ] Testar funcionalidades principais
|
|
||||||
|
|
||||||
## 📜 Scripts Disponíveis
|
|
||||||
|
|
||||||
### Desenvolvimento
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm dev # Inicia servidor de desenvolvimento (http://localhost:3000)
|
git clone https://git.evandro.dev.br/evandro/nutriscan.git
|
||||||
pnpm build # Build para produção
|
cd nutriscan
|
||||||
pnpm start # Inicia servidor de produção
|
pnpm install # o postinstall já roda `prisma generate`
|
||||||
pnpm lint # Executa ESLint
|
|
||||||
|
# .env na raiz (o Prisma lê .env, não .env.local)
|
||||||
|
echo 'DATABASE_URL="file:./db/database.sqlite"' > .env
|
||||||
|
|
||||||
|
pnpm db:push # cria o banco SQLite a partir do schema
|
||||||
|
pnpm dev # http://localhost:3000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Banco de Dados
|
> [!WARNING]
|
||||||
|
> **Não existe `.env.example`** e **`pnpm db:migrate` não funciona num clone novo**: ele roda `prisma migrate deploy`, mas `/prisma/migrations` está no `.gitignore`. Crie o banco com `pnpm db:push`. O `DATABASE_URL` é resolvido a partir da pasta `prisma/`, então `file:./db/database.sqlite` vira `prisma/db/database.sqlite` (pasta também ignorada pelo git).
|
||||||
|
|
||||||
```bash
|
Outros scripts: `pnpm build` (`prisma generate && next build`), `pnpm start`, `pnpm lint` (`next lint`), `pnpm db:generate`.
|
||||||
pnpm db:push # Push do schema Prisma para o banco
|
|
||||||
pnpm db:generate # Gera Prisma Client
|
|
||||||
pnpm db:migrate # Executa migrações do banco
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pós-instalação
|
## Configuração
|
||||||
|
|
||||||
```bash
|
| Variável | Efeito |
|
||||||
pnpm postinstall # Gera Prisma Client após instalação
|
|---|---|
|
||||||
```
|
| `DATABASE_URL` | Banco SQLite das listas de compras (obrigatória) |
|
||||||
|
| `NEXT_PUBLIC_CACHE_ONLY_MODE=true` | As rotas de busca e de produto respondem só com o cache JSON |
|
||||||
|
| `NEXT_PUBLIC_RYBBIT_HOST` | Destino do proxy `/analytics/*` (padrão `https://analytics.evandro.dev.br/api`) |
|
||||||
|
|
||||||
## 🤝 Contribuindo
|
O switch de cache-only na interface só funciona em produção (`NODE_ENV=production`); as rotas `/api/search` e `/api/products/[barcode]` aceitam `?cache_only=true` em qualquer ambiente.
|
||||||
|
|
||||||
Agradecemos contribuições da comunidade! Aqui está como você pode ajudar:
|
O que sai do seu servidor:
|
||||||
|
|
||||||
### Para Desenvolvedores
|
- **Open Food Facts**: dados e imagens de produtos (`next.config.mjs` libera `static.openfoodfacts.org` e `images.openfoodfacts.org`).
|
||||||
|
- **ip-api.com**: o IP do visitante, enviado pelo servidor por HTTP, para descobrir o país.
|
||||||
|
- **Rybbit Analytics** (self-hosted, via proxy `/analytics/`): com session replay e rastreamento de erros.
|
||||||
|
- O app também exibe um card de doação via [Buy Me a Coffee](https://buymeacoffee.com/evandrotruuta).
|
||||||
|
|
||||||
1. **Fork o repositório**
|
## Estado do projeto
|
||||||
2. **Crie uma branch de feature**
|
|
||||||
```bash
|
|
||||||
git checkout -b feature/amazing-feature
|
|
||||||
```
|
|
||||||
3. **Faça suas alterações**
|
|
||||||
4. **Commit suas alterações**
|
|
||||||
```bash
|
|
||||||
git commit -m 'Add: amazing feature'
|
|
||||||
```
|
|
||||||
5. **Push para a branch**
|
|
||||||
```bash
|
|
||||||
git push origin feature/amazing-feature
|
|
||||||
```
|
|
||||||
6. **Abra um Pull Request**
|
|
||||||
|
|
||||||
### Para Usuários Finais
|
Projeto pessoal, sem suíte de testes; o único check é `pnpm lint`. O último trabalho de código foi o redesign completo e os ajustes no deploy com Prisma/SQLite, em 2026-07-16. O repositório traz [`dokploy.yaml`](dokploy.yaml) e [`nixpacks.toml`](nixpacks.toml) para o deploy do autor, sem workflow de CI. A instância pública do autor em `nutriscan.evandro.dev.br` não respondia com o app em 2026-10-24.
|
||||||
|
|
||||||
- **Reportar Bugs**: Use [GitHub Issues](https://github.com/evandrodevbr/lista-compras/issues)
|
Limites conhecidos:
|
||||||
- **Solicitar Features**: Sugira novas funcionalidades via [GitHub Issues](https://github.com/evandrodevbr/lista-compras/issues)
|
|
||||||
- **Fornecer Feedback**: Compartilhe sua experiência e sugestões
|
|
||||||
|
|
||||||
### Guidelines de Desenvolvimento
|
- Toda busca nova depende do Open Food Facts; além do cache, não há fila nem fallback.
|
||||||
|
- A localização é por IP, não pela API de geolocalização do navegador.
|
||||||
|
- O `sitemap.xml` lista só a página inicial.
|
||||||
|
|
||||||
- Siga o estilo de código existente
|
## Licença
|
||||||
- Escreva mensagens de commit claras
|
|
||||||
- Adicione testes para novas funcionalidades
|
|
||||||
- Atualize documentação quando necessário
|
|
||||||
- Certifique-se de que todos os checks passem antes de submeter PR
|
|
||||||
|
|
||||||
## 📄 Licença
|
Licença de Uso Pessoal, em [`LICENSE`](LICENSE) (Copyright (c) 2024 Evandro): uso pessoal, não comercial e só em localhost. É proibido fazer deploy público, redistribuir, usar comercialmente ou criar obras derivadas para distribuição. Dúvidas sobre a licença: evandro@evandro.dev.br.
|
||||||
|
|
||||||
Este projeto está licenciado sob uma **Licença de Uso Pessoal**.
|
Créditos: [Open Food Facts](https://world.openfoodfacts.org/), [Next.js](https://nextjs.org/), [Prisma](https://www.prisma.io/), [shadcn/ui](https://ui.shadcn.com/) e [Radix UI](https://www.radix-ui.com/).
|
||||||
|
|
||||||
### Permissões
|
|
||||||
|
|
||||||
- ✅ Uso pessoal em localhost
|
|
||||||
- ✅ Inspeção de código e aprendizado
|
|
||||||
- ✅ Desenvolvimento e teste local
|
|
||||||
|
|
||||||
### Restrições
|
|
||||||
|
|
||||||
- ❌ Deploy público na web
|
|
||||||
- ❌ Uso comercial
|
|
||||||
- ❌ Redistribuição para terceiros
|
|
||||||
- ❌ Criação de obras derivadas para distribuição pública
|
|
||||||
|
|
||||||
Para os termos completos da licença, consulte o arquivo [LICENSE](LICENSE).
|
|
||||||
|
|
||||||
## 📫 Contato
|
|
||||||
|
|
||||||
**Autor:** Evandro
|
|
||||||
**Website:** [evandro.dev.br](https://evandro.dev.br)
|
|
||||||
**GitHub:** [@evandrodevbr](https://github.com/evandrodevbr)
|
|
||||||
**Email:** evandro@evandro.dev.br
|
|
||||||
|
|
||||||
### Links do Projeto
|
|
||||||
|
|
||||||
- **Live Demo:** [nutriscan.evandro.dev.br](https://nutriscan.evandro.dev.br)
|
|
||||||
- **Repositório:** [github.com/evandrodevbr/lista-compras](https://github.com/evandrodevbr/lista-compras)
|
|
||||||
- **Issues:** [GitHub Issues](https://github.com/evandrodevbr/lista-compras/issues)
|
|
||||||
|
|
||||||
## 🙏 Agradecimentos
|
|
||||||
|
|
||||||
- **[Open Food Facts](https://world.openfoodfacts.org/)** - Pela base de dados abrangente de alimentos
|
|
||||||
- **[shadcn/ui](https://ui.shadcn.com/)** - Pela biblioteca de componentes acessíveis
|
|
||||||
- **[Next.js Team](https://nextjs.org/)** - Pelo framework React incrível
|
|
||||||
- **[Vercel](https://vercel.com/)** - Por soluções de hosting e deployment
|
|
||||||
- **[Prisma](https://www.prisma.io/)** - Pelo excelente ORM
|
|
||||||
- **Contribuidores** - Obrigado a todos que ajudam a melhorar este projeto
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<p>Desenvolvido com ❤️ por <a href="https://evandro.dev.br">evandro.dev.br</a></p>
|
|
||||||
<p>Feito para usuários conscientes com a saúde e desenvolvedores ao redor do mundo</p>
|
<sub>Feito por <a href="https://evandro.dev.br">Evandro Fonseca Junior</a> · <a href="https://git.evandro.dev.br/evandro">git.evandro.dev.br</a></sub>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="420" viewBox="0 0 1200 420" role="img" aria-labelledby="title desc">
|
||||||
|
<title id="title">NutriScan</title>
|
||||||
|
<desc id="desc">NutriScan busca produtos alimentícios no Open Food Facts por código de barras ou nome. À direita, a busca pelo código 7891962032450 devolve o Biscoito Maizena Bauducco com Nutri-Score D e NOVA grupo 4, dados reais do cache do repositório.</desc>
|
||||||
|
|
||||||
|
<rect width="1200" height="420" rx="24" fill="#f4f0e8"/>
|
||||||
|
|
||||||
|
<g id="title-block" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||||
|
<text x="64" y="104" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="20" fill="#7c6a54">Open Food Facts · busca e listas</text>
|
||||||
|
<text x="64" y="186" font-size="72" font-weight="700" fill="#1e1810">NutriScan</text>
|
||||||
|
<text x="64" y="246" font-size="28" fill="#1e1810">Busque alimentos por código de barras</text>
|
||||||
|
<text x="64" y="282" font-size="28" fill="#1e1810">ou nome e compare Nutri-Score e NOVA.</text>
|
||||||
|
<text x="64" y="344" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="20" fill="#317257">Next.js 15 · Prisma + SQLite</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="project-proof" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
|
||||||
|
<rect x="632" y="48" width="504" height="324" rx="20" fill="#ffffff" stroke="#e8e0d0" stroke-width="2"/>
|
||||||
|
|
||||||
|
<g id="search">
|
||||||
|
<rect x="664" y="80" width="440" height="64" rx="12" fill="#faf8f5" stroke="#d4c8b0" stroke-width="2"/>
|
||||||
|
<g fill="#1e1810">
|
||||||
|
<rect x="684" y="96" width="3" height="32"/>
|
||||||
|
<rect x="690" y="96" width="2" height="32"/>
|
||||||
|
<rect x="695" y="96" width="5" height="32"/>
|
||||||
|
<rect x="703" y="96" width="2" height="32"/>
|
||||||
|
<rect x="708" y="96" width="3" height="32"/>
|
||||||
|
<rect x="715" y="96" width="2" height="32"/>
|
||||||
|
<rect x="720" y="96" width="5" height="32"/>
|
||||||
|
<rect x="728" y="96" width="2" height="32"/>
|
||||||
|
<rect x="733" y="96" width="3" height="32"/>
|
||||||
|
</g>
|
||||||
|
<text x="752" y="121" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="24" fill="#1e1810">7891962032450</text>
|
||||||
|
<text x="1084" y="119" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="18" fill="#317257" text-anchor="end">EAN-13</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<text x="664" y="204" font-size="26" font-weight="700" fill="#1e1810">Biscoito Maizena</text>
|
||||||
|
<text x="664" y="236" font-size="20" fill="#7c6a54">Bauducco · pacote 170 g</text>
|
||||||
|
|
||||||
|
<g id="nutri-score" font-weight="700" text-anchor="middle">
|
||||||
|
<text x="664" y="282" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="18" font-weight="400" fill="#7c6a54" text-anchor="start">NUTRI-SCORE</text>
|
||||||
|
<rect x="664" y="300" width="44" height="44" rx="8" fill="#038141" fill-opacity="0.3"/>
|
||||||
|
<text x="686" y="330" font-size="22" fill="#1e1810">A</text>
|
||||||
|
<rect x="712" y="300" width="44" height="44" rx="8" fill="#85bb2f" fill-opacity="0.3"/>
|
||||||
|
<text x="734" y="330" font-size="22" fill="#1e1810">B</text>
|
||||||
|
<rect x="760" y="300" width="44" height="44" rx="8" fill="#fecb02" fill-opacity="0.3"/>
|
||||||
|
<text x="782" y="330" font-size="22" fill="#1e1810">C</text>
|
||||||
|
<rect x="808" y="292" width="60" height="60" rx="10" fill="#ee8100"/>
|
||||||
|
<text x="838" y="333" font-size="32" fill="#ffffff">D</text>
|
||||||
|
<rect x="872" y="300" width="44" height="44" rx="8" fill="#e63e11" fill-opacity="0.3"/>
|
||||||
|
<text x="894" y="330" font-size="22" fill="#1e1810">E</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g id="nova">
|
||||||
|
<text x="964" y="282" font-family="ui-monospace, 'SF Mono', Consolas, monospace" font-size="18" fill="#7c6a54">NOVA</text>
|
||||||
|
<rect x="964" y="300" width="140" height="44" rx="22" fill="#1e1810"/>
|
||||||
|
<text x="1034" y="329" font-size="20" font-weight="700" fill="#ffffff" text-anchor="middle">grupo 4</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
Reference in new issue
Block a user