# 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