Duration: 15 minutes
Learning Objectives:
- Generate comprehensive test suites using
/testscommand - Create documentation with
/doccommand - Write Conventional Commit messages with AI assistance
- Draft PR descriptions using
@workspacefor full context - Integrate Copilot into complete development workflow
This lab brings together everything you've learned by focusing on the "glue" activities that complete the development lifecycle:
- Testing - Generate comprehensive test coverage
- Documentation - Create clear, maintainable docs
- Version Control - Write meaningful commit messages
- Code Review - Prepare thorough PR descriptions
These activities are often rushed or skipped, but Copilot makes them fast and consistent.
- ✅ Completed Labs 1, 2, and 3
- ✅ Working Task Manager API with CRUD operations
- ✅ Git initialized with commits from previous labs
- ✅ Familiar with all Copilot features (chat, inline chat, slash commands, context variables)
You have basic tests from TDD, but need comprehensive coverage including edge cases, integration tests, and error scenarios.
Open src/TaskManager.Application/Commands/CreateTaskCommandHandler.cs and select the HandleAsync method.
With the method selected, open Copilot Chat (Ctrl+Alt+I / Cmd+Shift+I) and enter:
/tests
Or use Inline Chat (Ctrl+I / Cmd+I):
/tests
Copilot should generate comprehensive tests covering:
namespace TaskManager.UnitTests.Commands.CreateTaskCommandHandlerTests;
public sealed class HandleAsyncTests
{
private readonly ITaskRepository _repository;
private readonly ILogger<CreateTaskCommandHandler> _logger;
private readonly CreateTaskCommandHandler _sut;
public HandleAsyncTests()
{
_repository = A.Fake<ITaskRepository>();
_logger = A.Fake<ILogger<CreateTaskCommandHandler>>();
_sut = new CreateTaskCommandHandler(_repository, _logger);
}
[Fact]
public async Task HandleAsync_WithValidCommand_CreatesTask()
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Description = "Test Description",
Priority = "High",
DueDate = DateTime.UtcNow.AddDays(7)
};
// Act
var result = await _sut.HandleAsync(command);
// Assert
Assert.NotNull(result);
Assert.Equal("Test Task", result.Title);
Assert.Equal("High", result.Priority.Name);
A.CallTo(() => _repository.AddAsync(
A<Domain.Entities.Task>._,
A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}
[Fact]
public async Task HandleAsync_WithNullCommand_ThrowsArgumentNullException()
{
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(() =>
_sut.HandleAsync(null!));
}
[Theory]
[InlineData("")]
[InlineData(" ")]
public async Task HandleAsync_WithInvalidTitle_ThrowsArgumentException(string invalidTitle)
{
// Arrange
var command = new CreateTaskCommand
{
Title = invalidTitle,
Priority = "Medium"
};
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(() =>
_sut.HandleAsync(command));
}
[Theory]
[InlineData("InvalidPriority")]
[InlineData("SuperUrgent")]
[InlineData("")]
public async Task HandleAsync_WithInvalidPriority_ThrowsArgumentException(string invalidPriority)
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Priority = invalidPriority
};
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(() =>
_sut.HandleAsync(command));
}
[Fact]
public async Task HandleAsync_WithPastDueDate_ThrowsArgumentException()
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Priority = "Low",
DueDate = DateTime.UtcNow.AddDays(-1)
};
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(() =>
_sut.HandleAsync(command));
}
[Fact]
public async Task HandleAsync_WithNullDueDate_CreatesTaskSuccessfully()
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Priority = "Medium",
DueDate = null
};
// Act
var result = await _sut.HandleAsync(command);
// Assert
Assert.NotNull(result);
Assert.Null(result.DueDate);
}
[Fact]
public async Task HandleAsync_LogsInformationMessages()
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Priority = "Critical"
};
// Act
await _sut.HandleAsync(command);
// Assert
A.CallTo(_logger)
.Where(call =>
call.Method.Name == "Log" &&
call.GetArgument<LogLevel>(0) == LogLevel.Information)
.MustHaveHappened(Repeated.AtLeast.Twice);
}
[Fact]
public async Task HandleAsync_RespectsCancellationToken()
{
// Arrange
var command = new CreateTaskCommand
{
Title = "Test Task",
Priority = "Low"
};
var cts = new CancellationTokenSource();
cts.Cancel();
// Act & Assert
await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
_sut.HandleAsync(command, cts.Token));
}
}For API endpoints, generate integration tests:
Create integration tests for the POST /tasks endpoint using WebApplicationFactory. Test:
- Valid request returns 201 Created
- Invalid priority returns 400 Bad Request with ProblemDetails
- Past due date returns 400 Bad Request
- Missing required fields returns 400 Bad Request
- Response body contains all expected fields
Use xUnit and realistic test data
Expected Output - tests/TaskManager.IntegrationTests/Api/TaskEndpointsTests.cs:
namespace TaskManager.IntegrationTests.Api;
public sealed class TaskEndpointsTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public TaskEndpointsTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task PostTask_WithValidRequest_Returns201Created()
{
// Arrange
var request = new
{
title = "Integration Test Task",
description = "Testing POST endpoint",
priority = "High",
dueDate = DateTime.UtcNow.AddDays(7)
};
// Act
var response = await _client.PostAsJsonAsync("/tasks", request);
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var task = await response.Content.ReadFromJsonAsync<TaskResponse>();
Assert.NotNull(task);
Assert.Equal("Integration Test Task", task.Title);
Assert.Equal("High", task.Priority);
}
[Theory]
[InlineData("InvalidPriority")]
[InlineData("")]
[InlineData("SuperCritical")]
public async Task PostTask_WithInvalidPriority_Returns400BadRequest(string invalidPriority)
{
// Arrange
var request = new
{
title = "Test Task",
priority = invalidPriority,
dueDate = DateTime.UtcNow.AddDays(1)
};
// Act
var response = await _client.PostAsJsonAsync("/tasks", request);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>();
Assert.NotNull(problem);
Assert.Contains("priority", problem.Detail, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public async Task PostTask_WithPastDueDate_Returns400BadRequest()
{
// Arrange
var request = new
{
title = "Test Task",
priority = "Medium",
dueDate = DateTime.UtcNow.AddDays(-7)
};
// Act
var response = await _client.PostAsJsonAsync("/tasks", request);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>();
Assert.NotNull(problem);
Assert.Contains("due date", problem.Detail, StringComparison.OrdinalIgnoreCase);
}
}dotnet test --logger "console;verbosity=detailed"Verify coverage includes:
- ✅ Happy path tests
- ✅ Guard clause tests
- ✅ Edge case tests (nulls, empty strings, boundaries)
- ✅ Validation tests
- ✅ Error handling tests
- ✅ Cancellation token tests
- ✅ Logging verification tests
- ✅ Integration tests
Create comprehensive documentation for the Task Manager API.
Open src/TaskManager.Application/Commands/CreateTaskCommandHandler.cs and select the class declaration.
With the class selected, use Inline Chat (Ctrl+I):
/doc
Expected Output:
/// <summary>
/// Handles the creation of new tasks in the task management system.
/// Validates input, creates task entities, and persists them to the repository.
/// </summary>
public sealed class CreateTaskCommandHandler
{
private readonly ITaskRepository _repository;
private readonly ILogger<CreateTaskCommandHandler> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="CreateTaskCommandHandler"/> class.
/// </summary>
/// <param name="repository">The repository for persisting task entities.</param>
/// <param name="logger">The logger for structured logging.</param>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="repository"/> or <paramref name="logger"/> is null.
/// </exception>
public CreateTaskCommandHandler(
ITaskRepository repository,
ILogger<CreateTaskCommandHandler> logger)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// Handles the creation of a new task based on the provided command.
/// </summary>
/// <param name="command">The command containing task creation details.</param>
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
/// <returns>The newly created task entity.</returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="command"/> is null.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown when command contains invalid data (empty title, invalid priority, past due date).
/// </exception>
public async Task<Domain.Entities.Task> HandleAsync(
CreateTaskCommand command,
CancellationToken cancellationToken = default)
{
// ... implementation ...
}
}Ask Copilot Chat:
Create an API documentation section for #file:README.md that documents all the Task Manager API endpoints (POST, GET, GET by ID, PUT, DELETE). Include:
- Endpoint URL
- HTTP method
- Request body examples
- Response examples
- Status codes
- Error responses
Format as Markdown
Expected Output - Added to README.md:
## API Documentation
### Base URL
http://localhost:5000
### Endpoints
#### 1. Create Task
Creates a new task with priority and optional due date.
**Endpoint**: `POST /tasks`
**Request Body**:
```json
{
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"priority": "High",
"dueDate": "2025-10-30T17:00:00Z"
---
## API Documentation
### Base URL
`http://localhost:5000`
### Endpoints
#### 1. Create Task
Creates a new task with priority and optional due date.
**Endpoint**: `POST /tasks`
**Request Body:**
```json
{
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"priority": "High",
"dueDate": "2025-10-30T17:00:00Z"
}
```
**Success Response** (201 Created):
```json
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"priority": "High",
"status": "Todo",
"dueDate": "2025-10-30T17:00:00Z",
"createdAt": "2025-10-20T10:30:00Z"
}
```
**Note**: The response uses `status` field (enum: Todo, InProgress, Done, Cancelled) rather than boolean `isCompleted`. See Lab 3 documentation for details.
**Error Responses:**
```json
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "Invalid priority name: SuperUrgent"
}
```
Other possible errors:
- `400 Bad Request` - Invalid priority or past due date
- `500 Internal Server Error` - Server error
---
"priority": "High",
"status": "InProgress",
"createdAt": "2025-10-20T10:30:00Z"
}
]
```
---
#### 3. Get Task by ID
Retrieves a specific task by its unique identifier.
**Endpoint**: `GET /tasks/{id}`
**Path Parameters**:
- `id` (required): Task unique identifier (GUID)
**Success Response** (200 OK):
```json
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"title": "Complete project documentation",
"description": "Write comprehensive API documentation",
"priority": "High",
"status": "Todo",
"dueDate": "2025-10-30T17:00:00Z",
"createdAt": "2025-10-20T10:30:00Z"
}
```
**Error Responses**:
- `404 Not Found` - Task with specified ID does not exist
---
#### 4. Update Task
Updates an existing task's properties.
**Endpoint**: `PUT /tasks/{id}`
**Request Body**:
```json
{
"title": "Updated task title",
"description": "Updated description",
"priority": "Critical",
"status": "Done",
"dueDate": "2025-11-01T17:00:00Z"
}
```
**Success Response** (200 OK):
```json
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"title": "Updated task title",
"description": "Updated description",
"priority": "Critical",
"status": "Done",
"dueDate": "2025-11-01T17:00:00Z",
"createdAt": "2025-10-20T10:30:00Z"
}
```
**Error Responses**:
- `400 Bad Request` - Invalid data
- `404 Not Found` - Task not found
---
#### 5. Delete Task
Permanently deletes a task.
**Endpoint**: `DELETE /tasks/{id}`
**Success Response** (204 No Content)
**Error Responses**:
- `404 Not Found` - Task not found
---
### Priority Values
Valid priority values for task creation and updates:
- `Low` (0)
- `Medium` (1)
- `High` (2)
- `Critical` (3)
### Error Response Format
All error responses follow [RFC 7807 Problem Details](https://datatracker.ietf.org/doc/html/rfc7807) format:
```json
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "Invalid priority name: SuperUrgent"
}
```
### 2.3 Generate Architecture Documentation (ADR)
Ask Copilot:
```text
Create an Architecture Decision Record (ADR) in docs/adr/001-clean-architecture-choice.md documenting why we chose Clean Architecture for this Task Manager application. Include:
- Context
- Decision
- Consequences (positive and negative)
- Alternatives considered
Follow the ADR template format
```
---
## Part 3: Write Conventional Commit Messages (3 minutes)
### Scenario: Commit Your Changes
You've made significant changes across multiple files. Write meaningful commit messages following Conventional Commits format.
### 3.1 Stage Changes
```bash
git add src/TaskManager.Api/Extensions/EndpointExtensions.cs
git add src/TaskManager.Application/Queries/
git add tests/TaskManager.IntegrationTests/
```
### 3.2 Generate Commit Message
In Copilot Chat:
```text
Write a Conventional Commit message for the staged changes. Include a concise subject line (<=72 chars) and a detailed body explaining what was added.
```
**Expected Output**:
```text
feat(api): add GET endpoints for task retrieval
- Add GET /tasks endpoint with optional completed filter
- Add GET /tasks/{id} endpoint for single task retrieval
- Implement GetTasksQuery and GetTaskByIdQuery handlers
- Add integration tests for both endpoints
- Update endpoint documentation in README
These endpoints complete the CRUD API for task management,
allowing clients to retrieve tasks individually or as a list
with optional filtering by completion status.
```
### 3.3 Commit with Generated Message
```bash
git commit -m "feat(api): add GET endpoints for task retrieval
- Add GET /tasks endpoint with optional completed filter
- Add GET /tasks/{id} endpoint for single task retrieval
- Implement GetTasksQuery and GetTaskByIdQuery handlers
- Add integration tests for both endpoints
- Update endpoint documentation in README
These endpoints complete the CRUD API for task management,
allowing clients to retrieve tasks individually or as a list
with optional filtering by completion status."
```
### 3.4 Practice: Stage More Changes
Stage the refactored legacy code:
```bash
git add src/TaskManager.Infrastructure/Legacy/LegacyTaskProcessor.cs
git add tests/TaskManager.UnitTests/Legacy/
```
Ask Copilot:
```text
Write a Conventional Commit message for refactoring LegacyTaskProcessor. Include details about what was improved (async/await, guard clauses, logging, extracted methods).
```
**Expected Output**:
```text
refactor(legacy): modernize LegacyTaskProcessor with clean code principles
- Convert synchronous methods to async/await pattern
- Replace nested if statements with guard clauses
- Add structured logging with ILogger throughout
- Extract ProcessSingleTaskAsync and IsTaskValid methods
- Improve error handling with proper exception catching
- Add comprehensive unit tests
Reduces complexity from cyclomatic complexity of 15 to 4 per method.
Follows Object Calisthenics: one level of indentation per method.
```
Commit:
```bash
git commit -F- <<'EOF'
refactor(legacy): modernize LegacyTaskProcessor with clean code principles
- Convert synchronous methods to async/await pattern
- Replace nested if statements with guard clauses
- Add structured logging with ILogger throughout
- Extract ProcessSingleTaskAsync and IsTaskValid methods
- Improve error handling with proper exception catching
- Add comprehensive unit tests
Reduces complexity from cyclomatic complexity of 15 to 4 per method.
Follows Object Calisthenics: one level of indentation per method.
EOF
```
---
## Part 4: Draft Pull Request Descriptions (4 minutes)
### Scenario: Prepare for Code Review
You've completed the workshop implementation. Create a comprehensive PR description for review.
### 4.1 Generate PR Description with @workspace
In Copilot Chat:
```text
@workspace Draft a Pull Request description for all the changes made in this branch. Include:
- Summary of changes
- What was implemented (features, refactoring, tests)
- Intent and motivation
- Testing performed
- Breaking changes (if any)
- Checklist for reviewers
Use Markdown formatting
```
**Expected Output**:
````markdown
# Task Manager API - Complete Implementation
## Summary
This PR implements a complete CRUD API for task management following Clean Architecture and DDD patterns, with comprehensive test coverage and documentation.
## Changes
### Features Implemented
- ✅ **Create Task** (`POST /tasks`) - Create tasks with priority and due date
- ✅ **List Tasks** (`GET /tasks`) - Retrieve all tasks with optional completion filter
- ✅ **Get Task by ID** (`GET /tasks/{id}`) - Retrieve single task
- ✅ **Update Task** (`PUT /tasks/{id}`) - Update task properties
- ✅ **Delete Task** (`DELETE /tasks/{id}`) - Remove task
### Architecture & Design
- Implemented Clean Architecture layers (Domain, Application, Infrastructure, API)
- Applied DDD patterns: Aggregates, Value Objects, Factory Methods
- CQRS pattern for commands and queries
- Dependency injection throughout
- Proper error handling with ProblemDetails (RFC 7807)
### Code Quality Improvements
- Refactored `LegacyTaskProcessor` to modern standards:
- Async/await pattern
- Guard clauses (no nested ifs)
- Structured logging
- Extracted methods for single responsibility
- Reduced cyclomatic complexity from 15 to 4
- Applied Object Calisthenics principles:
- One level of indentation per method
- No else keyword
- Wrapped primitives in value objects
- Descriptive naming (no abbreviations)
### Testing
- **Unit Tests**: 45+ tests covering all handlers, commands, queries, and domain logic
- **Integration Tests**: 12+ tests for all API endpoints
- Test framework: xUnit v3 with FakeItEasy for mocking
- Test organization: Feature-based with class-per-method folders
- Coverage: ~92% code coverage (excluding infrastructure)
### Documentation
- XML documentation for all public APIs
- Comprehensive README with:
- API endpoint documentation
- Request/response examples
- Error response formats
- Architecture Decision Records (ADRs) for key decisions
- Inline code comments for complex logic
## Intent & Motivation
This implementation serves as a reference for:
- AI-assisted development workflow with GitHub Copilot
- Clean Architecture in .NET 9
- TDD practices (Red-Green-Refactor)
- DDD patterns in practice
- Modern C# conventions and best practices
## Testing Performed
### Automated Tests
```bash
dotnet build # ✅ Success, 0 warnings
dotnet test # ✅ 57 passed, 0 failed
```
### Manual API Testing
All endpoints tested with curl:
- ✅ Valid requests return correct responses
- ✅ Invalid data returns 400 Bad Request with details
- ✅ Not found scenarios return 404
- ✅ Server errors return 500 with ProblemDetails
### Performance
- Average response time: <50ms for CRUD operations
- No memory leaks detected in load testing
## Breaking Changes
⚠️ **None** - This is initial implementation
## Migration Required
None - Uses in-memory repository for workshop purposes
## Reviewer Checklist
Please verify:
- [ ] All tests pass (`dotnet test`)
- [ ] Build succeeds with no warnings (`dotnet build`)
- [ ] Code follows our .NET conventions (automatically loaded from `.github/instructions/`)
- [ ] Clean Architecture dependencies respected (no circular references)
- [ ] Domain logic stays in Domain layer (no business logic in API/Infrastructure)
- [ ] All public APIs have XML documentation
- [ ] Error handling uses proper status codes and ProblemDetails
- [ ] Async/await pattern used consistently
- [ ] Structured logging with ILogger (no string interpolation)
- [ ] Guard clauses for parameter validation
- [ ] Tests organized by feature and method
## Related Issues
Closes #1 - Implement Task Manager CRUD API
Closes #2 - Refactor legacy code
Closes #3 - Add comprehensive test coverage
## Screenshots
N/A - API only, no UI
## Deployment Notes
- Requires .NET 9.0 SDK or higher
- Uses in-memory data store (no database configuration needed)
- Default port: 5000 (HTTP)
## Next Steps (Future Work)
- [ ] Add database persistence (EF Core with SQL Server)
- [ ] Implement authentication/authorization
- [ ] Add pagination and advanced filtering
- [ ] Implement task notification service
- [ ] Add OpenTelemetry distributed tracing
- [ ] Create Swagger/OpenAPI documentationReview the generated PR description and adjust:
- Add specific issue numbers
- Include actual test counts
- Add screenshots if you created a UI
- Highlight any specific areas needing review
- /tests Command: Generates comprehensive test suites instantly
- Test Coverage: Happy path, edge cases, error conditions, cancellation
- Test Organization: Feature-based folders, class-per-method files
- Integration Tests: WebApplicationFactory for full API testing
- /doc Command: XML documentation generated from code context
- API Docs: Clear examples with request/response formats
- Architecture Docs: ADRs document important decisions
- Consistency: AI ensures consistent documentation style
- Conventional Commits: Structured, parsable commit messages
- Semantic Commits: Type, scope, description format
- Detailed Bodies: Explain what, why, and how
- Changelog Ready: Commits can generate CHANGELOG.md automatically
- @workspace Context: Full codebase understanding for PR description
- Comprehensive PRs: All changes documented and explained
- Reviewer Checklist: Clear acceptance criteria
- Impact Analysis: Breaking changes, migrations, deployment notes
Ask Copilot to generate a CHANGELOG.md file from your commit history:
Generate a CHANGELOG.md file based on the git commit history. Group by version, follow Keep a Changelog format.
Generate CONTRIBUTING.md with guidelines for contributors:
Create a CONTRIBUTING.md file that explains:
- How to set up the development environment
- Coding conventions (reference .github/instructions/ for context-aware standards)
- Testing requirements
- PR process
- Commit message format
Generate documentation for consuming the API:
Create a quick start guide in docs/guides/api-quickstart.md for developers consuming our Task Manager API. Include authentication (if applicable), endpoint examples, and common error handling patterns.
You've completed this lab successfully when:
- ✅ Comprehensive test suite generated with
/tests(unit + integration) - ✅ All public APIs have XML documentation via
/doc - ✅ API documentation in README.md with examples
- ✅ Conventional Commit messages written for all changes
- ✅ Complete PR description drafted with
@workspace - ✅ All tests passing
- ✅ Documentation is clear and maintainable
- ✅ Ready for code review
Congratulations! You've completed all four labs. You now know how to:
- Follow Red-Green-Refactor cycle
- Use Copilot to generate tests before implementation
- Apply Copilot Instructions for consistent code quality
- Decompose user stories into backlog items
- Generate acceptance criteria
- Implement features using TDD
- Maintain Clean Architecture across all layers
- Generate complete API endpoints with context
- Refactor legacy code with
/refactor - Apply Object Calisthenics principles
- Use Copilot Edits for multi-file changes
- Generate comprehensive test coverage
- Create clear documentation
- Write meaningful commit messages
- Prepare thorough PR descriptions
Problem: Tests don't cover all edge cases
Solution: Be explicit: "/tests including edge cases, error handling, and cancellation"
Problem: XML comments don't add value beyond method signature
Solution: Select more context (class + method), provide business context in prompt
Problem: Copilot generates "Update files" type messages
Solution: Stage related changes only, provide context: "Write commit for adding GET endpoints"
Problem: PR description is too high-level
Solution: Use @workspace and be specific: "Include testing details, breaking changes, and reviewer checklist"
- Add context-aware instruction files (
.github/instructions/) to your team's repositories - Establish Conventional Commits standard
- Use
/testsfor all new code - Use
/docfor public APIs - Use
@workspacein daily work
- Custom instructions for team-specific patterns
- Copilot for Business with organization policies
- Fine-tuned models for domain-specific code
- Integration with CI/CD pipelines
- Practice TDD with different features
- Explore advanced DDD patterns
- Learn OpenTelemetry for observability
- Study Clean Architecture in depth