At a Glance
Persona: Product Administrator · Module: product · Workflow stages: Create / edittb_product(active) · classification chain (category / sub-category / item-group) · units and conversions · location and vendor mappings · bulk import / export · deactivate / re-activate / soft-delete / restore · respond to inbound comments · Key permissions: full CRUD on master data (PRD_AUTH_001/PRD_AUTH_003/PRD_AUTH_004); SoD onstandard_costchange above tenant threshold (PRD_AUTH_012— Cost Controller / Finance second signature)
What this persona does: Owns the catalogue — creates / maintains products, classifications, units, mappings, and runs the product-record lifecycle.
The Product Administrator persona is the owner of the catalogue. Within the product module they hold full CRUD authority on every master-data surface: tb_product rows (create, edit, deactivate, soft-delete, restore), the classification chain (tb_product_category → tb_product_sub_category → tb_product_item_group), unit definitions (tb_unit), conversion factors (tb_unit_conversion for both order_unit and ingredient_unit scopes), per-location stock policy mappings (tb_product_location), and vendor mappings (tb_product_tb_vendor). They run bulk imports and exports for the products / categories / units / conversions surfaces, manage the product lifecycle (active ↔ inactive ↔ soft-deleted), and respond to inbound comments from Purchasers (stale catalogue feedback, new-product requests) and Store Keepers (barcode mismatches, handling-note updates). The Product Administrator does not approve transactional documents (PR / PO / GRN / SR), does not edit per-location stock-policy values for replenishment (tb_product_location.min_qty / max_qty / re_order_qty / par_qty is technically writeable by the Product Administrator but the policy authority lives with the Inventory Controller per inventory/02-business-rules INV_AUTH_004 — in practice the Product Administrator creates the tb_product_location row to enable a location for a product, and the Inventory Controller fine-tunes the policy values), and does not participate in period close or financial reconciliation. Segregation of duties (PRD_AUTH_012) restricts the Product Administrator from approving their own standard_cost changes above the tenant SoD threshold — Cost Controller / Finance is the second signature.
Entry points: Five primary paths into the Product Administrator's daily work — one for each major surface they own.
PRD_CALC_002 / PRD_CALC_003.Primary flow (create a single new product, 10 steps — illustrative of the full-CRUD pattern):
active. If not, create the category nodes first. Confirm the inventory base unit (tb_unit) exists and the order-unit / recipe-unit conversion factors will be definable. Confirm a tax profile is set on at least one level of the classification chain (per PRD_CALC_002 inheritance) — otherwise the product will inherit an effective tax rate of 0%.tb_product create mode with empty fields and inheritance previews disabled.code must be unique within (code, name, deleted_at) per PRD_VAL_001; the form's blur-time check warns of conflicts before submit. name is the English / primary display name; local_name is the localised display (Thai, etc.). Description is free-text.inventory_unit_id references an active tb_unit. This drives every downstream calculation (balances, costs, valuation) and is immutable once the product has inventory history per PRD_VAL_003, so the choice is consequential — the warning is surfaced on the form.tb_product_item_group. The form renders the resolved classification path ("Beverages / Hot / Coffee Beans") and shows the inherited tax profile and deviation tolerances per PRD_CALC_002 / PRD_CALC_003. The Product Administrator may override the inherited values at the product level by entering specific values on the product header.is_used_in_recipe and is_sold_directly default per the classification inheritance (PRD_CALC_004); override if the specific product diverges from category convention. barcode and sku are optional; if set, barcode uniqueness is enforced per PRD_VAL_005.standard_cost is the reference / standard cost in the base inventory unit (per PRD_VAL_007, must be ≥ 0). Used by the standard count-costing method and by recipe baselining. price_deviation_limit and qty_deviation_limit are bounded [0, 100] percentage tolerances (per PRD_VAL_006) and inherit from the classification chain if zero; override if needed. Above-threshold standard-cost values may route to Cost Controller for approval per PRD_AUTH_012 — the form indicates this with a notice.unit_type = order_unit, e.g. 1 CASE = 12 EACH) and each recipe-unit (unit_type = ingredient_unit, e.g. 1 TBSP = 15 ML) the product needs. Per PRD_VAL_010 each row has positive qty on both sides and distinct from/to units; per PRD_VAL_011 bidirectional consistency is validated across the set. The "default" flag (is_default) picks the conversion surfaced first on PR/PO/recipe pickers.tb_product_location): Per location, set min_qty / max_qty / re_order_qty / par_qty. Per PRD_VAL_012 constraints (max ≥ min, all ≥ 0). The Product Administrator creates the row to enable the product at the location; policy fine-tuning (the specific numeric values) is typically delegated to the Inventory Controller per PRD_AUTH_008. Zero values mean "not configured" and the location will not surface replenishment alerts for the product.tb_product_tb_vendor): Pick one or more vendors who supply the product; enter vendor_product_code and vendor_product_name for cross-reference on POs and pricelists. Per PRD_VAL_013 each (vendor_id, product_id) pair is unique. The mapping is what makes the product appear on vendor-pricelist pickers and PR / PO vendor-defaulting.PRD_VAL_*; passing rows write tb_product with product_status_type = active, is_active = true, plus the associated tb_unit_conversion, tb_product_location, tb_product_tb_vendor rows. Activity log records the create per PRD_LIFE_001. The product is immediately visible on every downstream picker (per PRD_AUTH_009); no notification is emitted (pickers read on demand).The bulk-import flow is the dominant create path for initial catalogue load (multi-property go-lives, large supplier feeds). The Product Administrator uploads an Excel / CSV with the same column shape, runs dry-run mode first to surface per-row validation errors, downloads the error report, fixes the source file, re-runs dry-run until clean, then runs strict-mode commit which inserts / updates rows in a single transaction (or partial-success mode, the default, where passing rows commit and failing rows are reported). Bulk import is subject to the same validation rules per row.
The classification-change flow (create or edit a category / sub-category / item-group) follows steps 2–10 but at the relevant tree level. The cascading-default impact is previewed before save: changing a category's tax_profile_id, for example, shows how many sub-categories / item-groups / products will inherit the new value. Per PRD_LIFE_010 the change is prospective — open documents that snapshotted the old tax-profile keep their snapshot.
The lifecycle-transition flow (activate, deactivate, soft-delete, restore) follows the state diagram in 03-user-flow.md Section 2. The dominant guard is in-use checks:
active → inactive) — soft-block if referenced by a published recipe (override with reason text). Hard-block if any open PR / PO / SR line references the product.active | inactive → soft-deleted) — hard-block if any document line references the product (including completed history), if any non-deleted recipe references it, or if current on-hand at any location is non-zero (derived per PRD_CALC_009). The product must be drained (inventory written off / consumed / transferred) before delete.soft-deleted → active) — rejected if the (code, name) has been re-used by a live product in the interim.tb_unit (e.g. PUNNET for a new produce SKU), create the unit first (Units → New) and then create the conversion factor to the base inventory unit. Avoid one-off units that won't be reused — convention is to keep tb_unit lean and reuse standard units (KG, LITRE, EACH, CASE, DOZEN, BOTTLE, BAG).tb_unit_conversion table; differentiate via enum_unit_type. Order-unit conversions are read by procurement / receiving / pricelist (PR / PO / GRN line qty → base unit translation); ingredient-unit conversions are read by recipe (recipe ingredient qty → base unit for theoretical consumption). The same physical conversion (1 CASE = 12 EACH) may exist as both an order_unit row and an ingredient_unit row if the same unit is used in both contexts — that's deliberate to keep the two namespaces independent.PRD_LIFE_005):
product_status_type = inactive — product removed from new-transaction pickers; still admin-visible; reversible via re-activation. Use this for "temporary out of use" (seasonal items off-menu, recall pending re-introduction).is_active = false — product hidden everywhere including admin views; reversible by re-setting the flag. Use this for "should be invisible to everyone" without yet soft-deleting (e.g. compliance hold).soft-delete (deleted_at set) — terminal in normal use; only Auditor sees soft-deleted rows. Use this when the product is truly retired and the (code, name) should become re-usable.PRD_AUTH_012, a standard_cost change exceeding the tenant SoD threshold (typically 10–20% movement, configurable) routes the update to Cost Controller / Finance review. Below threshold, the edit is immediate. The form surfaces the threshold and the routing decision before submit.product_item_group_id) updates the inherited defaults prospectively (PRD_LIFE_010). Open documents keep their snapshotted values. The Product Administrator reviews the impact preview before committing — for a product on many active documents this is rare and disruptive.PRD_LIFE_004).The Product Administrator's involvement on a given catalogue surface ends at one of these boundaries:
PRD_AUTH_012; the Product Administrator waits for the second signature. On approval, the change is final; on rejection, the original standard_cost is restored and the Administrator iterates.PRD_CALC_002); the Product Administrator's work is done at commit. Open documents that snapshotted the old values are not retroactively edited.deleted_at is set, the product is removed from all live views. The audit log retains the delete event; restore is possible but typically not used. The Product Administrator's involvement ends.created_by_id records the Administrator; the error report covers any failed rows. Iterative re-runs until the source file is clean; final commit ends the Administrator's involvement.tb_product_location to enable the product at a location; Inventory Controller takes over to set min / max / par / reorder policy per INV_AUTH_004. Pure mapping (location enabled or not) stays with Product Administrator; policy numbers go to Inventory Controller.tb_product shape (steps 3–7 of the primary flow), classification chain (tb_product_category / tb_product_sub_category / tb_product_item_group, step 5), tb_unit and tb_unit_conversion shape (steps 4 and 8), tb_product_location / tb_product_tb_vendor (step 9), and enum_product_status_type (lifecycle transitions).PRD_VAL_001–PRD_VAL_018) referenced in steps 3–10 of the primary flow; calculation / inheritance rules (PRD_CALC_001–PRD_CALC_010) referenced in step 1 (prerequisite check) and step 5 (classification inheritance); authorization rules (PRD_AUTH_001–PRD_AUTH_004, PRD_AUTH_012) gating the Product Administrator's authority; lifecycle rules (PRD_LIFE_001–PRD_LIFE_010) governing the state transitions Section 1 of this page describes; cross-module rules (PRD_XMOD_001–PRD_XMOD_012) defining how the catalogue connects to consumers.tb_product_location mapping enables the product at a location; replenishment-policy numbers belong to the Inventory Controller (INV_AUTH_004). On-hand qty is derived from the cost-layer ledger (PRD_CALC_009) and surfaced on the product detail view's location tab.tb_product.standard_cost is the reference-cost source; the FIFO / WA cost-pick method lives at tb_business_unit.calculation_method, not on the product (per product/01-data-model § 5 item 7). Standard-cost changes above SoD threshold route for Cost Controller / Finance approval (PRD_AUTH_012).tb_product_tb_vendor mapping makes the product appear on vendor pricelists; pricelist lines reference tb_product via product_id.PRD_LIFE_002 (soft-block, override available) and block soft-delete per PRD_LIFE_004 (hard-block, no override).