Skip to content

Commit af63367

Browse files
committed
Updated readme with live project link
1 parent ed3eb3b commit af63367

1 file changed

Lines changed: 187 additions & 56 deletions

File tree

README.md

Lines changed: 187 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,233 @@
1-
# ScrapFlow SA – Enterprise Scrapyard Management System
1+
<div align="center">
22

3-
[![ASP.NET Core 8](https://img.shields.io/badge/ASP.NET%20Core%208-512BD4?logo=.net&logoColor=white)](https://dotnet.microsoft.com/en-us/apps/aspnet)
3+
# ScrapFlow SA
4+
5+
### The complete scrap metal management platform for South African scrapyards
6+
### SAPS/ITAC compliant · Real-time · Multi-site · Production-ready
7+
8+
[![ASP.NET Core 8](https://img.shields.io/badge/ASP.NET%20Core%208-512BD4?logo=.net&logoColor=white)](https://dotnet.microsoft.com/)
49
[![React 18](https://img.shields.io/badge/React%2018-61DAFB?logo=react&logoColor=black)](https://react.dev/)
510
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white)](https://www.postgresql.org/)
6-
[![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwind-css&logoColor=white)](https://tailwindcss.com/)
11+
[![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
712
[![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white)](https://www.docker.com/)
13+
[![Vercel](https://img.shields.io/badge/Live%20on%20Vercel-000000?logo=vercel&logoColor=white)](https://scrap-flow-xi.vercel.app/)
14+
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
15+
16+
<br/>
17+
18+
[Live Demo](https://scrap-flow-xi.vercel.app/) &nbsp;·&nbsp; [API Docs](https://scrapflow-api.onrender.com/swagger) &nbsp;·&nbsp; [Report Bug](https://github.com/dev-k99/ScrapFlow/issues)
19+
20+
</div>
21+
22+
---
823

9-
**ScrapFlow SA** is a full-stack, production-ready solution built specifically for the South African scrap metal industry. It modernizes the legacy "pen-and-paper" metal trade with a high-performance, **SAPS/ITAC-compliant** digital platform.
24+
> [!NOTE]
25+
> **Try the live demo instantly — no sign-up needed.** Use any of the test accounts below:
26+
>
27+
> | Role | Email | Password |
28+
> |------|-------|----------|
29+
> | **Owner** *(full access)* | `owner@scrapflow.co.za` | `ScrapFlow@2026!` |
30+
> | Manager | `manager@scrapflow.co.za` | `ScrapFlow@2026!` |
31+
> | Scale Operator | `scale@scrapflow.co.za` | `ScrapFlow@2026!` |
32+
> | Grader | `grader@scrapflow.co.za` | `ScrapFlow@2026!` |
33+
> | Accountant | `accounts@scrapflow.co.za` | `ScrapFlow@2026!` |
34+
>
35+
> **Frontend**: https://scrap-flow-xi.vercel.app/ &nbsp;|&nbsp; **API**: https://scrapflow-api.onrender.com
1036
1137
---
1238

13-
## 📽️ The Problem vs. The Solution
39+
## The Problem vs. The Solution
1440

15-
### The Problem
41+
South African scrapyards face three existential threats from legacy pen-and-paper operations:
1642

17-
Legacy scrapyards in South Africa face three existential threats:
43+
| Pain Point | Before ScrapFlow | After ScrapFlow |
44+
|------------|-----------------|-----------------|
45+
| **Compliance Chaos** | Paper registers fail SAPS audits → fines & license revocation | Compliance baked into code — ticket cannot complete without EFT ref + ID photos |
46+
| **Operational Blindness** | No real-time tonnage or profit visibility | Live dashboard with inventory value, revenue, and ticket stats |
47+
| **Cash Ban Burden** | Manual EFT tracking is error-prone and un-auditable | Integrated payment workflow with verified references and 5-year audit trail |
1848

19-
1. **Compliance Chaos**: The _South African Second-Hand Goods Act_ and the recent **2024/2025 Metal Cash Ban** require strict record-keeping. Yards using paper registers often fail SAPS audits, leading to heavy fines or license revocation.
20-
2. **Operational Blindness**: Without real-time inventory tracking, owners are unaware of their exact tonnage on hand or their true profit margins after price fluctuations.
21-
3. **The Electronic Payment Gap**: Switching from cash to electronic payments (EFT) is a huge administrative burden without an integrated workflow to track proof-of-payments.
49+
> The **South African Second-Hand Goods Act** and the **2024/2025 Metal Cash Ban** require strict digital record-keeping. ScrapFlow acts as a *Digital Auditor* — hard-blocking non-compliant actions at the service layer.
2250
23-
### The ScrapFlow Solution
51+
---
2452

25-
ScrapFlow digitizes the entire lifecycle of a scrapyard transaction, ensuring that **compliance is baked into the code, not an afterthought.** By hard-blocking non-compliant actions (like missing ID photos or lacking EFT references), it acts as a "Digital Auditor" for the yard.
53+
## Features
54+
55+
| Category | Feature | Detail |
56+
|----------|---------|--------|
57+
| **Compliance** | Cash-ban enforcement | Blocks ticket completion without a verified EFT reference |
58+
| **Compliance** | Mandatory photo capture | 3 required photos: Seller ID, Load, Proof-of-Payment |
59+
| **Compliance** | 5-year audit trail | Rolling registers stored per SAPS/ITAC requirements |
60+
| **Operations** | 6-step inbound ticket | Arrive → Gross Weigh → Grade → Tare → Pay → Complete |
61+
| **Operations** | Outbound tickets | Full customer invoice workflow with lot selection |
62+
| **Inventory** | Real-time lot tracking | Automatic lot creation on ticket completion |
63+
| **Inventory** | Adjust & write-off | Manager-approved lot adjustments with reason logging |
64+
| **Real-time** | SignalR inventory hub | Live updates pushed to all connected clients instantly |
65+
| **Automation** | Webhook system | Fires on ticket/inventory events → Zapier, n8n, Make |
66+
| **UX** | Offline-first PWA | IndexedDB drafts survive connectivity loss |
67+
| **UX** | Weighbridge integration | Web Serial API direct industrial scale communication |
68+
| **Admin** | 5-role RBAC | Owner / Manager / ScaleOp / Grader / Accountant |
69+
| **Admin** | Multi-site support | Manage multiple scrapyards from one account |
70+
| **Reports** | Revenue & tonnage reports | Filterable by site, date range, and material grade |
2671

2772
---
2873

29-
## 🌟 Key Features
74+
## Tech Stack
3075

31-
### ⚖️ 1. Compliance-First Engine
76+
| Backend | Frontend |
77+
|---------|----------|
78+
| ASP.NET Core 8 (Clean Architecture) | React 18 (JSX + Vite) |
79+
| Entity Framework Core 8 | Tailwind CSS + Glassmorphism UI |
80+
| PostgreSQL (Supabase) | Zustand state management |
81+
| SignalR (real-time hubs) | @microsoft/signalr client |
82+
| JWT authentication (12h tokens) | Axios + React Query patterns |
83+
| HMAC-SHA256 webhook signing | Web Serial API (weighbridge) |
84+
| Serilog structured logging | IndexedDB offline drafts |
85+
| Docker + docker-compose | Deployed on Vercel |
3286

33-
- **Automatic Cash-Ban Enforcement**: The `TicketService` strictly prevents completion without valid EFT references.
34-
- **Mandatory ID/Photo Capture**: Integrated Media API captures 3 mandatory photos (Seller, Load, ID) before a ticket can be finalized.
35-
- **Audit-Ready Registers**: Rolling registers stored for 5 years as required by the Second-Hand Goods Act.
87+
---
3688

37-
### 🍎 2. Premium Apple-Style UX
89+
## Architecture
3890

39-
- **Aesthetic Engineering**: A minimalist, high-contrast UI designed for the harsh lighting conditions of a scrapyard. Built with glassmorphism and Tailwind's emerald palette.
40-
- **Weighbridge Integration**: Direct communication with industrial scales via the **Web Serial API**.
91+
```mermaid
92+
graph TD
93+
Client["React Client\n(Vercel)"]
94+
API["ScrapFlow.API\n(Render)"]
95+
APP["ScrapFlow.Application\nDTOs · Interfaces · Services"]
96+
DOMAIN["ScrapFlow.Domain\nEntities · Enums · Business Rules"]
97+
INFRA["ScrapFlow.Infrastructure\nEF Core · Migrations · Services"]
98+
DB[("PostgreSQL\n(Supabase)")]
99+
SIG["SignalR Hubs\nInventory · Tickets"]
100+
HOOK["Webhook Service\nHMAC-SHA256 signing"]
101+
N8N["n8n / Zapier\nAutomation workflows"]
102+
103+
Client -- "REST + SignalR" --> API
104+
API --> APP
105+
APP --> DOMAIN
106+
INFRA --> APP
107+
INFRA --> DOMAIN
108+
INFRA --> DB
109+
API --> SIG
110+
API --> HOOK
111+
HOOK -- "HTTP POST" --> N8N
112+
```
41113

42114
---
43115

44-
## 🛠️ Engineering Challenges & Solves
116+
## Deployment
45117

46-
Building a system for a highly regulated environment revealed several technical hurdles:
118+
| Layer | Platform | Notes |
119+
|-------|----------|-------|
120+
| **Frontend** | [Vercel](https://vercel.com/) | Auto-deploys on push to `main` |
121+
| **Backend API** | [Render](https://render.com/) | Dockerized ASP.NET Core 8 |
122+
| **Database** | [Supabase](https://supabase.com/) | Managed PostgreSQL |
123+
| **Automation** | n8n (Docker) + Zapier | 4 pre-built workflow templates |
47124

48-
### 🔄 1. The Circular Dependency Trap
125+
---
49126

50-
**Problem**: During the split between `Application` and `Infrastructure` layers, I encountered a circular dependency where services needed the `DbContext`, but the `DbContext` needed service-related logic.
51-
**Solution**: I moved high-level business services (like `TicketService`) into the **Infrastructure layer**. By implementing interfaces defined in the `Application` layer, I maintained Clean Architecture principles while resolving the cyclic reference.
127+
## Engineering Challenges & Solves
52128

53-
### 💉 2. Dependency Injection & Service Scoping
129+
### 1. Circular Dependency in Clean Architecture
130+
**Problem**: During the Application/Infrastructure split, services needed `DbContext` but `DbContext` needed service logic — a circular reference.
131+
**Solution**: Moved `TicketService` into the Infrastructure layer, implementing interfaces defined in Application. Maintained Clean Architecture principles while resolving the cyclic reference.
54132

55-
**Problem**: Standalone services (like the `NotificationService` for WhatsApp) initially threw runtime errors due to missing `ILogger` implementations and improper DI registrations.
56-
**Solution**: I standardized DI registrations in `Program.cs` and utilized generic `ILogger<T>` patterns. In unit tests, I used **Moq** to provide verified mock loggers, ensuring the business logic could be tested in isolation from external logging providers.
133+
### 2. Dependency Injection & Service Scoping
134+
**Problem**: Standalone services threw runtime errors due to missing `ILogger` implementations and improper DI registrations.
135+
**Solution**: Standardized all DI registrations in `Program.cs` using generic `ILogger<T>`. In unit tests, used **Moq** to provide verified mock loggers — isolating business logic from external providers.
57136

58-
### 🧪 3. In-Memory Database Versioning
137+
### 3. In-Memory Database Versioning
138+
**Problem**: The xUnit test suite failed because `InMemoryDatabase v10` was incompatible with the .NET 8 target.
139+
**Solution**: Manual downgrade to `Microsoft.EntityFrameworkCore.InMemory v8.0.0`, aligning test infrastructure with the core runtime.
59140

60-
**Problem**: When setting up the xUnit test suite, the latest `InMemoryDatabase` version (v10) was incompatible with the project's .NET 8 target.
61-
**Solution**: I performed a manual downgrade to **Microsoft.EntityFrameworkCore.InMemory v8.0.0**, aligning the test infrastructure with the core runtime and ensuring stable "database-in-memory" testing for compliance rules.
141+
### 4. Non-Blocking Webhook Dispatch
142+
**Problem**: Firing webhooks synchronously would add latency to every ticket completion HTTP response.
143+
**Solution**: Implemented fire-and-forget using `_ = Task.Run(() => _webhookService.FireAsync(...))` — the HTTP response returns immediately while the webhook dispatches in the background. HMAC-SHA256 signature header ensures receiver authenticity.
62144

63145
---
64146

65-
## 🧠 What I Learnt
147+
## What I Learnt
66148

67-
1. **Industry-Specific Architecture**: Learnt how to translate legal requirements (SAPS/ITAC) into strict software "guards" and validation logic.
68-
2. **Browser-Hardware Interfacing**: Explored the power of the **Web Serial API** to bridge the gap between industrial hardware (scales) and modern web browsers.
69-
3. **Offline-First Resilience**: Implemented PWA strategies (Service Workers + IndexedDB) to ensure data integrity even when South African yard connectivity is unstable.
70-
4. **Clean Architecture Discipline**: Deepened my understanding of how to maintain strict separation of concerns even when complex infrastructure dependencies arise.
149+
1. **Industry-Specific Architecture** — Translating legal requirements (SAPS/ITAC) into strict software guards and validation logic at the service layer.
150+
2. **Browser-Hardware Interfacing** — Using the **Web Serial API** to bridge industrial weighbridge hardware and modern web browsers without drivers.
151+
3. **Offline-First Resilience** — PWA strategies with Service Workers + IndexedDB to handle South African connectivity instability.
152+
4. **Clean Architecture Discipline** — Maintaining strict separation of concerns even when complex infrastructure dependencies arise in real-world projects.
153+
5. **Real-time Systems** — Building SignalR hubs with group-based broadcasting (per-site) and stable client reconnection handling.
71154

72155
---
73156

74-
## 🏗️ Technical Architecture
157+
## Getting Started (Local Dev)
75158

76-
```mermaid
77-
graph TD
78-
API[ScrapFlow.API] --> APP[ScrapFlow.Application]
79-
INFRA[ScrapFlow.Infrastructure] --> APP
80-
INFRA --> DOMAIN[ScrapFlow.Domain]
81-
APP --> DOMAIN
159+
### Prerequisites
160+
- .NET 8 SDK
161+
- Node.js 18+
162+
- Docker Desktop
82163

83-
subgraph "Infrastructure"
84-
DB[(PostgreSQL)]
85-
SignalR[SignalR Hubs]
86-
Comp[Compliance Engine]
87-
Notif[Notification Service]
88-
end
164+
### 1. Clone & configure
165+
```bash
166+
git clone https://github.com/dev-k99/ScrapFlow.git
167+
cd ScrapFlow
168+
cp src/ScrapFlow.API/appsettings.example.json src/ScrapFlow.API/appsettings.json
169+
# Edit appsettings.json — add your PostgreSQL connection string and JWT secret
89170
```
90171

91-
---
172+
### 2. Docker quick start
173+
```bash
174+
docker compose up --build
175+
# API: http://localhost:5010
176+
# n8n: http://localhost:5678
177+
```
178+
179+
### 3. Or run individually
180+
```bash
181+
# Backend
182+
cd src/ScrapFlow.API && dotnet run
92183

93-
## 🚀 Getting Started
184+
# Frontend
185+
cd scrapflow-client && npm install && npm run dev
186+
# → http://localhost:5173
187+
```
94188

95-
1. **Docker Quick Start**: `docker-compose up --build`
96-
2. **Backend**: `cd src/ScrapFlow.API && dotnet run`
97-
3. **Frontend**: `cd scrapflow-client && npm run dev`
98-
4. **Tests**: `dotnet test`
189+
### 4. Seed data
190+
On first run, the API automatically seeds:
191+
- 5 user accounts (Owner, Manager, ScaleOp, Grader, Accountant)
192+
- 2 sites (Germiston Main Yard, Durban North Depot)
193+
- 20 material grades (ferrous + non-ferrous) with realistic ZAR prices
194+
- 10 suppliers + 3 customers + 5 sample completed tickets
99195

100196
---
101197

102-
_Designed & Engineered for South African Scrapyards._
198+
## API Reference
199+
200+
| Resource | Method | Endpoint | Auth |
201+
|----------|--------|----------|------|
202+
| Auth | POST | `/api/auth/login` | Public |
203+
| Auth | POST | `/api/auth/register` | Public |
204+
| Dashboard | GET | `/api/dashboard?siteId=` | Any role |
205+
| Inbound Tickets | POST | `/api/tickets/inbound` | ScaleOp+ |
206+
| Inbound Tickets | PUT | `/api/tickets/inbound/{id}/gross-weight` | ScaleOp+ |
207+
| Inbound Tickets | PUT | `/api/tickets/inbound/{id}/grading` | Grader+ |
208+
| Inbound Tickets | PUT | `/api/tickets/inbound/{id}/payment` | Accountant+ |
209+
| Inbound Tickets | PUT | `/api/tickets/inbound/{id}/complete` | Manager+ |
210+
| Outbound Tickets | GET/POST | `/api/tickets/outbound` | ScaleOp+ |
211+
| Inventory | GET | `/api/inventory?siteId=&status=` | Any role |
212+
| Inventory | PUT | `/api/inventory/{id}/adjust` | Manager+ |
213+
| Inventory | PUT | `/api/inventory/{id}/write-off` | Manager+ |
214+
| Materials | GET | `/api/materials` | Any role |
215+
| Suppliers | GET/POST | `/api/suppliers` | ScaleOp+ |
216+
| Customers | GET/POST | `/api/customers` | ScaleOp+ |
217+
| Reports | GET | `/api/reports` | Manager+ |
218+
| Webhooks | GET/POST/DELETE | `/api/webhooks` | Owner only |
219+
| Sites | GET/POST | `/api/sites` | Owner (POST) |
220+
| Audit Log | GET | `/api/auditlogs` | Manager+ |
221+
| Health | GET | `/health` | Public |
222+
223+
> Full interactive docs: **https://scrapflow-api.onrender.com/swagger**
224+
225+
---
226+
227+
<div align="center">
228+
229+
**Designed & Engineered for South African Scrapyards**
230+
231+
*Built by [Kwanele Ntshangase](https://github.com/dev-k99) · [Live Demo](https://scrap-flow-xi.vercel.app/) · [View Source](https://github.com/dev-k99/ScrapFlow)*
232+
233+
</div>

0 commit comments

Comments
 (0)