Skip to content

Commit 9809189

Browse files
authored
feat(templates): add .github\copilot-instructions.md to bit Boilerplate #11020 (#11021)
1 parent 321d860 commit 9809189

File tree

7 files changed

+99
-10
lines changed

7 files changed

+99
-10
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# copilot-instructions.md
2+
3+
## Architecture & Project Structure
4+
5+
- **Client Projects**: Multiple platform-specific clients sharing core infrastructure
6+
- `Client.Core`: Blazor pages, shared components, service, typescript and SCSS files.
7+
- `Client.Web`: PWA Blazor WebAssembly.
8+
- `Client.Maui`: Cross-platform MAUI based Blazor Hybrid app.
9+
- `Client.Windows`: Windows forms based Blazor Hybrid app.
10+
11+
- **Server Projects**: API and web
12+
- `Server.Api`: Web API controllers, entity framework core db context, type configurations and migrations plus SignalR, Hangfire, models, services and mappers.
13+
- `Server.Web`: Blazor Server, Auto and WebAssembly, with or without pre-rendering.
14+
15+
- **Shared**: Dto classes, enums, interfaces etc.
16+
17+
- **Boilerplate.Tests**: Integration api and UI tests using Playwright and MSTest.
18+
19+
## Technology Stack
20+
21+
### Technologies
22+
- **C# 13.0**
23+
- **ASP.NET Core 9.0**
24+
- **Blazor**: Component-based web UI framework
25+
- **MAUI**: Cross-platform app development
26+
- **ASP.NET Core Identity**: Authentication and authorization
27+
- **Entity Framework Core**: Data access
28+
- **SignalR**: Real-time communication
29+
- **Hangfire**: Background job processing
30+
- **OData**: Advanced querying capabilities
31+
- **Bit.BlazorUI**: Primary UI framework
32+
- **Microsoft.Extensions.AI**: AI integration
33+
- **TypeScript**: Type-safe JavaScript development
34+
- **SCSS**: Advanced CSS preprocessing
35+
36+
## Development Guidelines
37+
38+
### Code Style & Conventions
39+
- **C# 13.0**: Use latest language features
40+
- **Nullable Reference Types**: Enabled project-wide
41+
- **Implicit Usings**: Leverage global using statements
42+
- **.editorconfig**: Use for consistent code style across IDEs
43+
44+
### Global Using Statements
45+
The project uses extensive global using statements for common namespaces:
46+
47+
### Building the Application
48+
Navigate to the server directory and run:
49+
```bash
50+
cd src/Server/Boilerplate.Server.Web
51+
dotnet build
52+
```
53+
54+
### Running the Application
55+
To run the application, execute the following command in the server directory:
56+
```bash
57+
cd src/Server/Boilerplate.Server.Web
58+
dotnet run
59+
```
60+
61+
### Testing the Application
62+
To run the tests, navigate to the test project directory and execute:
63+
```bash
64+
cd src/Tests
65+
dotnet test
66+
```
67+
68+
### GitHub Codespaces Support
69+
The project is optimized for GitHub Codespaces development with pre-configured container support.
70+
71+
## Best Practices
72+
73+
1. **Follow the established project structure**
74+
2. **Use Bit.BlazorUI components** - leverage the framework's built-in components and utilities
75+
3. **Follow nullable reference type conventions** - all new code should be nullable-aware
76+
4. **Use dependency injection** - leverage the built-in DI container for service registration
77+
5. **Implement proper logging** - use structured logging throughout the application
78+
6. **Follow security best practices** - use proper authentication and authorization patterns
79+
7. **Async Programming** - prefer async/await for I/O-bound operations, avoid blocking calls

src/Templates/Boilerplate/Bit.Boilerplate/Boilerplate.sln

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
3737
.azure-devops\workflows\ci.yml = .azure-devops\workflows\ci.yml
3838
EndProjectSection
3939
EndProject
40-
#elif (pipeline == "GitHub")
40+
#endif
4141
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{3E577755-186F-4E63-8153-B8DE890015C9}"
42+
ProjectSection(SolutionItems) = preProject
43+
.github\copilot-instructions.md = .github\copilot-instructions.md
44+
EndProjectSection
4245
EndProject
46+
#if (pipeline == "GitHub")
4347
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{2347E3B2-FDDE-427E-A0AE-E4DCD47C2989}"
4448
ProjectSection(SolutionItems) = preProject
4549
.github\workflows\cd.yml = .github\workflows\cd.yml

