Fase 03 — Product Delivery
Aguardando HITLs #7-#10 Architect + Backend + Frontend + QA

Fase 03 — Product Delivery

Arquitetura, implementação backend (API + persistência), frontend (UI + integração) e quality gate.

68
Arquivos criados
35
Endpoints API
12
Tabelas SQLite
12
Páginas React

Arquitetura

Stack Tecnológica

CamadaTecnologiaVersãoPapel
BackendFastify5.0Servidor HTTP de alta performance
TypeScript5.5Linguagem base (strict mode)
Zod3.23Validação de inputs e schemas
better-sqlite3Banco SQLite síncrono
jsonwebtoken + bcryptjsAuth JWT
FrontendReact18.3UI library
TypeScript5.6Tipagem segura
React Router6.26Navegação SPA
Tailwind CSS3.4Estilização utility-first
Vite5.4Build tool + HMR
Lucide ReactÍcones SVG
BancoSQLite3database-emps.sqlite (WAL mode)

Bounded Contexts (Domain-Driven Design)

6 Bounded Contexts em monólito modular Fastify. Separação lógica por módulos com JWT compartilhado PF/PJ.

classDiagram class IdentityPJ { +AuthPJ (switch PF-PJ) +RBAC Middleware +JWT shared com PF POST /auth/pj/switch GET /auth/pj/me } class CompanyMgmt { +Company (aggregate root) +TeamMember +CNPJ, NaturezaJuridica POST /companies GET /companies/me PATCH /companies/me } class BankingPJ { +PJAccount (aggregate root) +PJTransaction +Money, Category GET /pj/accounts/balance POST /pj/accounts/transfer-pf } class PixPJ { +PJPixKey (aggregate root) +PixTransfer +PixKeyType, RateLimit POST /pj/pix/transfer CRUD /pj/pix/keys } class Billing { +Invoice (aggregate root) +Barcode, PixQRCode +InvoiceStatus POST /pj/invoices GET /pj/invoices } class CorporateCards { +CorporateCard (aggregate root) +CardPurchase, CardInvoice +CardLimit CRUD /pj/corporate-cards GET /pj/corporate-cards/:id/invoice } IdentityPJ --> CompanyMgmt : PJ context IdentityPJ --> BankingPJ : User authenticated CompanyMgmt --> BankingPJ : Company owns Account PixPJ --> BankingPJ : debit/credit Billing --> BankingPJ : credit on payment CorporateCards --> BankingPJ : debit on purchase

Diagramas de Sequência

Switch PF → PJ — Autenticação Compartilhada

sequenceDiagram participant U as Usuário (Browser) participant F as Frontend (React) participant A as API Emps (Fastify :3334) participant DB as SQLite (database-emps) Note over U,DB: Usuário já logado no Bank PF U->>F: Clica "Mudar para PJ" F->>A: POST /api/auth/pj/switch Note over A: Header: Authorization Bearer (JWT do PF) A->>A: Valida JWT (shared secret com PF) A->>DB: SELECT company WHERE owner_user_id = ? DB-->>A: company { id, cnpj, razao_social } A->>DB: SELECT team_member WHERE user_id = ? AND company_id = ? DB-->>A: { role: "admin" } A->>A: Gera contexto PJ (companyId + role) A-->>F: { company, role, pjAccount } F->>F: Ativa modo PJ no ProfileSwitcher F-->>U: Dashboard PJ carregado

Pix PJ — Transferência Empresarial

sequenceDiagram participant U as Usuário (Browser) participant F as Frontend (React) participant A as API Emps (Fastify) participant DB as SQLite U->>F: Informa chave Pix destino F->>A: GET /api/pj/pix/lookup?key=... A->>DB: SELECT pix_key WHERE key_value = ? A-->>F: { name, keyType } F-->>U: Exibe destinatário U->>F: Informa valor (ex: R$ 2.000) F->>A: POST /api/pj/pix/transfer Note over A: Middleware: JWT + requireRole(financial) A->>A: Verificar rate limit (20/hora) A->>DB: SELECT COUNT pj_pix_rate_limit (ultima hora) DB-->>A: count = 5 (OK) A->>A: Verificar saldo PJ A->>DB: SELECT balance FROM pj_accounts DB-->>A: balance = 850000 (R$ 8.500) Note over A,DB: Transação atômica (SQLite) A->>DB: BEGIN TRANSACTION A->>DB: UPDATE pj_accounts SET balance -= 200000 A->>DB: INSERT pj_transactions (débito, category: pix_out) A->>DB: INSERT pj_pix_rate_limit A->>DB: INSERT pj_audit_logs (action: pix_transfer) A->>DB: COMMIT A-->>F: { transactionId, status: "completed", balanceAfter } F-->>U: Comprovante de transferência PJ

