Skip to content

feat: Employee HR management – .NET Core Web API backend (Phase 1)#1

Draft
Copilot wants to merge 6 commits into
mainfrom
copilot/employee-list-screen-backend-api
Draft

feat: Employee HR management – .NET Core Web API backend (Phase 1)#1
Copilot wants to merge 6 commits into
mainfrom
copilot/employee-list-screen-backend-api

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 17, 2026

  • Explore Angular app structure and patterns
  • Fix backend: search endpoint moved to POST /api/Employees/search (resolves route conflict with create)
  • Rebuild backend and regenerate TypeScript API client via nswag
  • Create employees/employees.component.ts with signals, search, create/edit logic, role awareness
  • Create employees/employees.component.html (search form with multi-select chips, results table, create/edit dialog)
  • Add employee styles to styles.scss
  • Register component in app.module.ts with route /employees and AuthGuard
  • Add "Employees" nav link in nav-menu.component.html
  • Angular build passes (dev mode) with zero errors
  • Fix: PersonalMobileNumber optional in UpdateEmployeeCommandValidator (code review feedback)

Copilot AI and others added 2 commits April 17, 2026 13:54
- Add Employee entity, SourceType enum, HumanResourcesAdminSourceTypes role
- Add SearchEmployees query with role-aware filtering and at-least-one-criterion validation
- Add GetNextRegistrationNumber query for UI hint
- Add GetEmployeeLookups query (role-filtered source types + active/passive codes)
- Add CreateEmployee command with business rules and race-condition-safe registration number generation
- Add UpdateEmployee command with full update validations
- Add IEmployeeRegistrationNumberService interface with atomic GenerateNextAsync
- Add EmployeeRegistrationNumberService using DB transaction to prevent race conditions
- Add Employees minimal API endpoint group with all 7 endpoints
- Seed HumanResourcesAdminSourceTypes role in DB initializer
- Pre-existing NU1903 vulnerability unrelated to this feature

Agent-Logs-Url: https://github.com/defactoAdil/CleanArchitecture/sessions/5820a821-591e-44e7-ad12-0141efb2e2f4

Co-authored-by: defactoAdil <189980729+defactoAdil@users.noreply.github.com>
- Fix transaction race condition: generate+insert now wrapped in single BeginTransactionAsync call
- Add BeginTransactionAsync to IApplicationDbContext and ApplicationDbContext
- Extract shared ActivePassiveCodes.Normalize helper to eliminate duplication
- Fix duplicate lookup endpoints to return specific data (SourceTypes vs ActivePassiveCodes)
- Simplify EmployeeRegistrationNumberService (transaction managed by caller)

Agent-Logs-Url: https://github.com/defactoAdil/CleanArchitecture/sessions/5820a821-591e-44e7-ad12-0141efb2e2f4

Co-authored-by: defactoAdil <189980729+defactoAdil@users.noreply.github.com>
@defactoAdil
Copy link
Copy Markdown
Owner

yapay zekaya analiz verip kod yazdırma testi yaptım.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Phase 1 of the Employee HR management backend for the migrated EmployeeList screen, adding the Employee domain model, CQRS/MediatR handlers (search/create/update/lookups/registration number preview), EF Core persistence, and minimal API endpoints under the existing Clean Architecture structure.

Changes:

  • Added Employee domain entity + SourceType enum + EF Core configuration and DbContext wiring.
  • Implemented Employee CQRS handlers/validators, lookup queries, and registration-number generation service.
  • Added minimal API endpoints for employee search/read/create/update and lookups; seeded the new HR admin role.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/Web/Endpoints/Employees.cs Adds minimal API endpoints for employee operations and lookups.
