A modern, full-stack Stock Management System designed for tracking products, managing categories, and monitoring stock levels in real-time. Built with a unified ASP.NET Core Web API backend and a responsive Blazor WebAssembly frontend using MudBlazor.
- Interactive Dashboard: Gain immediate business insights with high-level KPI cards displaying Total Products, Total Categories, Low Stock Alerts, and Out of Stock counts.
- Product Management: Complete CRUD capabilities, custom SKU generation, real-time stock status monitoring, and low-stock indicators.
- Category Management: Organise products into categories with detailed descriptions and full CRUD controls.
- Role-Based JWT Authentication: Secure registration and login flows with JWT Bearer tokens, featuring token persistence (localStorage) and a dynamic password visibility toggle.
- Unified Single-Container Deployment: The frontend Blazor WebAssembly app is built and hosted statically by the ASP.NET Core API server, meaning you only need to deploy one single service/container.
- PostgreSQL Database: Powered by Neon DB (PostgreSQL) with automatic schema creation and auto-increment sequence resets on startup.
- Modern Responsive Design: Crafted using MudBlazor for a sleek, fast, and fully responsive user interface.
| Layer | Technology |
|---|---|
| Frontend UI | Blazor WebAssembly (.NET 8.0) |
| Component Library | MudBlazor (Material Design components) |
| Backend API | ASP.NET Core Web API (.NET 8.0) |
| Database ORM | Entity Framework Core (EF Core) |
| Database | PostgreSQL (Neon DB) |
| Authentication | JWT Bearer Tokens |
| Containerization | Docker (Multi-stage build) |
StockManagement/
├── StockManagement.Api/ # ASP.NET Core Web API (Backend + Blazor Host)
├── StockManagement.Client/ # Blazor WebAssembly UI (Frontend)
├── StockManagement.Shared/ # Shared Data Models, DTOs & business logic
├── Dockerfile # Multi-stage Dockerfile for containerized deployment
├── StockManagement.sln # Visual Studio Solution File
└── README.md # Project Documentation
To log in and manage the application out of the box, use the following default administrator credentials:
- Username:
admin - Password:
admin123
- .NET 8.0 SDK
- PostgreSQL (or a live connection string to Neon DB)
- Visual Studio 2022 or VS Code
-
Clone the Repository:
git clone https://github.com/farens27/Stock-Management.git cd Stock-Management -
Configure Database Connection: Open
StockManagement.Api/appsettings.json(orappsettings.Development.jsonif debugging) and configure your PostgreSQL connection string:"ConnectionStrings": { "DefaultConnection": "Host=your-postgres-host;Database=your-db;Username=your-user;Password=your-password;SslMode=Require" }
-
Run the Application: Run both the API and the Client using your IDE, or run the following commands via terminal:
# Run the Backend API dotnet run --project StockManagement.ApiNote: In development mode, the backend starts on
https://localhost:7087. The client usesappsettings.Development.jsonto automatically communicate with it.
The system is configured to work out-of-the-box with Neon DB (Serverless PostgreSQL). Follow these steps to set up your database instance:
-
Sign Up & Create Project:
- Go to Neon.tech and sign up.
- Create a new project (e.g., named
StockManagement). - Select your preferred region (e.g.,
Singapore (ap-southeast-1)).
-
Retrieve Connection String:
- On the Neon console homepage, look at the Connection Details card.
- Select the connection string type (e.g., PostgreSQL or ADO.NET).
- Copy the string. It will look similar to this:
Host=ep-solitary-mouse-aoe91p2g-pooler.c-2.ap-southeast-1.aws.neon.tech;Database=neondb;Username=neondb_owner;Password=your-password;SslMode=Require
-
Zero-Configuration Initialization:
- You do not need to manually execute any SQL scripts or run migrations on the Neon console.
- On startup, the backend automatically runs
context.Database.EnsureCreated(). - This automatically creates the schema on your Neon DB, creates all tables (
Categories,Products), seeds initial data, and aligns the PostgreSQL sequences automatically.
This repository is optimized for zero-config deployment on Railway. The Dockerfile at the root automatically builds the Blazor Client and copies the static files to the API's wwwroot folder so everything is hosted in a single, lightweight container.
-
Create a Service:
- Go to your Railway Dashboard.
- Click New Project -> Deploy from GitHub repo.
- Choose the
Stock-Managementrepository.
-
Configure Environment Variables: Under the service Variables tab, add your live database connection details:
ConnectionStrings__DefaultConnection:Host=your-neon-host;Database=neondb;Username=neondb_owner;Password=your-password;SslMode=Require
-
Generate Public Domain:
- Under the service Settings tab, scroll to Networking.
- Click Generate Domain to get a public URL (e.g.
https://stock-management-production.up.railway.app). - Visiting this domain in your browser will launch the Blazor Frontend immediately!
-
Verify Swagger UI:
- To interact directly with the backend API or run manual endpoints, go to
/swaggerrelative to your generated domain (e.g.https://your-app.up.railway.app/swagger).
- To interact directly with the backend API or run manual endpoints, go to
Instead of deploying the client and API as separate services (which incurs extra hosting costs and complex CORS configuration), this project compiles the Blazor WASM application during the API publish pipeline. The Web API's Program.cs is configured with:
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
// ...
app.MapFallbackToFile("index.html");This serves index.html as a fallback for all client-side Blazor routing, while still allowing the controllers under /api/* and Swagger UI under /swagger to handle backend requests.
When using EF Core seed data with explicit primary key IDs on PostgreSQL, the primary key identity sequences do not auto-advance. On application startup, the database runs:
SELECT setval(pg_get_serial_sequence('"Categories"', 'Id'), COALESCE(MAX("Id"), 0) + 1, false) FROM "Categories";
SELECT setval(pg_get_serial_sequence('"Products"', 'Id'), COALESCE(MAX("Id"), 0) + 1, false) FROM "Products";This resets the primary key serial index to the correct threshold, preventing duplicate key value violates unique constraint errors when users insert new categories or products.
Contributions are welcome! Follow these steps to contribute to this project:
- Fork the repository.
- Create a Branch for your feature or bug fix:
git checkout -b feature/amazing-feature
- Commit your changes:
git commit -m "feat: Add some amazing feature" - Push to the branch:
git push origin feature/amazing-feature
- Open a Pull Request describing your changes.
This project is licensed under the MIT License. Feel free to use and modify it for your own projects.