Lofn is a multi-tenant sales and e-commerce platform backend built with .NET 8 following Clean Architecture principles. It provides a GraphQL API (via HotChocolate) for read operations and REST API for write operations, managing products, categories, stores, and multi-tenant networks with sellers. Supports payment processing via Stripe, file storage with AWS S3, and delegated authentication through NAuth.
The solution is organized into 8 layered projects with clear dependency boundaries, including a dedicated Lofn.GraphQL project for all GraphQL schemas, queries, and type extensions.
- πͺ Multi-Tenant Networks - Support for multiple seller networks with isolated data via TenantResolver
- π¦ Product Management - Full CRUD with slug generation, image handling, discount, product types, and paged search
- π Shopping Cart - ShopCart entity for cart management
- π·οΈ Category Management - Categories with automatic product count
- π GraphQL API - HotChocolate-powered queries with projection, filtering, and sorting
- π‘ REST API - Write operations with Swagger documentation
- π³ Stripe Integration - Payment processing with Stripe product/price IDs
- π NAuth Authentication - Delegated Bearer token authentication via custom handler
- βοΈ AWS S3 Storage - File upload and signed URL resolution
- π§ zTools Integration - ChatGPT, email sending, file management utilities
- π Swagger/OpenAPI - Auto-generated API documentation
- π³ Docker Support - Docker Compose for development and production
- π CI/CD - GitHub Actions for versioning, releases, NuGet publishing, and deployment
- .NET 8 - Backend runtime and SDK
- ASP.NET Core - Web API framework
- HotChocolate 14.3 - GraphQL server with projection, filtering, and sorting
- HotChocolate.Data.EntityFramework - EF Core integration for IQueryable resolvers
- PostgreSQL 17 - Primary relational database
- Entity Framework Core 9 - ORM with lazy loading proxies
- Npgsql - PostgreSQL provider for EF Core
- NAuth - External authentication service integration
- Custom RemoteAuthHandler - Bearer token validation middleware
- Stripe.net - Payment gateway integration
- AWSSDK.S3 - Amazon S3 file storage
- SixLabors.ImageSharp - Image processing
- Newtonsoft.Json - JSON serialization
- Swashbuckle - Swagger/OpenAPI documentation
- xUnit 2.9 - Test framework
- Moq 4.20 - Mocking library
- coverlet - Code coverage
- Docker - Containerization with multi-stage builds
- Docker Compose - Service orchestration (API + PostgreSQL)
- GitHub Actions - CI/CD pipelines (versioning, NuGet publishing, releases, deployment)
- GitVersion - Semantic versioning from conventional commits
Lofn/
βββ Lofn.API/ # Web API entry point
β βββ Controllers/ # REST controllers (Product, Category, Store, Image, StoreUser, ShopCart)
β βββ Middlewares/ # TenantMiddleware
β βββ Startup.cs # DI, auth, CORS, Swagger, GraphQL endpoints
β βββ Dockerfile # Multi-stage Docker build
βββ Lofn.GraphQL/ # GraphQL schemas and resolvers
β βββ Public/ # Public queries (stores, products, categories)
β βββ Admin/ # Authenticated queries (myStores, myProducts, myCategories)
β βββ Types/ # Type extensions (logoUrl, imageUrl, productCount)
β βββ GraphQLServiceExtensions.cs # Schema registration
β βββ GraphQLErrorLogger.cs # Error diagnostics
βββ Lofn.Application/ # DI bootstrap (ConfigureLofn)
βββ Lofn.Domain/ # Business logic layer
β βββ Interfaces/ # Service contracts
β βββ Models/ # Domain models
β βββ Services/ # Service implementations
β βββ Mappers/ # Model β DTO mappers
βββ Lofn/ # Shared package (DTOs + ACL)
β βββ ACL/ # Anti-Corruption Layer (external API clients)
β βββ DTO/ # Data Transfer Objects (Product, Category, Store, ShopCart)
βββ Lofn.Infra.Interfaces/ # Repository interfaces (IUnitOfWork, IRepository)
βββ Lofn.Infra/ # Infrastructure implementation
β βββ Context/ # EF Core DbContext + entities
β βββ Repository/ # Repository implementations
βββ Lofn.Tests/ # Unit tests (xUnit + Moq)
βββ bruno-collection/ # Bruno API testing collection
βββ scripts/ # Seed scripts (info-store.py)
βββ docs/ # Documentation
βββ docker-compose.yml # Development (API + PostgreSQL)
βββ docker-compose-prod.yml # Production
βββ lofn.sql # Database creation script
βββ .github/workflows/ # CI/CD (versioning, NuGet, releases, deploy)
βββ GitVersion.yml # Semantic versioning config
βββ Lofn.sln # Solution file
βββ README.md # This file
The following diagram illustrates the high-level architecture of Lofn:
Dependency flow: API / GraphQL β Application β Domain β Infra β PostgreSQL
- Lofn.API receives REST requests and delegates to Domain services
- Lofn.GraphQL handles GraphQL queries directly against EF Core DbContext with type extensions for computed fields
- Lofn.Application bootstraps all DI registrations via
ConfigureLofn()and manages multi-tenant context - Lofn.Domain contains business rules, service implementations, and domain models
- Lofn (Shared) provides DTOs and ACL clients for external consumers
- Lofn.Infra implements repositories using EF Core 9 with PostgreSQL
π Source: The editable Mermaid source is available at
docs/system-design.mmd.
| Document | Description |
|---|---|
| API_REFERENCE.md | Complete REST and GraphQL API reference with all endpoints, DTOs, enums, and examples |
Before running the application, configure the environment variables:
cp .env.example .env# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password_here
POSTGRES_DB=lofn
# Tenant: monexup
MONEXUP_CONNECTION_STRING=Host=db;Port=5432;Database=lofn;Username=postgres;Password=your_password_here
MONEXUP_JWT_SECRET=dev-jwt-secret-min-32-chars-long-here
# Lofn
LOFN_BUCKET_NAME=lofn
# NAuth
NAUTH_API_URL=https://your-nauth-url/auth-api
NAUTH_BUCKET_NAME=nauth
# zTools
ZTOOLS_API_URL=https://your-ztools-url/tools-api
# App
APP_PORT=5000- Never commit the
.envfile with real credentials - Only
.env.exampleand.env.prod.exampleshould be version controlled - Change all default passwords and secrets before deployment
# Create the external Docker network (shared with other services)
docker network create emagine-networkdocker-compose up -d --buildThis starts:
- lofn-api - .NET 8 API on port 5000 (configurable via
APP_PORT) - lofn-db - PostgreSQL 17 on port 5432
docker-compose ps
docker-compose logs -f api| Service | URL |
|---|---|
| API | http://localhost:5000 |
| Swagger UI | http://localhost:5000/swagger/ui |
| GraphQL Playground | http://localhost:5000/graphql |
| GraphQL Admin | http://localhost:5000/graphql/admin |
| Health Check | http://localhost:5000/ |
| Action | Command |
|---|---|
| Start services | docker-compose up -d |
| Start with rebuild | docker-compose up -d --build |
| Stop services | docker-compose stop |
| View status | docker-compose ps |
| View logs | docker-compose logs -f |
| Remove containers | docker-compose down |
| Remove containers and volumes | docker-compose down -v |
docker-compose -f docker-compose-prod.yml up -d --buildgit clone https://github.com/emaginebr/Lofn.git
cd Lofnpsql -U postgres -c "CREATE DATABASE lofn;"
psql -U postgres -d lofn -f lofn.sqldotnet build Lofn.slndotnet run --project Lofn.APIThe API will be available at https://localhost:44374.
All Tests:
dotnet test Lofn.slnWith Coverage:
dotnet test Lofn.sln --collect:"XPlat Code Coverage"Lofn.Tests/
βββ Domain/
β βββ Mappers/ # DTO β Model mapping tests
β β βββ CategoryMapperTest.cs
β β βββ ProductMapperTest.cs
β β βββ StoreMapperTest.cs
β βββ Services/ # Business logic tests
β βββ CategoryServiceTest.cs
β βββ ProductServiceTest.cs
β βββ StoreServiceTest.cs
β βββ StoreUserServiceTest.cs
1. Client sends Bearer token β 2. RemoteAuthHandler validates via NAuth β 3. TenantMiddleware resolves tenant β 4. Request processed
| Endpoint | Auth | Queries |
|---|---|---|
POST /graphql |
No | stores, products, categories, storeBySlug, featuredProducts |
POST /graphql/admin |
Yes | myStores, myProducts, myCategories |
Example query:
{
stores {
storeId
name
logoUrl
products {
name
price
discount
imageUrl
productImages { imageUrl sortOrder }
}
categories {
name
productCount
}
}
}| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /product/{storeSlug}/insert |
Create product | Yes |
| POST | /product/{storeSlug}/update |
Update product | Yes |
| POST | /product/search |
Search products (paged) | No |
| POST | /category/{storeSlug}/insert |
Create category | Yes |
| POST | /category/{storeSlug}/update |
Update category | Yes |
| DELETE | /category/{storeSlug}/delete/{id} |
Delete category | Yes |
| POST | /store/insert |
Create store | Yes |
| POST | /store/update |
Update store | Yes |
| POST | /store/uploadLogo/{storeId} |
Upload logo | Yes |
| DELETE | /store/delete/{storeId} |
Delete store | Yes |
| POST | /image/upload/{productId} |
Upload image | Yes |
| GET | /image/list/{productId} |
List images | Yes |
| DELETE | /image/delete/{imageId} |
Delete image | Yes |
| POST | /shopcar/insert |
Create shopping cart | Yes |
| GET | /storeuser/{storeSlug}/list |
List store members | Yes |
| POST | /storeuser/{storeSlug}/insert |
Add store member | Yes |
| DELETE | /storeuser/{storeSlug}/delete/{id} |
Remove store member | Yes |
Full interactive documentation available at
/swagger/uiwhen running the API.
Complete API reference with DTOs, enums, and examples at
docs/API_REFERENCE.md.
- Bearer Token - All protected endpoints require a valid Bearer token
- Remote Validation - Tokens are validated against the NAuth external service
- Session Management - User context (userId, session) maintained per request
- Multi-Tenant Isolation - Tenant-specific database connections and JWT secrets
- CORS - Configurable cross-origin resource sharing
- Request Size Limits - 100MB limit for file upload endpoints
psql -U postgres -d lofn -f lofn.sqlpg_dump -U postgres lofn > backup_lofn_$(date +%Y%m%d).sqlpsql -U postgres -d lofn < backup_lofn_20260319.sql| Workflow | Trigger | Description |
|---|---|---|
| Version & Tag | Push to main |
Creates semantic version tags using GitVersion |
| Create Release | After version tag | Creates GitHub releases for minor/major versions |
| Publish NuGet | After version tag | Builds and publishes the Lofn NuGet package |
| Deploy Prod | Manual dispatch | Deploys to production via SSH |
Versioning strategy (GitVersion - ContinuousDelivery):
feat:/feature:β Minor version bumpfix:/patch:β Patch version bumpbreaking:/major:β Major version bump
A Python script is available to populate a demo store with products and AI-generated images:
cd scripts
pip install requests python-dotenv openai
python info-store.pyThe script creates a "Loja de Informatica" with 30 products across 6 categories (Notebooks, Processors, RAM, Storage, Cases, Keyboards, Mice), including discount and featured flags.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Make your changes
- Run tests (
dotnet test Lofn.sln) - Commit your changes using conventional commits (
git commit -m 'feat: add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow Clean Architecture dependency rules
- Use conventional commits for semantic versioning
- All new endpoints must include authorization where appropriate
- Repository pattern for all data access
- Read operations via GraphQL, write operations via REST
Developed by Rodrigo Landim Carneiro
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with .NET 8
- GraphQL powered by HotChocolate
- Database powered by PostgreSQL
- ORM by Entity Framework Core
- Payments by Stripe
- Image processing by SixLabors ImageSharp
- Issues: GitHub Issues
- Discussions: GitHub Discussions
β If you find this project useful, please consider giving it a star!