src/Infrastructure/Services/EmployeeRegistrationNumberService.cs Implements MAX+1 registration number generation/preview per source type.
src/Infrastructure/DependencyInjection.cs Registers IEmployeeRegistrationNumberService.
src/Infrastructure/Data/Configurations/EmployeeConfiguration.cs Adds EF mapping and constraints (unique index, max lengths, required fields).
src/Infrastructure/Data/ApplicationDbContextInitialiser.cs Seeds the new HumanResourcesAdminSourceTypes role.
src/Infrastructure/Data/ApplicationDbContext.cs Adds DbSet<Employee> and exposes BeginTransactionAsync.
src/Domain/Enums/SourceType.cs Defines source type enum values.
src/Domain/Entities/Employee.cs Introduces Employee entity fields (auditable).
src/Domain/Constants/Roles.cs Adds HumanResourcesAdminSourceTypes role constant.
src/Application/Employees/Queries/SearchEmployees/SearchEmployees.cs Adds employee search query, validator, and handler with role-based filtering.
src/Application/Employees/Queries/SearchEmployees/EmployeeSearchRequest.cs Defines search request contract for filtering.
src/Application/Employees/Queries/SearchEmployees/EmployeeDto.cs Adds DTO + AutoMapper mapping with derived fields.
src/Application/Employees/Queries/GetNextRegistrationNumber/GetNextRegistrationNumber.cs Adds “peek” query for next registration number.
src/Application/Employees/Queries/GetEmployeeLookups/GetEmployeeLookups.cs Adds role-filtered lookups for source types and active/passive codes.
src/Application/Employees/Queries/GetEmployeeLookups/EmployeeLookupsVm.cs Defines lookup VM and DTOs.
src/Application/Employees/Common/ActivePassiveCodes.cs Adds shared normalization helper for active/passive codes.
src/Application/Employees/Commands/UpdateEmployee/UpdateEmployeeCommandValidator.cs Adds update validation rules, including source type restrictions.
src/Application/Employees/Commands/UpdateEmployee/UpdateEmployee.cs Adds update command + handler with role-based edit restrictions.
src/Application/Employees/Commands/CreateEmployee/CreateEmployeeCommandValidator.cs Adds create validation rules (incl. restricted source types).
src/Application/Employees/Commands/CreateEmployee/CreateEmployee.cs Adds create command + handler with transactional registration number generation.
src/Application/Common/Interfaces/IEmployeeRegistrationNumberService.cs Introduces interface for registration number generation/peek.
src/Application/Common/Interfaces/IApplicationDbContext.cs Extends app DbContext interface with Employees and BeginTransactionAsync.
Comments suppressed due to low confidence (1)

