2026-06-06 12:07:18 +03:00
2026-05-12 16:50:18 +03:00
2026-05-12 15:17:16 +03:00
2026-05-12 15:17:16 +03:00
2026-05-18 23:23:51 +03:00
2026-05-12 15:17:16 +03:00

EDR Platform

Monorepo for the Ethio-Djibouti Railway digital platform. Hosts two product lines — Freight Management and Passenger Management — each with a NestJS API plus React portal and back-office web apps, sharing TypeScript types, NestJS utilities, and a React component library.


Tech Stack

Backend

Layer Tech
Runtime Node.js ≥ 20
Framework NestJS 11 (modular architecture)
Language TypeScript 5 (strict mode, project-wide)
ORM TypeORM 0.3 (UUID PKs, soft deletes, snake_case columns)
Database PostgreSQL 16 (one DB per domain)
Validation class-validator + class-transformer
API docs Swagger via @nestjs/swagger
Messaging @nestjs/microservices (inter-service ready)
Testing Jest + Supertest

Frontend

Layer Tech
Framework React 18 + Vite 5
Language TypeScript 5 (strict)
Routing React Router v6
Styling Tailwind CSS v4 (@tailwindcss/vite) + tailwind-merge + class-variance-authority
UI primitives Radix UI (meta radix-ui package, shadcn-style components)
Icons lucide-react
State / Data Zustand (client state) · TanStack Query (server state)
HTTP Axios
Auth UI @tria-plc/iamui-common (external IAM)

Shared Packages

Package Purpose
@edr/types Shared TypeScript interfaces and enums
@edr/api-common NestJS decorators, filters, interceptors, pipes, BaseEntity, BaseRepository
@edr/ui-common Shared React components (DashboardLayout, Sidebar, Button, Modal, etc.) and theme tokens
@edr/eslint-config Shared ESLint configs (base / nestjs / react)
@edr/tsconfig Shared TypeScript configs
@edr/prettier-config Shared Prettier configuration

Tooling

  • pnpm 9 — workspace package manager (sole supported PM)
  • Turborepo 2 — task orchestrator with caching
  • Husky + lint-staged + commitlint — pre-commit ESLint/Prettier and conventional-commit enforcement
  • Docker Compose — local Postgres instances + production stack (see infrastructure/)
  • Nginx — reverse proxy / static asset server in production

Planned Integrations

  • MinIO — S3-compatible object storage for documents (object keys already shaped under edr-freight/{linkedType}/{ref}/{filename})

Architecture

High-level layout

┌──────────────────────────────────────────────────────────────────┐
│                        EDR Platform (monorepo)                   │
├──────────────────────┬───────────────────────────────────────────┤
│  Freight domain      │  Passenger domain                         │
│  ┌────────────────┐  │  ┌────────────────┐                      │
│  │ freight-portal │  │  │ passenger-     │                      │
│  │  (React)       │  │  │  portal (React)│                      │
│  ├────────────────┤  │  ├────────────────┤                      │
│  │ freight-       │  │  │ passenger-     │                      │
│  │  backoffice    │  │  │  backoffice    │                      │
│  └───────┬────────┘  │  └───────┬────────┘                      │
│          │           │          │                                │
│          ▼           │          ▼                                │
│  ┌────────────────┐  │  ┌────────────────┐                      │
│  │ freight-api    │  │  │ passenger-api  │                      │
│  │  (NestJS)      │  │  │  (NestJS)      │                      │
│  └───────┬────────┘  │  └───────┬────────┘                      │
│          │           │          │                                │
│          ▼           │          ▼                                │
│  ┌────────────────┐  │  ┌────────────────┐                      │
│  │ postgres-      │  │  │ postgres-      │                      │
│  │  freight       │  │  │  passenger     │                      │
│  └────────────────┘  │  └────────────────┘                      │
└──────────────────────┴───────────────────────────────────────────┘
                  Shared (workspace) packages
       @edr/types · @edr/api-common · @edr/ui-common · @edr/{eslint,tsconfig,prettier}-config

Domain isolation

  • One database per domain. postgres-freight (port 5433, db edr_freight) and postgres-passenger (port 5434, db edr_passenger). No cross-database joins. Cross-domain data flows only through API calls or message queues.
  • Each domain owns its data model. Freight bookings/consignments/shipments/trains/invoices/documents live only in the freight DB; passenger journeys/tickets live only in the passenger DB.

NestJS module pattern (per feature)

modules/<feature>/
  entities/<feature>.entity.ts          // extends BaseEntity (UUID, timestamps, soft delete)
  dto/<verb>-<feature>.dto.ts           // class-validator DTOs
  <feature>.module.ts                   // wires controller + service + repository
  <feature>.controller.ts               // HTTP layer only — no business logic
  <feature>.service.ts                  // business logic
  <feature>.repository.ts               // extends BaseRepository<Entity>; services inject this, NEVER `Repository<T>` directly

Conventions enforced across the codebase:

  • All entities have UUID primary keys (@PrimaryGeneratedColumn('uuid')).
  • All entities inherit createdAt / updatedAt / deletedAt from BaseEntity (soft delete).
  • DB columns use snake_case via @Column({ name: '...' }); TS properties stay camelCase.
  • No synchronize: true in production — schema changes go through TypeORM migrations.
  • ESLint + Prettier run on pre-commit via Husky + lint-staged.
  • Conventional-commits enforced via commitlint.

