← All projects
Full-Stack · Enterprise Inventory System

Inventiq

An enterprise-style inventory and procurement system: an ASP.NET Core 8 API built on Clean Architecture, paired with a React + TypeScript SPA. Built to mirror how a real internal business system is structured — layered architecture, an auditable inventory ledger, a multi-step purchasing approval workflow, and the operational hardening a system needs before real traffic hits it.

Inventiq dashboard with product, category, supplier, and pending order counts

Project Overview

Inventiq is a full operational tool for tracking products, suppliers, purchase orders, and stock movements — with role-based access across three permission levels (Admin, Manager, Clerk). It's built as two independent, purpose-built services: a REST API and a React SPA that consumes it, each modeled after how a real internal business system is actually structured rather than a single-file CRUD demo.

Problem

Small operations tracking inventory in spreadsheets lose visibility fast: stock levels drift out of sync, reorder points get missed, purchasing has no approval trail, and there's no single source of truth for what's actually on hand versus what the paperwork says.

Solution

Inventiq centralizes that operational data behind role-gated screens: live stock counts computed from an append-only transaction ledger (never a stored, driftable number), a purchase-order lifecycle with a real approval chain, and reporting with CSV export — backed by a rate-limited, hardened API rather than an open CRUD surface.

Inventiq sign-in screen
Authenticated access — JWT-backed sign in

Key Features

  • Dashboard: live counts of products, categories, suppliers, and pending orders, plus total inventory value and low-stock alerts.
  • Catalog: categories with parent/child hierarchy, suppliers, and SKU-level product detail — full CRUD with search, filtering, and pagination.
  • Inventory ledger: stock in / stock out / manual adjustment, each recorded as an append-only transaction — current stock is always computed, never stored.
  • Purchase orders: a real approval lifecycle — Draft → Submitted → Approved → (Partially) Received → Received — with partial-receiving support.
  • Reports: date-ranged inventory and purchase reports with CSV export.
  • Users & roles (Admin only): role assignment and account activation/deactivation, with two safety rules baked in — an Admin can't strip their own Admin role, and the system always keeps at least one active Admin.
  • Role-aware UI: every screen shows different available actions for Clerk / Manager / Admin, mirroring the backend's own authorization rules.
Inventiq purchase orders list with status badges
Purchase orders — Draft / Approved / Received lifecycle
Inventiq reports view with date range filter and CSV export
Reports — date-ranged, exportable to CSV
Inventiq inventory tracking view
Inventory ledger & stock movement
Inventiq user and role management screen
Admin-only user & role management

Architecture

React + TypeScript SPA
↓
ASP.NET Core Web API
↓
Application Layer — DTOs, Services, Validation
↓
Domain Layer — Entities, Business Rules
↓
Infrastructure / Persistence — EF Core, JWT, Repositories
↓
SQL Server

The backend follows Clean Architecture with dependencies pointing strictly inward:

  • Inventiq.Domain — entities, enums, domain exceptions; zero external dependencies.
  • Inventiq.Application — DTOs, service interfaces/implementations, FluentValidation validators.
  • Inventiq.Infrastructure — JWT issuing, BCrypt password hashing.
  • Inventiq.Persistence — EF Core DbContext, entity configurations, repositories, Unit of Work.
  • Inventiq.API — controllers, middleware, Program.cs, Swagger.
  • Inventiq.Tests — xUnit + Moq unit tests against Application services, with no database or HTTP host required to run.

The React frontend mirrors this structure on the client: a types/ folder maps the backend's DTOs field-for-field (a backend change surfaces as a compile error, not a silent runtime bug), an Axios client with interceptor-based token refresh, and one api/ file per backend controller area.

Technology Stack

Backend

ASP.NET Core 8 (C#) Entity Framework Core SQL Server FluentValidation JWT Bearer Auth Serilog Swagger / Swashbuckle xUnit + Moq

Frontend

React 19 + TypeScript Vite TanStack Query React Hook Form + Zod Axios Tailwind CSS v4

Engineering Highlights

  • Stock as a computed value, not a stored column. Product has no Quantity field — current stock is always SUM(StockIn) − SUM(StockOut) + SUM(Adjustment) over the transaction ledger. This rules out an entire class of race-condition bugs and gives a full audit trail of why a number changed, not just what it is now.
  • Projected reads instead of mapped entities. Read paths project directly into DTOs inside the LINQ query (.Select(p => new ProductDto(...))) rather than loading an entity and mapping it afterward — EF Core doesn't load related data unless the query explicitly asks for it, so this avoids silently-blank fields and only pulls the columns actually needed.
  • Explicit transactional commit. Purchase-order receiving writes to the inventory ledger inside an explicit database transaction that rolls back by default and only commits as the last line of the success path — a partially-failed receive can never leave stock and PO status out of sync.
  • Rotating refresh tokens. Every refresh marks the old token revoked and chains it via ReplacedByToken, which makes token theft detectable — a revoked token being presented again is a strong compromise signal.
  • Soft deletes throughout (an IsActive flag) on Products, Categories, and Suppliers, since inventory and purchase-order history reference them and a hard delete would corrupt the ledger.
  • Operational hardening: per-endpoint rate limiting (tighter on login/register to blunt brute-force attempts), HSTS, standard security headers, and request size limits.
  • Client-side validation mirrors server-side rules. React Hook Form + Zod validation on the frontend mirrors the backend's FluentValidation rules, so obviously invalid input never reaches the API.

Results

Inventiq is deployed and publicly reachable as a working demo, seeded with a realistic dataset (18 products across 5 categories, 4 suppliers, 3 purchase orders in different lifecycle stages). No production usage metrics (real customer volume, uptime history) are published here — this is a live, fully functional build, not a claim of commercial scale.

Links