Pular para o conteúdo principal

Modelagem de Dados

Como organizamos e estruturamos todos os dados do BITIO para que funcione de forma eficiente e segura.

O Grande Quadro

Imagine o banco de dados como uma biblioteca bem organizada:

  • Cada restaurante tem sua própria seção (multi-tenant)
  • Cada módulo (cardápio, reservas, etc.) tem suas próprias estantes (tabelas)
  • Todos seguem o mesmo sistema de catalogação (padrões)

Princípios Simples

1. Isolamento por Restaurante
Dados do Restaurante A nunca se misturam com dados do Restaurante B

2. Um Lugar para Cada Coisa
Cada tipo de informação tem sua tabela específica

3. Ligações Inteligentes
Tabelas se conectam de forma lógica (cliente → pedido → produto)

4. Preparado para o Futuro
Estrutura suporta todos os 8 módulos desde o início

Como Nomeamos as Coisas

Para evitar confusão, usamos nomes consistentes em todo o sistema:

Conceito RealNome na TabelaPor que esse nome
RestaurantetenantsCada restaurante é um "inquilino" do sistema
Dono do restauranteusersPessoas que fazem login no painel
Cliente do restaurantecustomersPessoas que usam o cardápio
Contato do clientecustomer_contactsTelefones e emails em uma única tabela

Entidades Principais - Explicação Simples

Tenants (Restaurantes)

O que é: Cada registro representa um restaurante no sistema
Por que existe: Mantém os dados de cada restaurante separados

CREATE TABLE tenants (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL, -- "Pizzaria do João"
slug VARCHAR(100) UNIQUE NOT NULL, -- "pizzaria-joao" (para URLs)
enabled_modules TEXT[], -- ['menu', 'reservations'] (módulos ativos)
status ENUM('active', 'inactive') DEFAULT 'active',
settings JSONB, -- Configurações específicas
created_at TIMESTAMP DEFAULT NOW()
);

Exemplo real:

  • name: "Pizzaria do João"
  • slug: "pizzaria-joao" → vira pizzaria-joao.cardapio2biz.com.br
  • enabled_modules: ['menu', 'reservations'] → só esses módulos aparecem

Users (Usuários do Painel)

O que é: Pessoas que fazem login para gerenciar o restaurante
Tipos: Dono, gerente, ou equipe 2biz

CREATE TABLE users (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id), -- A qual restaurante pertence
email VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
role ENUM('owner', 'manager', 'admin_2biz') NOT NULL,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW()
);

Exemplo real:

  • João (owner) → pode tudo na Pizzaria do João
  • Maria (manager) → pode gerenciar, mas não alterar configurações
  • Carlos (admin_2biz) → equipe 2biz, acesso a todos os restaurantes

Customers (Clientes dos Restaurantes)

O que é: Pessoas que usam o cardápio, fazem reservas, etc.
Importância: É a tabela mais importante, conecta todos os módulos

CREATE TABLE customers (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id), -- A qual restaurante pertence
phone VARCHAR(20), -- Telefone principal
email VARCHAR(255), -- Email principal
name VARCHAR(255), -- Nome da pessoa
birth_date DATE, -- Para campanhas de aniversário
source ENUM('menu', 'reservation', 'manual'), -- Como chegou ao sistema
created_at TIMESTAMP DEFAULT NOW()
);

Exemplo real:

  • Ana gerou um cupom no cardápio → source: 'menu'
  • Depois fez uma reserva → mesmo registro, não duplica
  • Sistema lembra dela em todas as interações

Módulos Específicos

Cardápio Digital

Categories: Organiza os produtos (Pizzas, Bebidas, Sobremesas)

CREATE TABLE categories (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id),
name VARCHAR(255) NOT NULL, -- "Pizzas Doces"
sort_order INTEGER DEFAULT 0, -- Ordem no cardápio
active BOOLEAN DEFAULT true -- Pode desativar temporariamente
);

Products: Os itens do cardápio

CREATE TABLE products (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id),
category_id UUID REFERENCES categories(id),
name VARCHAR(255) NOT NULL, -- "Pizza Margherita"
description TEXT, -- "Molho de tomate, mozzarela..."
price DECIMAL(10,2) NOT NULL, -- 25.90
photo_url VARCHAR(500), -- Link da foto
available BOOLEAN DEFAULT true -- Disponível hoje?
);

Coupons: Cupons de desconto gerados

