Recipe World is a full-stack web application designed to demonstrate enterprise-level software development practices using ASP.NET Core MVC (.NET 8).
This project was built to showcase proficiency in N-Tier Architecture, Secure Authentication, Database Management, and Unit Testing. It features a complete recipe management ecosystem with role-based security, ingredient tracking, and an admin approval workflow.
Live demo: https://recipeworld-p1x5.onrender.com/
The hosted Render demo uses SQLite on the free tier, so seeded sample data can reset on redeploy. Public demo credentials are limited to the demo user; admin credentials and signing keys are supplied through private environment variables.
|
|
|
|
- Clean Architecture: Implements a Service Layer pattern to decouple Controllers from Business Logic and Data Access, ensuring maintainability and testability.
- Identity & Security: Rigorous implementation of ASP.NET Core Identity with Role-Based Access Control (RBAC) to differentiate between Administrators and Standard Users.
- Database Engineering: Utilizes Entity Framework Core with a Code-First approach, including complex relationships (Many-to-Many for Recipes-Ingredients), lazy loading proxies, and robust seeding strategies.
- Quality Assurance: Includes a test project (
worldRecipeMvc.Tests) utilizing xUnit and Moq to verify business logic isolation using an In-Memory database. - Hybrid Interface: Features both a traditional MVC frontend and a Swagger-documented API layer, demonstrating versatility in handling different client types.
| Category | Technologies |
|---|---|
| Framework | .NET 8, ASP.NET Core MVC |
| Data Access | Entity Framework Core (SQL Server), LINQ |
| Authentication | ASP.NET Core Identity (Cookies & JWT Support) |
| Frontend | Razor Views, Bootstrap 5, jQuery Validation, CSS3 |
| Testing | xUnit, Moq, EF Core In-Memory DB |
| Tools | Swagger/OpenAPI, Dependency Injection (DI), Git |
The solution follows a separation of concerns principle to ensure scalability:
graph TB
subgraph Presentation["π¨ Presentation Layer"]
VIEWS["Razor Views<br/>(UI/UX)"]
MVC["MVC Controllers<br/>(Orchestration)"]
API["API Controllers<br/>(REST Endpoints)"]
MW["Middleware<br/>Global Error Handling"]
end
subgraph Application["βοΈ Business Logic Layer"]
SVC["Services<br/>(RecipeService, IngredientService)"]
DTO["DTOs & ViewModels<br/>(Data Transfer)"]
end
subgraph Infrastructure["π§ Infrastructure Layer"]
DBCTX["EF Core DbContext<br/>(Data Access)"]
ID["Identity Provider<br/>(Auth & Roles)"]
SQL["SQL Server"]
end
VIEWS --> MVC
MVC --> SVC
API --> SVC
MW --> MVC
SVC --> DTO
SVC --> DBCTX
DBCTX --> SQL
ID --> DBCTX
style Application fill:#2196F3,color:#fff
style Infrastructure fill:#FF9800,color:#fff
style Presentation fill:#4CAF50,color:#fff
- Recipe management: Users can create, read, update, and delete (CRUD) their own recipes.
- Favorites: Bookmark recipes with one click and revisit them on a personal My Favorites page.
- Ratings & reviews: 1β5 star reviews with comments; averages shown on cards and detail pages.
- Trending home page: Top-rated and most-favorited recipes, served from an in-memory cache.
- Smart search & pagination: Search and windowed pagination across recipes, categories, and ingredients.
- Image handling: Uploads validated by extension, size, and file signature (magic bytes).
- Approval workflows: New ingredients and categories enter a Pending state and require admin approval.
- Role management: Distinct capabilities for Admin vs User roles, enforced in the service layer.
- Rate limiting: Per-IP global limits plus a strict policy on the login endpoint (HTTP 429).
- Configurable seeding: Demo/admin account passwords come from configuration; production secrets are supplied by environment variables, not source files.
- REST API with JWT:
POST /api/auth/loginissues Bearer tokens; endpoints documented in Swagger UI. - Result pattern: Services return FluentResults
Result<T>mapped to proper HTTP codes (400/403/404/409). - Testing: 90 tests β xUnit service tests (EF Core In-Memory) plus full integration tests
(
WebApplicationFactory+ SQLite in-memory) covering auth, rate limiting, and the API surface. - Observability: Serilog structured logging and a
/healthendpoint.
High-level overview of where to find things:
src/worldRecipeMvc/β main ASP.NET Core MVC applicationControllers/β MVC controllers andControllers/Api/REST endpointsDTOs/β DTOs used by the API layerServices/β business logic (service layer)Data/β EF Core DbContext, migrations, seedingModels/β domain entities andModels/ViewModels/used by viewsMiddleware/β custom middleware (global error handling)Views/β Razor viewswwwroot/β static assets (CSS/JS/images)
src/worldRecipeMvc.Tests/β xUnit test project (service-level tests)img/worldRecipeMvc/wwwroot/images/recipes/β image storage folder used for uploadssql/β optional SQL scripts/utilities
- .NET 8 SDK
- SQL Server Express or LocalDB
- Clone the repository
git clone https://github.com/MatheusFerraro/RecipeWorld.git
cd RecipeWorld- Configure database
Update the connection string in src/worldRecipeMvc/appsettings.json if you are not using a local SQL Server:
{
"ConnectionStrings": {
"RecipeWorldConnectionString": "Server=(local);Database=WorldRecipeDb;Trusted_Connection=True;MultipleActiveResultSets=true;Encrypt=false"
}
}- Run the application (migrations and sample data are applied automatically at startup)
dotnet run --project src/worldRecipeMvc- Web UI: https://localhost:7008 (port may vary)
- Swagger API: https://localhost:7008/swagger
- Health check: https://localhost:7008/health
Demo account: demo@recipeworld.com / Demo123!
For local development, you can also seed an admin account by setting SeedData:AdminPassword in user secrets, an ignored appsettings.Development.json, or environment variables. Do not commit real admin passwords, JWT keys, database passwords, or .env files.
The compose stack includes the app and a SQL Server 2022 container, with named volumes for database data and uploaded images:
cp .env.example .env # set MSSQL_SA_PASSWORD and JWT_KEY
docker compose up --buildThen open http://localhost:8080 β see README.Docker.md for details.
# 1. Get a token
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"demo@recipeworld.com","password":"Demo123!"}'
# 2. Call authenticated endpoints with the Bearer token
curl -X POST http://localhost:8080/api/RecipesApi \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"recipeName":"My Recipe","instructions":"1. Cook."}'dotnet test worldRecipeMvc.sln90 tests: service-level unit tests (xUnit + EF Core In-Memory) and end-to-end integration
tests (WebApplicationFactory over SQLite in-memory) covering the API, JWT auth, rate limiting,
and MVC smoke paths.
MIT β see LICENSE.
I am currently looking for internship or junior developer opportunities.



