1. Purpose

A Code is an admin-defined, required classifier on an entity — distinct from optional Categorization. Codes drive integration with downstream systems (Workbench) and enforce tiered validation at export time. Unlike Categorizations (reporting-only, never affect behaviour), Codes are integration-linked and their enforcement hardens as the Estimate moves toward Cost Management export.

Two Codes are seeded and locked (via Workbench integration):

  • Workcentre — applied to Items, migrated from Benchmark’s activity (113 options)
  • Activity Code — applied to Resources, migrated from Benchmark’s cost_code (33 options)

Key difference from Categorization: Codes are required (soft in Estimate, hard at export); Categorizations are optional and never affect system behaviour.


2. Attributes

Code

AttributeTypeRequiredDefaultNotes
idUUIDgeneratedSystem-managed
namestringHuman-readable name (e.g., “Workcentre”, “Activity Code”)
scopeenum (multi-select)Entity types this Code applies to: Items or Resources. v1 locked scope—no Tenders or Estimates. Codes are line-level classifiers only; Categorization handles broader entities.
sync_sourcestring (nullable)nullExternal system identifier if synced (e.g., “workbench”, “xero”). Null = admin-defined. BR-128: Codes can be sourced from external systems
descriptionlong textnullExplainer for admins; e.g., “Aligns with Workbench workcentre dimension for integration”
lockedbooleanfalseTwo Codes locked by Oxcon via Workbench: Workcentre and Activity Code. Protects integration integrity; admins cannot edit these definitions, only sync updates. Custom Codes can be created (locked = false)
created_at / updated_attimestampsystemAudit
created_by / updated_byUser refsystemAudit

Code Option

AttributeTypeRequiredDefaultNotes
idUUIDgeneratedSystem-managed
valuestringThe code itself; e.g., “A-PG00”, “PL-EXCAVTE”
display_labelstringnullHuman-friendly label; e.g., “Management Staff” for value “A-PG00”. Falls back to value if null
code_idCode refParent Code (foreign key)
parent_option_idCode Option ref (nullable)nullFor hierarchical Codes (e.g., parent category → child subcategory). Initial Codes are flat; reserved for future hierarchies
external_idstring (nullable)nullIf synced from external system (BR-128), maps back to the external ID. E.g., Workbench workcentre ID
created_at / updated_attimestampsystemAudit
created_by / updated_byUser refsystemAudit

3. Relationships

Inbound (things referring to Code)

FromCardinalityNotes
Code OptionCodeOption M:1 CodeEvery Code Option belongs to exactly one Code

Outbound (things Code references)

ToCardinalityRequiredNotes
Code OptionCode 1:M CodeOptionA Code defines its allowed options (1 to many)

Code Option usage (applied to entities)

ToCardinalityRequiredNotes
ItemItem M:0..1 CodeOption (Workcentre)tiered (BR-127)Soft at Estimate (nullable); hard at Cost Mgmt export
ResourceResource M:0..1 CodeOption (Activity Code)tiered (BR-127)Soft at Estimate (nullable); hard at Cost Mgmt export
(future)Tender / EstimateM:0..1Extensible for additional Code scopes

4. Validation / Invariants

Rules that must hold at all times:

  1. Exactly one Code per scope. Within a given entity type (Items, Resources), at most one Code per entity. E.g., an Item has one Workcentre Code Option, not multiple.
  2. Code Option cardinality. A Code Option belongs to exactly one Code; no orphaned options.
  3. Scope validity. scope must be one of: Items or Resources. (v1 enforcement; no Tenders or Estimates).
  4. Locked Code edit protection. Codes with locked = true cannot have their definition or options edited by users (UI enforces). Only sync updates from external source allowed.
  5. Hierarchical consistency. If a Code Option has a parent_option_id, the parent must belong to the same Code.
  6. Required Code enforcement (BR-127).
    • Items with Workcentre scope: workcentre_option_id is soft-required in working Estimate; hard-required at Cost Mgmt export
    • Resources with Activity Code scope: activity_code_option_id is soft-required in working Estimate; hard-required at Cost Mgmt export
  7. External ID uniqueness. If external_id is populated (synced Codes), it should be unique within the Code’s sync source.

5. Derived / Computed Attributes

AttributeDerivationNotes
has_missing_assignmentsCount entities in scope with null Code Option refsUsed by Anomaly Review to flag incomplete Codes
is_externally_syncedsync_source is not nullRead-only UI state; affects editability

6. Worked Examples

Example 1 — Workcentre Code (Items), migrated from Benchmark

Context: Benchmark’s activity table (113 rows) migrates to oxFlow as the Workcentre Code, applied to Items. Shows how Items get tagged, and what happens when some Items are untagged.

Code:
  id: <UUID-workcentre>
  name: "Workcentre"
  scope: [Items]
  sync_source: "workbench"
  description: "Aligns with Workbench workcentre dimension for project cost tracking"
  locked: true
  created_by: <system>

Code Options (sample of 113):
  1. value: "A-PG00", display_label: "Management Staff", external_id: "wc_001"
  2. value: "A-PG01", display_label: "Site Supervision", external_id: "wc_002"
  3. value: "E-EX01", display_label: "Excavation & Earthworks", external_id: "wc_003"
  ...
  113. value: "Z-RISK", display_label: "Risk & Contingency", external_id: "wc_113"

