Skip to content

Commit ed3eb3b

Browse files
committed
bypass Radix Dialog that is constraining the overlay
1 parent a09fff1 commit ed3eb3b

164 files changed

Lines changed: 129 additions & 14033 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# ScrapFlow SA – Enterprise Scrapyard Management System
2+
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)
4+
[![React 18](https://img.shields.io/badge/React%2018-61DAFB?logo=react&logoColor=black)](https://react.dev/)
5+
[![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/)
7+
[![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white)](https://www.docker.com/)
8+
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.
10+
11+
---
12+
13+
## 📽️ The Problem vs. The Solution
14+
15+
### The Problem
16+
17+
Legacy scrapyards in South Africa face three existential threats:
18+
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.
22+
23+
### The ScrapFlow Solution
24+
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.
26+
27+
---
28+
29+
## 🌟 Key Features
30+
31+
### ⚖️ 1. Compliance-First Engine
32+
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.
36+
37+
### 🍎 2. Premium Apple-Style UX
38+
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**.
41+
42+
---
43+
44+
## 🛠️ Engineering Challenges & Solves
45+
46+
Building a system for a highly regulated environment revealed several technical hurdles:
47+
48+
### 🔄 1. The Circular Dependency Trap
49+
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.
52+
53+
### 💉 2. Dependency Injection & Service Scoping
54+
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.
57+
58+
### 🧪 3. In-Memory Database Versioning
59+
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.
62+
63+
---
64+
65+
## 🧠 What I Learnt
66+
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.
71+
72+
---
73+
74+
## 🏗️ Technical Architecture
75+
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
82+
83+
subgraph "Infrastructure"
84+
DB[(PostgreSQL)]
85+
SignalR[SignalR Hubs]
86+
Comp[Compliance Engine]
87+
Notif[Notification Service]
88+
end
89+
```
90+
91+
---
92+
93+
## 🚀 Getting Started
94+
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`
99+
100+
---
101+
102+
_Designed & Engineered for South African Scrapyards._

n8n-workflows/03-scheduled-daily-report.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
},
2222
{
2323
"parameters": {
24-
"url": "http://host.docker.internal:5010/api/dashboard",
24+
"url": "https://scrapflow-api.onrender.com/api/dashboard",
2525
"authentication": "genericCredentialType",
2626
"genericAuthType": "httpHeaderAuth",
2727
"sendHeaders": true,

scrapflow-client/src/components/ui/Modal.jsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,38 @@ import { motion, AnimatePresence } from 'framer-motion'
33
import { X } from 'lucide-react'
44

55
export default function Modal({ open, onOpenChange, title, description, children, size = 'md' }) {
6-
const widths = { sm: 'max-w-sm', md: 'max-w-lg', lg: 'max-w-2xl', xl: 'max-w-4xl' }
6+
const widths = { sm: '28rem', md: '32rem', lg: '42rem', xl: '56rem' }
77

88
return (
99
<Dialog.Root open={open} onOpenChange={onOpenChange}>
1010
<AnimatePresence>
1111
{open && (
1212
<Dialog.Portal forceMount>
13-
{/* Overlay doubles as the scroll container */}
13+
{/* Dimmed backdrop */}
1414
<Dialog.Overlay asChild>
1515
<motion.div
1616
initial={{ opacity: 0 }}
1717
animate={{ opacity: 1 }}
1818
exit={{ opacity: 0 }}
19-
style={{ overflowY: 'auto' }}
20-
className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm flex items-start justify-center p-4 py-8"
21-
>
19+
className="fixed inset-0 z-50 bg-black/40 backdrop-blur-sm"
20+
/>
21+
</Dialog.Overlay>
22+
23+
{/* Scroll container — sits above backdrop */}
24+
<div
25+
className="fixed inset-0 z-50 overflow-y-auto"
26+
onClick={(e) => { if (e.target === e.currentTarget) onOpenChange(false) }}
27+
>
28+
{/* Centering wrapper */}
29+
<div className="flex min-h-full items-center justify-center p-4">
2230
<Dialog.Content asChild>
2331
<motion.div
2432
initial={{ opacity: 0, scale: 0.96, y: 12 }}
2533
animate={{ opacity: 1, scale: 1, y: 0 }}
2634
exit={{ opacity: 0, scale: 0.96, y: 12 }}
2735
transition={{ duration: 0.2, ease: 'easeOut' }}
28-
className={`relative w-full ${widths[size] ?? widths.md} glass-card p-6 outline-none my-auto`}
36+
className="relative w-full glass-card p-6 outline-none"
37+
style={{ maxWidth: widths[size] ?? widths.md }}
2938
>
3039
{/* Header */}
3140
{(title || description) && (
@@ -43,7 +52,7 @@ export default function Modal({ open, onOpenChange, title, description, children
4352
</div>
4453
)}
4554

46-
{/* Close */}
55+
{/* Close button */}
4756
<Dialog.Close asChild>
4857
<button className="absolute top-4 right-4 w-7 h-7 flex items-center justify-center
4958
rounded-lg text-[var(--color-text-muted)] hover:text-[var(--color-text)]
@@ -55,8 +64,8 @@ export default function Modal({ open, onOpenChange, title, description, children
5564
{children}
5665
</motion.div>
5766
</Dialog.Content>
58-
</motion.div>
59-
</Dialog.Overlay>
67+
</div>
68+
</div>
6069
</Dialog.Portal>
6170
)}
6271
</AnimatePresence>

src/ScrapFlow.API/obj/Debug/net8.0/ScrapFlow.API.AssemblyInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// This code was generated by a tool.
4-
// Runtime Version:4.0.30319.42000
54
//
65
// Changes to this file may cause incorrect behavior and will be lost if
76
// the code is regenerated.
@@ -14,7 +13,7 @@
1413
[assembly: System.Reflection.AssemblyCompanyAttribute("ScrapFlow.API")]
1514
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
1615
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17-
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2535f5d36a7a5652ef582dfce5d31da651475cc0")]
16+
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1f6eec7d084edc81d3ac0e78ad6196e533cf9f5e")]
1817
[assembly: System.Reflection.AssemblyProductAttribute("ScrapFlow.API")]
1918
[assembly: System.Reflection.AssemblyTitleAttribute("ScrapFlow.API")]
2019
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b96d2f292b71258de603833cb8744b5d847b836772f63f1d00736fefd769c1ac
1+
69c5a69e1467ce6f2f1bd0e78bbf7fc874a167b0afa442a11abef57eac4bf960

src/ScrapFlow.Application/obj/Debug/net8.0/ScrapFlow.Application.AssemblyInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// This code was generated by a tool.
4-
// Runtime Version:4.0.30319.42000
54
//
65
// Changes to this file may cause incorrect behavior and will be lost if
76
// the code is regenerated.
@@ -14,7 +13,7 @@
1413
[assembly: System.Reflection.AssemblyCompanyAttribute("ScrapFlow.Application")]
1514
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
1615
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17-
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2535f5d36a7a5652ef582dfce5d31da651475cc0")]
16+
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1f6eec7d084edc81d3ac0e78ad6196e533cf9f5e")]
1817
[assembly: System.Reflection.AssemblyProductAttribute("ScrapFlow.Application")]
1918
[assembly: System.Reflection.AssemblyTitleAttribute("ScrapFlow.Application")]
2019
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2e091c770846fa22855726f66653334f250255aedaee8660999d1dd0f399f9b7
1+
9139790341f1b1fc3ae475bb415cf86a710e3db50e109cce106eb505b6662c6e

src/ScrapFlow.Domain/obj/Debug/net8.0/ScrapFlow.Domain.AssemblyInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// This code was generated by a tool.
4-
// Runtime Version:4.0.30319.42000
54
//
65
// Changes to this file may cause incorrect behavior and will be lost if
76
// the code is regenerated.
@@ -14,7 +13,7 @@
1413
[assembly: System.Reflection.AssemblyCompanyAttribute("ScrapFlow.Domain")]
1514
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
1615
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17-
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2535f5d36a7a5652ef582dfce5d31da651475cc0")]
16+
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1f6eec7d084edc81d3ac0e78ad6196e533cf9f5e")]
1817
[assembly: System.Reflection.AssemblyProductAttribute("ScrapFlow.Domain")]
1918
[assembly: System.Reflection.AssemblyTitleAttribute("ScrapFlow.Domain")]
2019
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
befd187e6d8669bc4f72a0eb384e4dfaf0515daad250fdf96257fc64d9cf3cc2
1+
ef1a1dd464a83a67a2507654e53f3b7ec0941aad21e3c1026d93cbafa527f1f5

src/ScrapFlow.Infrastructure/obj/Debug/net8.0/ScrapFlow.Infrastructure.AssemblyInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//------------------------------------------------------------------------------
22
// <auto-generated>
33
// This code was generated by a tool.
4-
// Runtime Version:4.0.30319.42000
54
//
65
// Changes to this file may cause incorrect behavior and will be lost if
76
// the code is regenerated.
@@ -14,7 +13,7 @@
1413
[assembly: System.Reflection.AssemblyCompanyAttribute("ScrapFlow.Infrastructure")]
1514
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
1615
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
17-
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2535f5d36a7a5652ef582dfce5d31da651475cc0")]
16+
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1f6eec7d084edc81d3ac0e78ad6196e533cf9f5e")]
1817
[assembly: System.Reflection.AssemblyProductAttribute("ScrapFlow.Infrastructure")]
1918
[assembly: System.Reflection.AssemblyTitleAttribute("ScrapFlow.Infrastructure")]
2019
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

0 commit comments

Comments
 (0)