An internal enterprise web application engineered for Majd Technology Company (شركة مجد للتقنية) to digitize and enforce a structured, two-level approval workflow for procurement operations. The system automates the lifecycle of internal purchase requests, moving seamlessly from employee submission to departmental manager review, and finally to finance officer verification for Purchase Order (PO) issuance.
Educational Project Notice: Majd Technology Company (شركة مجد للتقنية) is a completely fictional company. This system is a self-taught, independent software engineering portfolio project built strictly for learning, architectural modeling, and educational purposes. It does not represent or associate with any real-world entity.
This project is built using a modern, decoupled full-stack architecture optimized for strict data integrity, type safety, and real-time state synchronization.
- Frontend: React 19, TypeScript, Tailwind CSS, Shadcn UI components, React Router v7 (latest unified routing architecture).
- API Fetching & State: Axios (HTTP client for asynchronous data fetching), Zustand (global auth & notification stores), React Hook Form.
- Backend: ASP.NET Core 10 Web API, Entity Framework Core (Code-First).
- Database: PostgreSQL (Cloud-hosted via Neon DB).
- Authentication: JWT Bearer Token Authentication with custom expired session token rotation.
- Real-time Communication: SignalR for event-driven, system-wide in-app notifications.
Requests are driven by a strict backend-enforced state machine. Status transitions follow an irreversible sequential pipeline unless pushed back via a rejection:
[DRAFT] ──> [PENDING_MANAGER] ──> [PENDING_FINANCE] ──> [APPROVED] (PO Issued)
│ │
▼ ▼
[REJECTED] [REJECTED]
- DRAFT: Created by employee; fully editable.
- PENDING_MANAGER: Awaiting action from the designated department manager.
- PENDING_FINANCE: Approved by manager; awaiting final finance confirmation.
- APPROVED: Finalized by finance; a required unique Purchase Order (PO) number is bound.
- REJECTED / CANCELLED: Terminal states. Once moved here, the request locks completely.
The application implements strict four-tier role segmentation enforced simultaneously via frontend route guards using React Router v7 layout configurations and backend authorization policies ([Authorize(Roles = "...")]):
| User Role | Arabic Label | System Responsibility |
|---|---|---|
| Employee | موظف | Submits and tracks own departmental requests; handles draft revisions. |
| Manager | مدير قسم | Dashboard queue tracking; approves/rejects requests within their department. |
| Finance | مسؤول مالي | Final verification layer; evaluates all manager-approved requests and issues PO numbers. |
| Admin | مشرف النظام | Full system oversight; manages users, deactivations, departments, and categories. |
- Zero-Zero Client Layer: Total price tracking is strictly computed on the backend as
Quantity * UnitPriceto eliminate client-side payload tampering. - Deterministic Key Generation: Tracking keys are systematically auto-generated using an automated database sequence formatting structure (
PR-YYYY-NNNN). - Conditional Risk Validation: High-value procurement requests exceeding 50,000 SAR dynamically invoke strict model validation rules, enforcing a comprehensive justification string within the
Descriptionfield. - Immutability Windows: The system completely locks a record from external updates the moment its state shifts out of
DRAFT. - Strict Scope Isolation: Departmental managers are cryptographically restricted from reading, querying, or intercepting data structures originating outside their assigned organizational unit.
├── IPRS.Server/ # ASP.NET Core 10 Web API
│ ├── Controllers/ # REST API endpoints & Http route endpoints
│ ├── Models/ # EF Core data entities & database schema models
│ ├── DTOs/ # Data Transfer Objects for strict validation
│ ├── Services/ # Core business logic processing layers
│ ├── Repositories/ # Data access abstraction layers
│ ├── Data/ # Database contexts & seed initialization handlers (runs if DB empty)
│ ├── Extensions/ # Model conversion tooling & clean DTO object mapping hooks
│ ├── Helpers/ # Shared utilities and system text tools
│ ├── Hubs/ # SignalR real-time messaging pipeline systems
│ ├── Infrastructure/ # Lower-level core system configuration layers
│ ├── Providers/ # Core functional cross-cutting logic modules
│ ├── Middleware/ # Global error interceptors & identity filters
│ ├── Common/ # Shared generic structures & ServiceResult patterns
│ └── Program.cs # Dependency injection & service configuration
│
└── iprs.client/ # React 19 Single Page Application (SPA)
├── src/
│ ├── assets/ # Images, SVGs, and brand design elements
│ ├── components/ # Shared UI modular components (DataTables, Badges)
│ ├── config/ # React Router v7 configuration, loaders, and API routes
│ ├── contexts/ # Custom React context modules or event frames
│ ├── hooks/ # Custom functional hooks & state behaviors
│ ├── pages/ # Role-specific dashboard layouts & workflow panels
│ ├── providers/ # Application shell wrappers & configuration boundaries
│ ├── schemas/ # Form validation trees (Zod/Yup matrices)
│ ├── services/ # Integrated Axios API communication pipelines
│ ├── shadcn-ui/ # Configured core design library primitives
│ ├── store/ # Reactive Zustand global data stores
│ ├── types/ # Unified TypeScript interfaces
│ └── utils/ # Formatter helpers (Currency serialization, date systems)
- .NET 10.0 SDK
- Node.js (v24 or higher - utilized automatically by backend tooling proxy layers)
- PostgreSQL Database Instance (Hosted on Neon DB)
Ensure your Neon DB connection string is properly updated under ConnectionStrings:DefaultConnection in your appsettings.json. Then run the following to apply the Entity Framework core migrations directly onto your remote PostgreSQL cluster:
cd IPRS.Server
dotnet ef database updateThanks to the integrated .NET SPA Proxy architecture (<SpaProxyLaunchCommand>), you don't need to open two separate terminals. Simply boot up the server directory environment, and .NET will automatically spawn Node.js in the background to serve your React frontend asset environment concurrently:
dotnet runThe database seeder provisions standard testing context records out of the box directly onto your Neon database instance if no user entities are detected:
- System Admin:
admin@majd.com(Password:Admin@123) - Finance Officer:
finance@majd.com(Password:Finance@123) - IT Department Manager:
manager.it@majd.com(Password:Manager@123) - IT Employee:
ahmed@majd.com(Password:Employee@123)
This project served as a deep-dive laboratory for mastering enterprise engineering patterns:
- Cutting-Edge Framework Configurations: Built using .NET 10 and React 19, taking full advantage of the new React Router v7 routing structures to encapsulate structural authorization logic cleaner than ever.
- Advanced Full-Stack Tool Orchestration: Leveraged the official .NET SpaProxy pipeline to seamlessly link backend systems directly to a background Vite asset pipeline.
- Serverless Cloud Infrastructure Integration: Structured data schemas using decoupled PostgreSQL configurations, addressing low-latency transactional bindings via cloud instances on Neon DB.
- Robust Client-Server Communication: Leveraged Axios instances directly to control HTTP state validation pipelines, request/response interception, and state synchronization without standard Node proxy overheads.
- Secure Token Handshaking: Crafted a highly resilient token verification pipeline inside
AuthServiceusing manualTokenValidationParametersto safely parse expired access payloads for secure session token rotation. - Strict Build Compliance: Resolved intricate compilation and type inheritance bugs across standard Shadcn UI primitive abstractions by restructuring explicit React compiler tokens (
ComponentProps,ReactNode). - Reactive UI Syncing: Coupled relational tracking indices to real-time event loops using a unified Zustand and SignalR synchronization infrastructure.