A full-stack web application built with .NET 9, Angular 19, SQL Server, and NGINX — fully containerised with Docker Compose for both development and production environments.
| Layer | Technology |
|---|---|
| Frontend | Angular 19 |
| Backend | .NET 9 (ASP.NET Core) |
| Database | Azure SQL Edge (SQL Server) |
| Proxy | NGINX |
| Container | Docker & Docker Compose |
Client
└──▶ NGINX (:80 / :443)
├──▶ Angular frontend (ng serve / static build)
├──▶ Background Service (:5001 Hangfire)
└──▶ .NET 9 API (:8080 internally)
└──▶ SQL Server (:1433)
All services communicate over an isolated Docker bridge network (app-network). SQL Server data is persisted via a named Docker volume.
- Docker & Docker Compose v2+
- A
.envfile in the project root (see below) - Database with correct name needs to be created on first docker compose
Create a .env file in the project root:
DB_PASSWORD=YourStrongPassword123!
DB_NAME=YourDatabaseName.
├── angularFe/ # Angular 19 frontend
│ └── Dockerfile
├── fullstack2026BE/ # .NET 9 backend API
│ └── Dockerfile
├── nginx/ # NGINX config & Dockerfile
│ └── Dockerfile
├── docker-compose.yml # Base / dev compose
├── docker-compose.prod.yml # Production overrides
└── .env # Local secrets (git-ignored)
Starts the full stack with hot reload on the Angular frontend and Swagger accessible on the backend.
docker compose up --build
docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d| Service | URL |
|---|---|
| App | http://localhost:80 |
| API | http://localhost:5001 (Swagger UI) |
| CRON JOBS | http://localhost:5000 (Hangfire) |
| SQL Server | localhost:1433 (SSMS / Azure Data Studio) |
The Angular dev server runs with ng serve and source files are mounted into the container for instant hot reload without rebuilding.
docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -dIn production:
- Angular builds a static bundle served by NGINX
- HTTPS is enabled via port 443
- Backend runs in
ProductionASP.NET Core environment
- Image:
mcr.microsoft.com/azure-sql-edge:latest - Exposes port
1433locally for direct DB access - Health-checked before backend starts
- Data persisted in
sqlserver_datavolume
- .NET 9 ASP.NET Core API
- Waits for SQL Server to be healthy before starting
- Swagger available at
http://localhost:5001in development
- .NET 9 ASP.NET Hangfire
- Used for queieing time-heavy operations or cron jobs
- Waits for SQL Server to be healthy before starting
- UI available at
http://localhost:5000in development
- Angular 19 dev server with hot reload in development
- Mounts
./angularFesource for live changes - Builds to static files in production
- Reverse proxy and web server
- Routes
/apitraffic to backend, serves frontend - Handles HTTP (:80) and HTTPS (:443)
# Start in development
docker compose up --build
# Start in background
docker compose up -d
# View logs
docker compose logs -f
# Stop all services
docker compose down
# Rebuild a single service
docker compose up --build backendSQL Server includes a health check that the backend depends_on, ensuring the database is accepting connections before the API starts.
Frontend has no tests. .Net testing is with NUnit, NSubstitutes for dependancy mocking and Shoudly for assertion.
Currently no server or domain is hosting this project, but github has workflow for every PR commit directed towards main. UnitTests are ran and result is shown.