# BOM Advanced Authoring — Phased Roadmap

## Context

While fixing the BOM Tree view's 6 reported bugs (see git history around `AccountOutstandingKpiQB`-adjacent commits on the same date — actually: `MMDAL/Query/BOM/BOMQB.cs`, `MMDAL/DTO/BOM/BOMItemDetailDTO.cs`), a deeper gap surfaced: **gb5 has no BOM expansion/posting write path at all.** `MBOMDETAIL`'s existing multi-level rows on GB5DEMO were migrated/seeded from GB4-era data, not produced by any code in this repo. A live data defect (401 rows across 72 BOMs with `PARENTBOMLINEID` pointing into the wrong BOM) was corrected via `DB/Migrations/20260824_MBOMDETAIL_PARENTBOMLINEID_Correction_SqlServer.sql`, using `LEVELCODE` as the authoritative source — but that only fixes existing data. Nothing prevents the same drift on the next BOM save, because nothing in gb5 *does* a BOM save-triggered expansion yet.

This roadmap captures the follow-on work, phased so each piece ships independently and stays reviewable.

## Phase 1 — BOM expansion/posting write function (gb5, new)

**Goal:** a `PostBOM`/`ExpandBOM` BLL method that (re)materializes a BOM's full multi-level `MBOMDETAIL` tree whenever its authored (`BOMLEVEL=0`) rows change, replacing the currently-nonexistent write path.

**Reference implementation:** GB4's `BOMBLL.TaildetailsFinal`/`Taildetails`
(`/Users/venkatv/Downloads/GB4Solution/BLL/MMBLL/BOM/BOMBLL.cs`, ~line 2792) — recursively walks
each component item's own default sub-BOM, computes `LEVELCODE` correctly
(`LevelCode + '-' + sibling-number`), and rolls up `RequiredProductionQuantity`/`FinalQuantity`
proportionally through the chain. Use this for the recursion shape and quantity math — both are
sound.

