Crear un archivo .env en la raíz del proyecto con el siguiente contenido (de referencia .env.example):
Nota: Se puede hacer directammente: $ cp .env.example .env
ENV=dev
PORT=3000
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=user
DB_PASSWORD=password
DB_DATABASE=wallet_dbInstalar dependencias usando:
npm installEl proyecto utiliza PostgreSQL. Para mayor simpleza, cuenta con un archivo docker-compose.yml. Asegurarse de tener Docker instalado y ejecutándose, luego levantar el entorno de desarrollo usando el comando Make:
make devNOTA: El comando levanta el contenedor de Docker (up-docker) y luego iniciar la aplicación (npm run dev)
Para ejecutar los tests junto al reporte de cobertura, usar el comando:
make testEste comando ejecuta npm run test:cov por detrás
La especificación completa de la API se encuentra disponible en formato OpenAPI 3.0 en el archivo:
./docs/swagger.yaml
La aplicación está construida siguiendo los principios de Clean Architecture, dividiendo el código en capas:
- Domain (Dominio): Contiene el corazón de la aplicación. Modelos de dominio ricos (
User,Transaction,LedgerEntry) que encapsulan la lógica de negocio, validaciones y cambios de estado. No tiene dependencias externas - Application (Casos de Uso): Contiene las reglas de negocio de la aplicación. Orquesta la interacción entre las entidades de dominio y los repositorios
- Infrastructure (Infraestructura): Implementa las interfaces de las capas superiores, se encarga de la integración con libs externas
- Idempotencia: Cada transacción de transferencia requiere un
idempotencyKeyúnico. Para simpleza del challenge se guarda en la base de datos, pero podría moverse a un Redis, haciendo uso de los TTLs. - Auditoría y Trazabilidad (Ledger): Para auditoria de los movientos, por cada transferecia de fondos se genera una doble entrada en el ledger (only-append): resta en el emisor y suma en el receptor.
- Transacciones ACID: Toda la transferencia se envuelve en una transacción de la base de datos. Si algo se rompe en el medio del proceso, se hace Rollback automático.
- Separación del Repositorio: Actualmente,
TypeOrmWalletRepositoryfunciona como un repositorio gigante o Facade que maneja operaciones de Usuarios, Transacciones y Ledger al mismo tiempo. Lo ideal sería splitearlo enUserRepository,TransactionRepositoryyLedgerRepository.
- Procesamiento Asíncrono (Colas): Hoy en día la transferencia se procesa de manera sincrónica en el hilo principal. Si el sistema llegara a tener picos de millones de transacciones, mantener las conexiones abiertas a la base por cada Request podría bloquear el sistema. El next step sería encolar la intención de pago (ej. RabbitMQ, SQS, o Kafka) y tener workers que consuman la cola y ejecuten la operación correspondiente.
- Base de Datos Dedicada al Ledger: A medida que el sistema escale, la tabla de
LedgerEntrycrece de forma exponencial frente a los Usuarios