CREATE TABLE coupons (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id),
customer_id UUID REFERENCES customers(id),
code VARCHAR(50) UNIQUE NOT NULL, -- "PIZZA10"
type ENUM('percentage', 'fixed_amount'), -- 10% ou R$ 5,00
value DECIMAL(10,2) NOT NULL, -- 10 ou 5.00
used_count INTEGER DEFAULT 0, -- Quantas vezes foi usado
valid_until TIMESTAMP -- Data de expiração
);

Reservas

Tables: Mesas do restaurante

CREATE TABLE tables (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id),
name VARCHAR(50) NOT NULL, -- "Mesa 1", "Varanda 3"
capacity INTEGER NOT NULL, -- Quantas pessoas cabem
active BOOLEAN DEFAULT true
);

Reservations: As reservas feitas

CREATE TABLE reservations (
id UUID PRIMARY KEY,
tenant_id UUID REFERENCES tenants(id),
customer_id UUID REFERENCES customers(id), -- Quem fez a reserva
table_id UUID REFERENCES tables(id), -- Em qual mesa
date DATE NOT NULL, -- Que dia
time TIME NOT NULL, -- Que hora
party_size INTEGER NOT NULL, -- Quantas pessoas
status ENUM('pending', 'confirmed', 'cancelled') DEFAULT 'pending',
notes TEXT -- Observações especiais
);

Como Tudo se Conecta

O diagrama mostra as conexões principais entre as tabelas:

erDiagram
TENANTS ||--o{ USERS : "possui"
TENANTS ||--o{ CUSTOMERS : "atende"
TENANTS ||--o{ CATEGORIES : "organiza"
TENANTS ||--o{ PRODUCTS : "vende"
TENANTS ||--o{ RESERVATIONS : "recebe"

CUSTOMERS ||--o{ COUPONS : "recebe"
CUSTOMERS ||--o{ RESERVATIONS : "faz"

CATEGORIES ||--o{ PRODUCTS : "agrupa"
TABLES ||--o{ RESERVATIONS : "hospeda"

CUSTOMERS {
uuid id PK
uuid tenant_id FK
string phone
string email
string name
date birth_date
}

PRODUCTS {
uuid id PK
uuid tenant_id FK
uuid category_id FK
string name
decimal price
boolean available
}

Fluxo de Dados Típico

  1. Cliente acessa cardápio → sistema identifica o restaurante pelo slug
  2. Cliente gera cupom → cria registro em customers e coupons
  3. Cliente faz reserva → usa mesmo customer_id, cria reservation
  4. Restaurante vê dados → todos filtrados pelo tenant_id

Índices Estratégicos

TabelaColuna(s)TipoMotivo
customers(tenant_id, phone)UNIQUEBusca rápida por telefone
customers(tenant_id, email)UNIQUEBusca por email
products(tenant_id, category_id)B-treeFiltro por categoria
orders(tenant_id, customer_id, order_date)B-treeHistórico do cliente
reservations(tenant_id, date, time)B-treeAgenda de reservas
campaign_recipients(campaign_id, customer_id)UNIQUEEvita envio duplicado

Data Warehouse (S3 + Athena)

Tabelas para Exportação Diária

TabelaFrequênciaParticionamento
menu_viewsDiáriayear/month/day
survey_responsesDiáriayear/month/day
reservationsDiáriayear/month/day
ordersDiáriayear/month/day
campaign_recipientsDiáriayear/month/day

Exemplo Athena Table

CREATE EXTERNAL TABLE bitio_analytics.orders (
id STRING,
tenant_id STRING,
customer_id STRING,
total_amount DOUBLE,
order_date TIMESTAMP
)
PARTITIONED BY (year INT, month INT, day INT)
STORED AS PARQUET
LOCATION 's3://bitio-analytics/orders/';

Implementação

Migration Strategy

  1. Prisma ORM para schema e migrations
  2. Multi-tenant setup com tenant_id em todas as tabelas
  3. Soft delete onde necessário (deleted_at)
  4. Row Level Security opcional no PostgreSQL

Performance

  • Connection pooling via RDS Proxy quando escalar
  • Read replicas para analytics (futuro)
  • Particionamento das tabelas de logs/eventos (futuro)

Backup e Recovery

  • Point-in-time recovery habilitado no RDS
  • Backup diário automático
  • Exportação para S3 como backup secundário

Esta modelagem garante que todos os módulos compartilhem uma base consistente, evitando retrabalho conforme novos recursos são adicionados.