Modelos de Dados MongoDB
Visão Geral
O sistema utiliza MongoDB como banco de dados. Todos os documentos possuem timestamps automáticos (createdAt, updatedAt).
Collections
Tenant
typescript
interface Tenant {
name: string; // Nome do restaurante
slug: string; // Identificador único na URL
email: string; // Email de contato
primaryColor: string; // Cor primária (hex)
secondaryColor?: string;
plan: 'free' | 'basic' | 'premium';
isActive: boolean;
createdAt: Date;
updatedAt: Date;
}Índice único: { slug: 1 }
User
typescript
interface User {
email: string;
password: string; // Hash bcrypt
name: string;
role: 'customer' | 'staff' | 'admin' | 'superadmin';
tenant?: ObjectId; // Referência para Tenant (exceto superadmin)
createdAt: Date;
updatedAt: Date;
}Índice único: { email: 1, tenant: 1 }
Category
typescript
interface Category {
name: string;
order: number; // Ordem de exibição
isActive: boolean;
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}MenuItem
typescript
interface MenuItem {
name: string;
description?: string;
price: number;
imageUrl?: string;
category: ObjectId;
preparationTime?: number; // Em minutos
available: boolean;
featured: boolean; // Exibido no destaque do cardápio
tags: string[]; // 'vegetariano' | 'vegano' | 'semGluten' | 'picante'
pdv?: ObjectId | null; // null = global (todas as filiais); ObjectId = filial específica
inventoryItem?: ObjectId | null; // Item de estoque vinculado para dedução automática
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}Order
typescript
interface Order {
orderNumber: string; // Formato: YYYYMMDD-XXXX
items: Array<{
menuItem: ObjectId;
name: string;
price: number;
quantity: number;
notes?: string;
}>;
customerName: string;
customerPhone: string;
customerEmail?: string;
customerCpf?: string;
type: 'dine_in' | 'takeout';
table?: ObjectId;
pdv?: ObjectId; // Filial que criou o pedido
notes?: string;
status: 'pending' | 'confirmed' | 'preparing' | 'ready' | 'delivered' | 'cancelled';
total: number;
paymentMethod?: 'cash' | 'credit_card' | 'debit_card' | 'pix' | 'voucher' | 'mixed';
isSplitBill: boolean; // Se é parte de conta dividida
splitBillReference?: string; // Número do pedido pai na divisão
trackingToken?: string;
pixPayload?: string; // Payload PIX para geração do QR code
pixQrCodeBase64?: string; // QR code PIX em base64
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}Índices:
{ orderNumber, tenant }— unique{ trackingToken }— sparse
Table
typescript
interface Table {
number: number;
capacity: number;
status: 'available' | 'occupied' | 'reserved';
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}Reservation
typescript
interface Reservation {
customerName: string;
customerPhone: string;
customerEmail?: string;
date: Date;
time: string;
partySize: number;
table?: ObjectId;
status: 'pending' | 'confirmed' | 'cancelled';
notes?: string;
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}InventoryItem
typescript
interface InventoryItem {
name: string;
sku: string;
currentStock: number;
minStock: number;
unit: string;
cost: number;
expirationDate?: Date;
status: 'active' | 'inactive';
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}PriceSchedule
typescript
interface PriceSchedule {
menuItem: ObjectId; // Item do cardápio a ser alterado
newPrice: number; // Novo preço
scheduledAt: Date; // Data/hora de aplicação
appliedAt?: Date; // Data/hora em que foi de fato aplicado
status: 'pending' | 'applied' | 'cancelled';
createdBy?: ObjectId; // Usuário que criou
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}Índice: { tenant, status, scheduledAt }
Filial (Pdv)
typescript
interface Pdv {
name: string;
description: string;
slug?: string; // Identificador legível para URLs do cliente
serviceMode: 'mesa' | 'balcao' | 'auto_atendimento';
active: boolean;
isDefault: boolean; // Filial padrão do tenant
pin?: string; // PIN de 4–6 dígitos (armazenado com hash)
assignedUsers: ObjectId[]; // Usuários autorizados a usar este terminal
address?: string;
city?: string;
phone?: string;
cnpj?: string;
cep?: string;
tenant: ObjectId;
createdAt: Date;
updatedAt: Date;
}Índices:
{ name, tenant }— unique{ slug, tenant }— unique sparse