**The one thing to NOT copy from GB4:** line 2818, `BOMDetailDTO.ParentBOMLineLineId =
BOMDetails[i].LineId;` — sets each new row's parent pointer to the line ID of the row it was
*copied from* (a different BOM's own detail row), never remapped to the newly-inserted row's real
parent within the current expansion. This is the exact defect the migration above corrected in
existing data, and it existed in GB4 too — GB4 only ever relied on `LEVELCODE` for hierarchy,
never `PARENTBOMLINEID`, which is why this went unnoticed there.

**Improvement to build in:** after inserting all rows for one expansion pass (in `LEVELCODE`
order, top-down), do a second pass — or a single `INSERT` followed by a same-transaction `UPDATE`
— that sets each row's `PARENTBOMLINEID` to the `BOMLINEID` of the sibling row in the *same*
`BOMID` whose `LEVELCODE` equals this row's `LEVELCODE` with its last `-NNN` segment stripped
(exactly the lookup used in the correction migration). That makes `PARENTBOMLINEID` a reliable
in-BOM pointer going forward, not just `LEVELCODE`.

**Re-expansion on edit:** delete-and-reinsert every `BOMLEVEL >= 1` row for a `BOMID` before each
re-expansion (matching GB4's own convention — see its `DELETE FROM MBOMDETAIL WHERE
PREVIOUSPARENTBOMLINEID IN (...)` cleanup). Only `BOMLEVEL = 0` rows (user-authored) are edited
directly; everything else is fully regenerated. This is also why Phase 2's draft-save matters —
regenerating a large tree on every keystroke-adjacent save is exactly the cost draft-save is
meant to avoid.

**Trigger points:** call the new posting function from `BOMBLL.SaveBOM` after the existing
cyclical-BOM guard (`BOMBLL.cs` ~line 114-123, already enforced — see Phase 3) passes, and expose
a standalone `POST /BOM/Post` (or similar) endpoint for an explicit "re-expand" action, matching
the "user should do a separate posting for the expansion" direction already given for the read
side.

## Phase 2 — Draft-save for large BOMs

**Goal:** editing a large, already-posted BOM shouldn't require a full remove-and-reinsert of
every detail row on every save.

**Reuse, don't rebuild:** a generic draft-save facility already exists —
`GB5Solution/Admin/AdminBLL/Draft/DraftBLL.cs` / `AdminDAL/CustomCode/Draft/DraftDAL.cs` /
`AdminSL/EndPoints/Draft/SaveDraft.cs` (`GetDraft`/`SaveDraft`/`GetSelectListDraft`/`DeleteDraft`
against a generic `DraftDTO`). Confirm its exact storage shape (JSON blob keyed by entity
type/id, most likely) and wire BOM's authoring screen through it: incremental edits save as a
draft (cheap, no re-expansion), and only committing the draft triggers Phase 1's full posting
pass. This avoids inventing a second draft mechanism.

## Phase 3 — Cyclical BOM prevention

**Status: already done.** `BOMBLL.SaveBOM` already calls `_BOMDAL.CheckCyclicalBom` (BOMBLL.cs
~line 114-123) and throws `InvalidOperationException` with a clear message identifying the
cyclical component and the BOM/line where it was found — explicitly noted in-code as an
improvement over GB4, which had no such guard. No further work needed here; Phase 1's new
expansion path should keep calling into the same guard before posting.

## Phase 4 — FE: flexible/configurable BOM authoring (simple → advanced)

**Goal:** one authoring experience that scales from a quick simple BOM to the full field set,
rather than two disconnected screens.

**Starting point, already partially built:** two existing gb4.7mfe components —
`projects/inventory/master/itemmenu/bom/` (full authoring, `formjson/bom.json` — 2062 lines,
every field) and `projects/inventory/master/itemmenu/assemblybom/` (`formjson/assemblybom.json` —
337 lines, a reduced field set). This is very likely the "new BOM screen design" already
referenced — confirm with design/product before assuming intent, but the two-tier split already
exists in code. Rather than maintaining two separate components long-term, evaluate collapsing
them into one component with a "Simple / Advanced" mode toggle driving which `formjson` sections
render (a pattern to check against how other GB5 screens already handle progressive-disclosure
forms, if any precedent exists) — or keep them separate if that's the deliberate design. Needs a
design decision, not just an engineering one.

## Phase 5 — C-BOM (order/configure-specific BOM)

**Goal:** a BOM variant tied to a specific sales order or design, not the standard reusable BOM.

**Schema groundwork already exists, wiring status unconfirmed:**
- `MBOM.BOMTYPE` (0=STANDARD, 1=DESIGN TO ORDER, 2=CONSUMABLE), `MBOM.LINKID`/`LINKTYPEID`
  ("in the case of Design to order, Link id reference to the design, order etc" — DDL comment).
- `MMHeadDTO.CBOMRequired` / `MMDocumentHeadDTO.CBOMRequired` — a flag on MM transaction
  documents indicating a C-BOM is required for that transaction.

Before building anything here: trace whether `BOMTYPE=1` and `CBOMRequired` are read/written by
*any* current gb5 BLL/DAL path (this roadmap's research did not go that deep) — if they're inert
scaffolding like `AccountReceivableDTO` was, this phase starts from schema-only, same as Phase 1.
Likely needs: a BOM save path that accepts `LinkId`/`LinkTypeId` (e.g. a `TSALESORDERDETAIL` row),
Phase 1's expansion function running scoped to that specific order context, and an MM document
save path that honors `CBOMRequired` by resolving/requiring the right C-BOM instead of the
item's standard default BOM.

## Suggested sequencing

Phase 1 blocks everything else (Phases 2, 4, and 5 all assume a real posting function exists).
Phase 3 is already done. Phase 4's design decision (merge vs. keep-separate) can happen in
parallel with Phase 1's engineering. Phase 5 needs its own scoping pass before estimating.
