add readme

This commit is contained in:
yaschalew
2026-05-15 22:25:29 +03:00
parent b5fe2c2e3c
commit bf4deb24cc

260
README.md
View File

@@ -1 +1,259 @@
# edr-platform
# 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; the brand color (`#33578D`) marks the active item.
- **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
```bash
pnpm install
```
### Start local databases
```bash
docker compose -f infrastructure/docker/docker-compose.db.dev.yml up -d
```
### Run apps
```bash
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 pattern** — `module → 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`](./CLAUDE.md) for the deeper developer guide used during AI-assisted contributions.