243 lines
10 KiB
Markdown
243 lines
10 KiB
Markdown
# Contexto do Projeto - Gastrobar PDV (Café em Saturno)
|
|
|
|
## Visão Geral
|
|
Sistema de PDV (Ponto de Venda) e gerenciamento para gastrobar/restaurante. Gerencia comandas de clientes, pedidos, cardápio de produtos, usuários com diferentes perfis de acesso e fluxo de preparo na cozinha/bar.
|
|
|
|
## Stack
|
|
|
|
### Backend (`src/`)
|
|
- **Runtime:** Node.js + TypeScript (CommonJS)
|
|
- **Framework:** Fastify v4.27 (porta 3333)
|
|
- **ORM:** Prisma v5.14 com SQLite (`prisma/dev.db`)
|
|
- **Validação:** Zod v3.23
|
|
- **Auth:** JWT (`@fastify/jwt`) + bcrypt
|
|
- **Dev:** tsx watch (`npm run dev`)
|
|
|
|
### Frontend (`web/`)
|
|
- **Bundler:** Vite v8.1
|
|
- **Linguagem:** TypeScript vanilla (sem framework, SPA)
|
|
- **Dev server:** porta 5173
|
|
- **API URL:** `http://localhost:3333/api`
|
|
- **Token storage:** `localStorage('@gastrobar:token')` e `localStorage('@gastrobar:user')`
|
|
|
|
## Estrutura do Projeto
|
|
|
|
```
|
|
app_ces/
|
|
├── .env # JWT_SECRET
|
|
├── package.json # Backend dependencies
|
|
├── tsconfig.json
|
|
├── prisma/
|
|
│ ├── schema.prisma # Schema do banco (SQLite)
|
|
│ ├── seed.ts # Seed: admin@gastrobar.com / 123456
|
|
│ └── dev.db # Banco SQLite (gerado)
|
|
├── src/ # Backend API
|
|
│ ├── server.ts # Entrypoint Fastify, porta 3333
|
|
│ ├── lib/
|
|
│ │ ├── prisma.ts # Instância PrismaClient
|
|
│ │ └── timezone.ts # Helpers UTC-3 (dateStart, dateEnd, dateTime, nowUTC3)
|
|
│ ├── middlewares/
|
|
│ │ └── auth.middleware.ts # authenticate + requireRoles
|
|
│ ├── controllers/
|
|
│ │ ├── auth.controller.ts
|
|
│ │ ├── category.controller.ts
|
|
│ │ ├── product.controller.ts
|
|
│ │ ├── order.controller.ts
|
|
│ │ ├── user.controller.ts
|
|
│ │ └── report.controller.ts
|
|
│ ├── services/
|
|
│ │ ├── auth.service.ts
|
|
│ │ ├── category.service.ts
|
|
│ │ ├── product.service.ts
|
|
│ │ ├── order.service.ts
|
|
│ │ ├── user.service.ts
|
|
│ │ └── report.service.ts
|
|
│ ├── schemas/ # Validação Zod
|
|
│ │ ├── auth.schema.ts
|
|
│ │ ├── user.schema.ts
|
|
│ │ ├── product.schema.ts
|
|
│ │ ├── category.schema.ts
|
|
│ │ └── order.schema.ts
|
|
│ └── routes/
|
|
│ ├── auth.routes.ts
|
|
│ ├── category.routes.ts
|
|
│ ├── product.routes.ts
|
|
│ ├── order.routes.ts
|
|
│ ├── user.routes.ts
|
|
│ └── report.routes.ts
|
|
└── web/ # Frontend SPA
|
|
├── package.json # Vite + TypeScript
|
|
├── tsconfig.json
|
|
└── src/
|
|
├── main.ts # Router SPA + navegação
|
|
├── api.ts # Cliente HTTP centralizado
|
|
├── utils.ts # renderNavbar, toast, helpers, toDisplayDate, parseDisplayDate
|
|
├── style.css # Dark theme + glassmorphism
|
|
└── views/
|
|
├── login.ts
|
|
├── kitchen.ts # Painel de preparo
|
|
├── orders.ts # Gerenciamento de comandas
|
|
├── checkout.ts # Caixa/pagamento
|
|
├── menu.ts # Cardápio CRUD
|
|
├── users.ts # Gestão de equipe
|
|
└── dashboard.ts # KPIs admin
|
|
```
|
|
|
|
## Banco de Dados (Schema Prisma)
|
|
|
|
### Models
|
|
|
|
**Usuario**
|
|
- `id` (UUID), `nome`, `email` (unique), `senha` (hash bcrypt), `role` (ADMIN|CAIXA|GARCOM|COZINHA|BARMAN), `ativo`, `criadoEm`
|
|
- Relations: `comandas` (1:N Comanda), `itensPedido` (1:N ItemPedido)
|
|
|
|
**Categoria**
|
|
- `id` (UUID), `nome`, `produtos` (relation 1:N Produto)
|
|
|
|
**Produto**
|
|
- `id` (UUID), `nome`, `descricao?`, `fotoUrl?`, `preco` (Float), `custo?`, `estoqueAtual`, `estoqueMinimo`, `itemCozinha` (boolean: true=cozinha, false=bar), `ativo`, `categoriaId` (FK)
|
|
|
|
**Comanda**
|
|
- `id` (UUID), `identificador` (mesa/código), `nomeCliente?`, `status` (ABERTA|FECHADA|PAGA|CANCELADA), `total`, `valorPago`, `desconto`, `acrescimo`, `taxaServico` (boolean, +10%), `formaPagamento?`, `motivoCancelamento?`, `criadoEm`, `fechadoEm?`
|
|
- `usuarioId?` (FK) - Usuário que abriu a comanda
|
|
- Relations: `itens` (1:N ItemPedido), `pagamentos` (1:N Pagamento), `usuario` (N:1 Usuario)
|
|
|
|
**ItemPedido**
|
|
- `id` (UUID), `quantidade`, `precoUnitario`, `observacao?`, `status` (PENDENTE|PREPARANDO|PRONTO|ENTREGUE), `produtoId` (FK), `comandaId` (FK), `criadoEm`
|
|
- `usuarioId?` (FK) - Usuário que adicionou o item
|
|
- Relations: `produto` (N:1 Produto), `comanda` (N:1 Comanda), `usuario` (N:1 Usuario)
|
|
|
|
**Pagamento**
|
|
- `id` (UUID), `comandaId` (FK), `valor`, `formaPagamento` (DINHEIRO|CARTAO_CREDITO|CARTAO_DEBITO|PIX), `observacao?`, `estornado` (boolean, default false), `criadoEm`
|
|
|
|
## Rotas da API
|
|
|
|
### Auth (`/api/auth`)
|
|
| Método | Rota | Permissão | Descrição |
|
|
|--------|------|-----------|-----------|
|
|
| POST | `/auth/login` | Público | Login, retorna JWT + user |
|
|
| PATCH | `/auth/senha` | Autenticado | Alterar própria senha |
|
|
|
|
### Categorias (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/categorias` | Autenticado |
|
|
| GET | `/categorias/:id` | Autenticado |
|
|
| POST | `/categorias` | ADMIN |
|
|
| PUT | `/categorias/:id` | ADMIN |
|
|
| DELETE | `/categorias/:id` | ADMIN |
|
|
|
|
### Produtos (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/produtos` | Autenticado |
|
|
| GET | `/produtos/mais-vendidos` | Autenticado |
|
|
| GET | `/produtos/busca` | Autenticado |
|
|
| GET | `/produtos/baixo-estoque` | ADMIN |
|
|
| GET | `/produtos/:id` | Autenticado |
|
|
| POST | `/produtos` | ADMIN |
|
|
| PUT | `/produtos/:id` | ADMIN |
|
|
| DELETE | `/produtos/:id` | ADMIN |
|
|
|
|
### Comandas (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/comandas` | Autenticado |
|
|
| GET | `/pagamentos` | Autenticado |
|
|
| POST | `/comandas` | GARCOM/CAIXA/ADMIN |
|
|
| POST | `/comandas/:id/itens` | GARCOM/CAIXA/ADMIN |
|
|
| PATCH | `/comandas/:id` | GARCOM/CAIXA/ADMIN |
|
|
| POST | `/comandas/:id/pagar` | CAIXA/ADMIN |
|
|
| POST | `/comandas/:id/pagamentos` | CAIXA/ADMIN |
|
|
| PATCH | `/pagamentos/:id/estornar` | CAIXA/ADMIN |
|
|
| PATCH | `/comandas/itens/:id/observacao` | GARCOM/CAIXA/ADMIN |
|
|
| DELETE | `/comandas/itens/:id` | CAIXA/ADMIN |
|
|
|
|
### Painel Cozinha/Bar (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/painel/itens` | COZINHA/BARMAN/ADMIN |
|
|
| PATCH | `/painel/itens/:id/status` | COZINHA/BARMAN/ADMIN |
|
|
|
|
### Relatórios (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/relatorios/vendas` | ADMIN |
|
|
| GET | `/relatorios/dashboard` | ADMIN |
|
|
|
|
### Usuários (`/api`)
|
|
| Método | Rota | Permissão |
|
|
|--------|------|-----------|
|
|
| GET | `/usuarios` | ADMIN |
|
|
| POST | `/usuarios` | ADMIN |
|
|
| PATCH | `/usuarios/:id` | ADMIN |
|
|
| PATCH | `/usuarios/:id/senha` | ADMIN |
|
|
| DELETE | `/usuarios/:id` | ADMIN |
|
|
|
|
## Roles e Permissões
|
|
|
|
| Role | Descrição | Acesso Principal |
|
|
|------|-----------|-----------------|
|
|
| `ADMIN` | Administrador | Acesso total ao sistema |
|
|
| `CAIXA` | Operador de caixa | Comandas, checkout, pagamento, exclusão de itens |
|
|
| `GARCOM` | Garçom | Criar/gerenciar comandas, adicionar itens |
|
|
| `COZINHA` | Cozinheiro | Painel de preparo (itens `itemCozinha=true`) |
|
|
| `BARMAN` | Bartender | Painel de preparo (itens `itemCozinha=false`) |
|
|
|
|
## Lógica de Negócio Importante
|
|
|
|
### Fluxo de Comanda
|
|
1. Criar comanda (identificador = mesa/código) - **registra usuário logado**
|
|
2. Adicionar itens (baixa estoque automaticamente, atualiza total) - **registra usuário logado**
|
|
3. Itens aparecem no painel de cozinha/bar com status `PENDENTE` (apenas últimos 12h)
|
|
4. Cozinha/bar avança: `PENDENTE → PREPARANDO → PRONTO → ENTREGUE`
|
|
5. Caixa fecha com pagamento (integral ou parcial)
|
|
6. Status da comanda: `ABERTA → PAGA`
|
|
|
|
### Pagamento
|
|
- **Integral**: `POST /comandas/:id/pagar` - registra pagamento do restante e fecha comanda
|
|
- **Parcial**: `POST /comandas/:id/pagamentos` - registra pagamento parcial, pode selecionar itens específicos
|
|
- **Cálculo do total final**: `total - desconto + acrescimo + (taxaServico ? 10% : 0)`
|
|
- Formas: `DINHEIRO`, `CARTAO_CREDITO`, `CARTAO_DEBITO`, `PIX`
|
|
- **Estorno**: `PATCH /pagamentos/:id/estornar` - marca pagamento como estornado, subtrai valor de `comanda.valorPago`, se comanda era `PAGA` volta para `FECHADA`. Pagamento continua visível com indicador visual (opacity + line-through + badge "ESTORNADO")
|
|
|
|
### Estoque
|
|
- Decrementa ao adicionar item na comanda
|
|
- Incrementa ao remover item da comanda
|
|
- **Permite estoque negativo** (sem validação de insuficiência)
|
|
|
|
### Frontend
|
|
- Rotas SPA manuais via `window.history.pushState`
|
|
- Auto-refresh no painel de cozinha a cada 10 segundos
|
|
- Notificações sonoras via Web Audio API para novos pedidos
|
|
- Navbar dinâmica baseada no role do usuário logado
|
|
- Filtros de data em formato `dd/mm/yyyy` (inputs `type="text"`, conversão via `parseDisplayDate`)
|
|
|
|
## Comandos Úteis
|
|
|
|
```bash
|
|
# Backend
|
|
npm run dev # Iniciar dev server (tsx watch)
|
|
npm run build # Compilar TypeScript
|
|
npm run db:push # Aplicar schema no banco
|
|
npm run db:seed # Popular banco com dados iniciais
|
|
|
|
# Frontend
|
|
cd web && npm run dev # Iniciar Vite dev server
|
|
cd web && npm run build # Build de produção
|
|
```
|
|
|
|
## Credenciais Padrão (Seed)
|
|
- **Email:** admin@gastrobar.com
|
|
- **Senha:** 123456
|
|
- **Role:** ADMIN
|
|
|
|
## Notas Técnicas
|
|
- CORS habilitado para qualquer origem (`origin: '*'`)
|
|
- JWT secret definido em `.env` (fallback: `fallback_secret_change_me`)
|
|
- Error handler global trata `ZodError` (400) e erros HTTP
|
|
- **Fuso horário UTC-3** configurado em `src/lib/timezone.ts` - todas as datas no backend e frontend usam offset UTC-3
|
|
- Frontend não usa framework UI - renderiza HTML via template literals
|
|
- Utiliza `event delegation` para botões dinâmicos no painel
|
|
- Cleanup de listeners ao navegar entre views
|