377 lines
17 KiB
Markdown
377 lines
17 KiB
Markdown
# 00 · CORE — ERP System (Phase 1: Inventory & Supply Chain)
|
|
|
|
> **This file is the hub. Start every task here.**
|
|
> It defines the repository structure, the tech stack, how to stand up a runnable backend, and — most importantly — **where to go next** for any piece of work. Do not begin backend or frontend work without first reading the relevant section below and following the routing table in §7.
|
|
|
|
---
|
|
|
|
## 1. What this project is
|
|
|
|
A modular ERP built in phases. **Phase 1** delivers the **Inventory & Supply Chain** subsystem: master data, procurement, goods receipt, and stock management (FIFO costing, multi-warehouse, single-tenant).
|
|
|
|
| Decision | Value |
|
|
|---|---|
|
|
| Costing method | **FIFO** (cost-layer tracking, per item per warehouse) |
|
|
| Warehouses | **Multi-warehouse** |
|
|
| Tenancy | **Single-tenant** |
|
|
| Approvals (PO, adjustment) | **Auto-approve**, config-gated off (RBAC deferred) |
|
|
| Access control | Authentication only; **RBAC deferred**, user identity stamped for audit |
|
|
| Vendor invoice / 3-way match | **Deferred** to Accounting phase (GRN retains hooks) |
|
|
|
|
Full requirements live in the backend spec (see §7). This file does **not** duplicate them.
|
|
|
|
**Phase 2 (HRM)** is now underway alongside Phase 1 — see §7 routing to `12-BACKEND-HRM.md` / `13-BACKEND-HRM-API.md` / `21-FRONTEND-HRM.md`.
|
|
|
|
---
|
|
|
|
## 2. Repository structure
|
|
|
|
```
|
|
erp-monorepo/
|
|
├── README.md # Root: what this is + how to run both sides
|
|
├── .gitignore # ignore appsettings.*.json secrets, .env*, bin/, obj/, node_modules/
|
|
│
|
|
├── Backend/ # ASP.NET Core Web API (.NET 10) — see §5 to initialize
|
|
│ ├── ERPCore.sln
|
|
│ ├── PROGRESS.md # ← backend change checklist (Claude-maintained, git-shared)
|
|
│ └── ERPCore/ # single Web API project (folders, not multi-project)
|
|
│
|
|
├── Frontend/ # Next.js (App Router + TypeScript) — already initialized
|
|
│ └── PROGRESS.md # ← frontend change checklist (Claude-maintained, git-shared)
|
|
│
|
|
└── docs/ # ALL documentation
|
|
├── 00-CORE.md # ← you are here (hub)
|
|
├── 01-DOC-GUIDE.md # documentation map + tracking conventions
|
|
├── 02-SECURITY.md # accepted-risks register + per-feature security checklist
|
|
├── 10-BACKEND-PHASE1.md # backend spec: SRS + ER/entities + tech + architecture
|
|
├── 11-BACKEND-PHASE1.md # backend API reference (complete req/res)
|
|
└── 20-FRONTEND.md # frontend user-flows + architecture rules + validation posture
|
|
```
|
|
|
|
The `Backend/ERPCore/` internal layout is created in §5.3.
|
|
|
|
---
|
|
|
|
## 3. Tech stack
|
|
|
|
### Backend
|
|
| Concern | Choice |
|
|
|---|---|
|
|
| Runtime | **.NET 10** (`net10.0`) |
|
|
| Framework | ASP.NET Core Web API (controllers) |
|
|
| ORM | EF Core 10 |
|
|
| Database | **PostgreSQL** (Npgsql provider) |
|
|
| Auth | JWT bearer (simple in-app login; RBAC deferred) |
|
|
| Logging | Serilog (file sink) |
|
|
| API docs | Swashbuckle / Swagger UI |
|
|
| Health | HealthChecks + EF Core DB check → `GET /health` |
|
|
|
|
### Frontend
|
|
| Concern | Choice |
|
|
|---|---|
|
|
| Framework | **Next.js** (App Router) + TypeScript |
|
|
| State/forms | **Plain React hooks** (`useState` / custom hooks) |
|
|
| Validation | **Dependency-free** (hand-rolled) — client-side for UX only; **server is authoritative** |
|
|
| API access | Typed fetch client against the backend (`NEXT_PUBLIC_API_BASE_URL`) |
|
|
|
|
> The Frontend project is **already initialized**. Do not scaffold it here. For all frontend architecture, flows, and validation rules, go to `20-FRONTEND.md`.
|
|
|
|
### Database
|
|
PostgreSQL, running on **localhost** for development. Secrets management (User Secrets / environment variables) is deferred; see §5.4 for the current local configuration and the note on secrets.
|
|
|
|
---
|
|
|
|
## 4. Architecture (high-level, both sides)
|
|
|
|
### Backend layering — strict, one direction
|
|
```
|
|
Controller → Service → Repository → UnitOfWork/DbContext
|
|
(DTOs) (logic) (entities) (transaction boundary)
|
|
```
|
|
|
|
Rules (non-negotiable for Phase 1):
|
|
- **DTOs at the controller boundary.** Controllers accept and return DTOs only — **never** EF entities and **never** `DbContext`.
|
|
- **Services hold business logic** and return DTOs. Controllers stay thin (HTTP concerns only).
|
|
- **Repositories own EF entities** and data access. No business rules in repositories.
|
|
- **UnitOfWork is the transaction boundary.** Every stock-affecting operation (GRN confirm, transfer dispatch/receive, adjustment, return, count post) runs inside a single UoW transaction.
|
|
- **FIFO lives in a domain service** (`FifoCostingService`), invoked by stock services inside the UoW transaction — **not** in a controller or repository. Layer consumption must lock affected rows for concurrency safety.
|
|
- **Errors use RFC 7807 `ProblemDetails`** (ASP.NET Core default). Domain errors carry a stable `code`. The error catalog is in `11-BACKEND-PHASE1.md`.
|
|
- **Audit actor** is derived from the authenticated principal (token `sub`), never from the request body.
|
|
|
|
### Frontend (summary — full rules in `20-FRONTEND.md`)
|
|
- Stick to the existing initialized architecture; do not restructure.
|
|
- **Validate on the client for UX, but never trust it.** The server re-validates everything. Business rules that depend on server state (stock availability, negative-stock block, over-receipt tolerance, FIFO sufficiency) are **server-authoritative** and must not be assumed valid client-side.
|
|
|
|
---
|
|
|
|
## 5. Backend initialization (runnable)
|
|
|
|
Follow in order. Commands assume repo root `erp-monorepo/`.
|
|
|
|
### 5.1 Prerequisites
|
|
- **.NET 10 SDK** (`dotnet --version` → `10.0.x`)
|
|
- **PostgreSQL** running on localhost, and a login you can use
|
|
- **EF Core CLI**: `dotnet tool install --global dotnet-ef` (or `dotnet tool update --global dotnet-ef`)
|
|
- Node.js (for the Frontend, handled separately)
|
|
|
|
### 5.2 Create solution and project
|
|
```bash
|
|
mkdir -p Backend && cd Backend
|
|
dotnet new sln -n ERPCore
|
|
dotnet new webapi -n ERPCore --use-controllers -f net10.0
|
|
dotnet sln add ERPCore/ERPCore.csproj
|
|
cd ERPCore
|
|
```
|
|
|
|
### 5.3 Create the internal folder structure
|
|
```bash
|
|
# from Backend/ERPCore/
|
|
mkdir -p Controllers Services/Interfaces Services/Stock \
|
|
Repositories/Interfaces \
|
|
Domain/Entities Domain/Enums \
|
|
Dtos/Common \
|
|
Common/Models \
|
|
Infra/UoW Infra/Persistence/Configurations Infra/Persistence/Migrations Infra/Auth Infra/Logging \
|
|
System/Errors \
|
|
HealthChecks
|
|
```
|
|
Target internal layout:
|
|
```
|
|
ERPCore/
|
|
├── ERPCore.csproj
|
|
├── Program.cs
|
|
├── appsettings.json # base (no real secrets)
|
|
├── appsettings.Development.json # local dev (localhost Postgres)
|
|
├── appsettings.Production.json # env-var driven
|
|
├── Controllers/ # HTTP; DTOs in/out
|
|
├── Services/ # business logic → DTOs
|
|
│ ├── Interfaces/
|
|
│ └── Stock/ (StockService, FifoCostingService)
|
|
├── Repositories/ # EF data access (entities)
|
|
│ └── Interfaces/
|
|
├── Domain/
|
|
│ ├── Entities/ # 38 EF entities
|
|
│ └── Enums/ # ItemType, TrackingMode, HoldStatus, Direction, *Status
|
|
├── Dtos/ # request/response DTOs (+ Common: paging)
|
|
├── Common/Models/ # PagedResult<T>, PaginationMeta, Result<T>
|
|
├── Infra/
|
|
│ ├── UoW/ # IUnitOfWork, UnitOfWork
|
|
│ ├── Persistence/ # ErpDbContext, Configurations/, Migrations/
|
|
│ ├── Auth/ # JWT setup, ICurrentUser (audit source)
|
|
│ └── Logging/ # Serilog config
|
|
├── System/Errors/ # domain exceptions, error codes, ProblemDetails middleware
|
|
└── HealthChecks/ # EF Core DB health check
|
|
```
|
|
|
|
### 5.4 Add packages
|
|
Pinned versions below are current for .NET 10 at time of writing. All `Microsoft.EntityFrameworkCore.*` packages **must share the same version**.
|
|
|
|
```bash
|
|
# from Backend/ERPCore/
|
|
dotnet add package Microsoft.EntityFrameworkCore --version 10.0.9
|
|
dotnet add package Microsoft.EntityFrameworkCore.Design --version 10.0.9
|
|
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 10.0.9
|
|
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 10.0.2
|
|
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 10.0.9
|
|
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore --version 10.0.9
|
|
dotnet add package Serilog.AspNetCore --version 9.0.0
|
|
dotnet add package Serilog.Sinks.File --version 6.0.0
|
|
dotnet add package Swashbuckle.AspNetCore --version 10.2.3
|
|
```
|
|
|
|
Resulting `ERPCore.csproj`:
|
|
```xml
|
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
|
|
<PropertyGroup>
|
|
<TargetFramework>net10.0</TargetFramework>
|
|
<Nullable>enable</Nullable>
|
|
<ImplicitUsings>enable</ImplicitUsings>
|
|
</PropertyGroup>
|
|
|
|
<ItemGroup>
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" />
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
|
|
<PrivateAssets>all</PrivateAssets>
|
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
</PackageReference>
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.9">
|
|
<PrivateAssets>all</PrivateAssets>
|
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
</PackageReference>
|
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
|
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.9" />
|
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="10.0.9" />
|
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<Folder Include="Common\Models\" />
|
|
<Folder Include="Infra\UoW\" />
|
|
<Folder Include="System\Errors\" />
|
|
</ItemGroup>
|
|
|
|
</Project>
|
|
```
|
|
> **Swashbuckle v10 note:** v10 upgraded to `Microsoft.OpenApi` 2.x and emits **OpenAPI 3.1**. `Program.cs` uses `using Microsoft.OpenApi;` and `AddSwaggerGen(...)` / `UseSwagger()` / `UseSwaggerUI()`.
|
|
|
|
### 5.5 App settings (three files)
|
|
`appsettings.json` (base — no real secrets; placeholder only):
|
|
```json
|
|
{
|
|
"Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } },
|
|
"ConnectionStrings": {
|
|
"DefaultConnection": "Host=localhost;Port=5432;Database=ERPCore;Username=CHANGE_ME;Password=CHANGE_ME"
|
|
},
|
|
"Jwt": {
|
|
"Issuer": "ERPCore",
|
|
"Audience": "ERPCore.Clients",
|
|
"SigningKey": "CHANGE_ME_DEV_ONLY_32+_CHARS",
|
|
"AccessTokenMinutes": 120
|
|
},
|
|
"AllowedHosts": "*"
|
|
}
|
|
```
|
|
`appsettings.Development.json` (local dev — used by `dotnet run` in Development):
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"DefaultConnection": "Host=localhost;Port=5432;Database=ERPCore;Username=postgres;Password=postgres"
|
|
},
|
|
"Jwt": { "SigningKey": "dev-only-signing-key-please-change-me-0123456789" }
|
|
}
|
|
```
|
|
`appsettings.Production.json` (values injected from environment variables at deploy time):
|
|
```json
|
|
{
|
|
"ConnectionStrings": { "DefaultConnection": "" },
|
|
"Jwt": { "SigningKey": "" }
|
|
}
|
|
```
|
|
> **Secrets note (current phase):** we are on **localhost dev only**, so the Development file holds local credentials for convenience. Before any shared/staging/production use, move secrets to **User Secrets** (dev) and **environment variables** (prod), keep `appsettings.Development.json` / `appsettings.Production.json` out of git (see root `.gitignore`), and rotate any credential that was ever committed.
|
|
|
|
### 5.6 Minimal `Program.cs` wiring (outline)
|
|
```csharp
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.OpenApi;
|
|
using Serilog;
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
|
|
// Serilog (file sink)
|
|
builder.Host.UseSerilog((ctx, cfg) => cfg
|
|
.ReadFrom.Configuration(ctx.Configuration)
|
|
.WriteTo.File("logs/erpcore-.log", rollingInterval: RollingInterval.Day));
|
|
|
|
builder.Services.AddControllers();
|
|
|
|
// EF Core + PostgreSQL
|
|
builder.Services.AddDbContext<ErpDbContext>(o =>
|
|
o.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
|
|
|
// ProblemDetails (RFC 7807)
|
|
builder.Services.AddProblemDetails();
|
|
|
|
// JWT bearer auth (RBAC deferred; identity used for audit stamp)
|
|
builder.Services.AddAuthentication(/* JwtBearer options from config */);
|
|
builder.Services.AddAuthorization();
|
|
|
|
// Health checks (EF Core DB)
|
|
builder.Services.AddHealthChecks().AddDbContextCheck<ErpDbContext>();
|
|
|
|
// Swagger
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen(o => o.SwaggerDoc("v1", new() { Title = "ERPCore API", Version = "v1" }));
|
|
|
|
// DI: register UoW, repositories, services, ICurrentUser, FifoCostingService here
|
|
|
|
var app = builder.Build();
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
}
|
|
app.UseExceptionHandler(); // maps to ProblemDetails
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
app.MapControllers();
|
|
app.MapHealthChecks("/health");
|
|
app.Run();
|
|
```
|
|
|
|
### 5.7 Create the database and run
|
|
```bash
|
|
# ensure the ERPCore database exists in your local Postgres, then:
|
|
dotnet ef migrations add InitialCreate -o Infra/Persistence/Migrations
|
|
dotnet ef database update
|
|
dotnet run
|
|
```
|
|
**Verify:**
|
|
- Swagger UI at `https://localhost:<port>/swagger`
|
|
- Health at `https://localhost:<port>/health` → `Healthy`
|
|
|
|
Entity/DbContext modeling (the 42 entities, configurations, enums) is specified in `10-BACKEND-PHASE1.md`. Do not invent the schema here — follow that file.
|
|
|
|
---
|
|
|
|
## 6. Running the frontend
|
|
|
|
The Frontend is already initialized. Point it at the backend:
|
|
```bash
|
|
cd Frontend
|
|
cp .env.local.example .env.local # set NEXT_PUBLIC_API_BASE_URL=https://localhost:<port>
|
|
npm install
|
|
npm run dev
|
|
```
|
|
All frontend work is governed by `20-FRONTEND.md`.
|
|
|
|
---
|
|
|
|
## 7. Routing — where to go next
|
|
|
|
**Every task starts here, then jumps to the right doc.** Do not work from memory; open the target doc.
|
|
|
|
| If you are working on… | Go to |
|
|
|---|---|
|
|
| Requirements, business rules, entities, ER model, data types, architecture detail (Phase 1: Inventory & Supply Chain) | **`10-BACKEND-PHASE1.md`** |
|
|
| API endpoints, request/response shapes, error catalog, enums (Phase 1) | **`11-BACKEND-PHASE1.md`** |
|
|
| HRM requirements, business rules, entities, ER model (Phase 2) | **`12-BACKEND-HRM.md`** |
|
|
| HRM API endpoints, request/response shapes, error catalog (Phase 2) | **`13-BACKEND-HRM-API.md`** |
|
|
| Frontend user-flows, screen flow, architecture rules, validation posture (Phase 1) | **`20-FRONTEND.md`** |
|
|
| HRM frontend user-flows (Phase 2) | **`21-FRONTEND-HRM.md`** |
|
|
| Security risks per feature, accepted-risk register, pre-ship checklist | **`02-SECURITY.md`** |
|
|
| Understanding the doc system, reading order, tracking conventions | **`01-DOC-GUIDE.md`** |
|
|
| Recording backend changes made | **`Backend/PROGRESS.md`** |
|
|
| Recording frontend changes made | **`Frontend/PROGRESS.md`** |
|
|
|
|
Quick resolver:
|
|
- *"Where is the model / an entity defined?"* → `10-BACKEND-PHASE1.md` (Phase 1) / `12-BACKEND-HRM.md` (HRM) — schema is authoritative there.
|
|
- *"What does this endpoint accept/return?"* → `11-BACKEND-PHASE1.md` (Phase 1) / `13-BACKEND-HRM-API.md` (HRM).
|
|
- *"How should the UI flow / what do I validate where?"* → `20-FRONTEND.md` (Phase 1) / `21-FRONTEND-HRM.md` (HRM).
|
|
- *"What security risks / checks apply to this feature?"* → `02-SECURITY.md`.
|
|
|
|
---
|
|
|
|
## 8. Progress tracking (mandatory)
|
|
|
|
Two checklists track what has actually been built, and travel with code via git:
|
|
- **`Backend/PROGRESS.md`** — backend changes
|
|
- **`Frontend/PROGRESS.md`** — frontend changes
|
|
|
|
These are **Claude-maintained**: whenever a change is made on either side, the corresponding `PROGRESS.md` must be updated (tick items, add entries). The format and rules for these files are defined in **`01-DOC-GUIDE.md` §Tracking**. Both files must exist before feature work begins.
|
|
|
|
> **Security gate:** before ticking any data-mutating feature `[x]`, run its checklist in **`02-SECURITY.md`** (Part C) plus the foundational controls (Part B). Accepted Phase-1 exposures are recorded in `02-SECURITY.md` Part A — do not "fix" them ad-hoc.
|
|
|
|
---
|
|
|
|
## 9. Documentation maintenance rule
|
|
|
|
There is **one source of truth** per topic. The SRS and API content live **inside** the docs above (not in separate scattered files). When a requirement or endpoint changes, edit it **in place** in `10-`/`11-BACKEND-PHASE1.md` — do not fork copies. See `01-DOC-GUIDE.md` for the full maintenance and navigation rules.
|
|
|
|
---
|
|
|
|
*End of 00-CORE.md — the hub. Next: `01-DOC-GUIDE.md`.*
|