Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/api-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:
push:
branches: main
paths:
- 'backend/src/**'
- 'backend/**'

jobs:
main:
Expand All @@ -24,5 +24,5 @@ jobs:
id: docker_build
uses: docker/build-push-action@v2
with:
context: backend/src/.
file: backend/src/Dockerfile
context: backend/.
file: Dockerfile.api
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
*.user
*.userosscache
*.sln.docstates

.vs
.playwright-mcp
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
.env
Expand Down
26 changes: 19 additions & 7 deletions backend/src/Contact.Api.sln → Contact.Api.sln
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35208.52
# Visual Studio Version 18
VisualStudioVersion = 18.0.11222.15 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contact.Api", "Contact.Api\Contact.Api.csproj", "{E71B9B65-032D-4CC7-86B9-4712CC4E4B8E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contact.Api", "backend\Contact.Api\Contact.Api.csproj", "{E71B9B65-032D-4CC7-86B9-4712CC4E4B8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Infrastructure", "Contact.Infrastructure\Contact.Infrastructure.csproj", "{AD68A223-AFC1-4A11-B056-82D1DEF146F0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Infrastructure", "backend\Contact.Infrastructure\Contact.Infrastructure.csproj", "{AD68A223-AFC1-4A11-B056-82D1DEF146F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Application", "Contact.Application\Contact.Application.csproj", "{42EF202E-6AA6-42B8-9AE6-E4B06C36EB36}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Application", "backend\Contact.Application\Contact.Application.csproj", "{42EF202E-6AA6-42B8-9AE6-E4B06C36EB36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Domain", "Contact.Domain\Contact.Domain.csproj", "{41338193-C8C7-4348-9011-C7D2C437B36C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Domain", "backend\Contact.Domain\Contact.Domain.csproj", "{41338193-C8C7-4348-9011-C7D2C437B36C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Common", "Contact.Common\Contact.Common.csproj", "{32C9230B-EE1E-4F3C-806F-685EB36C55F4}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.Common", "backend\Contact.Common\Contact.Common.csproj", "{32C9230B-EE1E-4F3C-806F-685EB36C55F4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.AppHost", "aspire\AppHost\Contact.AppHost.csproj", "{9E5B8B78-8F0B-403E-A7AA-71A75C60D128}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contact.ServiceDefaults", "aspire\ServiceDefaults\Contact.ServiceDefaults.csproj", "{B649DAF0-42CE-92EA-0381-374285B927BF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -39,6 +43,14 @@ Global
{32C9230B-EE1E-4F3C-806F-685EB36C55F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32C9230B-EE1E-4F3C-806F-685EB36C55F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32C9230B-EE1E-4F3C-806F-685EB36C55F4}.Release|Any CPU.Build.0 = Release|Any CPU
{9E5B8B78-8F0B-403E-A7AA-71A75C60D128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E5B8B78-8F0B-403E-A7AA-71A75C60D128}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E5B8B78-8F0B-403E-A7AA-71A75C60D128}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E5B8B78-8F0B-403E-A7AA-71A75C60D128}.Release|Any CPU.Build.0 = Release|Any CPU
{B649DAF0-42CE-92EA-0381-374285B927BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B649DAF0-42CE-92EA-0381-374285B927BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B649DAF0-42CE-92EA-0381-374285B927BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B649DAF0-42CE-92EA-0381-374285B927BF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
39 changes: 39 additions & 0 deletions Dockerfile.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8000
ENV ASPNETCORE_URLS=http://+:8000
RUN groupadd -g 2000 dotnet \
&& useradd -m -u 2000 -g 2000 dotnet
USER dotnet

# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
ARG DOTNET_SKIP_POLICY_LOADING=true
WORKDIR /src
COPY ["backend/Contact.Api/Contact.Api.csproj", "backend/Contact.Api/"]
COPY ["backend/Contact.Application/Contact.Application.csproj", "backend/Contact.Application/"]
COPY ["backend/Contact.Domain/Contact.Domain.csproj", "backend/Contact.Domain/"]
COPY ["backend/Contact.Infrastructure/Contact.Infrastructure.csproj", "backend/Contact.Infrastructure/"]
COPY ["backend/Contact.Common/Contact.Common.csproj", "backend/Contact.Common/"]
COPY ["aspire/ServiceDefaults/Contact.ServiceDefaults.csproj", "aspire/ServiceDefaults/"]

RUN dotnet restore "./backend/Contact.Api/Contact.Api.csproj"
COPY backend/ backend/
COPY aspire/ServiceDefaults/ aspire/ServiceDefaults/
WORKDIR "/src/backend/Contact.Api"
RUN dotnet build "./Contact.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

RUN ls /app/build

# This stage is used to publish the service project to be copied to the final stage
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Contact.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
FROM base AS final
WORKDIR /app
# COPY --from=publish /app/publish/Contact.Api.dll .
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Contact.Api.dll"]
155 changes: 118 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# 🚀 Clean Architecture Full-Stack Starter: .NET, Angular, and PostgreSQL

<!-- <p align="center">
<img src="docs/logo.png" alt="Clean Architecture Logo" width="150px">
<br>
<em>Production-ready | Maintainable | Scalable</em>
</p> -->

# Clean Architecture Full-Stack Starter: .NET, Angular, and PostgreSQL
> Clean Architecture with RBAC implementation for API (.Net) and UI (Angular)
<p align="center">
<a href="https://github.com/nitin27may/clean-architecture-docker-dotnet-angular/actions/workflows/angular-build.yml">
<img src="https://github.com/nitin27may/clean-architecture-docker-dotnet-angular/actions/workflows/angular-build.yml/badge.svg" alt="Angular Build">
Expand All @@ -16,9 +10,10 @@
<a href="LICENSE">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License">
</a>
<img src="https://img.shields.io/badge/Angular-19-DD0031.svg" alt="Angular 20">
<img src="https://img.shields.io/badge/.NET-9-512BD4.svg" alt=".NET 9">
<img src="https://img.shields.io/badge/PostgreSQL-16-336791.svg" alt="PostgreSQL 16">
<img src="https://img.shields.io/badge/Angular-21-512BD4.svg" alt="Angular 21">
<img src="https://img.shields.io/badge/.NET-10-512BD4.svg" alt=".NET 10">
<img src="https://img.shields.io/badge/PostgreSQL-17-336791.svg" alt="PostgreSQL 17">
<img src="https://img.shields.io/badge/Aspire-9.5-6C3483.svg" alt=".NET Aspire 9.5">
</p>

<p align="center">
Expand All @@ -28,18 +23,19 @@
<em>Contact Management Application with Role-Based Access Control</em>
</p>

## What is this?
## What is this?

A production-ready **full-stack starter kit** built with modern technologies and best practices:

- **Frontend**: Angular 20 with signals, Material Design, and TailwindCSS
- **Backend**: .NET 9 API with Clean Architecture
- **Database**: PostgreSQL with Dapper
- **Frontend**: Angular 21 with signals, Material Design, TailwindCSS v4, and Fluent Design
- **Backend**: .NET 10 API with Clean Architecture and Scalar API documentation
- **Database**: PostgreSQL 17 with pgAdmin and Dapper ORM
- **Orchestration**: .NET Aspire 9.5 for local development with service discovery
- **DevOps**: Docker, GitHub Actions, NGINX

Perfect for developers who want to **focus on business logic** instead of configuring infrastructure.

## 🏗️ Why Clean Architecture?
## Why Clean Architecture?

<p align="center">
<img src="docs/screenshots/clean-architecture.png" alt="Clean Architecture Diagram" width="60%">
Expand All @@ -54,7 +50,44 @@ Clean Architecture provides **significant benefits** for your application:

[Clean Architecture Series](./docs/architecture-series.md) - Read more about it!

## 🚀 Quick Start
## Quick Start

### Option 1: Using .NET Aspire (Recommended for Development)

**.NET Aspire** provides a streamlined local development experience with automatic service discovery, health monitoring, and an integrated dashboard.

#### Prerequisites

> **Important**: Make sure you have the correct versions installed before proceeding.

- [.NET SDK 10.0](https://dotnet.microsoft.com/download/dotnet/10.0) or later
- [Node.js 22 LTS](https://nodejs.org/) (**not** Node 23 - use LTS version only)
- [Docker Desktop](https://www.docker.com/products/docker-desktop) (for PostgreSQL container)

#### Steps

```bash
# Clone the repository
git clone https://github.com/nitin27may/clean-architecture-docker-dotnet-angular.git clean-app
cd clean-app

# IMPORTANT: Install Angular dependencies first
cd frontend
npm install
cd ..

# Run with Aspire
dotnet run --project aspire/AppHost
```

🔗 Then access:
- **Aspire Dashboard**: https://localhost:17178 (see all services, logs, traces)
- **Frontend**: http://localhost:4200
- **API**: Check Aspire dashboard for the assigned port
- **Scalar API Docs**: `{API_URL}/scalar/v1`
- **pgAdmin**: Check Aspire dashboard for the assigned port

### Option 2: Using Docker Compose (Production-like)

```bash
# Clone the repository
Expand All @@ -68,10 +101,10 @@ cp .env.example .env
docker-compose up
```

🔗 Then access:
Then access:
- Frontend: http://localhost
- API: http://localhost/api
- Swagger: http://localhost/swagger
- Scalar API Docs: http://localhost/scalar/v1

### 👤 Default Users

Expand All @@ -81,78 +114,126 @@ docker-compose up
| [email protected] | P@ssword#321 | Editor |
| [email protected] | P@ssword#321 | Reader |

## 🔥 Key Features
## Key Features

<table>
<tr>
<td width="33%">
<h3>📱 Modern Frontend</h3>
<h3>Modern Frontend</h3>
<ul>
<li>Angular 20 with standalone components</li>
<li>Angular 21 with standalone components</li>
<li>Signal-based state management</li>
<li>Material Design + TailwindCSS</li>
<li>Material Design + TailwindCSS v4</li>
<li>Fluent Design System tokens</li>
<li>Dark/light theme support</li>
<li>Responsive mobile-first design</li>
<li>Role Based Routing and Menu</li>
<li>Role-based routing and menu</li>
</ul>
</td>
<td width="33%">
<h3>🔒 Secure Backend</h3>
<h3>Secure Backend</h3>
<ul>
<li>Clean Architecture implementation</li>
<li>Generic Repository pattern</li>
<li>JWT authentication</li>
<li>Role-based permissions</li>
<li>User Activity Logging</li>
<li>Golbal Exception Handling</li>
<li>PostgreSQL with Dapper</li>
<li>User activity logging</li>
<li>Global exception handling</li>
<li>Scalar API documentation</li>
<li>PostgreSQL 17 with Dapper</li>
</ul>
</td>
<td width="33%">
<h3>🚢 DevOps Ready</h3>
<h3>DevOps Ready</h3>
<ul>
<li>.NET Aspire orchestration</li>
<li>Docker containerization</li>
<li>GitHub Actions workflows</li>
<li>NGINX reverse proxy</li>
<li>pgAdmin database management</li>
<li>Multi-environment configs</li>
<li>Database migrations</li>
<li>Database seeding</li>
</ul>
</td>
</tr>
</table>

## 🧩 Architecture
## Project Structure

```
clean-architecture-docker-dotnet-angular/
├── aspire/ # .NET Aspire orchestration
│ ├── AppHost/ # Aspire host application
│ │ └── AppHost.cs # Service configuration
│ └── ServiceDefaults/ # Shared Aspire defaults
├── backend/ # .NET 10 API (Clean Architecture)
│ ├── Contact.Api/ # API Layer (Controllers, Middleware)
│ ├── Contact.Application/ # Application Layer (Services, DTOs)
│ ├── Contact.Domain/ # Domain Layer (Entities, Interfaces)
│ ├── Contact.Infrastructure/ # Infrastructure Layer (Repositories)
│ └── Contact.Common/ # Shared utilities
├── frontend/ # Angular 21 SPA
│ ├── src/app/@core/ # Core module (guards, interceptors, layout)
│ ├── src/app/feature/ # Feature modules (contact, user, admin)
│ └── src/app/styles/ # Global styles, Tailwind config
├── scripts/ # Database initialization
│ ├── 01-init-db.sh # Create database
│ └── 02-seed-data.sql # Seed initial data
├── api-collection/ # Bruno API collection for testing
├── docs/ # Documentation
├── loadbalancer/ # NGINX configuration
├── Contact.Api.sln # .NET Solution file
├── docker-compose.yml # Docker Compose configuration
└── Dockerfile.api # API Dockerfile
```

## Architecture

<p align="center">
<img src="docs/screenshots/architecture.png" alt="Container Architecture" width="80%">
<br>
<em>Container Architecture Overview</em>
</p>

## 📚 Documentation
## Documentation

📖 Comprehensive documentation is available:
Comprehensive documentation is available:

- [Aspire Guide](./docs/aspire-guide.md) - Running with .NET Aspire
- [Development Guide](./docs/development-guide.md) - Get started with development
- [Frontend Documentation](./docs/frontend.md) - Angular architecture details
- [Backend Documentation](./docs/backend.md) - .NET API implementation
- [Docker Guide](./docs/docker-guide.md) - Container configuration
- [Feature List](./docs/visual-feature-guide.md) - Detailed feature breakdown
- [Clean Architecture Series](./docs/architecture-series.md) - In-depth articles
- [Roadmap](./docs/roadmap.md) - Upcoming features

## Technology Stack

| Layer | Technology | Version |
|-------|------------|---------|
| Frontend | Angular | 21.0 |
| UI Components | Angular Material | 21.0 |
| CSS Framework | TailwindCSS | 4.1 |
| Backend | .NET | 10.0 |
| API Docs | Scalar | 2.1 |
| Database | PostgreSQL | 17 |
| ORM | Dapper | 2.1 |
| Orchestration | .NET Aspire | 9.5 |
| Containerization | Docker | Latest |

## 🤝 Contributing

We welcome contributions! See our [contributing guide](./CONTRIBUTING.md) for details on how to get involved.

## 📄 License
## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 📧 Contact
## Contact

For questions or support, please contact Nitin Singh at [email protected].

## 🌟 Star the Repository
## Star the Repository

If you find this project useful, please consider giving it a star on GitHub to show your support!
If you find this project useful, please consider giving it a star on GitHub to show your support!
File renamed without changes.
Loading
Loading