src/Templates/Boilerplate/Bit.Boilerplate/Boilerplate.slnx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
<File Path=".azure-devops/workflows/cd.yml" />
2323
<File Path=".azure-devops/workflows/ci.yml" />
2424
</Folder>
25-
//#elif (pipeline == "GitHub")
26-
<Folder Name="/.SolutionItems/.github/" Id="351df30f-2daa-a858-be55-4affc8d70af2" />
25+
//#endif
26+
<Folder Name="/.SolutionItems/.github/" Id="351df30f-2daa-a858-be55-4affc8d70af2">
27+
<File Path=".github/copilot-instructions.md" />
28+
</Folder>
29+
//#if (pipeline == "GitHub")
2730
<Folder Name="/.SolutionItems/.github/workflows/" Id="c0ca9c70-aac5-bd27-2f07-59fab982d30d">
2831
<File Path=".github/workflows/cd.yml" />
2932
<File Path=".github/workflows/ci.yml" />

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/Header/Header.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ protected override async Task OnInitAsync()
2222

2323
unsubscribePageTitleChanged = PubSubService.Subscribe(ClientPubSubMessages.PAGE_DATA_CHANGED, async payload =>
2424
{
25-
(pageTitle, pageSubtitle, showGoBackButton) = ((string?, string?,bool))payload!;
25+
(pageTitle, pageSubtitle, showGoBackButton) = ((string?, string?, bool))payload!;
2626

2727
StateHasChanged();
2828
});
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
namespace Boilerplate.Client.Core.Components;
1+
namespace Boilerplate.Client.Core.Components;
22

33
/// <summary>
44
/// To prevent rendering recursion into a particular subtree use this component as base class.
55
/// <see href="https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-9.0#avoid-unnecessary-rendering-of-component-subtrees"/>
66
/// </summary>
7-
public class StaticComponent: ComponentBase
7+
public class StaticComponent : ComponentBase
88
{
99
protected override bool ShouldRender() => false;
1010
}

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Services/ProductEmbeddingService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public async Task Embed(Product product, CancellationToken cancellationToken)
8686
return null;
8787
var embeddingGenerator = serviceProvider.GetService<IEmbeddingGenerator<string, Embedding<float>>>();
8888
if (embeddingGenerator is null)
89-
return env.IsDevelopment() ? throw new InvalidOperationException("Embedding generator is not registered.") : null;
89+
return env.IsDevelopment() ? null : throw new InvalidOperationException("Embedding generator is not registered.");
9090
var embedding = await embeddingGenerator.GenerateVectorAsync(input, options: new() { }, cancellationToken);
9191
return embedding.ToArray();
9292
//#endif

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ async Task HandleIncomingMessage(string incomingMessage, CancellationToken messa
9393
.LogError("Chat reported issue: User email: {emailAddress}, Conversation history: {conversationHistory}", emailAddress, conversationHistory);
9494
}, name: "SaveUserEmailAndConversationHistory", description: "Saves the user's email address and the conversation history for future reference. Use this tool when the user provides their email address during the conversation. Parameters: emailAddress (string), conversationHistory (string)"),
9595
//#if (module == "Sales")
96-
AIFunctionFactory.Create(async ([Description("Concise summary of these user requirements in English Language")] string userNeeds, [Description("Car manufactor's English name (Optional)")] string? manufactor) =>
96+
AIFunctionFactory.Create(async ([Description("Concise summary of these user requirements in English Language")] string userNeeds, [Description("Car manufacturer's English name (Optional)")] string? manufacturer) =>
9797
{
9898
if (messageSpecificCancellationToken.IsCancellationRequested)
9999
return null;
@@ -102,14 +102,17 @@ async Task HandleIncomingMessage(string incomingMessage, CancellationToken messa
102102

103103
await using var scope = serviceProvider.CreateAsyncScope();
104104
var productEmbeddingService = scope.ServiceProvider.GetRequiredService<ProductEmbeddingService>();
105-
var recommendedProducts = await (await productEmbeddingService.GetProductsBySearchQuery($"{userNeeds}, Manufactor: {manufactor}", messageSpecificCancellationToken))
105+
var searchQuery = string.IsNullOrWhiteSpace(manufacturer)
106+
? userNeeds
107+
: $"{userNeeds}, Manufacturer: {manufacturer}";
108+
var recommendedProducts = await (await productEmbeddingService.GetProductsBySearchQuery(searchQuery, messageSpecificCancellationToken))
106109
.Take(10)
107110
.Project()
108111
.Select(p => new
109112
{
110113
p.Name,
111114
PageUrl = new Uri(baseApiUrl, p.PageUrl),
112-
Manufactor = p.CategoryName,
115+
Manufacturer = p.CategoryName,
113116
Price = p.FormattedPrice,
114117
Description = p.DescriptionText
115118
})

0 commit comments

Comments
 (0)