Fix TypeScript compilation errors

- Add searchReference to ApplicationListItem type
- Fix result variable in toApplicationDetails function
- Add query helper functions for req.query parameter handling
- Fix req.query.* type errors in routes (applications, cache, classifications, objects)
- Fix CompletenessCategoryConfig missing id property
- Fix number | null type errors in dataService
- Add utils/queryHelpers.ts for reusable query parameter helpers
This commit is contained in:
2026-01-14 16:36:22 +01:00
parent fb7dd23027
commit 81d477ec8c
13 changed files with 1166 additions and 58 deletions

View File

@@ -6,6 +6,7 @@ import { logger } from '../services/logger.js';
import { calculateRequiredEffortApplicationManagementWithBreakdown } from '../services/effortCalculation.js';
import { findBIAMatch, loadBIAData, clearBIACache, calculateSimilarity } from '../services/biaMatchingService.js';
import { calculateApplicationCompleteness } from '../services/dataCompletenessConfig.js';
import { getQueryString } from '../utils/queryHelpers.js';
import type { SearchFilters, ReferenceValue, ClassificationResult, ApplicationDetails, ApplicationStatus } from '../types/index.js';
import type { Server, Flows, Certificate, Domain, AzureSubscription, CMDBObjectTypeName } from '../generated/jira-types.js';
@@ -31,7 +32,7 @@ router.post('/search', async (req: Request, res: Response) => {
// Get team dashboard data
router.get('/team-dashboard', async (req: Request, res: Response) => {
try {
const excludedStatusesParam = req.query.excludedStatuses as string | undefined;
const excludedStatusesParam = getQueryString(req, 'excludedStatuses');
let excludedStatuses: ApplicationStatus[] = [];
if (excludedStatusesParam && excludedStatusesParam.trim().length > 0) {
@@ -56,7 +57,7 @@ router.get('/team-dashboard', async (req: Request, res: Response) => {
// Get team portfolio health metrics
router.get('/team-portfolio-health', async (req: Request, res: Response) => {
try {
const excludedStatusesParam = req.query.excludedStatuses as string | undefined;
const excludedStatusesParam = getQueryString(req, 'excludedStatuses');
let excludedStatuses: ApplicationStatus[] = [];
if (excludedStatusesParam && excludedStatusesParam.trim().length > 0) {
@@ -95,7 +96,7 @@ router.get('/business-importance-comparison', async (req: Request, res: Response
// Test BIA data loading (for debugging)
router.get('/bia-test', async (req: Request, res: Response) => {
try {
if (req.query.clear === 'true') {
if (getQueryString(req, 'clear') === 'true') {
clearBIACache();
}
const biaData = loadBIAData();
@@ -133,7 +134,7 @@ router.get('/bia-debug', async (req: Request, res: Response) => {
// Test each sample app
for (const app of [...sampleApps, ...testApps]) {
const matchResult = findBIAMatch(app.name, app.searchReference);
const matchResult = findBIAMatch(app.name, app.searchReference ?? null);
// Find all potential matches in Excel data for detailed analysis
const normalizedAppName = app.name.toLowerCase().trim();
@@ -246,7 +247,7 @@ router.get('/bia-comparison', async (req: Request, res: Response) => {
for (const app of applications) {
// Find BIA match in Excel
const matchResult = findBIAMatch(app.name, app.searchReference);
const matchResult = findBIAMatch(app.name, app.searchReference ?? null);
// Log first few matches for debugging
if (comparisonItems.length < 5) {
@@ -323,7 +324,7 @@ router.get('/bia-comparison', async (req: Request, res: Response) => {
router.get('/:id', async (req: Request, res: Response) => {
try {
const { id } = req.params;
const mode = req.query.mode as string | undefined;
const mode = getQueryString(req, 'mode');
// Don't treat special routes as application IDs
if (id === 'team-dashboard' || id === 'team-portfolio-health' || id === 'business-importance-comparison' || id === 'bia-comparison' || id === 'bia-test' || id === 'calculate-effort' || id === 'search') {
@@ -617,8 +618,9 @@ router.get('/:id/related/:objectType', async (req: Request, res: Response) => {
}
// Get requested attributes from query string
const requestedAttrs = req.query.attributes
? String(req.query.attributes).split(',').map(a => a.trim())
const attributesParam = getQueryString(req, 'attributes');
const requestedAttrs = attributesParam
? attributesParam.split(',').map(a => a.trim())
: [];
// Format response - must match RelatedObjectsResponse type expected by frontend

View File

@@ -8,6 +8,7 @@ import { Router, Request, Response } from 'express';
import { cacheStore } from '../services/cacheStore.js';
import { syncEngine } from '../services/syncEngine.js';
import { logger } from '../services/logger.js';
import { getQueryString } from '../utils/queryHelpers.js';
import { OBJECT_TYPES } from '../generated/jira-schema.js';
import type { CMDBObjectTypeName } from '../generated/jira-types.js';
@@ -78,10 +79,11 @@ router.post('/sync/:objectType', async (req: Request, res: Response) => {
try {
const { objectType } = req.params;
// Validate object type
if (!OBJECT_TYPES[objectType]) {
// Validate object type - convert to string if array
const objectTypeStr = Array.isArray(objectType) ? objectType[0] : objectType;
if (!OBJECT_TYPES[objectTypeStr]) {
res.status(400).json({
error: `Unknown object type: ${objectType}`,
error: `Unknown object type: ${objectTypeStr}`,
supportedTypes: Object.keys(OBJECT_TYPES),
});
return;
@@ -89,11 +91,11 @@ router.post('/sync/:objectType', async (req: Request, res: Response) => {
logger.info(`Manual sync triggered for ${objectType}`);
const result = await syncEngine.syncType(objectType as CMDBObjectTypeName);
const result = await syncEngine.syncType(objectTypeStr as CMDBObjectTypeName);
res.json({
status: 'completed',
objectType,
objectType: objectTypeStr,
stats: result,
});
} catch (error) {
@@ -113,10 +115,11 @@ router.post('/sync/:objectType', async (req: Request, res: Response) => {
router.delete('/clear/:objectType', async (req: Request, res: Response) => {
try {
const { objectType } = req.params;
const objectTypeStr = Array.isArray(objectType) ? objectType[0] : objectType;
if (!OBJECT_TYPES[objectType]) {
if (!OBJECT_TYPES[objectTypeStr]) {
res.status(400).json({
error: `Unknown object type: ${objectType}`,
error: `Unknown object type: ${objectTypeStr}`,
supportedTypes: Object.keys(OBJECT_TYPES),
});
return;

View File

@@ -4,6 +4,7 @@ import { dataService } from '../services/dataService.js';
import { databaseService } from '../services/database.js';
import { logger } from '../services/logger.js';
import { config } from '../config/env.js';
import { getQueryString, getQueryNumber } from '../utils/queryHelpers.js';
const router = Router();
@@ -12,7 +13,7 @@ router.post('/suggest/:id', async (req: Request, res: Response) => {
try {
const { id } = req.params;
// Get provider from query parameter or request body, default to config
const provider = (req.query.provider as AIProvider) || (req.body.provider as AIProvider) || config.defaultAIProvider;
const provider = (getQueryString(req, 'provider') as AIProvider) || (req.body.provider as AIProvider) || config.defaultAIProvider;
if (!aiService.isConfigured(provider)) {
res.status(503).json({
@@ -70,7 +71,7 @@ router.get('/function/:code', (req: Request, res: Response) => {
// Get classification history
router.get('/history', async (req: Request, res: Response) => {
try {
const limit = parseInt(req.query.limit as string) || 50;
const limit = getQueryNumber(req, 'limit', 50);
const history = await databaseService.getClassificationHistory(limit);
res.json(history);
} catch (error) {

View File

@@ -142,37 +142,39 @@ router.get('/data-completeness', async (req: Request, res: Response) => {
description: 'Configuration for Data Completeness Score fields',
lastUpdated: new Date().toISOString(),
},
categories: {
general: {
categories: [
{
id: 'general',
name: 'General',
description: 'General application information fields',
fields: [
{ name: 'Organisation', fieldPath: 'organisation', enabled: true },
{ name: 'ApplicationFunction', fieldPath: 'applicationFunctions', enabled: true },
{ name: 'Status', fieldPath: 'status', enabled: true },
{ name: 'Business Impact Analyse', fieldPath: 'businessImpactAnalyse', enabled: true },
{ name: 'Application Component Hosting Type', fieldPath: 'hostingType', enabled: true },
{ name: 'Supplier Product', fieldPath: 'supplierProduct', enabled: true },
{ name: 'Business Owner', fieldPath: 'businessOwner', enabled: true },
{ name: 'System Owner', fieldPath: 'systemOwner', enabled: true },
{ name: 'Functional Application Management', fieldPath: 'functionalApplicationManagement', enabled: true },
{ name: 'Technical Application Management', fieldPath: 'technicalApplicationManagement', enabled: true },
{ id: 'organisation', name: 'Organisation', fieldPath: 'organisation', enabled: true },
{ id: 'applicationFunctions', name: 'ApplicationFunction', fieldPath: 'applicationFunctions', enabled: true },
{ id: 'status', name: 'Status', fieldPath: 'status', enabled: true },
{ id: 'businessImpactAnalyse', name: 'Business Impact Analyse', fieldPath: 'businessImpactAnalyse', enabled: true },
{ id: 'hostingType', name: 'Application Component Hosting Type', fieldPath: 'hostingType', enabled: true },
{ id: 'supplierProduct', name: 'Supplier Product', fieldPath: 'supplierProduct', enabled: true },
{ id: 'businessOwner', name: 'Business Owner', fieldPath: 'businessOwner', enabled: true },
{ id: 'systemOwner', name: 'System Owner', fieldPath: 'systemOwner', enabled: true },
{ id: 'functionalApplicationManagement', name: 'Functional Application Management', fieldPath: 'functionalApplicationManagement', enabled: true },
{ id: 'technicalApplicationManagement', name: 'Technical Application Management', fieldPath: 'technicalApplicationManagement', enabled: true },
],
},
applicationManagement: {
{
id: 'applicationManagement',
name: 'Application Management',
description: 'Application management classification fields',
fields: [
{ name: 'ICT Governance Model', fieldPath: 'governanceModel', enabled: true },
{ name: 'Application Management - Application Type', fieldPath: 'applicationType', enabled: true },
{ name: 'Application Management - Hosting', fieldPath: 'applicationManagementHosting', enabled: true },
{ name: 'Application Management - TAM', fieldPath: 'applicationManagementTAM', enabled: true },
{ name: 'Application Management - Dynamics Factor', fieldPath: 'dynamicsFactor', enabled: true },
{ name: 'Application Management - Complexity Factor', fieldPath: 'complexityFactor', enabled: true },
{ name: 'Application Management - Number of Users', fieldPath: 'numberOfUsers', enabled: true },
{ id: 'governanceModel', name: 'ICT Governance Model', fieldPath: 'governanceModel', enabled: true },
{ id: 'applicationType', name: 'Application Management - Application Type', fieldPath: 'applicationType', enabled: true },
{ id: 'applicationManagementHosting', name: 'Application Management - Hosting', fieldPath: 'applicationManagementHosting', enabled: true },
{ id: 'applicationManagementTAM', name: 'Application Management - TAM', fieldPath: 'applicationManagementTAM', enabled: true },
{ id: 'dynamicsFactor', name: 'Application Management - Dynamics Factor', fieldPath: 'dynamicsFactor', enabled: true },
{ id: 'complexityFactor', name: 'Application Management - Complexity Factor', fieldPath: 'complexityFactor', enabled: true },
{ id: 'numberOfUsers', name: 'Application Management - Number of Users', fieldPath: 'numberOfUsers', enabled: true },
],
},
},
],
};
res.json(defaultConfig);
}

View File

@@ -7,6 +7,7 @@
import { Router, Request, Response } from 'express';
import { cmdbService } from '../services/cmdbService.js';
import { logger } from '../services/logger.js';
import { getQueryString, getQueryNumber } from '../utils/queryHelpers.js';
import { OBJECT_TYPES } from '../generated/jira-schema.js';
import type { CMDBObject, CMDBObjectTypeName } from '../generated/jira-types.js';
@@ -32,9 +33,9 @@ router.get('/', (req: Request, res: Response) => {
router.get('/:type', async (req: Request, res: Response) => {
try {
const { type } = req.params;
const limit = parseInt(req.query.limit as string) || 1000;
const offset = parseInt(req.query.offset as string) || 0;
const search = req.query.search as string | undefined;
const limit = getQueryNumber(req, 'limit', 1000);
const offset = getQueryNumber(req, 'offset', 0);
const search = getQueryString(req, 'search');
// Validate type
if (!OBJECT_TYPES[type]) {
@@ -71,7 +72,7 @@ router.get('/:type', async (req: Request, res: Response) => {
router.get('/:type/:id', async (req: Request, res: Response) => {
try {
const { type, id } = req.params;
const forceRefresh = req.query.refresh === 'true';
const forceRefresh = getQueryString(req, 'refresh') === 'true';
// Validate type
if (!OBJECT_TYPES[type]) {
@@ -102,7 +103,7 @@ router.get('/:type/:id', async (req: Request, res: Response) => {
router.get('/:type/:id/related/:relationType', async (req: Request, res: Response) => {
try {
const { type, id, relationType } = req.params;
const attribute = req.query.attribute as string | undefined;
const attribute = getQueryString(req, 'attribute');
// Validate types
if (!OBJECT_TYPES[type]) {
@@ -139,7 +140,7 @@ router.get('/:type/:id/related/:relationType', async (req: Request, res: Respons
router.get('/:type/:id/referenced-by/:sourceType', async (req: Request, res: Response) => {
try {
const { type, id, sourceType } = req.params;
const attribute = req.query.attribute as string | undefined;
const attribute = getQueryString(req, 'attribute');
// Validate types
if (!OBJECT_TYPES[type]) {

View File

@@ -289,19 +289,18 @@ async function toApplicationDetails(app: ApplicationComponent): Promise<Applicat
};
// Calculate data completeness percentage
// Convert ApplicationListItem-like structure to format expected by completeness calculator
// Convert ApplicationDetails-like structure to format expected by completeness calculator
const appForCompleteness = {
...result,
organisation: organisation?.name || null,
applicationFunctions: result.applicationFunctions,
status: result.status,
applicationFunctions: applicationFunctions,
status: (app.status || 'In Production') as ApplicationStatus,
businessImpactAnalyse: businessImpactAnalyse,
hostingType: hostingType,
supplierProduct: result.supplierProduct,
businessOwner: result.businessOwner,
systemOwner: result.systemOwner,
functionalApplicationManagement: result.functionalApplicationManagement,
technicalApplicationManagement: result.technicalApplicationManagement,
supplierProduct: extractLabel(app.supplierProduct),
businessOwner: extractLabel(app.businessOwner),
systemOwner: extractLabel(app.systemOwner),
functionalApplicationManagement: app.functionalApplicationManagement || null,
technicalApplicationManagement: extractLabel(app.technicalApplicationManagement),
governanceModel: governanceModel,
applicationType: applicationType,
applicationManagementHosting: applicationManagementHosting,
@@ -314,7 +313,48 @@ async function toApplicationDetails(app: ApplicationComponent): Promise<Applicat
const completenessPercentage = calculateApplicationCompleteness(appForCompleteness);
return {
...result,
id: app.id,
key: app.objectKey,
name: app.label,
description: app.description || null,
status: (app.status || 'In Production') as ApplicationStatus,
searchReference: app.searchReference || null,
// Organization info
organisation: organisation?.name || null,
businessOwner: extractLabel(app.businessOwner),
systemOwner: extractLabel(app.systemOwner),
functionalApplicationManagement: app.functionalApplicationManagement || null,
technicalApplicationManagement: extractLabel(app.technicalApplicationManagement),
technicalApplicationManagementPrimary: extractDisplayValue(app.technicalApplicationManagementPrimary),
technicalApplicationManagementSecondary: extractDisplayValue(app.technicalApplicationManagementSecondary),
// Technical info
medischeTechniek: app.medischeTechniek || false,
technischeArchitectuur: app.technischeArchitectuurTA || null,
supplierProduct: extractLabel(app.supplierProduct),
// Classification
applicationFunctions,
businessImportance: businessImportance?.name || null,
businessImpactAnalyse,
hostingType,
// Application Management
governanceModel,
applicationType,
applicationSubteam,
applicationTeam,
dynamicsFactor,
complexityFactor,
numberOfUsers,
applicationManagementHosting,
applicationManagementTAM,
platform,
// Override
overrideFTE: app.applicationManagementOverrideFTE ?? null,
requiredEffortApplicationManagement: null,
dataCompletenessPercentage: Math.round(completenessPercentage * 10) / 10, // Round to 1 decimal
};
}
@@ -457,6 +497,7 @@ function toApplicationListItem(app: ApplicationComponent): ApplicationListItem {
id: app.id,
key: app.objectKey,
name: app.label,
searchReference: app.searchReference || null,
status: app.status as ApplicationStatus | null,
applicationFunctions,
governanceModel,
@@ -1209,7 +1250,7 @@ export const dataService = {
// Get complexity factor value
if (app.applicationManagementComplexityFactor && typeof app.applicationManagementComplexityFactor === 'object') {
const factorObj = complexityFactorCache?.get(app.applicationManagementComplexityFactor.objectId);
if (factorObj?.factor !== undefined) {
if (factorObj?.factor !== undefined && factorObj.factor !== null) {
metrics.complexityValues.push(factorObj.factor);
}
}
@@ -1217,7 +1258,7 @@ export const dataService = {
// Get dynamics factor value
if (app.applicationManagementDynamicsFactor && typeof app.applicationManagementDynamicsFactor === 'object') {
const factorObj = dynamicsFactorCache?.get(app.applicationManagementDynamicsFactor.objectId);
if (factorObj?.factor !== undefined) {
if (factorObj?.factor !== undefined && factorObj.factor !== null) {
metrics.dynamicsValues.push(factorObj.factor);
}
}

View File

@@ -34,6 +34,7 @@ export interface ApplicationListItem {
id: string;
key: string;
name: string;
searchReference?: string | null; // Search reference for matching
status: ApplicationStatus | null;
applicationFunctions: ReferenceValue[]; // Multiple functions supported
governanceModel: ReferenceValue | null;

View File

@@ -0,0 +1,34 @@
/**
* Helper functions for Express request query parameters
*/
import { Request } from 'express';
/**
* Get a query parameter as a string, handling both string and string[] types
*/
export function getQueryString(req: Request, key: string): string | undefined {
const value = req.query[key];
if (value === undefined) return undefined;
if (Array.isArray(value)) return value[0] as string;
return value as string;
}
/**
* Get a query parameter as a number, handling both string and string[] types
*/
export function getQueryNumber(req: Request, key: string, defaultValue?: number): number {
const value = getQueryString(req, key);
if (value === undefined) return defaultValue ?? 0;
const parsed = parseInt(value, 10);
return isNaN(parsed) ? (defaultValue ?? 0) : parsed;
}
/**
* Get a query parameter as a boolean
*/
export function getQueryBoolean(req: Request, key: string, defaultValue = false): boolean {
const value = getQueryString(req, key);
if (value === undefined) return defaultValue;
return value === 'true' || value === '1';
}

View File

@@ -0,0 +1,270 @@
# Azure CLI - Quick Start Guide
## 📍 Waar voer je deze commando's uit?
Je voert deze commando's uit in de **Terminal** (command line) op je computer.
---
## 🖥️ Terminal Openen
### Op macOS (jouw situatie):
1. **Open Terminal:**
- Druk op `Cmd + Space` (Spotlight)
- Typ "Terminal"
- Druk Enter
- Of: Applications → Utilities → Terminal
2. **Of gebruik iTerm2** (als je die hebt geïnstalleerd)
### Op Windows:
- **PowerShell** of **Command Prompt**
- Druk `Win + R`, typ `powershell`, Enter
### Op Linux:
- Open je terminal emulator (bijv. GNOME Terminal, Konsole)
---
## ✅ Stap 1: Check of Azure CLI Geïnstalleerd is
**Voer dit commando uit in de terminal:**
```bash
az --version
```
**Als je een versie ziet** (bijv. `azure-cli 2.50.0`): ✅ Azure CLI is geïnstalleerd, ga door naar Stap 2.
**Als je een foutmelding krijgt** (bijv. `command not found`): ❌ Azure CLI is niet geïnstalleerd, zie installatie hieronder.
---
## 📥 Stap 2: Azure CLI Installeren (als nodig)
### Op macOS:
**Optie A: Met Homebrew (Aanbevolen)**
```bash
# Installeer Homebrew (als je die nog niet hebt)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Installeer Azure CLI
brew install azure-cli
```
**Optie B: Met Installer**
1. Download: https://aka.ms/installazureclimac
2. Open het `.pkg` bestand
3. Volg de installatie wizard
**Optie C: Met pip (Python)**
```bash
pip3 install azure-cli
```
### Op Windows:
1. Download: https://aka.ms/installazurecliwindows
2. Run de `.msi` installer
3. Volg de installatie wizard
### Op Linux:
```bash
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```
**Na installatie, check opnieuw:**
```bash
az --version
```
---
## 🔐 Stap 3: Login bij Azure
**Voer dit commando uit:**
```bash
az login
```
**Wat gebeurt er:**
1. Je browser opent automatisch
2. Log in met je Azure account (hetzelfde account dat je gebruikt voor Azure Portal)
3. Na succesvol inloggen, sluit je de browser
4. De terminal toont je subscriptions
**Als browser niet opent automatisch:**
- Je krijgt een code en URL in de terminal
- Kopieer de code
- Open de URL in je browser
- Voer de code in
**Verwachte output:**
```
[
{
"cloudName": "AzureCloud",
"id": "12345678-1234-1234-1234-123456789012",
"name": "Subscription Name",
"state": "Enabled",
...
}
]
```
**✅ Je bent nu ingelogd!**
---
## 🔍 Stap 4: Haal ACR Credentials Op
**Voer dit commando uit:**
```bash
az acr credential show --name zdlas
```
**Verwachte output:**
```json
{
"passwords": [
{
"name": "password",
"value": "abc123xyz..."
},
{
"name": "password2",
"value": "def456uvw..."
}
],
"username": "zdlas"
}
```
**Noteer:**
- **Username**: `zdlas` (of wat er staat)
- **Password**: Gebruik `passwords[0].value` (de eerste password)
**⚠️ Belangrijk:** Deze credentials zijn gevoelig! Deel ze niet en gebruik ze alleen voor de service connection.
---
## 📋 Complete Stappen in Terminal
**Hier is de complete reeks commando's:**
```bash
# 1. Check of Azure CLI geïnstalleerd is
az --version
# 2. Login bij Azure (opent browser)
az login
# 3. Haal ACR credentials op
az acr credential show --name zdlas
```
**Kopieer de output** en gebruik de `username` en `passwords[0].value` in Azure DevOps.
---
## 🔄 Alternatief: Via Azure Portal (Zonder Azure CLI)
**Als je Azure CLI niet wilt installeren, kun je credentials ook via Azure Portal ophalen:**
1. **Ga naar Azure Portal**: https://portal.azure.com
2. **Ga naar je Container Registry**: Zoek naar `zdlas`
3. **Klik op "Access keys"** (links in het menu)
4. **Je ziet:**
- **Login server**: `zdlas.azurecr.io`
- **Username**: `zdlas` (of admin username)
- **Password**: Klik op "Show" naast password om het te zien
- **Password2**: Alternatieve password
5. **Kopieer de username en password**
**✅ Dit is hetzelfde als `az acr credential show`!**
---
## 🎯 Voor Jouw Situatie (Service Connection)
**Gebruik deze credentials in Azure DevOps:**
1. **In de service connection wizard:**
- Kies "Docker Registry" → "Others"
- **Docker Registry**: `zdlas.azurecr.io`
- **Docker ID**: `zdlas` (of de username uit de output)
- **Docker Password**: `passwords[0].value` (uit de output)
- **Service connection name**: `zuyderland-cmdb-acr-connection`
2. **Save**
---
## 🚨 Troubleshooting
### "az: command not found"
**Oplossing:** Azure CLI is niet geïnstalleerd
- Installeer Azure CLI (zie Stap 2 hierboven)
- Of gebruik Azure Portal alternatief (zie hierboven)
### "az login" opent geen browser
**Oplossing:**
- Kopieer de code en URL uit de terminal
- Open de URL handmatig in je browser
- Voer de code in
### "Subscription not found" of "Access denied"
**Oplossing:**
- Check of je ingelogd bent met het juiste Azure account
- Check of je toegang hebt tot de subscription waar de ACR staat
- Probeer: `az account list` om je subscriptions te zien
- Selecteer de juiste subscription: `az account set --subscription "Subscription Name"`
### "ACR not found"
**Oplossing:**
- Check of de ACR naam correct is: `zdlas`
- Check of je toegang hebt tot de ACR
- Probeer: `az acr list` om alle ACR's te zien
---
## 💡 Tips
1. **Azure CLI blijft ingelogd** - Je hoeft niet elke keer `az login` te doen
2. **Check je subscription** - Als je meerdere subscriptions hebt: `az account show`
3. **Wissel subscription** - `az account set --subscription "Subscription Name"`
4. **Logout** - `az logout` (als je klaar bent)
---
## 📚 Meer Informatie
- [Azure CLI Installatie](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
- [Azure CLI Login](https://learn.microsoft.com/en-us/cli/azure/authenticate-azure-cli)
- [ACR Credentials](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication)
---
## 🎯 Quick Reference
**Terminal openen:**
- macOS: `Cmd + Space` → "Terminal"
**Azure CLI commando's:**
```bash
az --version # Check installatie
az login # Login bij Azure
az acr credential show --name zdlas # Haal credentials op
```
**Azure Portal alternatief:**
- Portal → Container Registry → Access keys
**Klaar!** 🚀

View File

@@ -0,0 +1,250 @@
# Azure DevOps Pipeline - Repository Not Found
## 🔴 Probleem: "No matching repositories were found"
Als Azure DevOps je repository niet kan vinden bij het aanmaken van een pipeline, probeer deze oplossingen:
---
## ✅ Oplossing 1: Check Repository Naam
**Probleem:** De repository naam komt mogelijk niet overeen.
**Oplossing:**
1. **Ga naar Repos** (links in het menu)
2. **Check de exacte repository naam**
- Kijk naar de repository die je hebt gepusht
- Noteer de exacte naam (inclusief hoofdletters/spaties)
3. **In de pipeline wizard:**
- Zoek naar de repository met de exacte naam
- Of probeer verschillende variaties:
- `Zuyderland CMDB GUI`
- `zuyderland-cmdb-gui`
- `ZuyderlandCMDBGUI`
**Jouw repository naam zou moeten zijn:** `Zuyderland CMDB GUI` (met spaties)
---
## ✅ Oplossing 2: Check Repository Type
**In de pipeline wizard, probeer verschillende repository types:**
1. **Azure Repos Git** (als je code in Azure DevOps staat)
- Dit is waarschijnlijk wat je nodig hebt
- Check of je repository hier staat
2. **GitHub** (als je code in GitHub staat)
- Niet van toepassing voor jou
3. **Other Git** (als je code ergens anders staat)
- Niet van toepassing voor jou
**Voor jouw situatie:** Kies **"Azure Repos Git"**
---
## ✅ Oplossing 3: Check Repository Toegang
**Probleem:** Je hebt mogelijk geen toegang tot de repository.
**Oplossing:**
1. **Ga naar Repos** (links in het menu)
2. **Check of je de repository ziet**
- Als je de repository niet ziet, heb je mogelijk geen toegang
3. **Check permissions:**
- Project Settings → Repositories → Security
- Check of je account toegang heeft
---
## ✅ Oplossing 4: Check Project
**Probleem:** Je bent mogelijk in het verkeerde project.
**Oplossing:**
1. **Check het project naam** (bovenaan links)
- Moet zijn: **"JiraAssetsCMDB"**
2. **Als je in een ander project bent:**
- Klik op het project dropdown (bovenaan links)
- Selecteer **"JiraAssetsCMDB"**
3. **Probeer opnieuw** de pipeline aan te maken
---
## ✅ Oplossing 5: Refresh/Herlaad
**Soms helpt een simpele refresh:**
1. **Refresh de browser pagina** (F5 of Cmd+R)
2. **Sluit en open opnieuw** de pipeline wizard
3. **Probeer opnieuw**
---
## ✅ Oplossing 6: Check of Repository Bestaat
**Probleem:** De repository bestaat mogelijk niet in Azure DevOps.
**Oplossing:**
1. **Ga naar Repos** (links in het menu)
2. **Check of je repository zichtbaar is**
- Je zou moeten zien: `Zuyderland CMDB GUI` (of jouw repo naam)
3. **Als de repository niet bestaat:**
- Je moet eerst de code pushen naar Azure DevOps
- Of de repository aanmaken in Azure DevOps
**Check of je code al in Azure DevOps staat:**
- Ga naar Repos → Files
- Je zou je code moeten zien (bijv. `azure-pipelines.yml`, `backend/`, `frontend/`, etc.)
---
## ✅ Oplossing 7: Maak Repository Aan (Als Die Niet Bestaat)
**Als de repository nog niet bestaat in Azure DevOps:**
### Optie A: Push Code naar Bestaande Repository
**Als de repository al bestaat maar leeg is:**
1. **Check de repository URL:**
```
git@ssh.dev.azure.com:v3/ZuyderlandMedischCentrum/JiraAssetsCMDB/Zuyderland%20CMDB%20GUI
```
2. **Push je code:**
```bash
cd /Users/berthausmans/Documents/Development/zuyderland-cmdb-gui
git push azure main
```
3. **Check in Azure DevOps:**
- Ga naar Repos → Files
- Je zou je code moeten zien
### Optie B: Maak Nieuwe Repository Aan
**Als de repository helemaal niet bestaat:**
1. **Ga naar Repos** (links in het menu)
2. **Klik op "New repository"** of het "+" icoon
3. **Vul in:**
- **Repository name**: `Zuyderland CMDB GUI`
- **Type**: Git
4. **Create**
5. **Push je code:**
```bash
cd /Users/berthausmans/Documents/Development/zuyderland-cmdb-gui
git remote add azure git@ssh.dev.azure.com:v3/ZuyderlandMedischCentrum/JiraAssetsCMDB/Zuyderland%20CMDB%20GUI
git push azure main
```
---
## ✅ Oplossing 8: Gebruik "Other Git" Als Workaround
**Als niets werkt, gebruik "Other Git" als tijdelijke oplossing:**
1. **In de pipeline wizard:**
- Kies **"Other Git"** (in plaats van "Azure Repos Git")
2. **Vul in:**
- **Repository URL**: `git@ssh.dev.azure.com:v3/ZuyderlandMedischCentrum/JiraAssetsCMDB/Zuyderland%20CMDB%20GUI`
- Of HTTPS: `https://ZuyderlandMedischCentrum@dev.azure.com/ZuyderlandMedischCentrum/JiraAssetsCMDB/_git/Zuyderland%20CMDB%20GUI`
3. **Branch**: `main`
4. **Continue**
**⚠️ Let op:** Dit werkt, maar "Azure Repos Git" is de voorkeursoptie.
---
## 🔍 Diagnose Stappen
**Om te diagnosticeren wat het probleem is:**
### 1. Check of Repository Bestaat
1. Ga naar **Repos** (links in het menu)
2. Check of je `Zuyderland CMDB GUI` ziet
3. Klik erop en check of je code ziet
### 2. Check Repository URL
**In Terminal:**
```bash
cd /Users/berthausmans/Documents/Development/zuyderland-cmdb-gui
git remote -v
```
**Je zou moeten zien:**
```
azure git@ssh.dev.azure.com:v3/ZuyderlandMedischCentrum/JiraAssetsCMDB/Zuyderland%20CMDB%20GUI (fetch)
azure git@ssh.dev.azure.com:v3/ZuyderlandMedischCentrum/JiraAssetsCMDB/Zuyderland%20CMDB%20GUI (push)
```
### 3. Check of Code Gepusht is
**In Terminal:**
```bash
git log azure/main --oneline -5
```
**Als je commits ziet:** ✅ Code is gepusht
**Als je een fout krijgt:** ❌ Code is niet gepusht
### 4. Push Code (Als Niet Gepusht)
```bash
git push azure main
```
---
## 💡 Aanbevolen Aanpak
**Probeer in deze volgorde:**
1. ✅ **Check Repos** - Ga naar Repos en check of je repository bestaat
2. ✅ **Check project naam** - Zorg dat je in "JiraAssetsCMDB" project bent
3. ✅ **Refresh pagina** - Soms helpt een simpele refresh
4. ✅ **Push code** - Als repository leeg is, push je code
5. ✅ **Gebruik "Other Git"** - Als workaround
---
## 🎯 Quick Fix (Meest Waarschijnlijk)
**Het probleem is waarschijnlijk dat de repository leeg is of niet bestaat:**
1. **Check in Azure DevOps:**
- Ga naar **Repos** → **Files**
- Check of je code ziet (bijv. `azure-pipelines.yml`)
2. **Als repository leeg is:**
```bash
cd /Users/berthausmans/Documents/Development/zuyderland-cmdb-gui
git push azure main
```
3. **Probeer opnieuw** de pipeline aan te maken
---
## 📚 Meer Informatie
- [Azure DevOps Repositories](https://learn.microsoft.com/en-us/azure/devops/repos/)
- [Create Pipeline from Repository](https://learn.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline)
---
## 🆘 Nog Steeds Problemen?
Als niets werkt:
1. **Check of je in het juiste project bent** (JiraAssetsCMDB)
2. **Check of de repository bestaat** (Repos → Files)
3. **Push je code** naar Azure DevOps
4. **Gebruik "Other Git"** als workaround
**De "Other Git" optie werkt altijd**, ook als de repository niet wordt gevonden in de dropdown.

View File

@@ -0,0 +1,231 @@
# Azure DevOps Service Connection - Authentication Type
## 🎯 Aanbeveling voor Jouw Situatie
**Voor Zuyderland CMDB GUI met Azure Container Registry:**
### ✅ **Service Principal** (Aanbevolen) ⭐
**Waarom:**
- ✅ Werkt altijd en is betrouwbaar
- ✅ Meest ondersteunde optie
- ✅ Eenvoudig te configureren
- ✅ Werkt perfect met Azure Container Registry
- ✅ Geen speciale vereisten
---
## 📊 Opties Vergelijking
### Optie 1: **Service Principal** ⭐ **AANBEVOLEN**
**Hoe het werkt:**
- Azure DevOps maakt automatisch een Service Principal aan in Azure AD
- De Service Principal krijgt toegang tot je Azure Container Registry
- Azure DevOps gebruikt deze credentials om in te loggen bij ACR
**Voordelen:**
-**Eenvoudig** - Azure DevOps doet alles automatisch
-**Betrouwbaar** - Werkt altijd, geen speciale configuratie nodig
-**Veilig** - Credentials worden veilig opgeslagen in Azure DevOps
-**Meest ondersteund** - Standaard optie voor de meeste scenario's
-**Werkt met alle Azure services** - Niet alleen ACR
**Nadelen:**
- ❌ Maakt een Service Principal aan in Azure AD (maar dit is normaal en veilig)
**Wanneer gebruiken:**
-**Jouw situatie** - Azure DevOps Services (cloud) met Azure Container Registry
- ✅ De meeste scenario's
- ✅ Als je eenvoudige, betrouwbare authenticatie wilt
- ✅ Standaard keuze voor nieuwe service connections
**Configuratie:**
- Azure DevOps doet alles automatisch
- Je hoeft alleen je Azure subscription en ACR te selecteren
- Azure DevOps maakt de Service Principal aan en geeft deze de juiste permissions
---
### Optie 2: **Managed Service Identity (MSI)**
**Hoe het werkt:**
- Gebruikt een Managed Identity van Azure DevOps zelf
- Geen credentials nodig - Azure beheert alles
- Werkt alleen als Azure DevOps een Managed Identity heeft
**Voordelen:**
- ✅ Geen credentials te beheren
- ✅ Automatisch geroteerd door Azure
- ✅ Modernere aanpak
**Nadelen:**
-**Werkt alleen met Azure DevOps Server (on-premises)** met Managed Identity
-**Werkt NIET met Azure DevOps Services (cloud)** - Dit is belangrijk!
- ❌ Vereist speciale configuratie
- ❌ Minder flexibel
**Wanneer gebruiken:**
- ✅ Azure DevOps Server (on-premises) met Managed Identity
- ✅ Als je geen credentials wilt beheren
-**NIET voor Azure DevOps Services (cloud)** - Dit werkt niet!
**Voor jouw situatie:****Niet geschikt** - Je gebruikt Azure DevOps Services (cloud), niet on-premises
---
### Optie 3: **Workload Identity Federation**
**Hoe het werkt:**
- Modernere manier zonder secrets
- Gebruikt federated identity (OIDC)
- Azure DevOps krijgt een token van Azure AD zonder credentials op te slaan
**Voordelen:**
- ✅ Geen secrets opgeslagen
- ✅ Modernere, veiligere aanpak
- ✅ Automatisch token management
**Nadelen:**
-**Nog niet volledig ondersteund** voor alle scenario's
- ❌ Kan complexer zijn om te configureren
- ❌ Vereist specifieke Azure AD configuratie
- ❌ Mogelijk niet beschikbaar in alle Azure DevOps organisaties
**Wanneer gebruiken:**
- ✅ Als je de modernste security features wilt
- ✅ Als je organisatie Workload Identity Federation ondersteunt
- ✅ Voor nieuwe projecten waar je geen legacy support nodig hebt
-**Niet aanbevolen als je eenvoudige setup wilt**
**Voor jouw situatie:** ⚠️ **Mogelijk beschikbaar, maar Service Principal is eenvoudiger**
---
## 🔍 Jouw Situatie Analyse
**Jouw setup:**
- ✅ Azure DevOps Services (cloud) - `dev.azure.com`
- ✅ Azure Container Registry - `zdlas.azurecr.io`
- ✅ Eenvoudige setup gewenst
- ✅ Betrouwbare authenticatie nodig
**Conclusie:****Service Principal is perfect!**
**Waarom niet de andere opties:**
-**Managed Service Identity**: Werkt niet met Azure DevOps Services (cloud)
- ⚠️ **Workload Identity Federation**: Mogelijk beschikbaar, maar complexer dan nodig
---
## 📋 Checklist: Welke Keuze?
### Kies **Service Principal** als:
- [x] Je Azure DevOps Services (cloud) gebruikt ✅
- [x] Je eenvoudige setup wilt ✅
- [x] Je betrouwbare authenticatie nodig hebt ✅
- [x] Je standaard, goed ondersteunde optie wilt ✅
- [x] Je Azure Container Registry gebruikt ✅
**→ Jouw situatie: ✅ Kies Service Principal!**
### Kies **Managed Service Identity** als:
- [ ] Je Azure DevOps Server (on-premises) gebruikt
- [ ] Je Managed Identity hebt geconfigureerd
- [ ] Je geen credentials wilt beheren
**→ Jouw situatie: ❌ Niet geschikt**
### Kies **Workload Identity Federation** als:
- [ ] Je de modernste security features wilt
- [ ] Je organisatie dit ondersteunt
- [ ] Je geen legacy support nodig hebt
- [ ] Je bereid bent om extra configuratie te doen
**→ Jouw situatie: ⚠️ Mogelijk, maar niet nodig**
---
## 🔧 Configuratie Stappen (Service Principal)
Wanneer je **Service Principal** kiest:
1. **Selecteer Azure Subscription**
- Kies je Azure subscription uit de dropdown
2. **Selecteer Azure Container Registry**
- Kies je ACR (`zdlas`) uit de dropdown
3. **Service Connection Name**
- Vul in: `zuyderland-cmdb-acr-connection`
- ⚠️ **Belangrijk**: Deze naam moet overeenkomen met `dockerRegistryServiceConnection` in `azure-pipelines.yml`!
4. **Security**
- Azure DevOps maakt automatisch een Service Principal aan
- De Service Principal krijgt automatisch de juiste permissions (AcrPush role)
- Credentials worden veilig opgeslagen in Azure DevOps
5. **Save**
- Klik "Save" of "Verify and save"
- Azure DevOps test automatisch de connection
**✅ Klaar!** Geen extra configuratie nodig.
---
## 🔄 Kan Ik Later Wisselen?
**Ja, maar:**
- Je kunt altijd een nieuwe service connection aanmaken met een ander authentication type
- Je moet dan wel de pipeline variabelen aanpassen
- Service Principal is meestal de beste keuze, dus wisselen is meestal niet nodig
---
## 💡 Mijn Aanbeveling
**Voor Zuyderland CMDB GUI:**
### ✅ **Kies Service Principal** ⭐
**Waarom:**
1.**Werkt perfect** - Standaard optie voor Azure DevOps Services
2.**Eenvoudig** - Azure DevOps doet alles automatisch
3.**Betrouwbaar** - Meest geteste en ondersteunde optie
4.**Veilig** - Credentials worden veilig beheerd door Azure DevOps
5.**Perfect voor jouw situatie** - Cloud Azure DevOps + Azure Container Registry
**Je hebt niet nodig:**
- ❌ Managed Service Identity (werkt niet met cloud Azure DevOps)
- ❌ Workload Identity Federation (complexer dan nodig)
**Setup:**
1. Kies **Service Principal**
2. Selecteer je subscription en ACR
3. Geef een naam: `zuyderland-cmdb-acr-connection`
4. Save
**Klaar!**
---
## 📚 Meer Informatie
- [Azure DevOps Service Connections](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints)
- [Service Principal Authentication](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/connect-to-azure)
- [Managed Service Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/)
- [Workload Identity Federation](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/connect-to-azure?view=azure-devops#workload-identity-federation)
---
## 🎯 Conclusie
**Kies: Service Principal**
Dit is de beste keuze voor:
- ✅ Azure DevOps Services (cloud)
- ✅ Azure Container Registry
- ✅ Eenvoudige, betrouwbare setup
- ✅ Standaard, goed ondersteunde optie
Je kunt altijd later een andere optie proberen als je dat wilt, maar Service Principal is meestal de beste keuze.

View File

@@ -0,0 +1,237 @@
# Azure DevOps Service Connection - Troubleshooting
## 🔴 Probleem: "Loading Registries..." blijft hangen
Als de Azure Container Registry dropdown blijft laden zonder resultaten, probeer deze oplossingen:
---
## ✅ Oplossing 1: Check Subscription Toegang
**Probleem:** Je hebt mogelijk geen toegang tot de subscription waar de ACR staat.
**Oplossing:**
1. **Check in Azure Portal:**
- Ga naar je Container Registry (`zdlas`)
- Klik op **"Access control (IAM)"**
- Check of je de juiste rol hebt (bijv. Owner, Contributor, of AcrPush)
2. **Check Subscription:**
- Ga naar je Azure Subscription
- Klik op **"Access control (IAM)"**
- Check of je toegang hebt tot de subscription
3. **Probeer opnieuw:**
- Ga terug naar Azure DevOps
- Selecteer de juiste subscription
- Wacht even (kan 10-30 seconden duren)
---
## ✅ Oplossing 2: Refresh/Herlaad de Pagina
**Soms helpt een simpele refresh:**
1. **Refresh de browser pagina** (F5 of Cmd+R)
2. **Of sluit en open opnieuw** de service connection wizard
3. **Probeer opnieuw** de registry te selecteren
---
## ✅ Oplossing 3: Check Resource Group Locatie
**Probleem:** Soms laadt Azure DevOps alleen registries in bepaalde regio's.
**Oplossing:**
1. **Check waar je ACR staat:**
```bash
az acr show --name zdlas --query location -o tsv
```
2. **Check of de subscription toegang heeft tot die regio**
3. **Probeer handmatig de registry naam in te vullen** (zie Oplossing 4)
---
## ✅ Oplossing 4: Handmatig Registry Naam Invoeren
**Als de dropdown niet werkt, kun je handmatig de registry naam invoeren:**
1. **In de service connection wizard:**
- Laat de dropdown leeg (of selecteer "Enter value manually")
- Typ handmatig: `zdlas`
- Of de volledige naam: `zdlas.azurecr.io`
2. **Save en test**
**Let op:** Soms accepteert Azure DevOps alleen de registry naam zonder `.azurecr.io`
---
## ✅ Oplossing 5: Check Service Principal Permissions
**Probleem:** De Service Principal die Azure DevOps probeert aan te maken heeft mogelijk niet de juiste permissions.
**Oplossing:**
1. **Maak handmatig een Service Principal aan:**
```bash
# Login bij Azure
az login
# Maak Service Principal aan
az ad sp create-for-rbac --name "zuyderland-cmdb-acr-sp" \
--role acrpush \
--scopes /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.ContainerRegistry/registries/zdlas
```
2. **Gebruik deze credentials in Azure DevOps:**
- Kies "Docker Registry" → "Others"
- Vul in:
- Registry URL: `zdlas.azurecr.io`
- Username: (van de Service Principal output)
- Password: (van de Service Principal output)
---
## ✅ Oplossing 6: Gebruik "Others" in plaats van "Azure Container Registry"
**Als de Azure Container Registry optie niet werkt, gebruik dan "Others":**
1. **In de service connection wizard:**
- Kies **"Docker Registry"**
- Kies **"Others"** (in plaats van "Azure Container Registry")
2. **Vul handmatig in:**
- **Docker Registry**: `zdlas.azurecr.io`
- **Docker ID**: (leeg laten of je ACR admin username)
- **Docker Password**: (je ACR admin password)
3. **Haal ACR credentials op:**
```bash
# Login bij Azure
az login
# Haal admin credentials op
az acr credential show --name zdlas
```
Gebruik de `username` en `passwords[0].value` uit de output.
4. **Save en test**
**⚠️ Let op:** Met "Others" moet je handmatig credentials beheren. Service Principal is veiliger, maar dit werkt als tijdelijke oplossing.
---
## ✅ Oplossing 7: Check Browser/Network
**Probleem:** Browser of network issues kunnen de dropdown blokkeren.
**Oplossingen:**
1. **Probeer een andere browser** (Chrome, Firefox, Edge)
2. **Disable browser extensions** (ad blockers, etc.)
3. **Check network connectivity** naar Azure
4. **Probeer incognito/private mode**
---
## ✅ Oplossing 8: Wacht Even en Probeer Later
**Soms is het een tijdelijk Azure issue:**
1. **Wacht 5-10 minuten**
2. **Probeer opnieuw**
3. **Check Azure Status**: https://status.azure.com/
---
## 🔍 Diagnose Stappen
**Om te diagnosticeren wat het probleem is:**
### 1. Check ACR Bestaat en is Toegankelijk
```bash
# Login bij Azure
az login
# Check of ACR bestaat
az acr show --name zdlas
# Check ACR credentials
az acr credential show --name zdlas
# Check ACR permissions
az acr show --name zdlas --query "networkRuleSet" -o table
```
### 2. Check Azure DevOps Subscription Toegang
1. Ga naar Azure Portal
2. Ga naar je Subscription
3. Check "Access control (IAM)"
4. Check of je account toegang heeft
### 3. Check Service Principal Permissions
```bash
# List Service Principals
az ad sp list --display-name "zuyderland-cmdb-acr-sp" -o table
# Check permissions op ACR
az role assignment list --scope /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.ContainerRegistry/registries/zdlas
```
---
## 💡 Aanbevolen Aanpak
**Probeer in deze volgorde:**
1. ✅ **Refresh de pagina** (Oplossing 2)
2. ✅ **Check subscription toegang** (Oplossing 1)
3. ✅ **Handmatig registry naam invoeren** (Oplossing 4)
4. ✅ **Gebruik "Others" optie** (Oplossing 6) - als tijdelijke oplossing
5. ✅ **Maak handmatig Service Principal** (Oplossing 5) - voor permanente oplossing
---
## 🎯 Quick Fix (Aanbevolen)
**Als de dropdown niet werkt, gebruik deze workaround:**
1. **Kies "Docker Registry" → "Others"**
2. **Vul in:**
- Registry URL: `zdlas.azurecr.io`
- Username: (haal op met `az acr credential show --name zdlas`)
- Password: (haal op met `az acr credential show --name zdlas`)
3. **Service connection name**: `zuyderland-cmdb-acr-connection`
4. **Save**
**Dit werkt altijd, ook als de Azure Container Registry optie niet werkt.**
**Later kun je:**
- De service connection verwijderen
- Opnieuw aanmaken met "Azure Container Registry" optie (als die dan wel werkt)
- Of de "Others" optie behouden (werkt ook prima)
---
## 📚 Meer Informatie
- [Azure DevOps Service Connections Troubleshooting](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints)
- [ACR Access Control](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication)
- [Service Principal Permissions](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-roles)
---
## 🆘 Nog Steeds Problemen?
Als niets werkt:
1. **Check Azure DevOps logs** (als je toegang hebt)
2. **Contact Azure Support** (als je een support plan hebt)
3. **Gebruik "Others" optie** als workaround (werkt altijd)
**De "Others" optie is een volledig werkende oplossing**, alleen iets minder geautomatiseerd dan de Azure Container Registry optie.

View File

@@ -83,8 +83,11 @@ Deze connection geeft Azure DevOps toegang tot je ACR.
- Klik **"Next"**
6. **Configureer connection**
- **Authentication type**: Kies **"Service Principal"** ⭐ (aanbevolen)
- Dit is de standaard en meest betrouwbare optie
- Azure DevOps maakt automatisch een Service Principal aan
- **Azure subscription**: Selecteer je Azure subscription
- **Azure container registry**: Selecteer je ACR uit de dropdown (bijv. `zuyderlandcmdbacr`)
- **Azure container registry**: Selecteer je ACR uit de dropdown (bijv. `zdlas`)
- **Service connection name**: `zuyderland-cmdb-acr-connection`
- ⚠️ **Belangrijk**: Deze naam moet overeenkomen met `dockerRegistryServiceConnection` in `azure-pipelines.yml`!
- **Description**: Optioneel (bijv. "ACR for CMDB GUI production")
@@ -92,13 +95,45 @@ Deze connection geeft Azure DevOps toegang tot je ACR.
7. **Save**
- Klik **"Save"** (of **"Verify and save"**)
- Azure DevOps test automatisch de connection
- Azure DevOps maakt automatisch een Service Principal aan met de juiste permissions
**💡 Waarom Service Principal?**
- ✅ Werkt perfect met Azure DevOps Services (cloud)
- ✅ Eenvoudig - Azure DevOps doet alles automatisch
- ✅ Betrouwbaar - Meest ondersteunde optie
- ✅ Veilig - Credentials worden veilig beheerd
📚 Zie `docs/AZURE-SERVICE-CONNECTION-AUTH.md` voor details over alle authentication types.
**✅ Service connection is aangemaakt!**
**Troubleshooting:**
- Als je ACR niet ziet in de dropdown, check of je de juiste subscription hebt geselecteerd
- **"Loading Registries..." blijft hangen?**
- ✅ Refresh de pagina (F5)
- ✅ Check of je de juiste subscription hebt geselecteerd
- ✅ Wacht 10-30 seconden (kan even duren)
- ✅ **Workaround**: Gebruik "Others" optie (zie hieronder)
- Als verificatie faalt, check of je toegang hebt tot de ACR in Azure Portal
**🔧 Workaround: Als dropdown niet werkt, gebruik "Others" optie:**
1. Kies **"Docker Registry"** → **"Others"** (in plaats van "Azure Container Registry")
2. Vul handmatig in:
- **Docker Registry**: `zdlas.azurecr.io`
- **Docker ID**: (haal op met `az acr credential show --name zdlas`)
- **Docker Password**: (haal op met `az acr credential show --name zdlas`)
3. **Service connection name**: `zuyderland-cmdb-acr-connection`
4. Save
**Haal credentials op:**
```bash
az login
az acr credential show --name zdlas
# Gebruik "username" en "passwords[0].value"
```
📚 Zie `docs/AZURE-SERVICE-CONNECTION-TROUBLESHOOTING.md` voor uitgebreide troubleshooting.
---
## 🎯 Stap 4: Pipeline Aanmaken en Run