Architecture — Project Structure¶
The solution NKO.Main/ERP-System.sln contains five projects, all targeting net6.0. One is the
web application; the rest are class libraries.
Dependency graph¶
flowchart TD
MAIN["NKO.Main<br/>web application"]
SHARED["NKO.Shared<br/>shared BAL, controllers, views"]
DATA["NKO.DataAccess<br/>core EF model"]
WARE["NKO.Warehouse.DataAccess<br/>warehouse EF model"]
HELP["NKO.Helpers<br/>validation attributes"]
MAIN --> DATA
MAIN --> SHARED
MAIN --> WARE
SHARED --> DATA
SHARED --> WARE
DATA --> HELP
NKO.Helpers and NKO.Warehouse.DataAccess are leaves. Note that the folder layout does not
match the dependency direction: NKO.Helpers sits physically under NKO.Main/ even though it is
the lowest-level library in the graph.
The five projects¶
| Project | Path | .cs files |
Role |
|---|---|---|---|
| NKO.Main | NKO. |
149 | The deployable web application — controllers, business logic, views, static assets |
| NKO.Shared | NKO. |
131 | Cross-cutting library: identity controllers, shared BAL, the permission engine, helpers, shared views |
| NKO.DataAccess | NKO. |
183 | Core EF model — 140 entities, NKO_DBEntities1, 18 migrations |
| NKO.Warehouse.DataAccess | NKO. |
33 | Warehouse EF model — 21 entities, Warehouse, 5 migrations |
| NKO.Helpers | NKO. |
1 | A single custom validation attribute |
NKO.Main — the web application¶
NKO.Main/NKO.Main/
├── Controllers/ 29 core controllers (+ inner view-model classes)
├── WarehouseControllers/ 10 warehouse controllers
├── BAL/ 32 business-logic classes — the core rules
├── WareBAL/ 8 warehouse business-logic classes
├── ViewModels/ view models grouped by feature
├── Views/ Razor views, one folder per controller
├── Helpers/ OperationConstants and app-specific helpers
├── Infrastructure/ IHostedService jobs + AddScheduledJobsExtention
├── ScheduledTasks/ Quartz IJob implementations
├── Resources/ .resx localisation (en / ar / tr)
├── wwwroot/ css, js, images, Rotativa binaries
├── Program.cs host builder + Quartz registration
└── Startup.cs DI container and middleware pipeline
Where the rules live. BAL/ and WareBAL/ hold everything that matters. The largest classes
are BAsset (4 206 lines), BStock (4 024), BRFQ (3 844), BLeave (2 704) and BJobs (2 690).
Controllers are thin by comparison — they resolve the user, call a BAL method and pick a view.
Warehouse code is separated by folder, not by project. WarehouseControllers/ and WareBAL/
live inside NKO.Main but talk to a different database. There is no compile-time boundary stopping
core code from touching warehouse code or vice versa.
NKO.Shared — the cross-cutting library¶
NKO.Lib/NKO.Shared/
├── Controllers/ AccountController, CommonController, FilesController,
│ CultureController, and the sidebar/topbar view components
├── BAL/ 7 shared business classes (BSign, Bsettings, BCalendar,
│ SharedBAL, AttenadancesHandler, BArchiveFile,
│ Permissionchecker)
├── Helpers/ Sec/ (ClaimRequirementFilter, PermissionsHandler,
│ HasPermission, BCryptPasswordHasher), NextUserHelper,
│ EmailManager, ExportHelper, CommonConstants,
│ BNotification, and **BUser** (1 909 ln — the largest
│ shared class, and not under BAL/ despite its name)
├── Configs/ BaseAppSettings, StorageConfigs, SiteSettings
├── Contracts/ IAttendancesHandler, DayTypeSummary, MissingAttendance
│ (IS3ServiceHandler and CurrentRequestData are in Helpers/Contracts/)
├── Models/ ApplicationUser and identity models
├── ViewModels/ shared view models, including the status enums
├── Attributes/ custom MVC attributes
├── Hangfire/ despite the name: the SignalR hub (RealTime), RealTimeNotifier and
│ CustomUserIdProvider — Hangfire itself is set up in Startup (R8-2)
└── Views/ shared Razor views, served as embedded resources
This project is why authentication and permissions are available to both the core and the warehouse
side: both reference it, and its views are embedded in the assembly and surfaced through
EmbeddedFileProvider.
A trap to remember
NKO.Shared/ViewModels/Training/TrainingStatus.cs does not only hold training statuses — it
defines seven status enums, including LeaveStatus, AdvanceStatus, OvertimeStatus and
UpgradeStatus. See R7-15 in Recommendations.
The two data-access projects¶
NKO.Lib/NKO.DataAccess/ NKO.Lib/NKO.Warehouse.DataAccess/
├── DbModel/ 140 entities ├── DbModel/ 15 entities
│ └── (+ NKO_DBEntities1.cs) │ └── Assets/ 6 more entities
└── Migrations/ 18 migrations │ └── (+ WarehouseDBContext.cs)
└── Migrations/ 5 migrations
Counting migrations
Migrations/ holds 37 files for the core model, but that is 18 migrations × 2 files
(<name>.cs + <name>.Designer.cs) plus one NKO_DBEntities1ModelSnapshot.cs. The real count
is 18, spanning 20241002070209_snapshot to 20260730200327_finSODRemoved. The warehouse
folder likewise holds 11 files for 5 migrations. Entity counts are DbSet<> properties on
each context: 140 core, 21 warehouse.
Two independent models with no cross-database foreign keys. The warehouse DbModel/Assets/
sub-folder is easy to miss — it holds Asset, AssetDetail, AssetPendingAmount, AssetsReturn,
Computer and GRNReport, which is why the entity count is 21, not 15.
Repository layout¶
E:\NKO_Project-main\
├── NKO.Main/ the web app + NKO.Helpers + the .sln
├── NKO.Lib/ the three libraries
├── docs/ this documentation site
├── mkdocs.yml site configuration
├── requirements-docs.txt
└── .gitignore
site/ (generated MkDocs output) and any local duplicate of the solution are excluded from version
control.
Conventions¶
| Pattern | Convention |
|---|---|
| Business class | B< (BPayroll, BLeave) or < (Allocation) |
| Workflow method | Set< — Set, Set |
| Visibility query | Get applies data scoping; Get does not |
| Permission key | < — Purchase, Stock |
| Constants | core in NKO., warehouse in NKO. |
Two source files are named with a trailing space before .cs (AdvanceController .cs,
TrainingController .cs) — R7-14.