Skip to content

Banco de Dados

O CSGOFlip utiliza PostgreSQL como banco de dados principal, com Prisma como ORM e Redis para cache e filas.

Arquitetura

Stack

TecnologiaUso
PostgreSQL 15+Banco principal
Prisma 5+ORM e migrations
Redis 7+Cache, sessions, queues
BullMQFilas de processamento

Seções

Configuração

PostgreSQL

typescript
// database.config.ts
export const databaseConfig = {
  url: process.env.DATABASE_URL,
  
  // Pool de conexões
  pool: {
    min: 5,
    max: 20,
  },
  
  // Timeouts
  connectionTimeout: 10000, // 10s
  queryTimeout: 30000,      // 30s
  
  // SSL em produção
  ssl: process.env.NODE_ENV === 'production' ? {
    rejectUnauthorized: true,
  } : false,
};

Prisma Client

typescript
// prisma.service.ts
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  constructor() {
    super({
      log: process.env.NODE_ENV === 'development'
        ? ['query', 'info', 'warn', 'error']
        : ['error'],
      
      errorFormat: 'minimal',
    });
  }
  
  async onModuleInit() {
    await this.$connect();
  }
  
  async onModuleDestroy() {
    await this.$disconnect();
  }
}

Redis

typescript
// redis.config.ts
export const redisConfig = {
  host: process.env.REDIS_HOST || 'localhost',
  port: parseInt(process.env.REDIS_PORT || '6379'),
  password: process.env.REDIS_PASSWORD,
  db: 0,
  
  // Retry strategy
  retryStrategy: (times: number) => {
    if (times > 10) return null; // Desistir após 10 tentativas
    return Math.min(times * 50, 2000); // Max 2s entre retries
  },
  
  // Timeouts
  connectTimeout: 10000,
  commandTimeout: 5000,
};

Convenções

Nomenclatura

TipoConvençãoExemplo
TabelasPascalCaseUser, CaseOpening
ColunascamelCaseuserId, createdAt
Índicesidx_{tabela}_{colunas}idx_user_steam_id
Foreign Keysfk_{tabela}_{referencia}fk_case_opening_user

IDs

Todos os IDs são Snowflake IDs (BigInt):

typescript
// snowflake.service.ts
@Injectable()
export class SnowflakeService {
  private readonly epoch = 1704067200000n; // 2024-01-01
  private sequence = 0n;
  private lastTimestamp = 0n;
  
  generate(): bigint {
    let timestamp = BigInt(Date.now()) - this.epoch;
    
    if (timestamp === this.lastTimestamp) {
      this.sequence = (this.sequence + 1n) & 4095n; // 12 bits
      if (this.sequence === 0n) {
        // Aguardar próximo ms
        while (timestamp <= this.lastTimestamp) {
          timestamp = BigInt(Date.now()) - this.epoch;
        }
      }
    } else {
      this.sequence = 0n;
    }
    
    this.lastTimestamp = timestamp;
    
    return (timestamp << 22n) | (1n << 12n) | this.sequence;
  }
}

Valores Monetários

Todos os valores monetários são armazenados em centavos como BigInt:

prisma
model Transaction {
  amountCents BigInt  // R$ 150,00 = 15000
}

Timestamps

Todas as tabelas têm createdAt e updatedAt:

prisma
model Example {
  id        BigInt   @id
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Modelo de Dados Simplificado

Principais Tabelas

TabelaDescriçãoVolume Esperado
UserUsuários~100K
TransactionTransações financeiras~10M/mês
CaseOpeningAberturas de caixas~1M/mês
BattleBatalhas~100K/mês
DepositDepósitos~50K/mês
WithdrawalSaques~20K/mês
AuditLogLogs de auditoria~5M/mês

Índices Críticos

sql
-- Transações por usuário e data
CREATE INDEX idx_transaction_user_created 
ON "Transaction" (user_id, created_at DESC);

-- Aberturas recentes
CREATE INDEX idx_case_opening_created 
ON "CaseOpening" (created_at DESC);

-- Batalhas ativas
CREATE INDEX idx_battle_status 
ON "Battle" (status) WHERE status IN ('WAITING', 'RUNNING');

-- Saques pendentes
CREATE INDEX idx_withdrawal_status 
ON "Withdrawal" (status) WHERE status = 'PENDING';

Particionamento

Para tabelas de alto volume, usar particionamento por data:

sql
-- Particionar transações por mês
CREATE TABLE "Transaction" (
    id BIGINT,
    created_at TIMESTAMP,
    ...
) PARTITION BY RANGE (created_at);

-- Criar partições
CREATE TABLE transaction_2024_01 PARTITION OF "Transaction"
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

Monitoramento

Métricas PostgreSQL

sql
-- Conexões ativas
SELECT count(*) FROM pg_stat_activity;

-- Queries lentas
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;

-- Tamanho das tabelas
SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;

Métricas Redis

bash
# Info geral
redis-cli INFO

# Memória
redis-cli INFO memory

# Clientes conectados
redis-cli CLIENT LIST

Documentação Técnica CSGOFlip