A logistics platform tackling freight fragmentation across South Africa and the SADC region. Built with landmark-based addressing in mind (for areas without formal street addresses), shipment creation, and carrier matching β designed for the African logistics context from the ground up. Currently in beta.
- Shipment management β create shipments, list pending shipments
- Carrier matching β find available carriers by country, register new carriers
- Clean Architecture β strict separation between Domain, Application, Infrastructure, and API layers
- CQRS with MediatR β commands and queries are isolated per feature (
Features/Shipments/Commands,Features/Shipments/Queries) - Validation pipeline β FluentValidation wired into the Application layer
- Swagger/OpenAPI β auto-generated interactive API docs via Swashbuckle
- Angular frontend β server-side rendered (SSR) Angular 21 app styled with Tailwind CSS
| Layer | Technology |
|---|---|
| Runtime | .NET 10 |
| API | ASP.NET Core Web API |
| Architecture | Clean Architecture (Domain / Application / Infrastructure / API) |
| CQRS | MediatR |
| Validation | FluentValidation |
| ORM | Entity Framework Core 9 |
| Database (current) | SQLite (afrihaul.db, local file) |
| API Docs | Swashbuckle (Swagger UI) |
| Layer | Technology |
|---|---|
| Framework | Angular 21 (standalone, with SSR via @angular/ssr) |
| Styling | Tailwind CSS 3 |
| Language | TypeScript |
| Server | Express (for SSR) |
Note on the database:
appsettings.jsoncurrently lists a PostgreSQL connection string, but the actual wiring inAfriHaul.Infrastructure/DependencyInjection.csuses SQLite (Data Source=afrihaul.db) β the Postgres string is unused leftover config. The plan (per the frontend's own project description) is SQLite β PostgreSQL as the project matures.
AfriHaul.API/appsettings.json currently has a real local database password committed to the repo (in the unused Postgres connection string) and the SQLite file afrihaul.db is also tracked. Before making this repo public or continuing development:
- Remove the hardcoded password from
appsettings.json, and move secrets toappsettings.Development.json(git-ignored) or .NET User Secrets - Add
*.dbandappsettings.Development.jsonto.gitignore - Rotate the exposed password if it's reused anywhere else
- .NET 10 SDK
- Node.js 20 or later (for the Angular frontend)
- Angular CLI:
npm install -g @angular/cli - Entity Framework Core tools:
dotnet tool install --global dotnet-ef
# 1. Clone the repository
git clone https://github.com/phiwakonkem/AfriHaul.git
cd AfriHaul
# 2. Restore .NET dependencies
dotnet restore
# 3. Apply EF Core migrations (creates/updates afrihaul.db)
cd AfriHaul.API
dotnet ef database update
# 4. Run the API
dotnet runThe API will start on the port shown in the console (check AfriHaul.API/Properties/launchSettings.json), with Swagger UI available at /swagger in development mode.
# In a separate terminal, from the repo root
cd afrihaul-frontend
# 1. Install dependencies
npm install
# 2. Start the dev server
npm startThe Angular app will be running at http://localhost:4200.
AfriHaul/
βββ AfriHaul.API/ # ASP.NET Core Web API, controllers, Program.cs
β βββ Controllers/
β βββ ShipmentsController.cs # GET /api/shipments/pending, POST /api/shipments
β βββ CarriersController.cs # GET /api/carriers/available/{country}, POST /api/carriers
βββ AfriHaul.Application/ # CQRS commands/queries, validators, DI setup
β βββ Features/Shipments/{Commands,Queries}
βββ AfriHaul.Domain/ # Entities: Shipment, Carrier, Fleet, Route, Shipper
βββ AfriHaul.Infrastructure/ # EF Core DbContext, migrations, UnitOfWork
βββ AfriHaul.slnx # Solution file
βββ afrihaul-frontend/ # Angular 21 SSR frontend
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/shipments/pending |
List all pending shipments |
POST |
/api/shipments |
Create a new shipment |
GET |
/api/carriers/available/{country} |
List carriers available in a given country |
POST |
/api/carriers |
Register a new carrier |
Full interactive docs are available via Swagger UI when running the API locally in Development mode.
- Migrate from SQLite to PostgreSQL for production
- Move secrets out of
appsettings.jsoninto environment-based configuration - Add authentication/authorization for shippers vs. carriers
- Route optimisation and fleet tracking
- Landmark-based addressing UI for areas without formal street addresses
Phiwakonke Mthethwa β Full-Stack Developer, South Africa GitHub Β· LinkedIn Β· phiwakonkem@gmail.com
MIT