Files
CES_SERVE_WEB/AGENTS.md

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