Banco de Dados
O CSGOFlip utiliza PostgreSQL como banco de dados principal, com Prisma como ORM e Redis para cache e filas.
Arquitetura
Stack
| Tecnologia | Uso |
|---|---|
| PostgreSQL 15+ | Banco principal |
| Prisma 5+ | ORM e migrations |
| Redis 7+ | Cache, sessions, queues |
| BullMQ | Filas de processamento |
Seções
- Schema Prisma - Modelos e relacionamentos
- Migrations - Versionamento do schema
- Queries Otimizadas - Performance e índices
- Backup e Recovery - Estratégias de backup
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
| Tipo | Convenção | Exemplo |
|---|---|---|
| Tabelas | PascalCase | User, CaseOpening |
| Colunas | camelCase | userId, createdAt |
| Índices | idx_{tabela}_{colunas} | idx_user_steam_id |
| Foreign Keys | fk_{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
| Tabela | Descrição | Volume Esperado |
|---|---|---|
User | Usuários | ~100K |
Transaction | Transações financeiras | ~10M/mês |
CaseOpening | Aberturas de caixas | ~1M/mês |
Battle | Batalhas | ~100K/mês |
Deposit | Depósitos | ~50K/mês |
Withdrawal | Saques | ~20K/mês |
AuditLog | Logs 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