Emissão de Boleto de Cobrança

sequenceDiagram participant U as Usuário (Browser) participant F as Frontend (React) participant A as API Emps (Fastify) participant DB as SQLite U->>F: Preenche dados da cobrança Note over F: customer_name, amount, due_date, type F->>A: POST /api/pj/invoices Note over A: Middleware: JWT + requireRole(financial) A->>A: Validar dados (Zod schema) A->>A: Gerar barcode FEBRABAN (mock) A->>A: Gerar Pix QR Code (copia-e-cola) A->>DB: INSERT invoices (status: pending) DB-->>A: { invoiceId } A->>DB: INSERT pj_notifications (nova cobrança criada) A-->>F: { id, barcode, pixQrcode, status: "pending" } F-->>U: Preview do boleto + QR Code Pix

Dashboard PJ — Carregamento Inicial

sequenceDiagram participant U as Usuário (Browser) participant F as Frontend (React) participant A as API Emps (Fastify) participant DB as SQLite U->>F: Acessa /pj/dashboard F->>F: Verifica JWT + contexto PJ par Chamadas paralelas F->>A: GET /api/pj/dashboard A->>DB: SELECT balance FROM pj_accounts A->>DB: SELECT SUM(amount) GROUP BY direction (cash flow) A->>DB: SELECT COUNT invoices BY status (cobranças) A-->>F: { balance, cashFlow, invoiceSummary } and F->>A: GET /api/pj/transactions?limit=5 A->>DB: SELECT * FROM pj_transactions ORDER BY created_at DESC A-->>F: { transactions: [...] } and F->>A: GET /api/pj/notifications/unread-count A->>DB: SELECT COUNT(*) WHERE is_read = 0 A-->>F: { count: 7 } end F->>F: Renderiza dashboard PJ completo F-->>U: Saldo + Cash Flow + Cobranças + Transações + Notificações

Architectural Decision Records (ADRs)

ADR-001Accepted
SQLite como banco de dados PJ separado
Decisão: Usar database-emps.sqlite separado do database.sqlite (PF), no mesmo servidor, com WAL mode habilitado.
Positivo: Isolamento de dados PF/PJ, backup independente, zero infra adicional, consistente com ecossistema ECP.
Negativo: SQLite single-writer pode causar contenção em escala. Aceitável para MVP (500 empresas).
ADR-002Accepted
JWT compartilhado entre PF e PJ
Decisão: Compartilhar JWT_SECRET entre ecp-digital-bank e ecp-digital-bank-emps. O auth-pj module valida tokens do PF e adiciona contexto PJ (companyId, role).
Positivo: SSO nativo, zero fricção no toggle PF↔PJ, sem novo login.
Negativo: Compromisso de uma chave compromete ambos. Aceitável para MVP; evoluir para auth service em produção.
ADR-003Accepted
RBAC com 3 perfis hierárquicos
Decisão: Admin > Financial > Viewer. Middleware requireRole() valida hierarquia por rota. Toda ação registra userId do operador.
Positivo: Granularidade suficiente para MVP, auditoria completa, simples de entender.
Negativo: Sem permissões customizáveis por recurso. Suficiente para 3 perfis; expandir se necessário.
ADR-004Accepted
Boleto com barcode mock FEBRABAN
Decisão: Gerar barcode e linha digitável com estrutura válida mas sem registro real em CIP (registradora). Mock para MVP.
Positivo: Permite desenvolvimento completo do fluxo de cobrança sem dependência externa.
Negativo: Boletos não são pagáveis em outros bancos. Integração real necessária para produção.
ADR-005Accepted
Valores monetários em centavos (integer)
Decisão: Todo valor financeiro armazenado como INTEGER em centavos. Frontend converte para exibição. Utilities money.ts para conversão.
Positivo: Zero erros de arredondamento, precisão absoluta, padrão da indústria fintech.
Negativo: Requer conversão em toda exibição. Custo mínimo vs. benefício enorme.

Modelo de Dados (12 tabelas + 22 índices)

