Skip to content

Commit 81afe34

Browse files
authored
Merge pull request #28 from nitin27may/add-role-page-permission-management-d66
Page, Operation, Role and User Mapping
2 parents 36f1027 + a95ebec commit 81afe34

File tree

201 files changed

+6642
-1325
lines changed

Some content is hidden

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

201 files changed

+6642
-1325
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# .NET 8+ Best Practices Instructions
2+
3+
# GitHub Copilot Instructions for .NET 8+
4+
5+
Generate code following these modern .NET 8+ best practices:
6+
7+
## C# Language and Syntax
8+
- Always maintain semicolons after namespace declarations
9+
- Use C# 12+ features including primary constructors, required properties, and file-scoped namespaces
10+
- Implement pattern matching for complex conditionals
11+
- Use nullable reference types with proper null checks everywhere
12+
- Use records for DTOs and immutable data structures
13+
- Use init-only properties for immutable objects
14+
- Use collection expressions where appropriate
15+
16+
## Logging
17+
- Include ILogger in all classes using constructor injection
18+
- Follow proper log level usage:
19+
- LogDebug: Detailed information for debugging
20+
- LogInformation: General operational information and successful operations
21+
- LogWarning: Non-critical issues or unexpected behavior
22+
- LogError: Errors and exceptions that prevent normal operation
23+
- LogCritical: Critical failures requiring immediate attention
24+
- Use structured logging with proper context:
25+
- Always include correlation IDs in logs
26+
- Use semantic logging with named parameters (e.g., `_logger.LogInformation("User {UserId} performed {Action}", userId, action)`)
27+
- Add logging for all major operations and exception paths
28+
29+
## API Endpoints and Controllers
30+
- Use minimal APIs for simple CRUD operations
31+
- Use controller-based APIs for complex business logic
32+
- Apply consistent HTTP status codes based on operation outcomes
33+
- Use proper route patterns with versioning support
34+
- Always use attribute routing
35+
- Return ActionResult<T> from controller methods
36+
- Apply authorization and custom attributes to each endpoint
37+
38+
## Custom Attributes
39+
- Apply ActivityLog attribute to all action methods to capture user activities:
40+
- Format: `[ActivityLog("Descriptive action message")]`
41+
- Apply AuthorizePermission attribute for fine-grained authorization:
42+
- Format: `[AuthorizePermission("Resource.Operation")]`
43+
- Place custom attributes before standard HTTP method attributes
44+
45+
## Input Validation
46+
- Use FluentValidation for complex validation rules
47+
- Implement proper model validation with consistent error responses
48+
- Return ProblemDetails for validation errors
49+
- Validate request models early in the pipeline
50+
51+
## Exception Handling
52+
- Implement global exception handling middleware
53+
- Use custom exception types for different business scenarios
54+
- Return appropriate status codes based on exception types
55+
- Include correlation IDs in error responses
56+
- Never expose sensitive information in error messages
57+
58+
## Authentication & Authorization
59+
- Use JWT authentication with proper token validation
60+
- Implement role and policy-based authorization
61+
- Apply AuthorizePermission attributes consistently
62+
- Use scoped authorization policies
63+
- Implement proper refresh token mechanisms
64+
65+
## Performance
66+
- Use asynchronous methods throughout the application
67+
- Implement appropriate caching strategies
68+
- Use output caching for GET endpoints
69+
- Implement rate limiting and request throttling
70+
- Use minimal serialization options
71+
72+
## API Documentation
73+
- Include comprehensive Swagger/OpenAPI documentation
74+
- Add proper XML comments for all public APIs
75+
- Provide examples for request/response models
76+
- Document all possible response codes
77+
78+
## Sample Controller Implementation
79+
80+
```
81+
using Contact.Api.Core.Attributes;
82+
using Contact.Application.Interfaces;
83+
using Contact.Application.UseCases.ContactPerson;
84+
using Microsoft.AspNetCore.Authorization;
85+
using Microsoft.AspNetCore.Mvc;
86+
87+
namespace Contact.Api.Controllers;
88+
89+
[Route("api/[controller]")]
90+
[ApiController]
91+
[Authorize]
92+
public class ContactPersonController(IContactPersonService contactPersonService) : ControllerBase
93+
{
94+
[HttpPost]
95+
[ActivityLog("Creating new Contact")]
96+
[AuthorizePermission("Contacts.Create")]
97+
public async Task<IActionResult> Add(CreateContactPerson createContactPerson)
98+
{
99+
var createdContactPerson = await contactPersonService.Add(createContactPerson);
100+
return CreatedAtAction(nameof(GetById), new { id = createdContactPerson.Id }, createdContactPerson);
101+
}
102+
103+
[HttpPut("{id}")]
104+
[ActivityLog("Updating Contact")]
105+
[AuthorizePermission("Contacts.Update")]
106+
public async Task<IActionResult> Update(Guid id, UpdateContactPerson updateContactPerson)
107+
{
108+
var contactPerson = await contactPersonService.FindByID(id);
109+
if (contactPerson is null) return NotFound();
110+
111+
var updatedContactPerson = await contactPersonService.Update(updateContactPerson);
112+
return Ok(updatedContactPerson);
113+
}
114+
115+
[HttpDelete("{id}")]
116+
[ActivityLog("Deleting Contact")]
117+
[AuthorizePermission("Contacts.Delete")]
118+
public async Task<IActionResult> Delete(Guid id)
119+
{
120+
var deleted = await contactPersonService.Delete(id);
121+
return deleted ? NoContent() : NotFound();
122+
}
123+
124+
[HttpGet("{id}")]
125+
[ActivityLog("Reading Contact By id")]
126+
[AuthorizePermission("Contacts.Read")]
127+
public async Task<IActionResult> GetById(Guid id)
128+
{
129+
var contactPerson = await contactPersonService.FindByID(id);
130+
return contactPerson is null ? NotFound() : Ok(contactPerson);
131+
}
132+
133+
[HttpGet]
134+
[ActivityLog("Reading All Contacts")]
135+
[AuthorizePermission("Contacts.Read")]
136+
public async Task<IActionResult> GetAll()
137+
{
138+
var contactPersons = await contactPersonService.FindAll();
139+
return Ok(contactPersons);
140+
}
141+
}
142+
143+
```

