Source Code — Solution Structure¶
Where every kind of file lives, how the five projects reference each other, and the two layout traps that cost the most time: namespaces do not follow folders, and two folder names describe something other than their contents.
Read alongside Architecture — Project Structure, which covers the same projects from a design angle rather than a navigation one.
The five projects¶
Solution file: NKO.Main/ERP-System.sln. Startup project: NKO.Main/NKO.Main.
| Project | Path | .cs |
Output |
|---|---|---|---|
| NKO.Main | NKO. |
149 | The deployable web application |
| NKO.Shared | NKO. |
131 | Class library — identity, permissions, shared BAL, embedded views |
| NKO.DataAccess | NKO. |
183 | Class library — core EF model (140 entities, 18 migrations) |
| NKO.Warehouse.DataAccess | NKO. |
33 | Class library — warehouse EF model (21 entities, 5 migrations) |
| NKO.Helpers | NKO. |
1 | Class library — one validation attribute |
Reference graph¶
flowchart TD
MAIN["NKO.Main<br/>web application"]
SHARED["NKO.Shared"]
DATA["NKO.DataAccess"]
WARE["NKO.Warehouse.DataAccess"]
HELP["NKO.Helpers"]
MAIN --> DATA
MAIN --> SHARED
MAIN --> WARE
SHARED --> DATA
SHARED --> WARE
DATA --> HELP
Read from NKO.Main.csproj and the four library .csproj files. NKO.Warehouse.DataAccess and
NKO.Helpers are leaves — neither references anything.
The folder layout contradicts the dependency direction
NKO.Helpers is the lowest-level library in the graph — NKO.DataAccess depends on it —
yet it sits physically under NKO.Main/, next to the web application, while the three
libraries it sits below live under NKO.Lib/. Nothing breaks; it just means the folder tree is
not a reliable guide to layering.
Build settings¶
All five projects target net6.0. Two settings are enabled in exactly one project:
| Setting | NKO.Helpers | The other four |
|---|---|---|
< |
enable |
(not set — disabled) |
< |
enable |
(not set — disabled) |
So the one-file project has modern C# defaults and the 496-file rest of the solution does not. A
file moved between them changes meaning: nullable reference warnings appear or vanish, and
using System; becomes required. Tracked as R8-5.
NKO.Main — the web application¶
NKO.Main/NKO.Main/
├── Controllers/ 29 files · core controllers
├── WarehouseControllers/ 10 files · warehouse controllers
├── BAL/ 32 files · core business logic ← the rules live here
├── WareBAL/ 8 files · warehouse business logic
├── ViewModels/ 61 files · grouped by feature
├── Views/ 488 .cshtml · one folder per controller
├── Helpers/ 1 file · OperationConstants.cs
├── Infrastructure/ 3 files · IHostedService jobs + the DI extension
├── ScheduledTasks/ 2 files · 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
Warehouse code is separated by folder, not by project. WarehouseControllers/ and WareBAL/
sit inside NKO.Main but talk to a different database through a different DbContext. Nothing at
compile time stops core code calling warehouse code or the reverse — the boundary is a convention.
NKO.Shared — the cross-cutting library¶
NKO.Lib/NKO.Shared/
├── Controllers/ Account, Common, Files, Culture + the two ViewComponents
├── BAL/ 7 files · BSign, Bsettings, BCalendar, SharedBAL,
│ AttenadancesHandler, BArchiveFile, Permissionchecker
├── Helpers/ BUser.cs (1 909 ln), CommonConstants.cs (826),
│ │ Enums.cs (972), ExportHelper.cs (1 111),
│ │ NextUserHelper.cs (668), Utils.cs (433), EmailManager.cs,
│ │ BNotification.cs, Security.cs, SiteSettings.cs
│ ├── Sec/ ClaimRequirementFilter, PermissionsHandler, HasPermission,
│ │ BCryptPasswordHasher, ApplicationUserManager, ClaimsProvider
│ ├── Contracts/ CurrentRequestData, IS3ServiceHandler, IStorageHandler, …
│ ├── Leave/ LeaveSetting, LeaveTypeCodes
│ └── Evaluation/ EvaluationStatus
├── Configs/ BaseAppSettings, StorageConfigs, S3ServiceHandler,
│ AttendanceConfigs, ScheduledJobsSettings
├── Models/ 12 files · ApplicationUser and identity models
├── ViewModels/ incl. Training/TrainingStatus.cs — see the trap below
├── Attributes/ 1 custom MVC attribute
├── Hangfire/ ← contains SignalR, not Hangfire (see below)
└── Views/ 29 .cshtml, 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.
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)
(37 files: 18 × 2 + snapshot) └── Migrations/ 5 migrations
Entity counts are DbSet<> properties on each context. The warehouse DbModel/Assets/ sub-folder
is easy to miss — it holds Asset, AssetDetail, AssetPendingAmount, AssetsReturn, Computer
and GRNReport, which is why the warehouse total is 21, not 15.
Counting migrations
Migrations/ holds 37 files for the core model, but that is 18 migrations × 2 files
(<name>.cs + <name>.Designer.cs) plus one ModelSnapshot. The migration count is 18.
Namespaces do not follow folders¶
This is the single most disorienting thing about the codebase. A file's folder tells you almost nothing about its namespace, and the same folder can hold several unrelated ones.
| File | Folder suggests | Actual namespace |
|---|---|---|
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
NKO. |
Note Configs/ in particular: BaseAppSettings.cs and S3ServiceHandler.cs are in the same
folder under two different namespaces. There are also two namespaces named Logic and Web
that have no corresponding folder anywhere — and one file, Controllers/AttendancesController.cs,
still declares namespace IYD.Controllers, from a different product entirely.
The practical consequences: a class cannot be located from its using statement, "go to folder"
and "go to namespace" give different answers, and adding a file to a folder does not tell you which
namespace to declare — you must copy a neighbour, and neighbours disagree. Tracked as R8-1.
Namespace spread¶
The same kind of code is split across unrelated namespace roots:
| Kind | Namespaces used |
|---|---|
| Controllers | NKO. (24), NKO. (10), NKO. (5), NKO. (5), IYD. (1) |
| Business logic | NKO. (23), NKO. (14), NKO. (8), NKO. (1), NKO. (1) |
| Entities | NKO. (142), NKO. (19), NKO. (3), NKO. (2) |
Folder names that lie¶
Two folders contain something other than what they are named. Both are easy to lose an hour to.
| Path | Name implies | Actually contains |
|---|---|---|
NKO. |
Hangfire configuration | SignalR. Real defines the Real and Real; Custom implements SignalR's IUser. No Hangfire code is in this folder — Hangfire is configured inline in Startup.. Tracked as R8-2. |
NKO. |
Training statuses | Seven enums for different modules — Training, Advance, Overtime, Leave, Upgrade, Planned, Training. Tracked as R7-15. |
To this add the two files whose names carry a trailing space before .cs —
AdvanceController .cs and TrainingController .cs (R7-14). They compile, but they break
path-matching scripts and some tooling.
Where to start reading¶
| If you are changing… | Start at |
|---|---|
| A screen's layout | Views/ |
| What a screen shows | the action in Controllers/, then the B* call it makes |
| A business rule | BAL/ — almost always one class |
| An approval step | Next + the Set…Accepted / Set…Refused methods on that B* class |
| A permission | the [Claim attribute, then App rows in the database |
| A constant or status | NKO. (58 static classes) or Enums. (59 enums) |
| Anything warehouse | Ware + Warehouse, against Warehouse |
Related¶
- Core Classes · Services & DI · Coding Conventions
- Architecture — Project Structure · Technology Stack
- Database — the entity model these projects wrap.