companies
Cadastro de empresas (MEI, EI, EIRELI, LTDA, SLU)
id, owner_user_id, cnpj, razao_social, nome_fantasia, natureza_juridica, endereco, status, created_at, updated_at, deleted_at
pj_accounts
Contas PJ com saldo em centavos
id, company_id, agency(0001), number, balance, daily_transfer_limit, status
team_members
Multi-usuários com RBAC
id, company_id, user_id, role(admin|financial|viewer), status(active|invited|removed)
pj_transactions
Transações PJ com categorização
id, account_id, operator_id, type, category, amount, balance_after, direction, reference_id(idempotency)
pj_pix_keys
Chaves Pix PJ (máx 20)
id, company_id, account_id, type(cnpj|email|phone|random), value, status
invoices
Boletos emitidos (cobranças)
id, company_id, customer_name, amount, due_date, barcode, pix_qrcode, status(pending|paid|overdue|cancelled), type(single|installment|recurring)
corporate_cards
Cartões corporativos virtuais
id, company_id, holder_id, last4, limit_cents, used_cents, due_day, status
corporate_card_purchases
Compras no cartão corporativo
id, card_id, merchant_name, merchant_category, amount, status
corporate_invoices
Faturas do cartão
id, card_id, reference_month, total_cents, due_date, status(open|closed|paid|overdue)
pj_notifications
Notificações da empresa
id, company_id, user_id, title, body, type, is_read
pj_pix_rate_limit
Rate limiting Pix (20/hora)
id, account_id, window_start, transfer_count
pj_audit_logs
Audit trail completo
id, company_id, user_id, action, resource, resource_id, metadata, ip_address

Diagrama Entidade-Relacionamento

12 tabelas, 22 índices. SQLite3 com WAL mode e foreign keys habilitadas. Valores monetários em centavos (INTEGER).

