Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/JReyna217/PharmaVault/llms.txt

Use this file to discover all available pages before exploring further.

PharmaVault is structured as a clean N-Tier application split across three .NET 10 projects. Each layer has a single, well-defined responsibility, and dependencies only flow in one direction — from the outer layers inward toward the domain core. This means business rules never depend on infrastructure details, and swapping a data access implementation requires no changes to the Core or Web layers.

The Three Layers

PharmaVault.Core

Domain layer. Contains all domain models (User, Inventory, MedicineCatalog, ErrorLog, SystemResponse), DTOs, and every interface that defines the contracts for data access and services. Has zero external project dependencies — it does not reference Data or Web.Key dependency: BCrypt.Net-Next 4.1.0 for password hashing.

PharmaVault.Data

Infrastructure layer. Implements the DAO interfaces from Core using raw ADO.NET with the Npgsql driver. Houses NpgsqlExtensions for lightweight reflection-based object mapping and all SQL queries. References Core only.Key dependencies: Npgsql 10.0.2, Microsoft.Extensions.Configuration.Abstractions 10.0.5.

PharmaVault.Web

Presentation layer. ASP.NET Core Blazor Server application. Hosts Razor components, middleware (ExceptionHandlingMiddleware), cookie authentication, and service registration in Program.cs. References both Core and Data.Key dependencies: BCrypt.Net-Next 4.1.0, Blazor-ApexCharts 6.1.0.

Dependency Direction

The dependency graph is strictly unidirectional:
PharmaVault.Web
    ├── PharmaVault.Core   (domain models + interfaces)
    └── PharmaVault.Data
            └── PharmaVault.Core
  • Core has no references to Data or Web. It is independently compilable and testable.
  • Data references Core to implement its interfaces and use domain models as return types.
  • Web references both Core (for interfaces and models in Blazor components) and Data (to register concrete implementations in the DI container).
All three projects target net10.0, as declared in each .csproj file. .NET 10 is required to build and run PharmaVault.

Interface-Based Design

All data access operations are expressed as interfaces declared in PharmaVault.Core.Interfaces. The Web layer consumes only these interfaces — never a concrete DAO class — making the data access layer fully replaceable without touching component code.
public interface IUserDao
{
    Task<User?> GetByEmailAsync(string email);
    Task<int> CreateAsync(User user);
}
public interface IMedicineCatalogDao
{
    Task<IEnumerable<MedicineCatalog>> GetAllAsync();
    Task<int> CreateAsync(MedicineCatalog medicine);
    Task<bool> UpdateAsync(MedicineCatalog medicine);
    Task<bool> ToggleActiveAsync(int catalogId, bool isActive);
}
public interface IInventoryDao
{
    Task<IEnumerable<InventoryItemDto>> GetUserInventoryAsync(int userId);
    Task<int> AddToInventoryAsync(Inventory inventory);
    Task<bool> UpdateInventoryAsync(Inventory inventory);
    Task<bool> DeleteFromInventoryAsync(int inventoryId, int userId);
    Task<DashboardStatsDto> GetDashboardStatsAsync(int userId);
}
public interface IErrorLogDao
{
    Task<Guid> LogErrorAsync(ExceptionLogDto request, int? userId = null);
}
public interface IAuthService
{
    Task<int> RegisterAsync(User user, string plainPassword);
    Task<User?> LoginAsync(string email, string plainPassword);
}

Dependency Injection

All services and DAOs are registered with a scoped lifetime in Program.cs. Scoped means one instance per HTTP request, which is the correct lifetime for database connections in Blazor Server.
Program.cs
// DAOs — infrastructure implementations of Core interfaces
builder.Services.AddScoped<IUserDao, UserDao>();
builder.Services.AddScoped<IMedicineCatalogDao, MedicineCatalogDao>();
builder.Services.AddScoped<IInventoryDao, InventoryDao>();
builder.Services.AddScoped<IErrorLogDao, ErrorLogDao>();

// Services — business logic implementations of Core interfaces
builder.Services.AddScoped<IAuthService, AuthService>();

Service registration table

InterfaceImplementationLayer
IUserDaoUserDaoData
IMedicineCatalogDaoMedicineCatalogDaoData
IInventoryDaoInventoryDaoData
IErrorLogDaoErrorLogDaoData
IAuthServiceAuthServiceCore/Services

Data Access Pattern

PharmaVault uses a custom ADO.NET approach rather than Entity Framework Core. All queries are written as raw SQL executed through NpgsqlCommand, and result sets are mapped to domain model objects via the NpgsqlExtensions helper class in PharmaVault.Data.Extensions. NpgsqlExtensions provides two primary methods:
NpgsqlExtensions.cs
// Map a result set to a List<T> using reflection
public static async Task<List<T>> FillToObjectListAsync<T>(this NpgsqlCommand dbCommand) where T : new()

// Map the first row of a result set to a single T?
public static async Task<T?> FillToObjectAsync<T>(this NpgsqlCommand dbCommand) where T : class, new()
The mapper matches column names to C# property names (case-insensitively), handles DBNull safely, and performs type coercion for booleans, DateTime, and enums. This gives DAO authors the same convenience as a micro-ORM like Dapper while keeping the full SQL query visible and editable.
The raw-SQL / ADO.NET approach was chosen to keep query logic fully explicit and to avoid the migration overhead that comes with EF Core when working directly against a PostgreSQL schema managed by hand-authored SQL scripts.

Middleware Pipeline

The HTTP middleware pipeline is assembled in Program.cs in the following order:
1

Exception handler / HSTS (production only)

In non-Development environments, unhandled exceptions are routed to /Error and HSTS headers are added.
2

Status code pages

UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true) serves a custom 404 page for all unmatched routes.
3

HTTPS redirection

All HTTP requests are permanently redirected to HTTPS.
4

ExceptionHandlingMiddleware

Custom middleware that catches unhandled exceptions, logs them to the error_logs table via IErrorLogDao, and returns a structured error response.
5

Authentication and Authorization

Cookie authentication (PharmaVaultSession) is validated on every request.
6

Antiforgery

CSRF protection for all Blazor Server form interactions.
7

Static assets and Razor components

Static files are served, then Razor components are mapped with Interactive Server render mode enabled.

Build docs developers (and LLMs) love