Files
ERP-core/Backend/PROGRESS.md
T

79 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backend — PROGRESS (Phase 1: Inventory & Supply Chain)
Legend: `[ ]` not started · `[~]` in progress · `[x]` done
Spec: `docs/10-BACKEND-PHASE1.md` (model + rules) · `docs/11-BACKEND-PHASE1.md` (API)
Convention: `docs/01-DOC-GUIDE.md §6`. Update this file in the **same commit** as the code. When ticking `[x]`, append a short note + any deviation.
## 0. Bootstrap
- [x] Solution + Web API project (`net10.0`), packages restored (00-CORE §5.4)
- [x] Folder structure per 00-CORE §5.3
- [x] `ErpDbContext` + Npgsql wired; `InitialCreate` migration **created and applied** (2026-07-10, 8 master-data tables). `/health``Healthy`.
- [x] Serilog, JWT, Swagger, HealthChecks, ProblemDetails in `Program.cs` (JWT bearer *validated*; endpoints not yet `[Authorize]`-gated — see §6 auth note)
- [x] `IUnitOfWork` + `UnitOfWork` (transaction boundary)
- [x] Generic repository base + interfaces
- [x] `ICurrentUser` (audit stamp from token `sub`)
- [x] ProblemDetails middleware + domain exception → `code` mapping (System/Errors; full §7 catalog added to `ErrorCodes`)
## 1. Master Data
> Code complete for all items below (2026-07-09). **Live smoke test PASSED against Postgres (2026-07-10):** create/get/list/update/status/reorder/uom-conversions across all 5 controllers; ETag round-trip 200 / stale→412 / missing→428; SKU_DUPLICATE→400; bad reference→422; missing-field→400 ValidationProblemDetails; category `?tree=true` nesting; `pageSize=9999` clamped to 200; deactivate via PATCH status→204. Still `[~]` (not `[x]`) for **one** reason: the **security gate** (00-CORE §8) — the foundational auth control (02-SECURITY B.1) and the audit trail (B.3, the AR-01 compensating control) land in §6. Flip to `[x]` once §6 auth+audit are wired.
- [x] Item: entity + config + enums (ItemType, TrackingMode; EntityStatus added) — `xmin`/RowVersion concurrency token (Npgsql), unique SKU
- [~] Item: repository (generic) + service + controller (CRUD, narrow DTOs, ETag/If-Match→412, SKU_DUPLICATE, reference validation) — server-controlled fields excluded (02-SECURITY C.1)
- [~] UOM + UOM conversions (`GET/POST /uoms`, `PUT /items/{id}/uom-conversions` full-replace upsert)
- [~] Category (hierarchy, `GET /categories?tree=true` nested build, parent-exists validation)
- [~] Vendor (CRUD, ETag/If-Match, unique code, deactivate via `PATCH /vendors/{id}/status`)
- [~] Warehouse + Bin (`/warehouses`, nested `/warehouses/{id}/bins`, bin code unique per warehouse)
- [~] Item reorder settings (`PUT /items/{id}/reorder` full-replace upsert, warehouse-exists validation)
## 2. Procurement
- [ ] Requisition (+ lines) + submit
- [ ] RFQ + quotations + comparison
- [ ] Purchase Order: create (auto-approve, `approvalRequired` flag), edit-while-open, approve (no-op), cancel
- [ ] Purchase Return (outbound movement, reason code)
## 3. Goods Receipt
- [ ] GRN create (against PO / direct), over-receipt tolerance
- [ ] GRN confirm → FIFO layer + ledger + PO `qtyReceived` (single UoW txn, Idempotency-Key)
- [ ] Inspection hold release / reject
## 4. Stock Core
- [ ] StockLayer + StockLedger entities/config (ledger append-only)
- [ ] `FifoCostingService` (consume oldest-first with row lock; valuation)
- [ ] Stock enquiry (onHand / available / onHold / inTransit)
- [ ] Ledger query · Valuation query
## 5. Stock Transactions
- [ ] Transfer: create → dispatch (consume, In-Transit) → receive (dest layer, cost-preserving)
- [ ] Adjustment (auto-post, mandatory reason code)
- [ ] Count (cycle/full → enter counts → variance → post)
- [ ] Reorder alerts (query) + suggest requisition
## 6. Cross-cutting
> **Auth-enforcement gap (open):** JWT bearer *validation* is wired, but no token issuer exists yet and controllers are **not** `[Authorize]`-gated, so §1 endpoints are currently open. This is the AR-01/NFR-03 control surface — gate all v1 endpoints (fallback authorization policy) in the same change as `POST /auth/login`, then re-run the 02-SECURITY B.1 checklist and flip §1 items to `[x]`.
- [ ] Audit log on every mutation (who/when/old→new)
- [ ] Document numbering sequences (per type, per year)
- [ ] Auth: simple in-app login → JWT (`POST /auth/login`)
- [ ] JournalEntryStub emitted per stock movement (data only)
- [ ] Negative-stock policy enforcement (default block)
- [ ] FEFO picking for perishables; block expired / on-hold issue
## Deferred (Phase 2+ — do NOT build now, hooks only)
- [ ] Vendor invoice + three-way match
- [ ] Reservation/allocation fulfilment
- [ ] RBAC policy enforcement + approval workflow activation
## Done
<!-- move [x] items here with date + note if the active list grows long -->
### 2026-07-09 — Bootstrap verified + Master Data (§1) implemented
- Bootstrap scaffolding confirmed against 00-CORE §5 (solution, packages, `Program.cs` wiring, UoW, generic repo, `ICurrentUser`, ProblemDetails handler). Added enum-as-string JSON (`JsonStringEnumConverter`) and registered the 5 master-data services.
- Domain: 3 enums (`ItemType`, `TrackingMode`, `EntityStatus`) + 8 entities (Category, Uom, UomConversion, Item, ItemReorder, Vendor, Warehouse, Bin) with one `IEntityTypeConfiguration` each; FKs `Restrict` (masters deactivate, not cascade-delete), unique indexes (SKU, vendor/warehouse code, uom name, bin code per-warehouse), decimal precision, `xmin` concurrency token on Item/Vendor.
- API: 5 controllers, lowercase routes matching `docs/11 §2` exactly (verified via generated `swagger.json`). ETag/If-Match (428 if missing, 412 on mismatch), narrow request DTOs (no over-posting), `PagedResponse<T>` list envelope (§1.4), `PageQuery` with pageSize clamp ≤200 (B.6).
- Migration `InitialCreate` generated (`xmin` correctly produces no DDL — uses the PG system column).
- **Verified:** `dotnet build` clean (0 warn/0 err); app boots (`Now listening… Application started`); `/api/meta` 200; `swagger.json` 200 with all 13 master-data paths; DI resolves controller→service→repo→DbContext (a DB-backed call reaches Npgsql, failing only on creds).
- **Blocked / follow-ups:** (1) auth enforcement + audit trail — §6 (the remaining security gate for `[x]`); (2) no `DELETE` master endpoints — `MASTER_IN_USE` code reserved until transaction tables exist (deactivate-only per FR-MD-08); (3) minor: bad-enum bind error leaks the CLR type name in `detail` (02-SECURITY B.5) — fine in Dev, tidy before prod.
### 2026-07-10 — Migration applied + live smoke test PASSED
- `dotnet ef database update` applied `InitialCreate` to local Postgres; `/health``Healthy`.
- End-to-end curl smoke across all 5 controllers — all green: warehouse/bin create+list; uom create; category + child + `?tree=true` nesting; vendor create + PUT (If-Match 200 / stale 412 / missing 428); item create (201, referencing category/uom/vendor) + GET (ETag header) + list/filter `q` + `pageSize=9999`→clamped 200; reorder PUT; uom-conversions PUT; full item PUT with fresh ETag→200; PATCH status Inactive→204; duplicate SKU→400 `SKU_DUPLICATE`; bad reference→422; missing required→400 ValidationProblemDetails; bad enum→400. Concurrency token (`xmin`) confirmed incrementing per mutation.
- Note: local dev DB now holds smoke-test rows (warehouse/bin/uom×2/category×2/vendor/item, item left Inactive). Reset any time with `dotnet ef database drop -f && dotnet ef database update`.