.github/copilot-instructions.md

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,71 @@
1-
# Use modern dependency injection syntax
1+
# GitHub Copilot Instructions for Angular
22

3-
- Whenever you have to inject a dependency using Angular DI system, use the `inject` function instead of constructor based injection.
4-
- this will apply to injecting services, tokens and parent components e.g. in directives as well
3+
Generate code following these modern Angular 19+ best practices:
54

5+
## Dependency Injection
6+
- Always use functional injection with `inject()` instead of constructor-based injection
7+
- Example: `private userService = inject(UserService);` instead of constructor injection
8+
- Apply this for services, tokens, and parent component references
69

10+
## State Management
11+
- Use signals for component state instead of class properties
12+
- Example: `counter = signal<number>(0);`
13+
- Use computed signals for derived state
14+
- Example: `doubleCounter = computed(() => this.counter() * 2);`
15+
- Prefer signals over RxJS observables for component-level state
716

8-
# For all state in components and directives, use a signal instead of a class property
9-
- For example:
17+
## Component Structure
18+
- Use standalone components as the default approach
19+
- Use the modern control flow syntax (`@if`, `@for`, etc.)
20+
- Implement OnPush change detection strategy for better performance
21+
- Always use separte html and scss file for view and styling
1022

11-
` counter = signal<number>(0); `
23+
## Services & HTTP
24+
- For service calls using subscribe, use the next syntax:
25+
this.userService.getUsers().subscribe({
26+
next: (users) => this.users.set(users),
27+
error: (error) => this.errorMessage.set(error)
28+
});
1229

13-
- For derived state from an existing signal, use computeds as follows.
30+
## Routing & Guards
31+
- Use functional syntax for guards and resolvers
32+
- Example:
33+
export const authGuard = () => {
34+
const router = inject(Router);
35+
const authService = inject(AuthService);
36+
37+
if (authService.isAuthenticated()) {
38+
return true;
39+
}
40+
41+
return router.parseUrl('/login');
42+
};
1443

15-
` doubleCounter = computed(() => this.counter() * 2); `
44+
## HTTP Interceptors
45+
- Use functional interceptors
46+
- Example:
47+
export const authInterceptor: HttpInterceptorFn = (req, next) => {
48+
const authService = inject(AuthService);
49+
const token = authService.getToken();
50+
51+
if (token) {
52+
const authReq = req.clone({
53+
headers: req.headers.set('Authorization', `Bearer ${token}`)
54+
});
55+
return next(authReq);
56+
}
57+
58+
return next(req);
59+
};
1660

