A full-stack web application developed as part of the RTB House technical assessment.
Backend
- NestJS with TypeScript
- Repository pattern with dependency injection
- JSON as persistence layer
- class-validator for request validation
- Swagger for API documentation
Frontend
- React with TypeScript
- Vite
- React Query
- Recharts
Infrastructure
- Docker + Docker Compose
The backend follows a layered architecture inspired by clean architecture principles:
HTTP Request
↓
Controller — routes requests, no business logic
↓
Service — business rules and data aggregation
↓
Repository — data access abstraction
↓
JSON files — persistence layer (orders.json / sellers.json)
The repository layer is abstracted behind interfaces (IOrdersRepository, ISellersRepository). The service layer depends only on these interfaces — never on concrete implementations. This means the persistence layer can be swapped (e.g. JSON → PostgreSQL) without any changes to the service or controller layers.
// Service depends on the interface, not the implementation
@Inject('IOrdersRepository')
private readonly ordersRepository: IOrdersRepositoryrtb-house/
├── docker-compose.yml
├── README.md
├── backend/
│ ├── Dockerfile
│ └── src/
│ ├── main.ts
│ ├── app.module.ts
│ ├── common/
│ │ ├── enums/
│ │ │ └── order-sort.enum.ts
│ │ └── interfaces/
│ │ └── paginated-result.interface.ts
│ ├── orders/
│ │ ├── dto/
│ │ │ └── get-orders-query.dto.ts
│ │ ├── enums/
│ │ │ └── order-sort-by.enum.ts
│ │ ├── interfaces/
│ │ │ └── orders.interface.ts
│ │ ├── repositories/
│ │ │ ├── orders.repository.interface.ts
│ │ │ └── json-orders.repository.ts
│ │ ├── utils/
│ │ │ └── order.utils.ts
│ │ ├── orders.controller.ts
│ │ ├── orders.service.ts
│ │ └── orders.module.ts
│ ├── sellers/
│ │ ├── dto/
│ │ │ └── get-sellers-query.dto.ts
│ │ ├── enums/
│ │ │ └── seller-sort-by.enum.ts
│ │ ├── interfaces/
│ │ │ └── sellers.interface.ts
│ │ ├── repositories/
│ │ │ ├── sellers.repository.interface.ts
│ │ │ └── json-sellers.repository.ts
│ │ ├── sellers.controller.ts
│ │ ├── sellers.service.ts
│ │ └── sellers.module.ts
│ └── data/
│ ├── orders.json
│ └── sellers.json
└── frontend/
├── Dockerfile
└── src/
├── components/
│ ├── charts/
│ │ ├── chart.constants.ts
│ │ ├── charts.css
│ │ ├── SalesByCountryChart.tsx
│ │ └── SalesBySellerChart.tsx
│ ├── OrderFilters.tsx
│ ├── OrdersTable.tsx
│ ├── Pagination.tsx
│ └── SellerCards.tsx
├── hooks/
│ ├── useOrders.ts
│ └── useSellers.ts
├── pages/
│ ├── InfoPage.tsx
│ └── OrdersPage.tsx
├── services/
│ └── api.ts
├── types/
│ ├── order.types.ts
│ └── seller.types.ts
├── utils/
│ └── export.utils.ts
├── App.tsx
├── main.tsx
└── index.css
docker-compose up --build| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend | http://localhost:3000 |
| Swagger | http://localhost:3000/api/docs |
Backend
cd backend
npm install
npm run start:devFrontend
cd frontend
npm install
npm run dev- Orders table with dynamic filtering by seller, country, price range
- Server-side pagination and sorting on all columns
- Revenue charts by seller and by country
- Seller revenue cards with order count
- CSV export of filtered results
- Country flags with local currency formatting
- Order ID parsed to display creation date
- Dark/light theme toggle
- Responsive layout with horizontal scroll on mobile
- Swagger API documentation
Full interactive documentation available at:
http://localhost:3000/api/docs
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/orders |
List orders with optional filters |
| GET | /api/v1/orders/:id |
Get order by ID |
Query params for GET /api/v1/orders:
| Param | Type | Description |
|---|---|---|
| seller | number | Filter by seller ID |
| country | string | Filter by country code (BRA, ARG, MEX) |
| minPrice | number | Minimum price |
| maxPrice | number | Maximum price |
| sortBy | enum | orderId, product, seller, country, price, createdAt |
| order | enum | asc, desc |
| page | number | Page number (default: 1) |
| limit | number | Items per page (default: 10) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/sellers |
List sellers with optional filters |
| GET | /api/v1/sellers/:id |
Get seller by ID |
Query params for GET /api/v1/sellers:
| Param | Type | Description |
|---|---|---|
| name | string | Filter by seller name |
| sortBy | enum | id, name |
| order | enum | asc, desc |
| page | number | Page number (default: 1) |
| limit | number | Items per page (default: 10) |
- CORS configured for frontend origin only
- Helmet for HTTP security headers
ValidationPipewithwhitelist: true— strips undeclared fields from requestsforbidNonWhitelisted: true— rejects requests with unknown fieldstransform: true— automatic type coercion for query params
Why NestJS over Express? NestJS enforces a modular, layered architecture out of the box — controllers, services, and dependency injection are first-class citizens. This mirrors patterns from Spring Boot that I have experience with other projects, making the codebase predictable and easy to navigate for any backend developer.
Why Repository Pattern? Decouples business logic from data access. The service layer depends on interfaces, not implementations — this is the Dependency Inversion Principle (SOLID) applied in practice.
Why React Query?
Handles caching, loading and error states cleanly. The placeholderData option keeps previous results visible during refetch, preventing layout shifts when filters or sort change.
createdAt parsed at repository level
The orderId encodes the creation date (2019060001 → 2019-06). Parsing happens in the repository constructor so the field exists before any sorting or filtering — enabling sort by date without recalculating on every query.
João Henrique Monteiro Alves
This project was developed as part of the RTB House technical assessment.
- REST API with NestJS and TypeScript following clean architecture principles
- Repository pattern with dependency injection for persistence abstraction
- Dynamic filtering, pagination and sorting on all endpoints
- Currency formatting per country and order date parsing from order ID
- Swagger documentation at
/api/docs - Frontend with React, TypeScript, React Query and Recharts
- Revenue dashboards with charts by seller and country
- CSV export of filtered results
- Dark/light theme toggle with full responsiveness
- Docker + Docker Compose for containerization
- GitHub: https://github.com/joaohmalves
- LinkedIn: https://linkedin.com/in/joao-henrique-monteiro-alves
- Email: joao.hmalves@gmail.com