src/Infrastructure/Data/ApplicationDbContextInitialiser.cs:94

  • The new HumanResourcesAdminSourceTypes role is created during seeding, but the default seeded administrator@localhost user is only added to the Administrator role. Since the new employee feature’s “admin” checks are based on HumanResourcesAdminSourceTypes, the seeded admin user won’t be able to access/administer SAP/OzonTekstil behaviors in dev/test environments. Consider adding the seeded admin user to the new role as well (or aligning the checks to include Administrator).
        var administratorRole = new IdentityRole(Roles.Administrator);
        var hrAdminRole = new IdentityRole(Roles.HumanResourcesAdminSourceTypes);

        if (_roleManager.Roles.All(r => r.Name != administratorRole.Name))
        {
            await _roleManager.CreateAsync(administratorRole);
        }

        if (_roleManager.Roles.All(r => r.Name != hrAdminRole.Name))
        {
            await _roleManager.CreateAsync(hrAdminRole);
        }

        // Default users
        var administrator = new ApplicationUser { UserName = "administrator@localhost", Email = "administrator@localhost" };

        if (_userManager.Users.All(u => u.UserName != administrator.UserName))
        {
            await _userManager.CreateAsync(administrator, "Administrator1!");
            if (!string.IsNullOrWhiteSpace(administratorRole.Name))
            {
                await _userManager.AddToRolesAsync(administrator, new [] { administratorRole.Name });
            }
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to +38
RuleFor(c => c.SourceTypeStr)
.Must(st => !RestrictedSourceTypes.Contains(st))
.WithMessage("SAP and OzonTekstil source types cannot be selected when creating an employee.")
.When(c => !string.IsNullOrWhiteSpace(c.SourceTypeStr));
Comment on lines +50 to +68
public async Task<string> Handle(CreateEmployeeCommand request, CancellationToken cancellationToken)
{
// Resolve default source type based on role
var sourceType = string.IsNullOrWhiteSpace(request.SourceTypeStr)
? DefaultSourceType()
: request.SourceTypeStr;

// BusinessUnitId is only set for admin users
var isAdmin = _user.Roles?.Contains(Roles.HumanResourcesAdminSourceTypes) ?? false;
var businessUnitId = isAdmin ? request.BusinessUnitId : null;

// Wrap number generation + INSERT in one transaction to prevent race conditions.
// The unique index on RegistrationNumber is the final safety net.
await using var transaction = await _context.BeginTransactionAsync(cancellationToken);
try
{
var registrationNumber = await _registrationNumberService
.GenerateNextAsync(sourceType, cancellationToken);

Comment thread src/Web/Endpoints/Employees.cs Outdated
Comment on lines +16 to +21
groupBuilder.MapPost(SearchEmployees);
groupBuilder.MapGet(GetEmployee, "{registrationNumber}");
groupBuilder.MapGet(GetNextRegistrationNumber, "next-registration-number/{sourceType}");
groupBuilder.MapPost(CreateEmployee, string.Empty);
groupBuilder.MapPut(UpdateEmployee, "{registrationNumber}");
groupBuilder.MapGet(GetSourceTypeLookups, "lookup/source-types");
ISender sender, CreateEmployeeCommand command)
{
var registrationNumber = await sender.Send(command);
return TypedResults.Created($"/api/employees/{registrationNumber}", registrationNumber);
if (!string.IsNullOrWhiteSpace(r.FirstName)) return true;
if (!string.IsNullOrWhiteSpace(r.LastName)) return true;
if (r.SourceTypeList is { Count: > 0 }) return true;
if (r.IsTerminated.HasValue && !string.IsNullOrWhiteSpace(r.ActivePassiveCode)) return true;
Comment thread src/Application/Employees/Queries/GetEmployeeLookups/GetEmployeeLookups.cs Outdated
Comment on lines +34 to +36
.NotEmpty()
.Length(12).WithMessage("Personal mobile number must be exactly 12 characters.")
.Must(n => n!.StartsWith("90")).WithMessage("Personal mobile number must start with '90'.");
Comment on lines +61 to +94
// Wrap number generation + INSERT in one transaction to prevent race conditions.
// The unique index on RegistrationNumber is the final safety net.
await using var transaction = await _context.BeginTransactionAsync(cancellationToken);
try
{
var registrationNumber = await _registrationNumberService
.GenerateNextAsync(sourceType, cancellationToken);

var employee = new Employee
{
RegistrationNumber = registrationNumber,
IdentityNumber = request.IdentityNumber,
Firstname = request.Firstname,
Lastname = request.Lastname,
PersonalMobileNumber = request.PersonalMobileNumber,
SourceTypeStr = sourceType,
ActivePassiveCode = ActivePassiveCodes.Normalize(request.ActivePassiveCode),
IsTerminated = request.IsTerminated,
CompanyName = request.CompanyName,
BusinessUnitId = businessUnitId,
Description = request.Description
};

_context.Employees.Add(employee);
await _context.SaveChangesAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);

return registrationNumber;
}
catch
{
await transaction.RollbackAsync(cancellationToken);
throw;
}
Comment on lines +90 to +91
if (allowedSourceTypes.Count > 0)
query = query.Where(e => allowedSourceTypes.Contains(e.SourceTypeStr));
Copilot AI and others added 2 commits April 17, 2026 14:31
- Fix backend route conflict: SearchEmployees → POST /api/Employees/search (was POST /api/Employees, conflicting with CreateEmployee)
- Regenerate TypeScript API client (searchEmployees method now generated)
- Add EmployeesComponent with search form, results table and create/edit dialog
- Role-based UX: admin detection via source-type lookup (SAP/OzonTekstil visible ↔ isAdmin)
- BusinessUnitId field shown only for admin users
- canEdit flag respected: Edit button shown only when employee is editable
- Registration number auto-populated from API on source type change (create only)
- Source type multi-select chip UI
- Active/Passive badge styling in results table
- Register route /employees with AuthGuard in app.module.ts
- Add Employees nav link in nav-menu
- Add employee CSS classes to global styles.scss

Agent-Logs-Url: https://github.com/defactoAdil/CleanArchitecture/sessions/8ad11855-a989-4523-be83-b5a1202b1270

Co-authored-by: defactoAdil <189980729+defactoAdil@users.noreply.github.com>
…ator

Mobile number is nullable on the domain entity — `.NotEmpty()` incorrectly
prevented blank values on update. Now applies length/prefix rules only when
the field is provided, matching CreateEmployeeCommandValidator behaviour.

Agent-Logs-Url: https://github.com/defactoAdil/CleanArchitecture/sessions/8ad11855-a989-4523-be83-b5a1202b1270

Co-authored-by: defactoAdil <189980729+defactoAdil@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants