|
Some checks failed
CI/CD Pipeline / Backend - Build, Test & Push (push) Failing after 1m33s
CI/CD Pipeline / Frontend - Build, Test & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Blocked by required conditions
CI/CD Pipeline / Deployment Summary (push) Blocked by required conditions
CI/CD Pipeline / Discord Notification (Success) (push) Blocked by required conditions
CI/CD Pipeline / Discord Notification (Failure) (push) Blocked by required conditions
Fixed CSV rate upload to use the company name provided in the upload form instead of reading it from the CSV file's companyName column. This prevents "unknown" or incorrect company names from being used. ## Changes **Domain Layer** - Updated `CsvRateLoaderPort` interface to accept optional `companyNameOverride` parameter - Modified `CsvRateSearchService.loadAllRates()` to pass company name from config when loading rates **Infrastructure Layer** - Updated `CsvRateLoaderAdapter.loadRatesFromCsv()` to accept `companyNameOverride` parameter - Modified `mapToCsvRate()` to use override company name if provided, otherwise fallback to CSV column value - Added logging to show which company name is being used (from override or CSV) **Application Layer** - Updated CSV upload controller to pass `dto.companyName` to the loader ## Impact - When uploading a CSV file through the admin interface, the company name from the form is now correctly used - Existing CSV files with "unknown" in the companyName column will now show the correct company name from the database configuration - Backward compatible: if no override is provided, the CSV column value is still used 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| docs | ||
| load-tests | ||
| postman | ||
| src | ||
| test | ||
| .dockerignore | ||
| .env.example | ||
| .eslintrc.js | ||
| apps.zip | ||
| DATABASE-SCHEMA.md | ||
| docker-compose.yaml | ||
| Dockerfile | ||
| fix-domain-imports.js | ||
| fix-imports.js | ||
| nest-cli.json | ||
| package.json | ||
| README.md | ||
| test-csv-api.js | ||
| test-csv-api.sh | ||
| tsconfig.build.json | ||
| tsconfig.json | ||
| tsconfig.test.json | ||
Xpeditis Backend API
NestJS-based API for the Xpeditis maritime freight booking platform, built with Hexagonal Architecture.
🏗️ Architecture
This backend follows Hexagonal Architecture (Ports & Adapters pattern):
src/
├── domain/ # 🔵 Pure business logic (NO external dependencies)
│ ├── entities/ # Business entities
│ ├── value-objects/ # Value objects (Email, PortCode, etc.)
│ ├── services/ # Domain services
│ ├── ports/
│ │ ├── in/ # API Ports (use cases exposed by domain)
│ │ └── out/ # SPI Ports (interfaces required by domain)
│ └── exceptions/ # Business exceptions
│
├── application/ # 🟢 Controllers & DTOs
│ ├── controllers/ # REST controllers
│ ├── dto/ # Data Transfer Objects
│ ├── mappers/ # DTO ↔ Domain mappers
│ └── config/ # Application configuration
│
└── infrastructure/ # 🟡 External integrations
├── persistence/ # TypeORM repositories
├── cache/ # Redis cache adapter
├── carriers/ # Maersk, MSC, CMA CGM connectors
├── email/ # Email service adapter
├── storage/ # S3 storage adapter
└── config/ # Infrastructure configuration
Key Principles
- Domain is isolated: No imports of NestJS, TypeORM, or any framework in domain layer
- Dependencies point inward: Infrastructure → Application → Domain
- Testable: Domain can be tested without any framework
- Flexible: Change database, framework, or external services without touching domain
🚀 Quick Start
Prerequisites
- Node.js 20+
- PostgreSQL 15+
- Redis 7+
- Docker (optional, for local development)
Install Dependencies
npm install
Setup Environment
cp .env.example .env
# Edit .env with your configuration
Start Development Server
npm run dev
Server runs on: http://localhost:4000
API Documentation: http://localhost:4000/api/docs
📝 Available Scripts
Development
npm run dev- Start development server with hot reloadnpm run start- Start servernpm run start:debug- Start with debuggingnpm run build- Build for productionnpm run start:prod- Start production server
Testing
npm test- Run unit testsnpm run test:watch- Run tests in watch modenpm run test:cov- Run tests with coveragenpm run test:e2e- Run end-to-end testsnpm run test:debug- Debug tests
Code Quality
npm run lint- Lint codenpm run format- Format code with Prettier
Database
npm run migration:generate -- src/infrastructure/persistence/migrations/MigrationName- Generate migrationnpm run migration:run- Run migrationsnpm run migration:revert- Revert last migration
🔑 Environment Variables
See .env.example for all available variables.
Required:
DATABASE_HOST,DATABASE_PORT,DATABASE_USER,DATABASE_PASSWORD,DATABASE_NAMEREDIS_HOST,REDIS_PORT,REDIS_PASSWORDJWT_SECRET
Optional (for production):
- OAuth credentials (Google, Microsoft)
- Carrier API keys (Maersk, MSC, CMA CGM, etc.)
- AWS S3 credentials
- Email service credentials
- Sentry DSN
📚 API Documentation
Swagger/OpenAPI documentation is available at /api/docs when the server is running.
Endpoints:
Health
GET /api/v1/health- Health checkGET /api/v1/health/ready- Readiness checkGET /api/v1/health/live- Liveness check
(More endpoints will be added in Phase 1)
🧪 Testing
Unit Tests
Test domain logic without any external dependencies:
npm test
Example (domain/services/booking.service.spec.ts):
describe('BookingService', () => {
it('should create booking with valid rate quote', () => {
const service = new BookingService(mockRepository);
const result = service.createBooking(validInput);
expect(result.bookingNumber).toMatch(/^WCM-\d{4}-[A-Z0-9]{6}$/);
});
});
Integration Tests
Test infrastructure adapters with real dependencies:
npm run test:e2e
Coverage
npm run test:cov
Targets:
- Domain: 90%+
- Application: 80%+
- Infrastructure: 70%+
🏛️ Hexagonal Architecture Guidelines
✅ DO
-
Domain layer:
- Pure TypeScript classes
- Define interfaces (ports)
- Implement business logic
- Throw domain exceptions
-
Application layer:
- Import from
@domain/*only - Validate DTOs
- Map DTOs ↔ Domain entities
- Handle HTTP-specific concerns
- Import from
-
Infrastructure layer:
- Import from
@domain/*only - Implement port interfaces
- Handle framework-specific code
- Map ORM entities ↔ Domain entities
- Import from
❌ DON'T
- Import NestJS decorators in domain
- Import TypeORM in domain
- Put business logic in controllers
- Put business logic in repositories
- Use
anytype - Skip tests
🔒 Security
- Passwords hashed with bcrypt (12 rounds)
- JWT tokens (access: 15min, refresh: 7 days)
- Helmet.js for security headers
- CORS configured
- Rate limiting enabled
- Input validation with class-validator
- SQL injection prevention (TypeORM)
- XSS protection
📊 Logging
Using Pino logger with structured JSON logs.
Log levels:
- Development:
debug - Production:
info
Pretty print in development with pino-pretty.
🚢 Carrier Integrations
MVP supports these carriers:
- Maersk
- MSC
- CMA CGM
- Hapag-Lloyd
- ONE (Ocean Network Express)
Each connector implements CarrierConnectorPort with:
- Circuit breaker (5s timeout)
- Retry logic
- Rate limiting
- Error normalization
📖 Further Reading
- CLAUDE.md - Complete architecture guidelines
- TODO.md - Development roadmap
- SPRINT-0-FINAL.md - Sprint 0 completion
🤝 Contributing
- Follow hexagonal architecture principles
- Write tests (domain: 90%+, application: 80%+)
- Use TypeScript strict mode
- Format with Prettier
- Lint with ESLint
- Document API with Swagger decorators
📝 License
Proprietary - All rights reserved
Built with ❤️ using NestJS and Hexagonal Architecture