61+
## Styling
62+
- Use Angular Material 19 with proper theming
63+
- Implement TailwindCSS v4 for utility-first styling
64+
- Ensure components support theme switching
65+
- Apply consistent color tokens from design system
1766

18-
- Use function style for guard, interceptors
19-
20-
- for the service call if using subscribe use next:
21-
22-
# For styling use Angular Material 19 with theming and tailwind v4
23-
- TailwindCSS for utility-first styling
24-
- make sure everything supporting the theme
25-
26-
# backend use .Net 9 clean architecture but not CQRS, plase refer the existing coding patterns for the Generic Repostiory and Generic Service as much possible
67+
## Input/Output Handling
68+
- Use strongly typed inputs and outputs
69+
- Example:
70+
@Input({ required: true }) id!: string;
71+
@Output() saved = new EventEmitter<User>();

.vscode/launch.json

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,52 @@
33
// Hover to view descriptions of existing attributes.
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
6+
"compounds": [
7+
{
8+
"name": "Full Stack: Angular + .NET",
9+
"configurations": ["Angular Frontend", ".NET Core Backend"],
10+
"stopAll": true
11+
}
12+
],
613
"configurations": [
14+
{
15+
"name": ".NET Core Backend",
16+
"type": "coreclr",
17+
"request": "launch",
18+
"preLaunchTask": "build-backend",
19+
"program": "${workspaceFolder}/backend/src/Contact.Api/bin/Debug/net9.0/Contact.Api.dll",
20+
"args": [],
21+
"cwd": "${workspaceFolder}/backend/src/Contact.Api",
22+
"stopAtEntry": false,
23+
"env": {
24+
"ASPNETCORE_ENVIRONMENT": "Development",
25+
"ASPNETCORE_URLS": "http://localhost:5000"
26+
}
27+
},
28+
{
29+
"name": "Angular Frontend",
30+
"type": "chrome",
31+
"request": "launch",
32+
"preLaunchTask": "npm-start",
33+
"url": "http://localhost:4200",
34+
"webRoot": "${workspaceFolder}/frontend",
35+
"sourceMapPathOverrides": {
36+
"webpack:/*": "${webRoot}/*",
37+
"/./*": "${webRoot}/*",
38+
"/src/*": "${webRoot}/src/*",
39+
"/app/*": "${webRoot}/src/app/*",
40+
"/*": "*",
41+
"/./~/*": "${webRoot}/node_modules/*"
42+
}
43+
},
744
{
845
"name": "Docker .NET Core Attach (Preview)",
946
"type": "coreclr",
1047
"request": "attach",
1148
"sourceFileMap": {
1249
"/src": "${workspaceFolder}/WebApi"
1350
},
14-
"processId" : "${command:pickRemoteProcess}",
51+
"processId": "${command:pickRemoteProcess}",
1552
"pipeTransport": {
1653
"debuggerPath": "/vsdbg/vsdbg",
1754
"pipeProgram": "docker",
@@ -20,8 +57,7 @@
2057
"pipeArgs": [
2158
"exec -i angular-dotnet_api_1"
2259
]
23-
}
60+
}
2461
}
25-
2662
]
2763
}

.vscode/tasks.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build-backend",
6+
"command": "dotnet",
7+
"type": "process",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/backend/src/Contact.Api/Contact.Api.csproj",
11+
"/property:GenerateFullPaths=true",
12+
"/consoleloggerparameters:NoSummary"
13+
],
14+
"problemMatcher": "$msCompile"
15+
},
16+
{
17+
"label": "frontend-build",
18+
"type": "shell",
19+
"command": "cd ${workspaceFolder}/frontend && npm run build",
20+
"problemMatcher": ["$tsc"],
21+
"group": {
22+
"kind": "build",
23+
"isDefault": false
24+
}
25+
},
26+
{
27+
"label": "npm-start",
28+
"type": "shell",
29+
"command": "cd ${workspaceFolder}/frontend && npm run serve",
30+
"isBackground": true,
31+
"problemMatcher": {
32+
"owner": "typescript",
33+
"pattern": {
34+
"regexp": ".",
35+
"file": 1,
36+
"location": 2,
37+
"message": 3
38+
},
39+
"background": {
40+
"activeOnStart": true,
41+
"beginsPattern": ".",
42+
"endsPattern": "Angular Live Development Server is listening"
43+
}
44+
},
45+
"presentation": {
46+
"reveal": "always",
47+
"panel": "dedicated"
48+
}
49+
}
50+
]
51+
}

0 commit comments

Comments
 (0)