- Adiciona Dockerfile e docker-compose para containerizacao - Adiciona docker-entrypoint.sh com inicializacao - Adiciona scripts/seed-admin.js para criar admin inicial - Adiciona docs/ com logos originais CambioReal - Atualiza README.md com instrucoes de uso - Atualiza queries.js com metricas de portfólio Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
350 lines
14 KiB
Markdown
350 lines
14 KiB
Markdown
# Arquitetura - BI Agentes
|
|
|
|
Documentacao tecnica da arquitetura do sistema BI Agentes.
|
|
|
|
## Visao Geral
|
|
|
|
O BI Agentes e uma aplicacao web monolitica construida com Node.js/Express que serve dashboards de BI para agentes de cambio. A arquitetura prioriza simplicidade, seguranca e isolamento de dados.
|
|
|
|
## Diagrama de Arquitetura
|
|
|
|
```
|
|
INTERNET
|
|
│
|
|
▼
|
|
┌───────────────────────────────────────────────────────────────────────────┐
|
|
│ SERVIDOR EXPRESS │
|
|
│ (PORT 3080) │
|
|
│ │
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ │
|
|
│ │ Static │ │ Session │ │ Auth │ │ Dashboard │ │
|
|
│ │ Files │ │ Middleware │ │ Middleware │ │ Generator │ │
|
|
│ │ /public │ │ (in-memory) │ │ requireAuth │ │ (HTML) │ │
|
|
│ └─────────────┘ └──────┬──────┘ └──────┬──────┘ └─────┬──────┘ │
|
|
│ │ │ │ │
|
|
│ ▼ ▼ ▼ │
|
|
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ REQUEST ROUTER │ │
|
|
│ │ │ │
|
|
│ │ GET /login ──────▶ login.html │ │
|
|
│ │ POST /login ─────▶ authenticate() ──▶ session.create() │ │
|
|
│ │ GET /logout ─────▶ session.destroy() │ │
|
|
│ │ GET /dashboard ──▶ requireAuth ──▶ fetchTransacoes() ──▶ HTML │ │
|
|
│ │ GET / ───────────▶ redirect /dashboard │ │
|
|
│ └────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │ │
|
|
└────────────────────────────┼───────────────────────────┼──────────────────┘
|
|
│ │
|
|
┌──────────────┘ └──────────────┐
|
|
▼ ▼
|
|
┌───────────────────┐ ┌───────────────────┐
|
|
│ SQLite │ │ AWS RDS │
|
|
│ (agentes.db) │ │ (cambio_db) │
|
|
│ │ │ │
|
|
│ ┌─────────────┐ │ │ ┌─────────────┐ │
|
|
│ │ agentes │ │ │ │br_transac...│ │
|
|
│ │ - id │ │ │ │- id │ │
|
|
│ │ - email │ │ │ │- id_conta │ │
|
|
│ │ - senha_hash│ │ │ │- amount_brl │ │
|
|
│ │ - agente_id │ │ │ │- amount_usd │ │
|
|
│ │ - nome │ │ │ │- exchange...| │
|
|
│ │ - ativo │ │ │ │- status │ │
|
|
│ └─────────────┘ │ │ └─────────────┘ │
|
|
│ │ │ │
|
|
│ LOCAL (WAL) │ │ ┌─────────────┐ │
|
|
│ WRITE + READ │ │ │pagamento_br │ │
|
|
└───────────────────┘ │ │- id │ │
|
|
│ │- id_conta │ │
|
|
│ │- valor │ │
|
|
│ │- valor_sol │ │
|
|
│ │- cotacao │ │
|
|
│ └─────────────┘ │
|
|
│ │
|
|
│ REMOTE (MySQL) │
|
|
│ READ-ONLY │
|
|
└───────────────────┘
|
|
```
|
|
|
|
## Componentes
|
|
|
|
### 1. Camada de Apresentacao
|
|
|
|
**Tecnologias:** HTML5, CSS3, Vanilla JavaScript, Chart.js
|
|
|
|
| Arquivo | Responsabilidade |
|
|
|---------|------------------|
|
|
| `public/login.html` | Formulario de login estilizado |
|
|
| `src/dashboard.js` | Geracao dinamica do HTML do dashboard |
|
|
|
|
**Caracteristicas:**
|
|
- Server-Side Rendering (SSR) - HTML gerado no backend
|
|
- Chart.js carregado via CDN (sem build step)
|
|
- CSS inline no dashboard para simplicidade
|
|
- Google Fonts Inter para tipografia
|
|
|
|
### 2. Camada de Aplicacao
|
|
|
|
**Tecnologias:** Node.js, Express.js
|
|
|
|
| Modulo | Responsabilidade |
|
|
|--------|------------------|
|
|
| `server.js` | Entry point, rotas, middleware |
|
|
| `src/auth.js` | Autenticacao, bcrypt, sessoes |
|
|
| `src/queries.js` | Queries SQL, serializacao de dados |
|
|
|
|
**Middleware Stack:**
|
|
```
|
|
Request
|
|
│
|
|
▼
|
|
express.urlencoded() ← Parse form data
|
|
│
|
|
▼
|
|
express.json() ← Parse JSON
|
|
│
|
|
▼
|
|
express-session() ← Gerenciar sessao
|
|
│
|
|
▼
|
|
requireAuth() ← Verificar autenticacao (rotas protegidas)
|
|
│
|
|
▼
|
|
Route Handler
|
|
```
|
|
|
|
### 3. Camada de Dados
|
|
|
|
#### SQLite (Local)
|
|
|
|
**Biblioteca:** better-sqlite3 (sincrono, WAL mode)
|
|
|
|
```sql
|
|
CREATE TABLE agentes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
email TEXT UNIQUE NOT NULL,
|
|
senha_hash TEXT NOT NULL,
|
|
agente_id INTEGER NOT NULL,
|
|
nome TEXT NOT NULL,
|
|
ativo INTEGER DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
**Caracteristicas:**
|
|
- WAL mode para melhor concorrencia
|
|
- Arquivo em `data/agentes.db`
|
|
- Criado automaticamente no primeiro start
|
|
|
|
#### MySQL (RDS)
|
|
|
|
**Biblioteca:** mysql2/promise (pool de conexoes)
|
|
|
|
**Configuracao do Pool:**
|
|
```javascript
|
|
{
|
|
host: process.env.MYSQL_URL,
|
|
user: process.env.USER_MYSQL,
|
|
password: process.env.PW_MYSQL,
|
|
database: 'cambio_db',
|
|
waitForConnections: true,
|
|
connectionLimit: 10,
|
|
queueLimit: 0
|
|
}
|
|
```
|
|
|
|
**Tabelas Consultadas:**
|
|
|
|
| Tabela | Fluxo | Campos Principais |
|
|
|--------|-------|-------------------|
|
|
| `br_transaction_to_usa` | BRL→USD | amount_brl, amount_usd, exchange_rate, iof, ptax |
|
|
| `pagamento_br` | USD→BRL | valor, valor_sol, cotacao, ptax |
|
|
| `ag_contas` | Join | agente_id, conta_id |
|
|
| `conta` | Join | id_conta, nome |
|
|
|
|
## Fluxo de Dados
|
|
|
|
### Autenticacao
|
|
|
|
```
|
|
┌──────────┐ POST /login ┌──────────┐
|
|
│ Browser │ ─────────────────▶ │ Express │
|
|
│ │ email, senha │ │
|
|
└──────────┘ └────┬─────┘
|
|
│
|
|
┌────────────────┘
|
|
▼
|
|
┌──────────────┐
|
|
│ SQLite │
|
|
│ SELECT WHERE │
|
|
│ email = ? │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ bcrypt │
|
|
│ compare │
|
|
└──────┬───────┘
|
|
│
|
|
┌───────┴───────┐
|
|
▼ ▼
|
|
[MATCH] [NO MATCH]
|
|
│ │
|
|
▼ ▼
|
|
session.agente redirect
|
|
= {...} /login?error=1
|
|
│
|
|
▼
|
|
redirect
|
|
/dashboard
|
|
```
|
|
|
|
### Carregamento do Dashboard
|
|
|
|
```
|
|
┌──────────┐ GET /dashboard ┌──────────┐
|
|
│ Browser │ ─────────────────▶ │ Express │
|
|
│ (cookie) │ │ │
|
|
└──────────┘ └────┬─────┘
|
|
│
|
|
requireAuth()────┘
|
|
│
|
|
┌─────────────┴─────────────┐
|
|
▼ ▼
|
|
[NO SESSION] [HAS SESSION]
|
|
│ │
|
|
▼ ▼
|
|
redirect ┌─────────────────┐
|
|
/login │ fetchTransacoes │
|
|
│ (agente_id) │
|
|
└────────┬────────┘
|
|
│
|
|
┌─────────────────┘
|
|
▼
|
|
┌──────────────┐
|
|
│ AWS RDS │
|
|
│ 2 queries: │
|
|
│ BRL→USD │
|
|
│ USD→BRL │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ serialize() │
|
|
│ merge + │
|
|
│ sort │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ buildHTML() │
|
|
│ KPIs + │
|
|
│ Charts + │
|
|
│ Table │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
res.send(html)
|
|
```
|
|
|
|
## Seguranca
|
|
|
|
### Autenticacao
|
|
|
|
| Aspecto | Implementacao |
|
|
|---------|---------------|
|
|
| Hash de senha | bcrypt, 10 salt rounds |
|
|
| Sessao | express-session, in-memory |
|
|
| Timeout | 8 horas (cookie maxAge) |
|
|
| Middleware | requireAuth em rotas protegidas |
|
|
|
|
### Protecao de Dados
|
|
|
|
| Aspecto | Implementacao |
|
|
|---------|---------------|
|
|
| SQL Injection | Queries parametrizadas (?) |
|
|
| Isolamento | WHERE agente_id = ? em todas queries |
|
|
| RDS Access | Usuario read-only (sem INSERT/UPDATE/DELETE) |
|
|
|
|
### Recomendacoes para Producao
|
|
|
|
- [ ] Usar Redis para sessoes (em vez de in-memory)
|
|
- [ ] HTTPS obrigatorio (TLS)
|
|
- [ ] Helmet.js para headers de seguranca
|
|
- [ ] Rate limiting no login
|
|
- [ ] Logs de auditoria
|
|
|
|
## Performance
|
|
|
|
### Estrategias Atuais
|
|
|
|
- **Connection Pool**: 10 conexoes MySQL reutilizaveis
|
|
- **WAL Mode**: SQLite com Write-Ahead Logging
|
|
- **CDN**: Chart.js e fonts via CDN (cache do browser)
|
|
- **SSR**: HTML pre-renderizado (sem SPA overhead)
|
|
|
|
### Gargalos Potenciais
|
|
|
|
| Componente | Risco | Mitigacao |
|
|
|------------|-------|-----------|
|
|
| Sessoes in-memory | Perda em restart | Migrar para Redis |
|
|
| Queries RDS | Tabelas grandes | Adicionar indices, paginacao |
|
|
| HTML generation | Muitas transacoes | Paginacao server-side |
|
|
|
|
## Estrutura de Modulos
|
|
|
|
```
|
|
src/
|
|
├── auth.js # Autenticacao
|
|
│ ├── authenticate(email, senha)
|
|
│ └── requireAuth(req, res, next)
|
|
│
|
|
├── db-local.js # SQLite setup
|
|
│ └── initDB()
|
|
│
|
|
├── db-rds.js # MySQL pool
|
|
│ └── pool (export)
|
|
│
|
|
├── queries.js # Data access
|
|
│ ├── fetchTransacoes(agenteId)
|
|
│ └── serialize(rowsBrlUsd, rowsUsdBrl)
|
|
│
|
|
└── dashboard.js # View generation
|
|
└── buildHTML(data, agente)
|
|
```
|
|
|
|
## Dependencias
|
|
|
|
| Pacote | Versao | Proposito |
|
|
|--------|--------|-----------|
|
|
| express | ^4.x | Framework web |
|
|
| express-session | ^1.x | Gerenciamento de sessao |
|
|
| better-sqlite3 | ^9.x | SQLite driver (sync) |
|
|
| mysql2 | ^3.x | MySQL driver (async) |
|
|
| bcrypt | ^5.x | Hash de senhas |
|
|
| dotenv | ^16.x | Variaveis de ambiente |
|
|
|
|
## Extensibilidade
|
|
|
|
### Adicionar Nova Feature
|
|
|
|
1. **Novo endpoint**: Adicionar rota em `server.js`
|
|
2. **Nova query**: Adicionar funcao em `src/queries.js`
|
|
3. **Nova UI**: Modificar `src/dashboard.js` ou criar novo modulo
|
|
|
|
### Adicionar Novo Fluxo de Transacao
|
|
|
|
1. Criar query em `src/queries.js`
|
|
2. Atualizar `serialize()` para incluir novo fluxo
|
|
3. Atualizar `buildHTML()` para exibir dados
|
|
|
|
## Decisoes de Arquitetura
|
|
|
|
| Decisao | Justificativa |
|
|
|---------|---------------|
|
|
| Monolito | Simplicidade para equipe pequena |
|
|
| SSR | Sem necessidade de SPA, SEO nao relevante |
|
|
| SQLite para auth | Independencia do RDS, portabilidade |
|
|
| Vanilla JS | Sem build step, menor complexidade |
|
|
| better-sqlite3 | Sync API mais simples para auth |
|
|
| mysql2 | Pool de conexoes async para RDS |
|