A comprehensive property management system built with .NET 6 backend, Angular 21 frontend, and microservices architecture featuring real-time messaging, email notifications, and access logging capabilities.
- Overview
- Screenshots
- Architecture
- Technology Stack
- Project Structure
- Features
- Prerequisites
- Installation
- Configuration
- Running the Application
- Deployment
- API Documentation
- Testing
- Contributing
Property Master V4.0 is a full-stack property management application designed with a modern microservices architecture. The system handles property listings, partner management, bookings, transactions, and includes advanced features like real-time access logging, email notifications, and comprehensive API versioning.
- Clean Architecture: Domain-Driven Design (DDD) with CQRS pattern using MediatR
- Microservices: Separate worker services for access logging and email processing
- Real-time Communication: SignalR integration for live updates
- Message Queue: RabbitMQ for asynchronous event processing
- NoSQL Database: MongoDB for flexible data storage
- Authentication: JWT-based authentication with Google OAuth2 support
- API Versioning: RESTful API with Swagger/OpenAPI documentation
- Containerization: Full Docker support with docker-compose orchestration
- Cloud Deployment: Deployed on Microsoft Azure (Azure App Service + Azure Static Web Apps)
To add screenshots: Create a
docs/screenshots/folder in the repo root, place your.pngimages there, commit them, and they will display here automatically.
The application follows a Clean Architecture pattern with clear separation of concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Presentation Layer β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Angular 21 SPA β β WebAPI (.NET) β β
β β (Frontend) βββββββββββββββΊβ Controllers β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MediatR (CQRS) β AutoMapper β FluentValidation β β
β β Commands/Queries β Behaviors β Validators β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Domain Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Entities β Value Objects β Domain Events β β
β β Product β Partner β Property β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Infrastructure Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MongoDB β RabbitMQ β JWT Auth β Serilog β β
β β Identity β AutoMapper β Azure KV β Redis β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Worker Services β
β βββββββββββββββββββββββββ ββββββββββββββββββββββββββββ β
β β AccessLogWorker β β EmailWorker β β
β β (.NET 8 Background) β β (.NET 8 Background) β β
β β Consumes RabbitMQ β β Processes Email Outbox β β
β βββββββββββββββββββββββββ ββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β WebAPI ββββββββββΊβ RabbitMQ ββββββββββΊβ AccessLog β
β β Publish β Exchange β Consume β Worker β
β β β + Queue β β β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β MongoDB β
β Storage β
ββββββββββββββββ
- .NET 6.0 - Main WebAPI framework
- .NET 8.0 - Worker services (AccessLogWorker, EmailWorker)
- C# 10.0 - Programming language
- ASP.NET Core 6.0 - Web framework
- MediatR 10.0.1 - CQRS and Mediator pattern implementation
- AutoMapper 11.0.0 - Object-to-object mapping
- FluentValidation 11.1.0 - Input validation
- Clean Architecture - Separation of concerns
- Domain-Driven Design (DDD) - Domain modeling
- MongoDB 2.19.1 / 3.6.0 - Primary NoSQL database
- Used for: Properties, Partners, Products, Bookings, Transactions, Users, Access Logs
- Custom repository pattern with Unit of Work
- Connection string: MongoDB Atlas or Azure Cosmos DB for MongoDB
- Entity Framework Core 6.0.6 - ORM (for SQL Server support)
- AspNetCore.Identity.MongoDbCore 3.1.2 - Identity management with MongoDB
- Redis - Caching layer (configured, connection:
machost:6379)
- RabbitMQ.Client 7.2.0/7.2.1 - Message broker
- CloudAMQP (raccoon.lmq.cloudamqp.com) - Hosted RabbitMQ service
- Exchange:
accesslog.exchange(Direct) - Queue:
accesslog.queue - Routing Key:
accesslog - SSL/TLS enabled (Port 5671)
- Used for: Access log event streaming, asynchronous processing
- Microsoft.AspNetCore.Authentication.JwtBearer 6.0.6 - JWT authentication
- Microsoft.IdentityModel.Tokens - Token validation
- Google.Apis.Auth 1.57.0 - Google OAuth2 authentication
- Azure.Identity 1.6.0 - Azure authentication
- Azure Key Vault - Secret management (optional)
- Azure.Extensions.AspNetCore.Configuration.Secrets 1.2.2
- Serilog 5.0.0 - Structured logging
- Serilog.AspNetCore
- Serilog.Enrichers.Environment 2.2.0
- Serilog.Sinks.Loggly 5.4.0
- Loggly - Cloud-based log management (configured)
- File logging to
logs/Error_log-.txt - Enrichers: MachineName, ProcessId, ThreadId, LogContext
- Swashbuckle.AspNetCore 6.3.1 - Swagger/OpenAPI
- Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer 5.0.0 - API versioning
- Custom Swagger filters for authorization and grouping
- Resend 0.2.1 - Modern email API service (EmailWorker)
- MailKit 4.14.1 - Email client library
- FluentEmail.Core 3.0.2 - Email composition
- Outbox pattern for reliable email delivery
- Microsoft.AspNetCore.SignalR 1.1.0 - Real-time web functionality
- ChatHub implementation for live messaging
- Microsoft.CodeAnalysis.NetAnalyzers 6.0.0 - Static code analysis
- Microsoft.EntityFrameworkCore.Design 6.0.6 - Design-time tools
- Microsoft.VisualStudio.Azure.Containers.Tools.Targets - Docker integration
- StringToExpression 1.1.1 - Dynamic LINQ expressions
- Angular 21.1.1 - Single Page Application framework
- TypeScript 5.9.3 - Programming language
- RxJS 7.8.0 - Reactive programming
- Zone.js 0.15.0 - Execution context management
- Angular Material 21.1.1 - Material Design components
- @angular/cdk 21.1.1 (Component Dev Kit)
- FontAwesome 7.1.0 - Icon library
- @fortawesome/angular-fontawesome 4.0.0
- @fortawesome/fontawesome-svg-core 7.1.0
- @fortawesome/free-solid-svg-icons 7.1.0
- jwt-decode 4.0.0 - JWT token decoding
- Express 5.1.0 - Server-side rendering (SSR)
- @angular/ssr - Angular Server-Side Rendering
- @angular/cli 21.1.1 - Command-line interface
- @angular/build 21.1.1 - Build system
- @angular/compiler-cli 21.1.1 - Template compiler
- Jasmine 5.7.0 - Testing framework
- Karma 6.4.0 - Test runner
- karma-chrome-launcher
- karma-coverage
- karma-jasmine 5.1.0
- karma-jasmine-html-reporter 2.1.0
- Docker - Container platform
- Multi-stage Dockerfiles for optimized images
- .dockerignore for build optimization
- Docker Compose - Multi-container orchestration
- Services: api, accesslog-worker, mongo, rabbitmq
- Volumes: mongo-data, rabbitmq-data
-
Azure App Service - Backend hosting
- Resource Group:
rg-propertymaster-dev - Region: France Central
- WebAPI:
https://propertymaster-api-de09-h0hqbzgsc4arfvez.francecentral-01.azurewebsites.net - Environment variable management via Azure App Service Configuration
- Published via Web Deploy
- Resource Group:
-
Azure Static Web Apps - Frontend hosting
- Angular SPA deployment:
https://brave-rock-0db8c8503.7.azurestaticapps.net - Global CDN distribution
- SPA navigation fallback via
staticwebapp.config.json
- Angular SPA deployment:
-
CloudAMQP - Managed RabbitMQ service
- Host: raccoon.lmq.cloudamqp.com
- Plan: Free tier with SSL
- Virtual host: fqccxvvi
-
Resend.com - Email delivery service
- Transactional email API
- High deliverability rates
- Git - Source control
- GitHub - Repository hosting
- Repository:
https://github.com/NevilleColaco23/testAngularAPIDocker - Branch: Mar2026
- Repository:
- Messaging.Shared - Custom shared library
- Multi-targeting: .NET 6.0 and .NET 8.0
- RabbitMQ models and interfaces
- AccessLogEvent models
- Newtonsoft.Json 13.0.3 - JSON serialization
- System.Text.Json - Built-in JSON handling
PropertyMasterV4.0/
β
βββ π app/ # Angular Frontend
β βββ src/
β β βββ app/
β β β βββ core/ # Core modules (auth, system)
β β β βββ Menu/ # Menu components
β β β βββ property/ # Property feature module
β β β βββ environments/ # Environment configs
β β βββ public/ # Static assets
β β βββ styles/ # Global styles
β βββ angular.json # Angular configuration
β βββ package.json # NPM dependencies
β βββ tsconfig.json # TypeScript config
β
βββ π WebApi/ # Main Web API Project
β βββ API/
β β βββ V1/ # Version 1 API endpoints
β β β βββ AccountController.cs # Authentication endpoints
β β β βββ PropertyController.cs # Property CRUD
β β β βββ PartnerController.cs # Partner management
β β β βββ ProductController.cs # Product management
β β β βββ BookingsController.cs # Booking operations
β β β βββ TransactionController.cs # Transaction handling
β β β βββ AccessLoggingController.cs # Access log endpoints
β β β βββ MessageController.cs # Messaging endpoints
β β βββ DomainControllers/
β β β βββ MenuController.cs # Menu/Navigation
β β βββ ApiStartup.cs # API configuration
β β
β βββ Authentication/ # Auth services
β β βββ Services/
β β β βββ CurrentUserService.cs # Current user context
β β βββ Dtos/ # Auth DTOs
β β βββ AuthenticationStartup.cs
β β
β βββ Messaging Queue/
β β βββ RabbitMqPublisher.cs # RabbitMQ publisher
β β
β βββ SignalR/
β β βββ ChatHub.cs # Real-time chat hub
β β
β βββ CORS/ # CORS configuration
β βββ ErrorHandling/ # Global error handling
β βββ Logging/ # Logging configuration
β βββ Swagger/ # API documentation
β βββ Versioning/ # API versioning
β β
β βββ Program.cs # Application entry point
β βββ Startup.cs # Services configuration
β βββ Dockerfile # Docker configuration
β βββ docker-compose.yml # Multi-container setup
β βββ appsettings.json # Application settings
β βββ WebApi.csproj # Project file
β
βββ π classfiles/ # Core Business Logic
β β
β βββ π Domain/ # Domain Layer (Entities)
β β βββ Property/
β β β βββ Property.cs # Property entity
β β βββ Partners/
β β β βββ Partner.cs # Partner entity
β β β βββ Address.cs # Value object
β β βββ Products/
β β β βββ Product.cs # Product entity
β β βββ Bookings/
β β β βββ Bookings.cs # Booking entity
β β βββ Transactions/
β β β βββ Transaction.cs # Transaction entity
β β β βββ TransactionLine.cs # Transaction details
β β βββ AccessLog/
β β β βββ AccessLog.cs # Access log entity
β β βββ Users/
β β β βββ Users.cs # User entity
β β βββ Common/
β β β βββ Menus/ # Menu entities
β β β βββ ValueObjects/ # Money, Mass value objects
β β β βββ IEntity.cs # Entity interface
β β β βββ IAudited.cs # Audit interface
β β β βββ ISoftDeletable.cs # Soft delete interface
β β βββ Domain.csproj
β β
β βββ π Application/ # Application Layer (CQRS)
β β βββ Property/
β β β βββ CreateProperty/
β β β β βββ CreatePropertyCommand.cs
β β β βββ GetProperty/
β β β β βββ GetPropertyListQuery.cs
β β β β βββ GetPropertyDTO.cs
β β β βββ UpdateProperty/
β β β βββ UpdatePropertyCommand.cs
β β βββ Partners/
β β β βββ UpdatePartner/
β β β βββ DeletePartner/
β β βββ Products/
β β β βββ UpdateProduct/
β β β βββ DeleteProduct/
β β βββ Logging/
β β β βββ CreateLog/
β β β βββ CreateLogCommand.cs
β β βββ Common/
β β β βββ Behaviors/
β β β β βββ RequestValidationBehavior.cs
β β β β βββ ExceptionLoggingBehavior.cs
β β β βββ Dependencies/
β β β βββ DataAccess/
β β β βββ Repositories/
β β βββ ApplicationStartup.cs # Application DI setup
β β βββ Application.csproj
β β
β βββ π Infrastructure/ # Infrastructure Layer
β β βββ Authentication/ # JWT, OAuth2
β β β βββ Core/
β β β β βββ Services/
β β β β βββ UserService.cs
β β β β βββ JwtTokenService.cs
β β β βββ External/
β β β β βββ Services/
β β β β βββ ExternalAuthenticationVerifier.cs
β β β β βββ ExternalSignInService.cs
β β β βββ Startup.cs
β β βββ Identity/ # ASP.NET Identity
β β βββ Persistence/ # Data access
β β βββ AzureKeyVault/ # Secret management
β β βββ ApplicationDependencies/ # DI configuration
β β βββ InfrastructureStartup.cs
β β βββ Infrastructure.csproj
β β
β βββ π MongoDBBackend/ # MongoDB Abstraction
β β βββ IMongoRepository.cs # Repository interface
β β βββ MongoRepository.cs # Repository implementation
β β βββ MongoContext.cs # DB context
β β βββ MongoUnitOfWork.cs # Unit of work pattern
β β βββ CounterService.cs # Auto-increment IDs
β β βββ MongoDBBackend.csproj
β β
β βββ π SampleData/ # Seed data
β βββ SampleData.csproj
β
βββ π AccessLogWorker/ # Access Log Consumer Service
β βββ Services/
β β βββ AccessLogMessageProcessor.cs # Message processing logic
β βββ Worker.cs # Background service
β βββ Program.cs # Entry point
β βββ Dockerfile # Docker config
β βββ appsettings.json # Worker settings
β βββ AccessLogConsumerWorker.csproj
β
βββ π EmailWorker/ # Email Processing Service
β βββ ResendEmailSender.cs # Resend integration
β βββ Worker.cs # Background service
β βββ Program.cs # Entry point
β βββ Dockerfile # Docker config
β βββ appsettings.json # Worker settings
β βββ EmailWorker.csproj
β
βββ π Messaging.Shared/ # Shared Messaging Library
β βββ Models/
β β βββ AccessLogEvent.cs # Event model
β βββ RabbitMqOptions.cs # Configuration model
β βββ IRabbitMqPublisher.cs # Publisher interface
β βββ Messaging.Shared.csproj
β
βββ π APIUnitProject.Tests/ # Unit Tests
β βββ APIUnitProject.Tests.csproj
β
βββ π Project.Documentation/ # Documentation
β βββ Messaging Queue/
β β βββ README.md.txt
β βββ Project.Documentation.csproj
β
βββ .dockerignore # Docker ignore file
βββ PropertyMasterV4.0.sln # Solution file
- Create, Read, Update, Delete (CRUD) properties
- Property listing with filtering and pagination
- Image upload and management
- Property details with rich metadata
- Partner profiles and contact information
- Address management (Value Object pattern)
- Partner-specific business rules (invariants)
- Soft delete capability
- Product catalog with categories
- Stock management
- Product invariants and validation
- Product variants support
- Property booking management
- Booking status tracking
- Date range validation
- Conflict detection
- Transaction recording
- Transaction lines (line items)
- Transaction types (Sale, Purchase, etc.)
- Financial reporting data
- User registration and login
- JWT token-based authentication
- Google OAuth2 integration
- Role-based authorization
- User profile management
- Automatic request/response logging
- IP address tracking
- User agent detection
- Action tracking
- Asynchronous log processing via RabbitMQ
- Centralized log storage in MongoDB
- Queue-based email delivery using MongoDB outbox pattern
- Resend.com integration for transactional emails
- Custom domain support (masterproperty.site via Namecheap)
- Automated retry mechanism with exponential backoff (up to 5 attempts)
- EmailWorker background service (.NET 8) for processing
- Email templates for user activation, notifications
- Delivery tracking with status persistence (Pending, Sent, Failed)
- High deliverability with SPF, DKIM, and DMARC configuration
- Production-ready deployment on Azure App Service
- Email templates (Razor templates)
- Bid invite notifications
- Transactional emails via Resend
- Background processing worker
- SignalR chat functionality
- Live notifications
- Real-time updates
- RESTful API design
- API versioning (v1)
- Swagger/OpenAPI documentation
- Health check endpoints
- CORS configuration
- Rate limiting ready
- CQRS (Command Query Responsibility Segregation)
- Mediator Pattern via MediatR
- Repository Pattern with Unit of Work
- Domain-Driven Design
- Value Objects (Money, Mass, Address)
- Specification Pattern
- FluentValidation for input validation
- Pipeline behaviors for cross-cutting concerns
- Exception handling middleware
- Model state validation
- Structured logging with Serilog
- Log enrichment (machine name, process ID, thread ID)
- Error file logging
- Loggly integration for cloud logging
- Request/response logging
- JWT token authentication
- Secure password hashing (Identity)
- HTTPS enforcement (development)
- CORS policy configuration
- Azure Key Vault integration (optional)
- Secret management
- MongoDB for horizontal scalability
- Redis caching layer
- Message queue for async processing
- Background workers for heavy tasks
- Connection pooling
-
.NET SDK
- .NET 6.0 SDK (for WebAPI)
- .NET 8.0 SDK (for Worker Services)
- Download: https://dotnet.microsoft.com/download
-
Node.js & NPM
- Node.js 20.x or higher
- NPM 10.x or higher
- Download: https://nodejs.org/
-
Angular CLI
npm install -g @angular/cli@21
-
MongoDB
- MongoDB 6.0 or higher
- Local installation or cloud service (MongoDB Atlas, Azure Cosmos DB for MongoDB)
- Download: https://www.mongodb.com/try/download/community
-
RabbitMQ
- RabbitMQ 3.x or higher
- Local installation or cloud service (CloudAMQP)
- Download: https://www.rabbitmq.com/download.html
-
Docker Desktop
- For containerized deployment
- Download: https://www.docker.com/products/docker-desktop
-
Redis (optional, for caching)
- Redis 6.x or higher
- Download: https://redis.io/download
-
Visual Studio 2022 or VS Code
- Visual Studio 2022 (recommended for .NET development)
- VS Code with C# extension
- Azure Account (for App Service + Static Web Apps hosting)
- CloudAMQP Account (for managed RabbitMQ)
- Resend Account (for email delivery)
git clone https://github.com/NevilleColaco23/testAngularAPIDocker.git
cd testAngularAPIDocker# Restore all NuGet packages
dotnet restore PropertyMasterV4.0.slnEdit WebApi/appsettings.json:
{
"ConnectionStrings": {
"MongoDb": "mongodb://localhost:27017/ListingDB",
"Redis": "localhost:6379"
},
"RabbitMq": {
"Host": "localhost",
"Port": 5672,
"Username": "guest",
"Password": "guest",
"VirtualHost": "/",
"Exchange": "accesslog.exchange",
"Queue": "accesslog.queue",
"RoutingKey": "accesslog",
"UseSsl": false
},
"AuthenticationSettings": {
"JwtIssuer": "PropertyMaster",
"JwtAudience": "PropertyMaster",
"TokenExpirationSeconds": 86400,
"JwtSigningKeyBase64": "your-secret-key-here-min-32-chars"
},
"ExternalAuthenticationSettings": {
"GoogleClientId": "your-google-client-id"
},
"CorsSettings": {
"AllowedOrigins": [
"http://localhost:4200",
"https://localhost:4200"
]
}
}Edit AccessLogWorker/appsettings.json:
{
"ConnectionStrings": {
"MongoDb": "mongodb://localhost:27017/ListingDB"
},
"RabbitMq": {
"Host": "localhost",
"Port": 5672,
"Username": "guest",
"Password": "guest",
"VirtualHost": "/",
"Exchange": "accesslog.exchange",
"Queue": "accesslog.queue",
"RoutingKey": "accesslog",
"UseSsl": false
}
}Edit EmailWorker/appsettings.json:
{
"ConnectionStrings": {
"MongoDb": "mongodb://localhost:27017/ListingDB"
},
"Email": {
"ApiKey": "your-resend-api-key",
"From": "noreply@yourdomain.com"
}
}# Navigate to Angular app
cd app
# Install NPM packages
npm install
# Return to root
cd ..Edit app/src/app/environments/environment.ts:
export const environment = {
production: false,
apiUrl: 'https://localhost:44346/api/v1'
};-
Start MongoDB service:
# Windows net start MongoDB # macOS (Homebrew) brew services start mongodb-community # Linux sudo systemctl start mongod
-
Create database (automatic on first run)
- Database:
ListingDB - Collections created automatically by application
- Database:
-
Start RabbitMQ service:
# Windows rabbitmq-server # macOS brew services start rabbitmq # Linux sudo systemctl start rabbitmq-server
-
Access Management UI:
- URL: http://localhost:15672
- Default credentials: guest/guest
-
Create exchange and queue (or let application auto-create):
- Exchange:
accesslog.exchange(type: direct, durable) - Queue:
accesslog.queue(durable) - Binding: Route queue to exchange with key
accesslog
- Exchange:
| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
HTTP port | 5000 | No |
ASPNETCORE_ENVIRONMENT |
Environment | Development | No |
MONGODB_URI |
MongoDB connection | See appsettings | Yes |
RabbitMq__Host |
RabbitMQ host | localhost | Yes |
RabbitMq__Port |
RabbitMQ port | 5672 | Yes |
RabbitMq__Username |
RabbitMQ user | guest | Yes |
RabbitMq__Password |
RabbitMQ password | guest | Yes |
JWT_SIGNING_KEY |
JWT secret | See appsettings | Yes |
| Variable | Description | Default | Required |
|---|---|---|---|
MONGODB_URI |
MongoDB connection | See appsettings | Yes |
RabbitMq__Host |
RabbitMQ host | localhost | Yes |
RabbitMq__Port |
RabbitMQ port | 5672 | Yes |
| Variable | Description | Default | Required |
|---|---|---|---|
MONGODB_URI |
MongoDB connection | See appsettings | Yes |
RESEND_API_KEY |
Resend API key | None | Yes |
EMAIL_FROM |
Sender email address | noreply@yourdomain.com | Yes |
AppSettings__MongoDbDatabaseName |
Database name | ListingDB | Yes |
The email system uses Resend.com for transactional email delivery with a MongoDB-based outbox pattern for reliability.
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β WebAPI ββββββββββΊβ MongoDB ββββββββββΊβ EmailWorker β
β β Queue β EmailOutbox β Poll β (Background) β
β β β Collection β β β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β Resend API β
β (Delivery) β
ββββββββββββββββ
- User Action (e.g., signup) β WebAPI
- EmailQueueService inserts email into MongoDB
EmailOutboxcollection - EmailWorker polls MongoDB every 2 seconds for pending emails
- EmailWorker sends email via Resend API
- Status Updated in MongoDB (Sent/Failed with retry logic)
- Go to Resend.com and sign up
- Navigate to API Keys
- Create a new API key
- Copy the API key (starts with
re_...)
To send emails from your custom domain (e.g., masterproperty.site):
- Go to Namecheap
- Search and purchase your domain
- Go to Domain List β Manage
- In Resend dashboard, go to Domains
- Click Add Domain
- Enter your domain (e.g.,
masterproperty.site) - Copy the DNS records provided by Resend
- In Namecheap, go to your domain β Advanced DNS tab
- Add the following records from Resend:
| Record Type | Host | Value | TTL |
|---|---|---|---|
| TXT (DKIM) | resend._domainkey |
p=... (from Resend) |
Automatic |
| TXT (SPF) | send |
v=spf1 include:send.resend.com ~all |
Automatic |
| MX | send |
feedback-smtp.{region}.amazonses.com |
Automatic |
| TXT (DMARC) | _dmarc |
v=DMARC1; p=none; (optional) |
Automatic |
- Click Save All Changes
- Wait 5-30 minutes for DNS to propagate
- Check propagation: DNSChecker.org
- Enter your domain and select TXT/MX records
- Wait for green checkmarks globally
- Return to Resend β Domains
- Click Verify Domain
- Status should change to Verified β
- You can now send from
noreply@masterproperty.site
Edit EmailWorker/appsettings.json:
{
"ConnectionStrings": {
"MongoDb": "mongodb://localhost:27017/ListingDB"
},
"AppSettings": {
"MongoDbDatabaseName": "ListingDB"
}
}Note: Do NOT put sensitive credentials in appsettings.json. Use environment variables or user secrets:
# Using .NET User Secrets (Development)
cd EmailWorker
dotnet user-secrets set "Resend:ApiKey" "re_your_api_key_here"
dotnet user-secrets set "Email:From" "noreply@masterproperty.site"Set environment variables in the Azure Portal under App Service β Configuration β Application Settings:
RESEND_API_KEY=re_your_api_key_here
EMAIL_FROM=noreply@masterproperty.site
ConnectionStrings__MongoDb=mongodb://your-atlas-or-cosmos-url
AppSettings__MongoDbDatabaseName=ListingDB
ASPNETCORE_ENVIRONMENT=ProductionEmail templates are defined in code. Example from UserService.cs:
var htmlBody = $@"
<html>
<body>
<h2>Welcome to Property Master!</h2>
<p>Hi {username},</p>
<p>Thank you for signing up. Please activate your account by clicking the link below:</p>
<p><a href='{activationLink}'>Activate Account</a></p>
<p>If you did not sign up for this account, please ignore this email.</p>
<p>Best regards,<br/>Property Master Team</p>
</body>
</html>";
await _emailQueueService.QueueEmailAsync(email, "Activate Your Account", htmlBody, "activation");The system uses a MongoDB collection called EmailOutbox:
{
_id: 1, // Auto-increment ID
type: "activation", // Email type
to: "user@example.com", // Recipient
subject: "Activate Your Account", // Subject line
bodyHtml: "<html>...</html>", // HTML body
status: 0, // 0=Pending, 1=Processing, 2=Sent, 3=Failed
attempts: 0, // Retry count
nextRunAtUtc: ISODate("..."), // When to process
createdAtUtc: ISODate("..."), // Creation timestamp
sentAtUtc: null, // When sent (null if not sent)
lockedUntilUtc: null, // Processing lock
lastError: null // Last error message
}- Start MongoDB and EmailWorker:
# Terminal 1: Start EmailWorker
cd EmailWorker
dotnet run- Start WebAPI:
# Terminal 2: Start WebAPI
cd WebApi
dotnet run- Sign up a new user via API:
curl -X POST http://localhost:5000/api/v1/account/SignUp \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "your-email@example.com",
"password": "Test@1234",
"phone": "1234567890"
}'- Check EmailWorker logs:
info: EmailWorker.Worker[0]
Sent outbox email 1 -> your-email@example.com
- Check your email inbox!
- Deploy EmailWorker to Azure (see Deployment section)
- Verify environment variables are set in Azure App Service Configuration
- Test via the deployed WebAPI URL
- Monitor logs via Azure Portal β App Service β Log stream or Application Insights
// Connect to MongoDB
use ListingDB
// View pending emails
db.EmailOutbox.find({ status: 0 })
// View sent emails
db.EmailOutbox.find({ status: 2 })
// View failed emails
db.EmailOutbox.find({ status: 3 })
// Count emails by status
db.EmailOutbox.aggregate([
{ $group: { _id: "$status", count: { $sum: 1 } } }
])| Issue | Cause | Solution |
|---|---|---|
| Domain not verified | DNS records not propagated | Wait 30 minutes, check DNSChecker.org |
| "You can only send to your own email" | Using test mode | Verify domain in Resend |
| Emails not sending | EmailWorker not running | Check Azure Log Stream, restart App Service |
| Missing API key error | Environment variable not set | Set RESEND_API_KEY in Azure App Service Configuration |
| MongoDB connection failed | Wrong connection string | Verify ConnectionStrings__MongoDb |
The EmailWorker has built-in retry logic:
- Max Attempts: 5
- Retry Delays: Exponential backoff (2, 4, 8, 16, 32 minutes)
- Status Tracking: Pending β Processing β Sent/Failed
- Automatic Recovery: Crashed sends are retried after 2 minutes
| Feature | Resend | SMTP (Gmail) | SendGrid |
|---|---|---|---|
| Azure Compatible | β Yes | β Yes | β Yes |
| Setup Complexity | ββ Easy | ββββ Hard | βββ Medium |
| Custom Domain | β Yes (Namecheap) | β Complex | β Yes |
| Deliverability | βββββ Excellent | βββ Good | ββββ Very Good |
| Free Tier | 100/day | 500/day | 100/day |
| Pricing | $20/month (50k) | Free (limited) | $20/month (40k) |
| Our Choice | β Selected | β Not compatible |
Why we chose Resend:
- β Works perfectly on Azure App Service
- β Simple API integration
- β Excellent deliverability with verified domains
- β Easy domain setup with Namecheap
- β Modern developer-friendly platform
- β Built-in bounce handling
Terminal 1 - MongoDB:
mongodTerminal 2 - RabbitMQ:
rabbitmq-serverTerminal 3 - WebAPI:
cd WebApi
dotnet run
# API available at: https://localhost:44346Terminal 4 - AccessLogWorker:
cd AccessLogWorker
dotnet runTerminal 5 - EmailWorker:
cd EmailWorker
dotnet runTerminal 6 - Angular Frontend:
cd app
npm start
# or: ng serve
# App available at: http://localhost:4200| Variable | Description | Default | Required |
|---|---|---|---|
MONGODB_URI |
MongoDB connection | See appsettings | Yes |
RESEND_API_KEY |
Resend API key | None | Yes |
EMAIL_FROM |
Sender email address | noreply@yourdomain.com | Yes |
EMAIL_FROM |
Sender email | - | Yes |
RESEND_API_KEY |
Resend API key | - | Yes |
Configure allowed origins in WebApi/appsettings.json:
{
"CorsSettings": {
"AllowedOrigins": [
"http://localhost:4200",
"https://your-production-domain.com"
]
}
}{
"SwaggerSettings": {
"ApiName": "PropertyMaster",
"UseSwagger": true,
"LoginPath": "/account/oauth2/access_token"
}
}Terminal 1 - WebAPI:
cd WebApi
dotnet run
# API runs on https://localhost:44346Terminal 2 - AccessLog Worker:
cd AccessLogWorker
dotnet runTerminal 3 - Email Worker:
cd EmailWorker
dotnet runTerminal 4 - Angular:
cd app
ng serve
# App runs on http://localhost:4200# Build and start all services
docker-compose -f WebApi/docker-compose.yml up --build
# Services:
# - WebAPI: http://localhost:8080
# - MongoDB: localhost:27017
# - RabbitMQ: localhost:5672 (Management UI: http://localhost:15672)
# - AccessLog Worker: Running in background# Build WebAPI image
docker build -t propertymaster-api -f WebApi/Dockerfile .
# Build AccessLog Worker image
docker build -t accesslog-worker -f AccessLogWorker/Dockerfile .
# Build Email Worker image
docker build -t email-worker -f EmailWorker/Dockerfile .
# Run containers (after starting MongoDB and RabbitMQ)
docker run -p 8080:80 propertymaster-api
docker run accesslog-worker
docker run email-worker-
WebAPI Health Check:
GET http://localhost:8080/health Expected: 200 OK -
Swagger UI:
http://localhost:8080/swagger -
Angular Application:
http://localhost:4200 -
RabbitMQ Management:
http://localhost:15672 Login: guest/guest
- Azure Account
- Azure CLI installed
- Visual Studio 2022 / 2026 with Azure workload (recommended)
- Right-click
WebApiproject β Publish - Select Azure β Azure App Service (Windows)
- Sign in to your Azure account and select or create an App Service
- Click Publish β Visual Studio handles the rest
The included publish profile (propertymaster-api-de09 - Web Deploy.pubxml) deploys to:
https://propertymaster-api-de09-h0hqbzgsc4arfvez.francecentral-01.azurewebsites.net
# Login to Azure
az login
# Deploy WebAPI (from WebApi directory)
az webapp deploy --resource-group rg-propertymaster-dev \
--name propertymaster-api-de09 \
--src-path ./publishIn Azure Portal β App Service β Configuration β Application Settings, add:
| Key | Value |
|---|---|
ASPNETCORE_ENVIRONMENT |
Production |
ConnectionStrings__MongoDb |
Your MongoDB Atlas / Cosmos DB URI |
ConnectionStrings__DefaultConnection |
Your Azure SQL connection string |
AuthenticationSettings__JwtSigningKeyBase64 |
Your base64 JWT key |
RabbitMq__Host |
CloudAMQP host |
RabbitMq__Username |
CloudAMQP username |
RabbitMq__Password |
CloudAMQP password |
# Build and push worker images
docker build -f EmailWorker/Dockerfile -t propertymaster-emailworker .
docker build -f AccessLogWorker/Dockerfile -t propertymaster-accesslogworker .
# Push to Azure Container Registry, then deploy via Azure Portal or CLI- Azure Account
- Azure Static Web Apps CLI (optional)
-
Update Production Environment:
Edit
app/src/app/environments/environment.prod.ts:export const environment = { production: true, apiUrl: 'https://propertymaster-api-de09-h0hqbzgsc4arfvez.francecentral-01.azurewebsites.net/api/v1' };
-
Build for Production:
cd app ng build --configuration production -
Deploy to Azure Static Web Apps:
- In the Azure Portal, create a new Static Web App
- Connect it to your GitHub repository for CI/CD, or use the SWA CLI:
npm install -g @azure/static-web-apps-cli swa deploy ./dist/propertyMasterV3.0/browser --env production
-
SPA Routing is pre-configured via
app/public/staticwebapp.config.json:{ "navigationFallback": { "rewrite": "/index.html" } }
Deployed at: https://brave-rock-0db8c8503.7.azurestaticapps.net
-
Create Account:
- Visit https://www.cloudamqp.com/
- Sign up for free tier
-
Create Instance:
- Select plan (Free tier available)
- Choose region closest to your Azure App Service region
- Note connection details
-
Get Connection Information:
- Host: e.g.,
raccoon.lmq.cloudamqp.com - Port: 5671 (SSL)
- Virtual Host: Your instance name
- Username: Provided
- Password: Provided
- Host: e.g.,
-
Update Configuration:
- Update
appsettings.jsonwith CloudAMQP details - Ensure
UseSsl: true
- Update
# Local backup
mongodump --uri="mongodb://localhost:27017/ListingDB" --out=./backup
# Remote MongoDB backup (Atlas / Cosmos DB)
mongodump --uri="your-production-mongodb-uri" --out=./backup# Restore to local
mongorestore --uri="mongodb://localhost:27017/ListingDB" ./backup/ListingDB
# Restore to production
mongorestore --uri="your-production-mongodb-uri" ./backup/ListingDB- Local Development:
https://localhost:44346/api/v1 - Production:
https://propertymaster-api-de09-h0hqbzgsc4arfvez.francecentral-01.azurewebsites.net/api/v1
Access interactive API documentation:
- Local:
https://localhost:44346/swagger - Production:
https://propertymaster-api-de09-h0hqbzgsc4arfvez.francecentral-01.azurewebsites.net/swagger
All protected endpoints require JWT token in Authorization header:
Authorization: Bearer <your-jwt-token>POST /api/v1/account/signup
POST /api/v1/account/login
POST /api/v1/account/oauth2/google
POST /api/v1/account/refresh-token
GET /api/v1/account/user-infoGET /api/v1/property # List properties
GET /api/v1/property/{id} # Get property by ID
POST /api/v1/property # Create property
PUT /api/v1/property/{id} # Update property
DELETE /api/v1/property/{id} # Delete propertyGET /api/v1/partner # List partners
GET /api/v1/partner/{id} # Get partner by ID
POST /api/v1/partner # Create partner
PUT /api/v1/partner/{id} # Update partner
DELETE /api/v1/partner/{id} # Delete partnerGET /api/v1/product # List products
GET /api/v1/product/{id} # Get product by ID
POST /api/v1/product # Create product
PUT /api/v1/product/{id} # Update product
DELETE /api/v1/product/{id} # Delete productGET /api/v1/bookings # List bookings
GET /api/v1/bookings/{id} # Get booking by ID
POST /api/v1/bookings # Create booking
PUT /api/v1/bookings/{id} # Update booking
DELETE /api/v1/bookings/{id} # Delete bookingGET /api/v1/transaction # List transactions
GET /api/v1/transaction/{id} # Get transaction by ID
POST /api/v1/transaction # Create transaction
PUT /api/v1/transaction/{id} # Update transaction
DELETE /api/v1/transaction/{id} # Delete transactionGET /api/v1/accesslogging # List access logs
GET /api/v1/accesslogging/{id} # Get log by ID
POST /api/v1/accesslogging # Create log entryGET /api/menu # Get menu structure
GET /api/menu/permissions/{roleId} # Get menu permissionsGET /health # Health check
GET / # API statusRequest:
POST /api/v1/property
Content-Type: application/json
Authorization: Bearer <token>
{
"name": "Luxury Apartment",
"address": "123 Main St, City, State",
"price": 500000,
"bedrooms": 3,
"bathrooms": 2,
"squareFeet": 1500,
"description": "Beautiful modern apartment"
}Response:
{
"id": 1,
"name": "Luxury Apartment",
"address": "123 Main St, City, State",
"price": 500000,
"bedrooms": 3,
"bathrooms": 2,
"squareFeet": 1500,
"description": "Beautiful modern apartment",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T10:30:00Z"
}All errors follow consistent format:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Name": ["The Name field is required."]
},
"traceId": "00-abc123-def456-00"
}# Run all tests
dotnet test PropertyMasterV4.0.sln
# Run tests with coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific test project
dotnet test APIUnitProject.Tests/APIUnitProject.Tests.csprojcd app
# Run unit tests
ng test
# Run tests with coverage
ng test --code-coverage
# Run tests headless (CI/CD)
ng test --browsers=ChromeHeadless --watch=falseUse Swagger UI or tools like Postman:
-
Import Swagger Spec:
- Export OpenAPI spec from
/swagger/v1/swagger.json - Import into Postman
- Export OpenAPI spec from
-
Test Scenarios:
- User registration and login flow
- Property CRUD operations
- Access log creation and retrieval
- Email outbox processing
Use tools like Apache JMeter or k6:
# Install k6
brew install k6 # macOS
choco install k6 # Windows
# Run load test
k6 run load-test-script.js-
Fork the Repository
# Click Fork button on GitHub git clone https://github.com/YOUR_USERNAME/testAngularAPIDocker.git -
Create Feature Branch
git checkout -b feature/your-feature-name
-
Make Changes
- Follow coding standards
- Add unit tests
- Update documentation
-
Commit Changes
git add . git commit -m "feat: add your feature description"
-
Push to Fork
git push origin feature/your-feature-name
-
Create Pull Request
- Go to original repository
- Click "New Pull Request"
- Describe changes
- Follow Microsoft C# Coding Conventions
- Use async/await for asynchronous operations
- Implement IDisposable for resource management
- Use dependency injection
- Write XML documentation for public APIs
- Follow Angular Style Guide
- Use TypeScript strict mode
- Implement RxJS best practices
- Use async pipe for subscriptions
- Write JSDoc comments
Follow Conventional Commits:
feat: add new feature
fix: bug fix
docs: documentation changes
style: formatting changes
refactor: code refactoring
test: add tests
chore: maintenance tasks
This project is proprietary and confidential. All rights reserved.
Neville Colaco
- GitHub: @NevilleColaco23
- Repository: testAngularAPIDocker
- Microsoft .NET Team for ASP.NET Core
- Angular Team for Angular framework
- MediatR for CQRS pattern implementation
- AutoMapper for object mapping
- FluentValidation for validation
- Serilog for structured logging
- MongoDB team for the database
- RabbitMQ team for messaging
- Microsoft Azure for App Service and Static Web Apps hosting
- CloudAMQP for managed RabbitMQ
- Resend for email delivery
- GitHub for source control
For issues, questions, or contributions:
- GitHub Issues: https://github.com/NevilleColaco23/testAngularAPIDocker/issues
- Pull Requests: https://github.com/NevilleColaco23/testAngularAPIDocker/pulls
- Email: [Your contact email]
- Complete rewrite with Clean Architecture
- Microservices with worker services
- RabbitMQ message queue integration
- MongoDB as primary database
- Angular 21 frontend upgrade
- Docker containerization
- Azure App Service + Static Web Apps deployment
- Angular Material integration
- Improved UI/UX
- Enhanced authentication
- Initial Angular frontend
- Basic CRUD operations
- JWT authentication
- Initial release
- .NET WebAPI
- Basic property management
- Azure Blob Storage for file uploads
- Advanced search with Elasticsearch
- Payment gateway integration (Stripe)
- Multi-tenant support
- Mobile app (React Native)
- GraphQL API endpoint
- Advanced reporting with charts
- Notification system (push notifications)
- Chat system with attachments
- Calendar integration
- Document management
- Audit trail visualization
- Performance monitoring dashboard
- Automated testing suite expansion
- CI/CD pipeline with GitHub Actions
Last Updated: January 2025
Status: Active Development
Branch: Mar2026
Maintainer: Neville Colaco






