Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
4640c61
Add article 6.1: Run a Local LLM in Your .NET 10 API with Ollama
workcontrolgit Mar 16, 2026
5a1b001
Update AI enhancement plan checklist: mark 6.1 and Phase 0 complete
workcontrolgit Mar 16, 2026
9d6db2f
Fix employee-form image link in POM article; update ApiResources subm…
workcontrolgit Mar 18, 2026
062465d
Standardize Series 4 sections: remove Summary, rename Key Patterns to…
workcontrolgit Mar 18, 2026
1082267
Update 4.5 hero image to use swagger-api-endpoints webapi screenshot
workcontrolgit Mar 18, 2026
cb19305
Add Azure OIDC automation script and update deployment docs with Angu…
workcontrolgit Mar 21, 2026
f926885
Standardize Series 5 sections: remove Summary, rename Key Patterns to…
workcontrolgit Mar 21, 2026
0532278
Add Key Design Decisions section to 5.1 database seeding article
workcontrolgit Mar 21, 2026
9983dc7
Elaborate Playwright seeding section in 5.1: request fixture, beforeA…
workcontrolgit Mar 21, 2026
4c665c9
Fix seed endpoint URL, auth requirement, and request format in 5.1 Pl…
workcontrolgit Mar 21, 2026
a0fc6ab
Update ApiResources submodule reference
workcontrolgit Mar 21, 2026
9f20808
Add Series 5 Azure deployment sub-series (5.3-5.8) to blog plan
workcontrolgit Mar 21, 2026
3eee1e7
Add articles 5.3 and 5.4 with Bicep infrastructure files
workcontrolgit Mar 21, 2026
b02e522
Add articles 5.5-5.8 and GitHub Actions deployment workflows
workcontrolgit Mar 22, 2026
bd50fa6
Update Angular submodule ref: add staticwebapp.config.json
workcontrolgit Mar 22, 2026
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
80 changes: 80 additions & 0 deletions .github/workflows/deploy-angular.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Deploy Angular to Azure Static Web Apps

on:
push:
branches:
- main
paths:
- 'Clients/TalentManagement-Angular-Material/**'
- '.github/workflows/deploy-angular.yml'
workflow_dispatch:

permissions:
id-token: write # Required for OIDC token request
contents: read

env:
ANGULAR_APP_DIR: 'Clients/TalentManagement-Angular-Material/talent-management'
STATIC_WEB_APP_NAME: 'swa-talent-ui-dev'
RESOURCE_GROUP: 'rg-talent-dev'

jobs:
build-and-deploy:
name: Build and Deploy Angular
runs-on: ubuntu-latest

steps:
- name: Checkout repository (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22.x'
cache: 'npm'
cache-dependency-path: '${{ env.ANGULAR_APP_DIR }}/package-lock.json'

- name: Install dependencies
working-directory: ${{ env.ANGULAR_APP_DIR }}
run: npm ci

- name: Inject production environment variables
working-directory: ${{ env.ANGULAR_APP_DIR }}
env:
API_URL: ${{ secrets.API_APP_URL }}
IDENTITY_SERVER_URL: ${{ secrets.IDENTITY_SERVER_URL }}
run: |
sed -i "s|https://your-production-api.com/api/v1|${API_URL}/api/v1|g" src/environments/environment.prod.ts
sed -i "s|https://localhost:44310|${IDENTITY_SERVER_URL}|g" src/environments/environment.prod.ts

- name: Build Angular (production)
working-directory: ${{ env.ANGULAR_APP_DIR }}
run: npm run build -- --configuration production

- name: Log in to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Get Static Web App deployment token
id: swa-token
run: |
SWA_TOKEN=$(az staticwebapp secrets list \
--name ${{ env.STATIC_WEB_APP_NAME }} \
--resource-group ${{ env.RESOURCE_GROUP }} \
--query properties.apiKey \
--output tsv)
echo "token=${SWA_TOKEN}" >> $GITHUB_OUTPUT

- name: Deploy to Azure Static Web Apps
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ steps.swa-token.outputs.token }}
action: upload
app_location: 'Clients/TalentManagement-Angular-Material/talent-management'
output_location: 'dist/talent-management/browser'
skip_app_build: true
84 changes: 84 additions & 0 deletions .github/workflows/deploy-api.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Deploy .NET API to Azure App Service

on:
push:
branches:
- main
paths:
- 'ApiResources/TalentManagement-API/**'
- '.github/workflows/deploy-api.yml'
workflow_dispatch:

permissions:
id-token: write # Required for OIDC token request
contents: read

env:
DOTNET_VERSION: '10.x'
PROJECT_PATH: 'ApiResources/TalentManagement-API/TalentManagementAPI.WebApi/TalentManagementAPI.WebApi.csproj'
SOLUTION_PATH: 'ApiResources/TalentManagement-API/TalentManagementAPI.slnx'
PUBLISH_DIR: '${{ github.workspace }}/publish/api'
APP_SERVICE_NAME: 'app-talent-api-dev'
RESOURCE_GROUP: 'rg-talent-dev'

jobs:
build-and-deploy:
name: Build, Test, and Deploy API
runs-on: ubuntu-latest

steps:
- name: Checkout repository (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Restore dependencies
run: dotnet restore ${{ env.SOLUTION_PATH }}

- name: Build
run: dotnet build ${{ env.SOLUTION_PATH }} --configuration Release --no-restore

- name: Run unit tests
run: dotnet test ${{ env.SOLUTION_PATH }} --configuration Release --no-build --verbosity normal

- name: Publish
run: |
dotnet publish ${{ env.PROJECT_PATH }} \
--configuration Release \
--no-build \
--output ${{ env.PUBLISH_DIR }}

- name: Log in to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Configure App Service settings
run: |
az webapp config appsettings set \
--resource-group ${{ env.RESOURCE_GROUP }} \
--name ${{ env.APP_SERVICE_NAME }} \
--settings \
"ConnectionStrings__DefaultConnection=${{ secrets.API_DB_CONNECTION_STRING }}" \
"Sts__ServerUrl=${{ secrets.IDENTITY_SERVER_URL }}" \
"Sts__ValidIssuer=${{ secrets.IDENTITY_SERVER_URL }}" \
"Sts__Audience=app.api.talentmanagement" \
"JWTSettings__Key=${{ secrets.JWT_KEY }}" \
"JWTSettings__Issuer=CoreIdentity" \
"JWTSettings__Audience=CoreIdentityUser" \
"JWTSettings__DurationInMinutes=60" \
"FeatureManagement__AuthEnabled=true" \
"ASPNETCORE_ENVIRONMENT=Production"

- name: Deploy to Azure App Service
uses: azure/webapps-deploy@v3
with:
app-name: ${{ env.APP_SERVICE_NAME }}
package: ${{ env.PUBLISH_DIR }}
76 changes: 76 additions & 0 deletions .github/workflows/deploy-identityserver.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Deploy IdentityServer to Azure App Service

on:
push:
branches:
- main
paths:
- 'TokenService/Duende-IdentityServer/**'
- '.github/workflows/deploy-identityserver.yml'
workflow_dispatch:

permissions:
id-token: write # Required for OIDC token request
contents: read

env:
DOTNET_VERSION: '8.x'
STS_PROJECT_PATH: 'TokenService/Duende-IdentityServer/src/DuendeIdentityServer.STS.Identity/DuendeIdentityServer.STS.Identity.csproj'
ADMIN_PROJECT_PATH: 'TokenService/Duende-IdentityServer/src/DuendeIdentityServer.Admin/DuendeIdentityServer.Admin.csproj'
PUBLISH_DIR: '${{ github.workspace }}/publish/ids'
APP_SERVICE_NAME: 'app-talent-ids-dev'
RESOURCE_GROUP: 'rg-talent-dev'

jobs:
build-and-deploy:
name: Build, Test, and Deploy IdentityServer
runs-on: ubuntu-latest

steps:
- name: Checkout repository (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up .NET ${{ env.DOTNET_VERSION }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Restore dependencies
run: dotnet restore ${{ env.STS_PROJECT_PATH }}

- name: Build
run: dotnet build ${{ env.STS_PROJECT_PATH }} --configuration Release --no-restore

- name: Publish
run: |
dotnet publish ${{ env.STS_PROJECT_PATH }} \
--configuration Release \
--no-build \
--output ${{ env.PUBLISH_DIR }}

- name: Log in to Azure
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Configure App Service settings
run: |
az webapp config appsettings set \
--resource-group ${{ env.RESOURCE_GROUP }} \
--name ${{ env.APP_SERVICE_NAME }} \
--settings \
"ConnectionStrings__ConfigurationDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}" \
"ConnectionStrings__PersistedGrantDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}" \
"ConnectionStrings__IdentityDbConnection=${{ secrets.IDS_DB_CONNECTION_STRING }}" \
"AdminConfiguration__IdentityServerBaseUrl=${{ secrets.IDENTITY_SERVER_URL }}" \
"ASPNETCORE_ENVIRONMENT=Production"

- name: Deploy to Azure App Service
uses: azure/webapps-deploy@v3
with:
app-name: ${{ env.APP_SERVICE_NAME }}
package: ${{ env.PUBLISH_DIR }}
43 changes: 23 additions & 20 deletions blogs/AI-ENHANCEMENT-SERIES-PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,29 +132,32 @@ git push --set-upstream origin feature/[N.N]-[slug]

- [x] Ollama running at `http://localhost:11434` ✅
- [x] `blogs/AI-ENHANCEMENT-SERIES-PLAN.md` created ✅
- [ ] Create `blogs/series-6-ai-app-features/` folder
- [ ] Create `blogs/series-7-developer-productivity-ai/` folder
- [ ] Create `docs/images/ai/` folder for screenshots
- [ ] Update `blogs/BLOG-SERIES-PLAN.md` with Series 6 & 7 entries
- [ ] Update `blogs/SERIES-NAVIGATION-TOC.md` to include new series
- [x] Create `blogs/series-6-ai-app-features/` folder
- [x] Create `blogs/series-7-developer-productivity-ai/` folder
- [x] Create `docs/images/ai/` folder for screenshots
- [x] Update `blogs/BLOG-SERIES-PLAN.md` with Series 6 & 7 entries
- [x] Update `blogs/SERIES-NAVIGATION-TOC.md` to include new series

### Phase 1: Series 6 — Backend Foundation

- [ ] **6.1 — .NET AI Foundation**
- [ ] `git checkout -b feature/6.1-dotnet-ai-foundation` in ApiResources submodule
- [ ] `git checkout -b feature/6.1-dotnet-ai-foundation` in parent repo
- [ ] Write article draft (`6.1-dotnet-ai-foundation.md`)
- [ ] Add to WebApi.csproj: `Microsoft.Extensions.AI`, `Microsoft.Extensions.AI.Ollama`
- [ ] Add `"FeatureManagement": { "AiEnabled": false }` to `appsettings.json`
- [ ] Add `aiEnabled: false` to `environment.ts`
- [ ] Create `Application/Interfaces/IAiChatService.cs`
- [ ] Create `Infrastructure.Shared/Services/OllamaAiService.cs`
- [ ] Create `WebApi/Controllers/v1/AiController.cs` with `[FeatureGate("AiEnabled")]`
- [ ] Screenshot: Swagger AI endpoint → `docs/images/ai/`
- [ ] Commit + push submodule feature branch
- [ ] Commit + push parent feature branch (blog + submodule ref)
- [ ] Open PR: ApiResources `feature/6.1-dotnet-ai-foundation` → `develop`
- [ ] Open PR: Parent `feature/6.1-dotnet-ai-foundation` → `develop`
- [x] **6.1 — .NET AI Foundation** ✅
- [x] `git checkout -b feature/6.1-dotnet-ai-foundation` in ApiResources submodule ✅
- [x] `git checkout -b feature/6.1-dotnet-ai-foundation` in parent repo ✅
- [x] Write article draft (`6.1-dotnet-ai-foundation.md`) ✅
- [x] Add to WebApi.csproj: `Microsoft.Extensions.AI.Ollama` ✅
- [x] Add to Infrastructure.Shared.csproj: `Microsoft.Extensions.AI` ✅
- [x] Add `"AiEnabled": false` to `FeatureManagement` in `appsettings.json` ✅
- [x] Add `"Ollama"` config block to `appsettings.json` ✅
- [x] Create `Application/Interfaces/IAiChatService.cs` ✅
- [x] Create `Infrastructure.Shared/Services/OllamaAiService.cs` ✅
- [x] Create `WebApi/Controllers/v1/AiController.cs` with `[FeatureGate("AiEnabled")]` ✅
- [x] Register `AddOllamaChatClient()` in `Program.cs` ✅
- [x] Register `IAiChatService` → `OllamaAiService` in `ServiceRegistration.cs` ✅
- [ ] Screenshot: Swagger AI endpoint → `docs/images/ai/` *(manual step)*
- [x] Commit + push ApiResources `feature/6.1-dotnet-ai-foundation` ✅
- [x] Commit + push parent `feature/6.1-dotnet-ai-foundation` ✅
- [ ] Open PR: ApiResources `feature/6.1-dotnet-ai-foundation` → `develop` — https://github.com/workcontrolgit/TalentManagement-API/pull/new/feature/6.1-dotnet-ai-foundation
- [ ] Open PR: Parent `feature/6.1-dotnet-ai-foundation` → `develop` — https://github.com/workcontrolgit/AngularNetTutorial/pull/new/feature/6.1-dotnet-ai-foundation

- [ ] **6.2 — HR AI Assistant (data-aware)**
- [ ] `git checkout -b feature/6.2-dotnet-ai-hr-assistant` in ApiResources submodule
Expand Down
54 changes: 52 additions & 2 deletions blogs/BLOG-SERIES-PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,56 @@
- **File:** `blogs/series-5-devops-data/5.2-cicd-github-actions.md`
- **Notes:** Draft complete. Ready for review.

### ☁️ Series 5 Azure Deployment Sub-Series

*Target audience: developers new to Azure with a Visual Studio Professional subscription ($50/month credit). Each article ships with real, runnable Bicep templates and GitHub Actions workflows.*

- [ ] **Article 5.3 — Azure Subscription Setup**
- **Title:** Your First Azure Deployment: Setting Up a Visual Studio Subscription
- **Subtitle:** Activate Your $50 Monthly Credit, Install the Azure CLI, and Understand What Fits in Your Budget
- **File:** `blogs/series-5-devops-data/5.3-azure-subscription-setup.md`
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Blog only — no code files. Setup guide for new Azure users.

- [ ] **Article 5.4 — Bicep Infrastructure**
- **Title:** Infrastructure as Code: Provision All Azure Resources with One Bicep Command
- **Subtitle:** From Empty Subscription to a Running App Service Plan, SQL Server, and Static Web App in Minutes
- **File:** `blogs/series-5-devops-data/5.4-azure-bicep-infrastructure.md`
- **Code:** `infra/main.bicep`, `infra/modules/*.bicep`, `infra/parameters/dev.bicepparam`
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Writes real Bicep templates that can be run against an actual Azure subscription.

- [ ] **Article 5.5 — OIDC GitHub Actions Setup**
- **Title:** Secure CI/CD: Connect GitHub Actions to Azure Without Storing Passwords
- **Subtitle:** How Federated Identity Credentials Replace Long-Lived Secrets With Short-Lived OIDC Tokens
- **File:** `blogs/series-5-devops-data/5.5-azure-oidc-github-actions.md`
- **Code:** Walkthrough of `infra/scripts/setup-oidc.sh` (already written)
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Explains the existing setup-oidc.sh script step by step; covers 4 GitHub Secrets.

- [ ] **Article 5.6 — Deploy .NET Apps**
- **Title:** Deploy .NET API and IdentityServer to Azure App Service with GitHub Actions
- **Subtitle:** Restore, Build, Test, Publish, and Deploy — Automatically on Every Push to Main
- **File:** `blogs/series-5-devops-data/5.6-azure-deploy-dotnet-apps.md`
- **Code:** `.github/workflows/deploy-api.yml`, `.github/workflows/deploy-identityserver.yml`
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Covers deployment order (IdentityServer first), App Service config, EF Core migrations.

- [ ] **Article 5.7 — Deploy Angular**
- **Title:** Deploy Angular to Azure Static Web Apps: Zero Cost, Global CDN, Auto PR Previews
- **Subtitle:** Inject Environment URLs at Build Time and Let GitHub Actions Handle the Rest
- **File:** `blogs/series-5-devops-data/5.7-azure-deploy-angular-swa.md`
- **Code:** `.github/workflows/deploy-angular.yml`, `staticwebapp.config.json`
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Covers environment URL injection at build time and SPA fallback routing config.

- [ ] **Article 5.8 — Post-Deployment Configuration and Validation**
- **Title:** Connect the Stack: Post-Deployment Configuration and Validation
- **Subtitle:** Wire Up IdentityServer Redirect URIs, CORS, and Validate the Full Login Flow on Azure
- **File:** `blogs/series-5-devops-data/5.8-azure-post-deployment-config.md`
- **Branch:** `feature/5.3-5.8-azure-deployment-series`
- **Notes:** Blog only — configuration checklist, common failure patterns, end-to-end validation steps.

---

## 🤖 Series 6: AI App Features
Expand Down Expand Up @@ -257,10 +307,10 @@

## 📊 Publication Tracker

**Total articles planned:** 31
**Total articles planned:** 37
**Published:** 1
**Draft ready:** 22
**Not started:** 10 (Series 6 & 7)
**Not started:** 16 (Series 5 Azure sub-series × 6, Series 6 × 6, Series 7 × 4)

---

Expand Down
Loading