Items applied (sample):
  Item A: "Concrete formwork"
    workcentre_option_id: <Option E-EX01 "Excavation & Earthworks">
  
  Item B: "Timber framing"
    workcentre_option_id: <Option A-PG00 "Management Staff">
  
  Item C: "Risk allowance"
    workcentre_option_id: null  // NOT YET ASSIGNED
    
Anomaly Review flags:
  ⚠️ Item C missing Workcentre Code — soft warning in Estimate view
  🔴 Cost Mgmt export BLOCKED until Item C assigned a Workcentre

Estimator action:
  1. In Anomaly Review, clicks Item C
  2. Selects "Z-RISK" (Risk & Contingency) from Workcentre dropdown
  3. Export now succeeds; Workbench receives all Items with assigned Workcentres

Example 2 — Activity Code (Resources), migrated from Benchmark; defaults post-migration

Context: Benchmark’s cost_code table (33 rows) migrates to oxFlow as the Activity Code Code, applied to Resources. Shows admin’s capability to assign defaults and edit options.

Code:
  id: <UUID-activitycode>
  name: "Activity Code"
  scope: [Resources]
  sync_source: "workbench"
  description: "Classifies resources by cost category for Workbench reporting"
  locked: true
  created_by: <system>

Code Options (sample of 33):
  1. value: "M-REININ", display_label: "Reinforcement (In)", external_id: "ac_001"
  2. value: "M-FORM", display_label: "Formwork Materials", external_id: "ac_002"
  3. value: "P-CRAN35", display_label: "Crane 35T (Plant)", external_id: "ac_003"
  4. value: "C-CARPENTRY", display_label: "Carpentry Labour", external_id: "ac_004"
  ...
  33. value: "S-FORM", display_label: "Formwork (Subcontract)", external_id: "ac_033"

Resources assigned (sample):
  Resource: "Carpenter — general (Auckland, incl. tools)"
    activity_code_option_id: <Option C-CARPENTRY "Carpentry Labour">
    [Post-migration default: admin mapped Benchmark cost_code PL-CARPEN → C-CARPENTRY]
  
  Resource: "Reinforcement steel — 500MPa coil"
    activity_code_option_id: <Option M-REININ "Reinforcement (In)">
  
  Resource: "Mobile crane 35T (dry hire)"
    activity_code_option_id: <Option P-CRAN35 "Crane 35T (Plant)">
  
  Resource: "Subcontracted formwork package"
    activity_code_option_id: <Option S-FORM "Formwork (Subcontract)">

Post-migration admin tasks:
  - Verify all Resources have Activity Code assigned
  - Edit `display_label` for clarity if Benchmark cost_code values were cryptic
  - Flag any Resources with null activity_code_option_id for estimator review (Anomaly Review lists them)
  - Set up Workbench sync to pull new Activity Code options if external system changes

7. Admin management

Who can edit Codes and options: Admins only (BR-085, roles-permissions.md).

Scenarios:

  1. Creating a custom Code (not Workbench-synced):

    • Admins only — Lead Estimators cannot create custom Codes
    • Admin defines name, scope (Items or Resources), description
    • Adds Code Options manually
    • locked = false (editable in future)
    • No sync_source
  2. Updating a locked Workbench-synced Code:

    • Per BR-128, sync is pull-only — Admin manually triggers a refresh in the UI to pull the latest Code Options from Workbench. There is no push from Workbench and no scheduled/automatic sync in v1.
    • On refresh, oxFlow pulls the current option list and reconciles: new options added, existing options kept, obsolete options archived.
    • Admins cannot manually edit the definition between refreshes; read-only in UI
    • sync_source = "workbench", locked = true
  3. Viewing missing Code assignments:

    • Anomaly Review reports which Items/Resources lack a required Code Option
    • Admin can bulk-assign defaults or export for estimator review
  4. Bulk Code assignment (UI pattern, v1):

    • Users with permission can select multiple Items (or Resources) and assign the same Code Option in one action
    • Improves UX for large-scale assignment workflows (e.g., post-migration cleanup)

8. Migration highlights

From Benchmark

  • Benchmark activity table (113 rows) → oxFlow Workcentre Code + 113 Code Options (applied to Items)

    • activity_idcode_option.external_id
    • activity_desccode_option.value (code) + code_option.display_label (if distinct)
    • Naming: “Workcentre” chosen to align with Workbench (Benchmark called it “Activity”)
  • Benchmark cost_code table (33 rows) → oxFlow Activity Code Code + 33 Code Options (applied to Resources)

    • cost_code_idcode_option.external_id
    • cost_code_desccode_option.value (code) + optional code_option.display_label
    • Naming: “Activity Code” chosen to align with Workbench (Benchmark naming reversed to clarify scope)
  • Post-migration tasks:

    • Map Benchmark’s item.activity_id → Item.workcentre_option_id
    • Map Benchmark’s resource.cost_code_id → Resource.activity_code_option_id
    • Any unmapped Items/Resources flagged as requiring Code assignment (Anomaly Review)
    • Estimate submissions/exports blocked until all Codes resolved