Solução para gerenciar uma conta de crédito com buckets (principal, juros, tarifas, limite disponível) via CLI.
A solução utiliza Clean Architecture com separação em camadas:
src/
├── index.js # Ponto de entrada (CLI)
├── application/
│ └── bucket-service.js # Orquestra operações
├── domain/
│ └── bucket-account.js # Lógica de negócio
└── infrastructure/
└── stdin-reader.js # Leitura de stdin
tests/
└── unit.test.js # Testes unitários
| Camada | Arquivo | O que faz |
|---|---|---|
| Infrastructure | stdin-reader.js |
Ler entrada de stdin |
| Domain | bucket-account.js |
Lógica financeira pura (sem dependências) |
| Application | bucket-service.js |
Orquestrar chamadas ao domain |
| Presentation | index.js |
CLI (coordena tudo) |
Benefício: Domain é isolado e testável independentemente.
- Cada camada tem responsabilidade clara
- Mudanças em I/O não afetam lógica de negócio
- Padrão moderno do JavaScript
- Configurado em
package.jsoncom"type": "module"
- Apenas Node.js nativo (módulo
readline) - Zero vulnerabilidades npm
- Deploy simples
- Cada linha de entrada cria um novo
BucketService - Não há vazamento de estado entre simulações
- Todos os valores:
Math.round(valor * 100) / 100 - Evita erros de ponto flutuante
- Ordem:
fees→interest→principal - Usa
Math.min(remaining, bucket)para segurança available-limit = creditLimit - principal(só principal reduz)
- Node.js v14 ou superior
npm install # Opcional (sem dependências npm)Modo 1: Interativo
node src/index.js
# Cole a linha JSON, pressione Enter 2x (linha vazia termina)Modo 2: Com pipe (mais simples)
echo '[{"type": "set-limit", "amount": 1000.00}, {"type": "purchase", "amount": 200.00}]
' | node src/index.jsModo 3: Com arquivo
node src/index.js < input.txtExemplo Completo
echo '[{"type": "set-limit", "amount": 1000.00}, {"type": "purchase", "amount": 500.00}, {"type": "fee", "amount": 50.00}, {"type": "interest", "amount": 100.00}, {"type": "payment", "amount": 100.00}, {"type": "payment", "amount": 200.00}]
' | node src/index.jsSaída:
[{"principal":0,"interest":0,"fees":0,"available-limit":1000},{"principal":500,"interest":0,"fees":0,"available-limit":500},{"principal":500,"interest":0,"fees":50,"available-limit":500},{"principal":500,"interest":100,"fees":50,"available-limit":500},{"principal":500,"interest":50,"fees":0,"available-limit":500},{"principal":350,"interest":0,"fees":0,"available-limit":650}]node tests/unit.test.jsResultado esperado:
Teste 1: set-limit reseta buckets
✓ PASSOU
Teste 2: purchase aumenta principal
✓ PASSOU
Teste 3: fee aumenta fees
✓ PASSOU
Teste 4: interest aumenta interest
✓ PASSOU
Teste 5: payment aplica em ordem correta
✓ PASSOU
Teste 6: Exemplo completo do desafio
Após set-limit: ✓
Após purchase 200: ✓
Após purchase 300: ✓
Após payment 250: ✓
✓ Todos os testes completados!
Todos os 6 testes passam ✅
- Domain (
BucketAccount) é puro e testável isoladamente - Infrastructure (
StdinReader) encapsula I/O - Application (
BucketService) orquestra operações - Cada componente tem responsabilidade única
- Apenas módulos nativos do Node.js
- Sem vulnerabilidades npm
- Rápido e leve
- 6 testes unitários, todos passando ✅
- Lógica de negócio é 100% testável
- Sem side effects
- Pagamento em cascata: fees → interest → principal
available-limit = creditLimit - principal(fees/interest não afetam)- Arredondamento a 2 casas decimais sem erros
Math.min()previne overpayment
- Nomes claros (
payment,addFee,getAvailableLimit) - Sem comentários desnecessários
- Funções pequenas e focadas
- Fácil de entender e modificar
- Cada linha é independente
- Não há vazamento entre simulações
- Previsível e determinístico
- Valida tipos de operação
- Try-catch para erros de JSON
- Saídas claras em caso de erro
| Operação | Campo | Efeito |
|---|---|---|
set-limit |
amount |
Define limite, zera buckets |
purchase |
amount |
Aumenta principal, reduz available-limit |
fee |
amount |
Aumenta fees |
interest |
amount |
Aumenta interest |
payment |
amount |
Paga (fees → interest → principal) |
Saída de cada operação:
{
"principal": <número>,
"interest": <número>,
"fees": <número>,
"available-limit": <creditLimit - principal>
}-
✅ Implementação correta de todas as operações
-
✅ Estado isolado entre linhas
-
✅ Arredondamento correto (2 casas decimais)
-
✅ Arquitetura limpa (Clean Architecture)
-
✅ Sem dependências externas
-
✅ 6/6 testes passando
-
✅ Código limpo e bem estruturado
-
Desenvolvido e estruturado por: Lucas Sassi de Souza | Estudante de Eng. de Software UEPG