Instructions for AI coding agents working on the Retrospectives Extension for Azure DevOps.
Full-stack Azure DevOps extension:
- Frontend: React 19 + TypeScript in
src/frontend/ - Backend: .NET 9 (ASP.NET Core + SignalR) in
src/backend/
src/
├── frontend/ # React/TypeScript frontend
│ ├── components/ # React components
│ │ ├── __tests__/ # Jest tests (*.test.tsx)
│ │ └── __mocks__/ # Test mocks
│ ├── dal/ # Data access layer
│ ├── interfaces/ # TypeScript interfaces
│ └── utilities/ # Utility functions
├── backend/ # C#/.NET SignalR backend
└── backend.tests/ # xUnit tests for backend
npm ci # Install dependencies
npm run build # Build for production
npm run format # Format with Prettier
npm test # Run all tests with coverage
# Run a single test file
npx jest --env=jsdom components/__tests__/feedbackItem.test.tsx
# Full check (lint + format + pre-commit + test)
npm run checkdotnet restore --locked-mode && dotnet build
# Run tests (from src/backend.tests/)
dotnet test
dotnet test --filter "FullyQualifiedName~TestMethodName" # Single testpre-commit install # Install hooks
pre-commit run --all-files # Run on all filesImports - organize in order:
- React and hooks
- Third-party libraries (@fluentui, azure-devops-extension-*)
- Local interfaces/types
- Local components
- Local utilities/services
Formatting (Prettier config):
- Tab width: 2 spaces, no tabs
- Arrow parens: avoid (
x => x) - Bracket spacing: true
TypeScript (tsconfig):
- Target: ES2020, Module: ESNext, JSX: react-jsx
noImplicitReturns,noImplicitThis,noImplicitAny: truestrictNullChecks: false
Naming Conventions:
- Interfaces: PascalCase with
Iprefix (IFeedbackItemDocument) - Components: PascalCase (
FeedbackItem) - Component files: camelCase (
feedbackItem.tsx) - Props/State interfaces:
I{ComponentName}Props,I{ComponentName}State - Utilities: camelCase functions (
getUserIdentity)
Component Pattern:
- Functional components with hooks (useState, useEffect, useCallback)
forwardRef+useImperativeHandlefor ref-exposing components- Define prop/state interfaces before component
Follow C# Coding Conventions:
- PascalCase for public members/methods/classes
_camelCasefor private fields (_logger,_insights)- XML documentation comments for public methods
- Async methods return
Task
/// <summary>
/// Broadcast receiveNewItem to all other clients.
/// </summary>
public Task BroadcastNewItem(string reflectBoardId, string columnId, string feedbackItemId)
{
_logger.LogInformation($"BroadcastNewItem connectionID: {Context.ConnectionId}");
return Clients.OthersInGroup(reflectBoardId).SendAsync(receiveNewItem.ToString(), columnId, feedbackItemId);
}- Test files:
components/__tests__/*.test.tsx - Mock Azure DevOps SDK, telemetry, and external services
- Use
@testing-library/reactand@testing-library/user-event
- Test files:
src/backend.tests/ - Use Moq for mocking, Arrange-Act-Assert pattern
Frontend: try/catch with telemetry:
try {
await itemDataService.updateFeedbackItem(item);
} catch (error) {
appInsights.trackException({ exception: error as Error });
}Backend: logging + Application Insights:
_logger.LogInformation($"Operation: {Context.ConnectionId}");
_insights.TrackEvent("Event name");- SignalR: Backend hub
ReflectHub.cs, frontenddal/reflectBackendService - Signal names: Defined in
ReflectBackendSignalsenum - Data storage: Azure DevOps data service (via extension SDK)
PRs trigger:
- Frontend: lint, build, test (with coverage)
- Backend: restore, build, test
- Pre-commit: gitleaks (secrets), shellcheck, formatting
Always run npm test before committing frontend changes.