Frontend application structure

apps/edr-freight-web/portal/src/
  App.tsx                   // routes + sidebar definition
  main.tsx                  // React Router + QueryClient providers
  components/
    Breadcrumbs.tsx         // shared local UI
    ui/                     // shadcn-style primitives (Button, Input, Dialog, Label, Textarea)
  pages/
    customers/              // CustomersPage + CustomerDetailPage + NewCustomerPage (dialog)
    bookings/               // ...                + multimodal Transport Legs editor
    consignments/
    tracking/               // Shipment grid + table view toggle
    trains/                 // Fleet roster
    billing/                // Invoices
    documents/              // MinIO-shaped document library
  hooks/                    // TanStack Query hooks (per feature)
  services/                 // Axios clients (per feature)
  store/                    // Zustand stores
  lib/                      // utilities (`cn` helper, formatters)

Each feature folder typically contains: *Page.tsx (list), *DetailPage.tsx, New*Page.tsx (create/edit dialog with mode: "create" | "edit"), Delete*Dialog.tsx, and a *.mock.ts seed file used by the current mock UI.

Shared layout (@edr/ui-common)

DashboardLayout provides the sidebar + header shell shared across all freight and passenger web apps:

  • Sidebar — brand-tinted, icon-led navigation. Main brand color: #10B981 (rgb(16, 185, 129) — emerald-500). Icon containers use the filled style: brand-color background with a white icon.
  • Header — language picker, notifications, user dropdown (click-driven, click-outside / Escape close); host apps opt into a light/dark theme toggle via enableThemeToggle (Tailwind class-based, persisted in localStorage).

Auth integration (planned)

Authentication is provided by an external @edr/iamui-common / @tria-plc/iamapi-common package. Do not implement login/JWT/password logic in this repo. Use placeholder TODO comments next to controllers and @CurrentUser decorators (in @edr/api-common) until the integration ships.


Apps & Ports

App Package name Purpose Port
edr-freight-api @edr/freight-api NestJS API for freight 3001
edr-freight-web/portal @edr/freight-portal React frontend for freight customers 5173
edr-freight-web/backoffice @edr/freight-backoffice React frontend for freight employees 5183
edr-passenger-api @edr/passenger-api NestJS API for passengers 3002
edr-passenger-web/portal @edr/passenger-portal React frontend for passenger customers 5174
edr-passenger-web/backoffice @edr/passenger-backoffice React frontend for passenger employees 5184

edr-freight-web and edr-passenger-web are grouping folders, not workspace packages. Each holds independent portal/ and backoffice/ workspace packages declared in pnpm-workspace.yaml.


Getting Started

Prerequisites

  • Node.js ≥ 20
  • pnpm 9 (corepack enable && corepack prepare pnpm@9.12.0 --activate)
  • Docker (for local Postgres)

Install

pnpm install

Start local databases

docker compose -f infrastructure/docker/docker-compose.db.dev.yml up -d

Run apps

pnpm dev               # every app
pnpm dev:freight       # freight API + portal + backoffice
pnpm dev:passenger     # passenger API + portal + backoffice

Common scripts

Script Description
pnpm install Install workspace dependencies
pnpm dev Run every app in watch mode
pnpm build Build every package and app
pnpm test Run all tests
pnpm lint Lint everything
pnpm type-check Type-check every package
pnpm format Format with Prettier

Repository Layout

.
├── apps/
│   ├── edr-freight-api/              NestJS — freight backend
│   ├── edr-freight-web/
│   │   ├── portal/                   React — freight customer portal
│   │   └── backoffice/               React — freight back-office
│   ├── edr-passenger-api/            NestJS — passenger backend
│   └── edr-passenger-web/
│       ├── portal/                   React — passenger customer portal
│       └── backoffice/               React — passenger back-office
├── packages/
│   ├── api-common/                   Shared NestJS utilities + BaseEntity/Repository
│   ├── types/                        Shared TS types/enums
│   ├── ui-common/                    Shared React components + theme
│   └── config/
│       ├── eslint/                   @edr/eslint-config
│       ├── tsconfig/                 @edr/tsconfig
│       └── prettier/                 @edr/prettier-config
├── infrastructure/
│   ├── docker/                       docker-compose files (db.dev / dev / prod)
│   └── nginx/                        Production nginx config
├── CLAUDE.md                         Developer guide for AI-assisted work
├── turbo.json                        Turborepo task pipeline
├── pnpm-workspace.yaml               Workspace manifest
└── README.md

Standards (recap)

  • TypeScript strict mode is enabled in every package.
  • pnpm only — never run npm install or yarn.
  • Conventional commits — enforced via commitlint on every commit.
  • NestJS 4-layer patternmodule → controller → service → repository.
  • Repository injection — services inject the custom *Repository class, not Repository<T>.
  • Controllers are thin — no business logic; delegate to services.
  • Migrations only — never enable TypeORM synchronize in production.
  • One DB per domain — no cross-database joins.

See CLAUDE.md for the deeper developer guide used during AI-assisted contributions.

Description
No description provided
Readme 211 MiB
Languages
TypeScript 86.1%
JavaScript 9.8%
CSS 2.3%
HTML 1.6%
Handlebars 0.1%