Skip to content

Commit 79dc2c0

Browse files
dcl10claude
andauthored
Project setup (#9)
* add github workflows * remove devops pipelines * initialise project as skill-matrix-llm Rename TemplateApp/templateapp and Reframe/reframe throughout — text, files, and directories — to SkillMatrixLlm / skill-matrix-llm. Update README for GitHub Actions instead of Azure DevOps. Remove one-time Project Setup instructions from CLAUDE.md and AGENTS.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix keycloak seeder mock in integration test factory Mock IKeycloakDataSeeder in ApiFactory so tests don't attempt a live Keycloak connection on startup. Also add PlaceholderTest to unit tests project to prevent test discovery failure in CI when no real tests exist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * extract IKeycloakDataSeeder interface to enable test mocking Add IKeycloakDataSeeder, implement it on KeycloakDataSeeder, register it via DI, and resolve it through the service container at startup. This allows ApiFactory to replace the seeder with a mock so integration tests no longer require a live Keycloak connection. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix missed TemplateApp reference * add frontend/public/.gitkeep Required for the CI build — the workflow copies public/ into the Next.js standalone output and fails if the directory doesn't exist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * update next-env.d.ts routes type path after production build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 0161b72 commit 79dc2c0

77 files changed

Lines changed: 869 additions & 1044 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/pull_request_template.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Description
2+
3+
<!-- Write a description of the changes here -->
4+
5+
## Linked issues
6+
7+
<!-- Write a list of issues this PR is related to -->
8+
<!-- e.g.
9+
- #1
10+
- #2
11+
- Closes #3
12+
-->
13+
14+
## (Optional) Screenshots
15+
16+
<!-- Please attach screenshots of UI changes or any other visual change -->

.github/workflows/cd-backend.yml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: CD — Backend
2+
3+
# Manually triggered. Builds the backend from the selected branch and deploys
4+
# it to UAT first, then prod. Approval gates on each environment control
5+
# whether each stage proceeds.
6+
#
7+
# Approval gates are configured in GitHub repo Settings > Environments:
8+
# skill-matrix-llm-uat — 1 required reviewer
9+
# skill-matrix-llm-prod — 2 required reviewers
10+
#
11+
# Required repository secrets: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID
12+
13+
on:
14+
workflow_dispatch:
15+
16+
env:
17+
DOTNET_VERSION: '10.x'
18+
BUILD_CONFIG: Release
19+
SOLUTION: backend/SkillMatrixLlm.sln
20+
PROJECT: backend/src/SkillMatrixLlm.Api/SkillMatrixLlm.Api.csproj
21+
22+
jobs:
23+
build:
24+
name: Build & Publish
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- uses: actions/setup-dotnet@v4
31+
with:
32+
dotnet-version: ${{ env.DOTNET_VERSION }}
33+
34+
- name: Restore & Build
35+
run: |
36+
dotnet restore ${{ env.SOLUTION }}
37+
dotnet build ${{ env.SOLUTION }} --configuration ${{ env.BUILD_CONFIG }} --no-restore
38+
39+
- name: Publish
40+
run: |
41+
dotnet publish ${{ env.PROJECT }} \
42+
--configuration ${{ env.BUILD_CONFIG }} \
43+
--no-build \
44+
--output publish/api
45+
46+
- name: Upload api-drop
47+
uses: actions/upload-artifact@v4
48+
with:
49+
name: api-drop
50+
path: publish/api
51+
52+
deploy-uat:
53+
name: Deploy to UAT
54+
needs: build
55+
runs-on: ubuntu-latest
56+
environment: skill-matrix-llm-uat
57+
permissions:
58+
id-token: write
59+
contents: read
60+
61+
steps:
62+
- name: Download api-drop
63+
uses: actions/download-artifact@v4
64+
with:
65+
name: api-drop
66+
path: api-drop
67+
68+
- uses: azure/login@v2
69+
with:
70+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
71+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
72+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
73+
74+
- name: Deploy API to UAT
75+
uses: azure/webapps-deploy@v3
76+
with:
77+
app-name: skill-matrix-llm-uat-api
78+
package: api-drop
79+
80+
deploy-prod:
81+
name: Deploy to Production
82+
needs: deploy-uat
83+
runs-on: ubuntu-latest
84+
environment: skill-matrix-llm-prod
85+
permissions:
86+
id-token: write
87+
contents: read
88+
89+
steps:
90+
- name: Download api-drop
91+
uses: actions/download-artifact@v4
92+
with:
93+
name: api-drop
94+
path: api-drop
95+
96+
- uses: azure/login@v2
97+
with:
98+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
99+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
100+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
101+
102+
- name: Deploy API to Production
103+
uses: azure/webapps-deploy@v3
104+
with:
105+
app-name: skill-matrix-llm-prod-api
106+
package: api-drop

.github/workflows/cd-frontend.yml

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: CD — Frontend
2+
3+
# Manually triggered. Builds the frontend from the selected branch and deploys
4+
# it to UAT first, then prod. Approval gates on each environment control
5+
# whether each stage proceeds.
6+
#
7+
# The artifact contains the Next.js standalone server (server.js).
8+
# The App Service startup command is set to 'node server.js' by Bicep (config/webapp.bicep).
9+
#
10+
# Approval gates are configured in GitHub repo Settings > Environments:
11+
# skill-matrix-llm-uat — 1 required reviewer
12+
# skill-matrix-llm-prod — 2 required reviewers
13+
#
14+
# Required repository secrets: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID
15+
16+
on:
17+
workflow_dispatch:
18+
19+
env:
20+
NODE_VERSION: '20.x'
21+
22+
jobs:
23+
build:
24+
name: Install, Build & Package
25+
runs-on: ubuntu-latest
26+
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- uses: actions/setup-node@v4
31+
with:
32+
node-version: ${{ env.NODE_VERSION }}
33+
cache: npm
34+
cache-dependency-path: frontend/package-lock.json
35+
36+
- name: Install dependencies
37+
run: npm ci
38+
working-directory: frontend
39+
40+
- name: Build Next.js
41+
run: npm run build
42+
working-directory: frontend
43+
env:
44+
NEXTAUTH_URL: 'http://placeholder'
45+
NEXTAUTH_SECRET: 'placeholder-build-secret-32-chars!!'
46+
KEYCLOAK_CLIENT_ID: placeholder
47+
KEYCLOAK_CLIENT_SECRET: placeholder
48+
KEYCLOAK_ISSUER: 'https://placeholder.example.com/realms/placeholder'
49+
NEXT_PUBLIC_API_BASE_URL: 'https://placeholder'
50+
51+
- name: Copy public/ and static/ into standalone output
52+
run: |
53+
cp -r frontend/public frontend/.next/standalone/
54+
cp -r frontend/.next/static frontend/.next/standalone/.next/static
55+
56+
- name: Upload frontend-drop
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: frontend-drop
60+
path: frontend/.next/standalone
61+
62+
deploy-uat:
63+
name: Deploy to UAT
64+
needs: build
65+
runs-on: ubuntu-latest
66+
environment: skill-matrix-llm-uat
67+
permissions:
68+
id-token: write
69+
contents: read
70+
71+
steps:
72+
- name: Download frontend-drop
73+
uses: actions/download-artifact@v4
74+
with:
75+
name: frontend-drop
76+
path: frontend-drop
77+
78+
- uses: azure/login@v2
79+
with:
80+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
81+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
82+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
83+
84+
- name: Deploy frontend to UAT
85+
uses: azure/webapps-deploy@v3
86+
with:
87+
app-name: skill-matrix-llm-uat-frontend
88+
package: frontend-drop
89+
startup-command: node server.js
90+
91+
deploy-prod:
92+
name: Deploy to Production
93+
needs: deploy-uat
94+
runs-on: ubuntu-latest
95+
environment: skill-matrix-llm-prod
96+
permissions:
97+
id-token: write
98+
contents: read
99+
100+
steps:
101+
- name: Download frontend-drop
102+
uses: actions/download-artifact@v4
103+
with:
104+
name: frontend-drop
105+
path: frontend-drop
106+
107+
- uses: azure/login@v2
108+
with:
109+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
110+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
111+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
112+
113+
- name: Deploy frontend to Production
114+
uses: azure/webapps-deploy@v3
115+
with:
116+
app-name: skill-matrix-llm-prod-frontend
117+
package: frontend-drop
118+
startup-command: node server.js
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: CD — Infrastructure
2+
3+
# Manual workflow for deploying Azure infrastructure via Bicep.
4+
#
5+
# Stages:
6+
# 1. validate — bicep lint + az deployment validate (uses placeholder password)
7+
# 2. what-if — az deployment what-if (shows planned changes without applying)
8+
# 3. deploy — az deployment group create (requires environment approval)
9+
#
10+
# Required repository secrets: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID
11+
# Required environment secrets (skill-matrix-llm-uat / skill-matrix-llm-prod): POSTGRES_ADMIN_PASSWORD
12+
13+
on:
14+
workflow_dispatch:
15+
inputs:
16+
target_environment:
17+
description: Target environment
18+
type: choice
19+
options: [uat, prod]
20+
default: uat
21+
22+
env:
23+
INFRA_PATH: infra
24+
25+
jobs:
26+
validate:
27+
name: Validate (${{ inputs.target_environment }})
28+
runs-on: ubuntu-latest
29+
permissions:
30+
id-token: write
31+
contents: read
32+
env:
33+
RESOURCE_GROUP: ${{ inputs.target_environment == 'uat' && 'skill-matrix-llm-uat-rg' || 'skill-matrix-llm-prod-rg' }}
34+
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- uses: azure/login@v2
39+
with:
40+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
41+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
42+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
43+
44+
- name: Bicep lint
45+
run: az bicep build --file ${{ env.INFRA_PATH }}/main.bicep
46+
47+
- name: ARM validate
48+
run: |
49+
az deployment group validate \
50+
--resource-group ${{ env.RESOURCE_GROUP }} \
51+
--template-file ${{ env.INFRA_PATH }}/main.bicep \
52+
--parameters ${{ env.INFRA_PATH }}/main.${{ inputs.target_environment }}.bicepparam \
53+
--parameters postgresAdminPassword='placeholder-for-validation'
54+
55+
what-if:
56+
name: What-If (${{ inputs.target_environment }})
57+
needs: validate
58+
runs-on: ubuntu-latest
59+
permissions:
60+
id-token: write
61+
contents: read
62+
env:
63+
RESOURCE_GROUP: ${{ inputs.target_environment == 'uat' && 'skill-matrix-llm-uat-rg' || 'skill-matrix-llm-prod-rg' }}
64+
65+
steps:
66+
- uses: actions/checkout@v4
67+
68+
- uses: azure/login@v2
69+
with:
70+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
71+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
72+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
73+
74+
- name: What-if analysis
75+
run: |
76+
az deployment group what-if \
77+
--resource-group ${{ env.RESOURCE_GROUP }} \
78+
--template-file ${{ env.INFRA_PATH }}/main.bicep \
79+
--parameters ${{ env.INFRA_PATH }}/main.${{ inputs.target_environment }}.bicepparam \
80+
--parameters postgresAdminPassword='placeholder-for-what-if'
81+
82+
deploy:
83+
name: Deploy (${{ inputs.target_environment }})
84+
needs: what-if
85+
runs-on: ubuntu-latest
86+
environment: skill-matrix-llm-${{ inputs.target_environment }}
87+
permissions:
88+
id-token: write
89+
contents: read
90+
env:
91+
RESOURCE_GROUP: ${{ inputs.target_environment == 'uat' && 'skill-matrix-llm-uat-rg' || 'skill-matrix-llm-prod-rg' }}
92+
93+
steps:
94+
- uses: actions/checkout@v4
95+
96+
- uses: azure/login@v2
97+
with:
98+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
99+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
100+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
101+
102+
- name: Deploy Bicep
103+
run: |
104+
az deployment group create \
105+
--resource-group ${{ env.RESOURCE_GROUP }} \
106+
--template-file ${{ env.INFRA_PATH }}/main.bicep \
107+
--parameters ${{ env.INFRA_PATH }}/main.${{ inputs.target_environment }}.bicepparam \
108+
--parameters postgresAdminPassword='${{ secrets.POSTGRES_ADMIN_PASSWORD }}' \
109+
--name infra-${{ inputs.target_environment }}-${{ github.run_number }}

0 commit comments

Comments
 (0)