3.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Run
dotnet build BMA.EHR.Recruit.Service.sln
dotnet build BMA.EHR.Recruit.Service.sln -c Release
dotnet publish -c Release -o /app/publish /p:UseAppHost=false
No test projects exist in this solution.
Architecture
Stack: ASP.NET Core 7.0 Web API / EF Core 7.0 / MySQL (Pomelo) / MinIO (S3) / Keycloak (JWT)
Pattern: Controllers → Services → EF Core DbContext (no repository layer for main data)
Multiple DbContexts
Three separate MySQL databases, each with its own DbContext:
ApplicationDbContext— Recruitment data (Recruits, Scores, Imports)OrgDbContext— Organization dataMetadataDbContext— Metadata
All registered as Transient lifetime. Auto-migration runs on startup.
Controllers
BaseControllerprovides standardizedSuccess()/Error()response methods returningResponseObject(Status, Message, Result)RecruitControlleris the sole business controller (route:api/v{version}/recruit)- API versioning enabled via
Microsoft.AspNetCore.Mvc.Versioning
Background Import System
Excel file imports run asynchronously through a Channel-based queue:
ImportBackgroundService(BackgroundService) — dequeues and processes jobsImportJobQueue— bounded Channel (capacity 100)ImportJobTracker— in-memory ConcurrentDictionary tracking
Four import types: CandidateFile, CandidateFileById, ScoreFile, ResultFile
All imports use EFCore.BulkExtensions.MySql (v6.7.16) for bulk operations to handle 50,000+ rows without memory issues. Pattern:
- Insert parent/history entities via
SaveChangesAsync(small operations) ChangeTracker.Clear()to release references- Collect entities into separate
List<T>per table BulkInsertAsyncwithSetOutputIdentity = truefor parent entities- Assign generated Ids to child entities
BulkInsertAsyncfor each child entity table separately- Batch size: 500
Entity Models
All entities inherit from EntityBase (Guid Id PK, audit fields: CreatedAt, CreatedUserId, LastUpdatedAt, etc.). Models are in Models/ with subdirectories: Recruits/, Documents/, HR/, MetaData/, Placement/.
Key relationships use navigation properties without explicit FK properties (EF shadow properties). Configured via fluent API in OnModelCreating.
External Services
- Authentication: Keycloak JWT Bearer (
hrmsbkk-id.case-collection.com/realms/hrms) - File Storage: MinIO via
MinIOService(AWS S3 SDK) - Search/Logging: Elasticsearch (NEST client)
- Excel: EPPlus for reading import files
Key Files
Program.cs— Service registration, middleware pipeline, auto-migrationData/ApplicationDbContext.cs— EF Core fluent API relationship configurationServices/ImportBackgroundService.cs— All bulk import logic (4 import methods)Services/RecruitService.cs— Core business logicControllers/BaseController.cs— Standard response helpersResponses/ResponseObject.cs— Standard API response envelope
Conventions
- Language: C# with nullable reference types enabled
- Naming: PascalCase properties,
_camelCaseparameters in service methods - API responses: Always wrapped in
ResponseObject - Authorization:
[Authorize]on controllers, user context from JWT claims