Technical guide for the Inventory Control Application
Inventory App is a comprehensive stock control system designed under Clean Architecture principles. It doesn't just manage physical inventory; it ensures data integrity and availability through a coordinated micro-services architecture for temporary file cleanup and automated cloud backups.
- ๐๏ธ Domain Structure
- ๐ Technologies & Tools
- โ๏ธ Setup & Configuration
- ๐ณ Container Infrastructure
- ๐ก๏ธ Resilience Strategy (DRP)
- ๐ ๏ธ Start & Migrations
- ๐ Globalization
- ๐ Security
- ๐ Key Features
The system uses a logical hierarchy for stock control:
- Boxes: Containers with support for infinite nesting (Box in Box).
- Items: Global product definitions from the catalog.
- Storage: The actual stock record, linking the triad: Box + Item + Brand.
- Backend: .NET 9.0 (C# 13), EF Core, SqlClient.
- Frontend: Angular 21, Signals, Angular Material.
- Cache: Redis for frequent query optimization.
- Storage: Hybrid system (Local + Google Drive API).
- Infrastructure: Docker & Nginx as CDN.
- Docker Desktop must be running.
- .NET 9 SDK & Node.js / Angular CLI.
- A Google Cloud account (for Google Drive API credentials).
Configure the .env file in the root directory. This file acts as the bridge between your Host and the containers:
STATIC_STORAGE_PATH=/host_mnt/c/your/path/Storage/front/static
DB_CONNECTION="Server=host.docker.internal,1433;Database=StockDb;User Id=YourUser;Password=YourPassword;TrustServerCertificate=True;"
DB_BACKUP_CONNECTION=Server=YourLocalServer;Database=StockDb;User Id=YourUser;Password=YourPassword;TrustServerCertificate=True;
DB_BACKUP_PATH=C:\your\path\Storage\front\static\temp
GOOGLE_DRIVE_FOLDER_ID=YourGoogleDriveFolderId
GOOGLE_CLIENT_ID=YourGoogleDriveClientId
GOOGLE_CLIENT_SECRET=YourGoogleDriveSecret
GOOGLE_REFRESH_TOKEN=YourGoogleDriveRefreshToken
WORKER_USER_ID=Storage OAuth
WORKER_APP_NAME=Storage-Data-Backup
KEYCLOAK_ADMIN_PASSWORD=YourAdminPassword
KC_DB_USERNAME=YourUser
KC_DB_PASSWORD=YourPasswordThis ensures your private configuration and connection strings are decoupled from the code.
You need to manually create two databases: one for the inventory application and one for user administration. The recommendations are:
StockDbKeycloakDbFor the last one, don't forget to check the security section to see the special features it requires.
When the container is created, it reads the file infra\keycloak realm-export.json, which contains the configuration for creating the realm, roles, and users needed to get started.
The system orchestrates 6 specialized services:
| Container | Function | Access |
|---|---|---|
| stock-back | Main API (ASP.NET Core) | http://localhost:5000 |
| stock-front | Web Application (Angular) | http://localhost:4200 |
| stock-worker | Background Service (Backups & Cloud Sync) | Logs via Docker |
| stock-cdn | Image Server (Nginx) | http://localhost/cdn/ |
| stock-cleaner | /temp folder cleanup (Python) |
Automated |
| stock-cache | Fast persistence engine (Redis) | Port 6379 |
Important: If you have a local IIS service running on port 80, you must stop it (iisreset /stop) before starting the containers to avoid port conflicts.
This application implements an automated Disaster Recovery Plan (DRP):
The stock-worker utilizes a FileSystemWatcher to detect new images or synchronization files. Once a file is created, it is automatically uploaded to Google Drive, preserving the original folder structure.
Every 12 hours, the Worker instructs SQL Server to generate a Full Backup (.bak).
- Local Resilience: The file is saved directly to the Host's physical volume.
- Cloud Resilience: The Worker detects the new backup and uploads it immediately to the cloud.
- Self-Healing: On startup, the Worker verifies the last existing backup to decide whether to execute a new one, avoiding unnecessary duplication.
The /setup/ folder contains PowerShell scripts to streamline the environment for example:
.\setup\start-all.ps1: Starts the entire ecosystem..\setup\start-cdn.ps1: Only starts the image server (useful for local API debugging).
The project follows a Code-First approach. The following migrations establish the core structure, stored procedures (SPs), and seed data:
dotnet ef migrations add InitialCreate --project Stock.Infrastructure --startup-project Stock.Api
dotnet ef migrations add AddInitialData --project Stock.Infrastructure --startup-project Stock.Api
dotnet ef migrations add AddInitialProcedures --project Stock.Infrastructure --startup-project Stock.Api# Add new migration
dotnet ef migrations add <Name> --project Stock.Infrastructure --startup-project Stock.Api
# Update database
dotnet ef database update --project Stock.Infrastructure --startup-project Stock.Api
# Revert the database to its initial state
dotnet ef database update 0 --project Stock.Infrastructure --startup-project Stock.ApiTo maintain translation integrity in the frontend, we use a Strong Typing system. This prevents typos when calling translation labels from HTML or components.
When new labels are added to the database (Label table), the Angular type contract must be updated.
Run the following script in your database environment to get the updated type string:
SELECT
'export type GlobalizationKey = ' +
STRING_AGG(CAST('''' + Context + '.' + LabelKey + '''' AS VARCHAR(MAX)), ' | ') + ';'
AS TypeScriptType
FROM Label;Once you have the script result (the TypeScriptType column):
- Open the type definition file:
src/app/core/types/globalization-keys.ts - Replace the existing content with the new result.
- The Angular compiler will automatically detect the new keys and validate their use in the TranslateDirective.
Note: By using Clean Architecture, we ensure the presentation layer does not rely on magic strings, but on a defined contract that guarantees each requested label actually exists in the database.
Thanks to this synchronization, usage in components is completely type-safe:
<span translate="Storage.SELECT_BOX"></span>
<span [translate]="'Storage.WRONG_KEY'"></span>This project implements a layered security architecture, delegating identity management to Keycloak. This approach provides:
- Single Sign-On (SSO): Centralized authentication.
- Role-Based Access Control (RBAC): Permissions managed via specific roles.
- JWT Tokens: Secure and standardized communication between the Frontend and the Backend API.
If you need to recreate the database instance for the identity server, follow these requirements:
- Create a database named KeycloakDB.
- Use a UTF8 compatible collation (e.g., Modern_Spanish_100_CI_AS_SC_UTF8 or any other compatible with your specific language).
- Mandatory: Set READ_COMMITTED_SNAPSHOT to ON to prevent transaction locking within Keycloak's internal operations.
USE master;
GO
CREATE DATABASE [KeycloakDb] COLLATE Modern_Spanish_100_CI_AS_SC_UTF8;
GO
ALTER DATABASE [KeycloakDb] SET READ_COMMITTED_SNAPSHOT ON;
GOThe system defines the following profiles to ensure users only access the data and actions they are authorized to perform:
| Role | Descripciรณn | Capabilities |
|---|---|---|
| viewer | General inquiry user | Read-only access. Cannot perform any action. |
| editor | Catalog manager | Authorized to edit brands and categories. Access to administrative forms and catalogs. |
| operator | Inventory manager | Authorized to move stock and handle inventory actions. |
| admin | Full system access | Can manage both inventory, catalogs, and system configurations. |
Note. Users with the same role name were created during the initial load to facilitate testing.
- Hybrid Storage: Files are served locally for speed (CDN) but backed up in the cloud for security.
- Audit Interceptors: Automatic management of
CreatedAtandUpdatedAtin EF Core. - Reactive State: Powered by Angular Signals for a fluid UI experience without unnecessary refreshes.
- Soft Delete Sync: Support for cloud file removal via temporary markers.
- Type-Safe Globalization: Automated synchronization between SQL Server labels and TypeScript Union Types to eliminate magic strings.
- Lazy-Loaded Architecture: Highly optimized bundle sizes with specific chunking for Material components and feature modules.
- Clean Architecture Principles: Strict separation of concerns between Domain, Infrastructure, and Presentation layers.
- Robust Role-Based Security: Fully integrated Keycloak-Angular implementation with functional providers and granular UI visibility through custom directives and computed signals.