erDiagram companies { TEXT id PK TEXT owner_user_id FK TEXT cnpj UK TEXT razao_social TEXT nome_fantasia TEXT natureza_juridica TEXT endereco TEXT status TEXT created_at } pj_accounts { TEXT id PK TEXT company_id FK "UK" TEXT agency TEXT number UK INTEGER balance INTEGER daily_transfer_limit TEXT status } team_members { TEXT id PK TEXT company_id FK TEXT user_id FK TEXT role "admin|financial|viewer" TEXT status "active|invited|removed" } pj_transactions { TEXT id PK TEXT account_id FK TEXT operator_id FK TEXT type TEXT category INTEGER amount INTEGER balance_after TEXT direction "in|out" TEXT reference_id UK } pj_pix_keys { TEXT id PK TEXT company_id FK TEXT account_id FK TEXT type "cnpj|email|phone|random" TEXT value UK TEXT status } invoices { TEXT id PK TEXT company_id FK TEXT customer_name INTEGER amount TEXT due_date TEXT barcode TEXT pix_qrcode TEXT status "pending|paid|overdue|cancelled" TEXT type "single|installment|recurring" } corporate_cards { TEXT id PK TEXT company_id FK TEXT holder_id FK TEXT last4 INTEGER limit_cents INTEGER used_cents INTEGER due_day TEXT status } corporate_card_purchases { TEXT id PK TEXT card_id FK TEXT merchant_name TEXT merchant_category INTEGER amount TEXT status } corporate_invoices { TEXT id PK TEXT card_id FK TEXT reference_month INTEGER total_cents TEXT due_date TEXT status "open|closed|paid|overdue" } pj_notifications { TEXT id PK TEXT company_id FK TEXT user_id FK TEXT title TEXT body TEXT type INTEGER is_read } pj_audit_logs { TEXT id PK TEXT company_id FK TEXT user_id FK TEXT action TEXT resource TEXT resource_id TEXT metadata TEXT ip_address } companies ||--|| pj_accounts : "has" companies ||--o{ team_members : "has" companies ||--o{ pj_pix_keys : "registers" companies ||--o{ invoices : "issues" companies ||--o{ corporate_cards : "owns" companies ||--o{ pj_notifications : "receives" companies ||--o{ pj_audit_logs : "logs" pj_accounts ||--o{ pj_transactions : "records" corporate_cards ||--o{ corporate_card_purchases : "has" corporate_cards ||--o{ corporate_invoices : "generates"

Módulos da API (35 endpoints)

auth-pj
Proxy auth + switch PF→PJ + RBAC
2 endpoints: POST /auth/pj/switch, GET /auth/pj/me
auth-pj.routes.ts · auth-pj.service.ts · auth-pj.schema.ts
companies
Cadastro e gestão de empresas
3 endpoints: POST, GET /me, PATCH /me
companies.routes.ts · companies.service.ts · companies.schema.ts
pj-accounts
Conta PJ + saldo + transfer PF↔PJ
3 endpoints: GET /me, GET /balance, POST /transfer-pf
pj-accounts.routes.ts · pj-accounts.service.ts · pj-accounts.schema.ts
pj-pix
Pix empresarial completo
6 endpoints: transfer, keys (CRUD), qrcode, lookup
pj-pix.routes.ts · pj-pix.service.ts · pj-pix.schema.ts
invoices
Boletos de cobrança
6 endpoints: create, list, detail, cancel, resend, summary
invoices.routes.ts · invoices.service.ts · invoices.schema.ts
pj-transactions
Extrato PJ + categorização
3 endpoints: list (cursor), detail, summary
pj-transactions.routes.ts · pj-transactions.service.ts · pj-transactions.schema.ts
corporate-cards
Cartões corporativos + faturas
7 endpoints: CRUD, limit, block, invoice, purchases
corporate-cards.routes.ts · corporate-cards.service.ts · corporate-cards.schema.ts
team
Multi-usuários + convites + RBAC
4 endpoints: invite, list, change role, remove
team.routes.ts · team.service.ts · team.schema.ts
pj-notifications
Notificações da empresa
4 endpoints: list, unread-count, mark-read, read-all
pj-notifications.routes.ts · pj-notifications.service.ts · pj-notifications.schema.ts
pj-dashboard
Dados agregados do dashboard
1 endpoint: GET /pj/dashboard
pj-dashboard.routes.ts · pj-dashboard.service.ts

Páginas React (12 telas)

/pj/dashboard
Dashboard PJ
Saldo, cash flow, cobranças, ações rápidas
/pj/extrato
Extrato PJ
Transações com categorias + filtros
/pj/pix/enviar
Pix Enviar
Wizard 4 passos + limites
/pj/pix/receber
Pix Receber
QR Code + copia e cola
/pj/pix/chaves
Pix Chaves
CRUD de chaves (máx 20)
/pj/cobrancas/nova
Nova Cobrança
Form 2 etapas + preview boleto
/pj/cobrancas
Lista de Cobranças
Tabela + badges + filtros
/pj/cobrancas/:id
Detalhe Cobrança
Timeline + barcode + ações
/pj/cartoes
Cartões Corporativos
Visual card + limit bar
/pj/cartoes/:id/fatura
Fatura do Cartão
Compras + total + vencimento
/pj/time
Gestão do Time
Membros + convite + roles
/pj/empresa
Dados da Empresa
Cadastro + edição (admin)

Estrutura de Pastas

ecp-digital-emps/ ├── server/ │ ├── src/ │ │ ├── app.ts ← Fastify + plugins + routes │ │ ├── server.ts ← Entry point (port 3334) │ │ ├── database/ │ │ │ ├── connection.ts ← SQLite3 + WAL mode │ │ │ ├── migrations/ ← 001-initial.sql (12 tabelas) │ │ │ └── seed.ts ← Dados demo AB Design Studio │ │ ├── modules/ ← 10 módulos (30 arquivos) │ │ │ ├── auth-pj/ companies/ pj-accounts/ │ │ │ ├── pj-pix/ invoices/ pj-transactions/ │ │ │ ├── corporate-cards/ team/ │ │ │ ├── pj-notifications/ pj-dashboard/ │ │ ├── shared/ │ │ │ ├── errors/ middleware/ utils/ │ │ └── types/ │ └── package.json ├── web/ │ ├── src/ │ │ ├── App.tsx ← Layout + Router │ │ ├── routes/ ← 12 páginas PJ │ │ ├── components/ │ │ │ ├── ui/ ← Button, Card, Input, Modal, Badge │ │ │ └── layout/ ← SidebarPJ, HeaderPJ, ProfileSwitcher │ │ ├── hooks/ services/ lib/ styles/ │ └── package.json ├── package.json ← Root (npm run dev) └── .env.example
HITLs #7 a #10 — Decisão de Aprovação da Fase 03
#7: Arquitetura sólida? Contratos prontos? • #8: APIs corretas? Persistência validada? • #9: Front integrado? Design fiel ao design_spec? • #10: Qualidade aprovada? Pronto para operar?