A full-stack e-commerce application with a customer storefront, an admin dashboard, Stripe payments, real-time updates via SignalR, and a complete CI/CD pipeline deployed on Microsoft Azure.
Live demo: https://skinet-2026.azurewebsites.net
- Product catalogue with search, filtering, sorting and pagination
- Shopping basket and checkout flow
- Secure online payments with Stripe
- Order history and order details
- Real-time order/payment status updates with SignalR
- Responsive UI built with Angular Material and Tailwind CSS
- Admin-only area protected by role-based authorization
- Manage products (create, edit, delete)
- View and manage customer orders
- Order status visibility in real time
| Layer | Technology |
|---|---|
| Frontend | Angular 21, Angular Material, Tailwind CSS, Signals |
| Backend | ASP.NET Core Web API (.NET) |
| Caching | Redis (UpStash) |
| Real-time | SignalR |
| Payments | Stripe (Payment Intents + Webhooks) |
| Database | Azure SQL Database |
| Hosting | Azure App Service (skinet-2026) |
| CI/CD | GitHub Actions |
┌──────────────┐ HTTPS / REST ┌────────────────────┐ ┌────────────────┐
│ Angular 21 │ ─────────────────────► │ ASP.NET Core API │ ───► │ Azure SQL DB │
│ (Client) │ ◄───── SignalR ─────── │ + SignalR Hub │ └────────────────┘
└──────────────┘ │ │
│ │ ┌────────────────┐
│ │ ───► │ Redis │
│ │ │ (Basket cache) │
└─────────┬──────────┘ └────────────────┘
│ ▲
Stripe API│ │Webhooks
▼ │
┌──────────┐
│ Stripe │
└──────────┘
- The Angular client calls the REST API for products, baskets, orders and auth.
- At checkout the API creates a Stripe Payment Intent; the client confirms payment with Stripe.js.
- Stripe sends a webhook to the API when payment succeeds or fails.
- The API updates the order and pushes the new status to the client through a SignalR hub.
Skinet/
├── API/ # ASP.NET Core Web API, SignalR hub, controllers
├── Core/ # Entities, interfaces, specifications
├── Infrastructure/ # EF Core, repositories, services, migrations
├── Client/ # Angular application
└── .github/workflows # GitHub Actions CI/CD
- .NET SDK
- Node.js (LTS) and npm
- Angular CLI:
npm install -g @angular/cli - SQL Server (local instance or Docker)
- Redis (Docker)
- A Stripe account (test mode) and the Stripe CLI
git clone https://github.com/beastkp/Skinet.git
cd skinetSet secrets with .NET user secrets or checkout the appsettings.json file in the repo:
cd API
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "<your-sql-connection-string>"
dotnet user-secrets set "StripeSettings:SecretKey" "<sk_test_...>"
dotnet user-secrets set "StripeSettings:WhSecret" "<whsec_...>"Apply migrations and run:
dotnet ef database update
dotnet runcd Client
npm install
ng serveThe app is served at http://localhost:4200.
stripe listen --forward-to https://localhost:7254/api/payments/webhook --events=payment_intent.succeededCopy the signing secret it prints into StripeSettings:WhSecret.
The app is deployed to Azure App Service (skinet-2026) with an Azure SQL Database (Skinet).
- App Service (web app) hosting the .NET API and the built Angular client
- Azure SQL Database
- Application settings configured in App Service for connection string and Stripe keys
Add these under Settings → Environment variables:
| Name | Purpose |
|---|---|
ConnectionStrings__DefaultConnection |
Azure SQL connection string |
StripeSettings__SecretKey |
Stripe secret key |
StripeSettings__WhSecret |
Stripe webhook signing secret |
Redis |
Upstash Redis Instance |
Also make sure Web sockets is enabled (Configuration → General settings) so SignalR can use WebSockets.
In the Stripe Dashboard, add an endpoint pointing to:
https://skinet-2026.azurewebsites.net/api/payments/webhook
and subscribe to payment_intent.succeeded and payment_intent.payment_failed.
On every push to main, the workflow:
- Builds the Angular app in the
Clientfolder - Builds and publishes the .NET API (with the Angular output served from
wwwroot) - Deploys the package to Azure App Service
| Storefront | Checkout | Admin |
|---|---|---|
![]() |
![]() |
![]() |


