Aplicação de linha de comando (CLI) para gerenciamento de bibliotecas, desenvolvida em Node.js e TypeScript, aplicando princípios de Arquitetura Hexagonal e Clean Code.
- Descrição do Projeto
- Objetivo
- Tecnologias e Bibliotecas Principais
- Arquitetura do Projeto
- Estrutura de Pastas
- Design Patterns e Decisões Técnicas
- Funcionalidades Implementadas
- Requisitos para Execução
- Configuração do Banco de Dados
- Instalação
- Execução
- Exemplos de Utilização
- Dificuldades Encontradas
- Futuras Implementações
- Link do Kanban
O Biblioteca Tech é uma aplicação CLI (Command Line Interface) desenvolvida em Node.js e TypeScript, voltada para o gerenciamento eficiente de bibliotecas. O sistema permite o controle completo de autores, livros, clientes e o processamento de empréstimos e devoluções, garantindo a integridade dos dados através de uma arquitetura organizada em camadas.
Desenvolver um software resiliente que isole a lógica de negócio dos detalhes de infraestrutura, utilizando padrões de projeto sólidos para facilitar a manutenção, a testabilidade e a escalabilidade da aplicação.
| Categoria | Tecnologia | Descrição |
|---|---|---|
| Linguagem | TypeScript | Tipagem estática sobre JavaScript |
| Runtime | Node.js | Ambiente de execução |
| Banco de Dados | PostgreSQL | Banco relacional |
| Containerização | Docker / Docker Compose | Provisionamento do banco de dados |
| Driver de Banco | pg |
Comunicação direta com o PostgreSQL via SQL |
| Interface (CLI) | inquirer |
Menus interativos no terminal |
| Estilização | chalk |
Cores e formatação visual no terminal |
| Ambiente | dotenv |
Gerenciamento de variáveis de ambiente |
| Execução em Dev | tsx |
Execução direta de TypeScript sem build prévio |
O projeto adota princípios da Arquitetura Hexagonal (Ports & Adapters), com o objetivo de manter a lógica de negócio (domínio) independente de detalhes de infraestrutura, como banco de dados ou interface de terminal.
O fluxo de dependências segue uma única direção:
CLI (infra) → Use Case (application) → Repository Interface (domain) → Postgres Repository (infra)
domainé o núcleo da aplicação. Contém as entidades (Author,Book,Customer,Loan), suas regras de validação e as interfaces (contratos) dos repositórios. Não depende de nenhuma outra camada.applicationorquestra os casos de uso do sistema (ex:CreateAuthorUseCase), utilizando apenas as interfaces definidas no domínio — nunca uma implementação concreta.infracontém os adaptadores: a interface de linha de comando (cli), as implementações concretas dos repositórios com PostgreSQL (database) e o sistema de logs (logger).mainé o ponto de entrada da aplicação, responsável por instanciar as dependências (injeção de dependência manual) e conectar as camadas.
Essa separação garante baixo acoplamento: seria possível, por exemplo, trocar o PostgreSQL por outro banco, ou o terminal por uma API REST, sem alterar uma linha sequer das regras de negócio.
bookstore-manager-cli/
├── init/
│ └── init.sql # Script de criação das tabelas do banco
├── src/
│ ├── application/
│ │ └── use-cases/ # Orquestração das regras de negócio
│ ├── domain/
│ │ ├── dto/ # Objetos de transferência de dados
│ │ ├── entities/ # Regras de negócio puras (Modelos)
│ │ ├── errors/ # Tratamento de exceções (Domain/System)
│ │ └── repositories/ # Interfaces dos contratos
│ ├── infra/
│ │ ├── cli/ # Adaptadores de entrada (Menus e Relatórios)
│ │ │ ├──reports/ # Menus dos relatório (Empréstimos e Acervo)
│ │ │
│ │ ├── database/ # Adaptadores de saída (Repositórios SQL)
│ │ └── logger/ # Camada de observabilidade
│ └── main/
│ └── main.ts # Ponto de entrada e injeção de dependências
├── .env.example # Modelo de variáveis de ambiente
├── docker-compose.yml # Provisionamento do banco de dados PostgreSQL
├── package.json
├── tsconfig.json
└── README.md
- Design Patterns e Decisões Técnicas
-
Princípios SOLID: aplicados ao longo de todo o domínio e da camada de aplicação. As entidades e repositórios seguem o Princípio da Responsabilidade Única (SRP), enquanto os casos de uso dependem exclusivamente de interfaces, nunca de implementações concretas (Princípio da Inversão de Dependência – DIP), permitindo que a lógica de negócio permaneça isolada dos detalhes de infraestrutura, como o PostgreSQL.
-
Repository Pattern: cada entidade possui uma interface de repositório no domínio (
AuthorRepository,BookRepository,CustomerRepository,LoanRepository), implementada de forma concreta na camada de infraestrutura, isolando completamente as queries SQL das regras de negócio. -
Adapter: as classes
Postgres*Repositoryfuncionam como adappters, traduzindo a API da bibliotecapg(queries SQL,client.query(),rows) para o formato esperado pelo domínio (ex.:save(author: Author): Promise<Author>). -
Factory Method: o método estático
SystemException.fromUnknown(cause, code)centraliza e padroniza a criação de exceções de sistema a partir de erros desconhecidos, evitando repetição da lógica de tratamento nos repositórios. -
Injeção de Dependência (Dependency Injection): utilizada para desacoplar as camadas, facilitando testes e a substituição de implementações (por exemplo, trocar
PostgresBookRepositorypor um mock em testes automatizados). Toda a composição das dependências ocorre de forma centralizada nomain.ts. -
Singleton: aplicado na conexão com o banco de dados (
PgConnection), garantindo que o pool de conexões seja reutilizado em toda a aplicação, evitando desperdício de recursos. -
Tratamento de Exceções Customizado: implementação de uma hierarquia de exceções (
BaseException,DomainException,SystemException), permitindo diferenciar falhas de regra de negócio (por exemplo, "estoque insuficiente") de falhas técnicas (como perda de conexão com o banco), com tratamento centralizado nomain.ts. -
Atomicidade: uso de transações SQL (
BEGIN,COMMITeROLLBACK) em operações críticas, como empréstimos e devoluções, garantindo que o estoque e os registros de empréstimo sejam atualizados de forma consistente.
- Gestão de Autores: cadastro, listagem, consulta detalhada (com livros vinculados), atualização e remoção.
- Gestão de Livros: cadastro (vinculado obrigatoriamente a um autor), listagem, consulta, atualização e remoção.
- Gestão de Clientes: cadastro, listagem, consulta, atualização e remoção.
- Empréstimos: registro de saída de livros com validação de disponibilidade em estoque.
- Devoluções: registro de devolução com atualização automática da quantidade disponível.
- Relatórios:
- Livros disponíveis;
- Livros emprestados (empréstimos ativos);
- Livros por autor;
- Livros mais populares (mais emprestados);
- Livros nunca emprestados;
- Autores com mais livros cadastrados;
- Clientes com empréstimos ativos;
- Histórico de empréstimos por cliente.
- Exclusão lógica (soft delete): registros removidos permanecem no banco marcados como inativos, preservando o histórico de empréstimos.
- Node.js v18 ou superior
- Docker e Docker Compose (recomendado), ou uma instância local do PostgreSQL 16+
O banco de dados é provisionado via Docker Compose, utilizando a imagem postgres:16-alpine. O script init/init.sql é executado automaticamente na primeira inicialização do container, criando toda a estrutura de tabelas (authors, books, customers, loans) e seus relacionamentos.
- Copie o arquivo de variáveis de ambiente:
cp .env.example .env- Preencha o
.envcom as credenciais desejadas:
DB_USER=seu_usuario
DB_PASSWORD=sua_senha
DB_NAME=biblioteca_tech
DB_HOST=localhost
DB_PORT=5433O
docker-compose.ymlexpõe o PostgreSQL na porta5433do host (mapeada para a5432do container), evitando conflito com instâncias locais do Postgres.
- Clone o repositório:
git clone https://github.com/daniel-dealmeida-dev/bookstore-manager-cli.git
cd bookstore-manager-cli- Instale as dependências:
npm install- Suba o banco de dados com Docker Compose (o script
init/init.sqlé executado automaticamente na criação do container):
docker-compose up -dCaso prefira não usar Docker, é possível apontar o
.envpara uma instância própria do PostgreSQL e executar o script manualmente:psql -U seu_usuario -d biblioteca_tech -f init/init.sql
Para iniciar a aplicação em modo de desenvolvimento:
npm run devPara gerar a build de produção e executá-la:
npm run build
npm startAo iniciar a aplicação, o menu principal é apresentado:
--- BIBLIOTECA SYSTEM ---
? Escolha uma opção: (Use as setas)
❯ Gerenciar Autores
Gerenciar Livros
Gerenciar Clientes
Gerenciar Relatórios
Realizar Empréstimo
Registrar Devolução
Sair
Exemplo — cadastrando um autor:
--- BIBLIOTECA SYSTEM: Gerenciar Autores ---
? Escolha uma opção: Cadastrar autores
? Nome do Autor: Machado de Assis
? Nacionalidade: Brasileira
? Descrição do autor: Escritor, considerado um dos maiores nomes da literatura brasileira.
✔ Autor salvo com sucesso!
Exemplo — realizando um empréstimo:
? Selecione o livro: Dom Casmurro
? Selecione o cliente: João Silva
✔ Empréstimo registrado com sucesso!
Exemplo — relatório de livros disponíveis:
┌─────────┬────────────────────┬────────────────────┐
│ (index) │ Título │ Qtd. Disponível │
├─────────┼────────────────────┼────────────────────┤
│ 0 │ 'Dom Casmurro' │ 2 │
│ 1 │ 'O Cortiço' │ 5 │
└─────────┴────────────────────┴────────────────────┘
- Padronização de Erros: o maior desafio foi criar um fluxo de tratamento de erros que fosse ao mesmo tempo técnico e amigável ao usuário, solucionado através de uma hierarquia de classes de exceção customizadas (
DomainExceptionxSystemException). - Gestão de Recursos: garantir a liberação segura das conexões do pool (
client.release()) em todos os cenários possíveis — inclusive em caminhos de erro — foi crítico para a estabilidade da aplicação sob uso prolongado. - Atomicidade em Operações Compostas: operações como empréstimo e devolução envolvem múltiplas escritas (atualizar estoque e registrar/atualizar o empréstimo). Garantir que ambas ocorressem de forma atômica exigiu o uso disciplinado de transações SQL com
ROLLBACKem caso de falha.
- Cobertura de testes automatizados (unitários e de integração) para as camadas de domínio e aplicação.
- Autenticação e controle de acesso (perfis de bibliotecário e cliente).
- Notificação de empréstimos em atraso.
- Paginação nas listagens, para melhor performance com grandes volumes de dados.
- Exportação de relatórios em CSV/PDF.
- Migração de scripts SQL manuais para uma ferramenta de migrations.
- Melhor tratamento de erros.