1. Purpose

A Tender is an external pricing opportunity — the outermost container in oxFlow. It captures the opportunity metadata (client, location, due date, win probability, status) and holds one or more Estimates (see estimate.md).

One client per Tender (BR-090); multi-client scenarios → separate Tenders.

Tender is tightly coupled to Estimate: Tender state cascades to Estimates (BR-094). See §4 for the cascade rules.


2. Attributes

AttributeTypeRequiredDefaultNotes
idUUIDgeneratedSystem-managed
namestring (text)Tender name; e.g., “Acme Corp Office Refurb”
numberstring (free text)Internal tracking number (e.g., “TND-2026-042”). Not client-facing
client_refstringnullClient’s reference number (e.g., their RFT/RFP ID). For cross-reference
client_idCompany refThe Client (Company with Client role). Exactly one per Tender (BR-090)
locationstringnullProject location / site address
contract_start_datedatenullPlanned contract commencement
tender_due_datedateWhen the proposal is due to the client
win_probabilityenumnullLow / Medium / High. Reporting metadata; no behavioural impact
statusenumActiveActive · Submitted · Won · Lost · Archived. See §4
categorization_optionsmany-to-many[]Multi-select Categorization Option references (Tenders can be tagged against any Categorization whose scope includes Tender)
tender_program_idTender Program refnullOptional MS Project file upload (1:0..1, BR-100)
noteslong textnullFree-form notes
created_at / updated_attimestampsystemAudit
created_by / updated_byUser refsystemAudit

3. Relationships

DirectionEntityCardinalityRequiredNotes
OutboundClient (Company)Tender M:1 CompanyClient role; one per Tender (BR-090)
OutboundTender ProgramTender 1:0..1 Tender ProgramOptional MS Project; at Tender level not Estimate (BR-100)
InboundEstimateTender 1:M EstimateOne or more Estimates per Tender (BR-091)
InboundCategorization OptionTender M:M Categorization OptionMulti-select tagging for reporting

4. Lifecycle States

StateMeaningTriggerManual/AutoRole
ActiveInitial state. Tender is being prepared; Estimates are being builtTender creationAuto
SubmittedOne or more Estimates have been delivered to the clientPublisher publishes (BR-094 implies Submit transition)Auto (on publish)
WonClient has accepted the proposal. The submitted Estimate is promoted to project; all others archived (BR-094)Client decision (manual transition)ManualAdmin + Lead Estimator
LostClient has rejected the proposal. All Estimates archived (BR-094)Client decision (manual transition)ManualAdmin + Lead Estimator
ArchivedTender withdrawn or not pursued. All Estimates archived (BR-094)Manual transition (from Active or Submitted)ManualAdmin + Lead Estimator

Role constraint: Manual Tender state transitions (Won, Lost, Archived) are restricted to Admin + Lead Estimator roles.

State transition diagram:

                    ┌─────────────────────┐
                    │     Active          │
                    │ (Estimates building)│
                    └────┬────────────┬───┘
                         │            │
                   (publish)      (not pursued)
                         │            │
                         ▼            ▼
                    ┌─────────────────────────┐
                    │      Submitted          │
                    │ (awaiting client reply) │
                    └────┬────────────┬───┬───┘
                         │            │   │
                      (client)    (loss) (withdraw)
                         │            │   │
            ┌────────────▼─┐    ┌──────▼──▼───┐
            │     Won      │    │  Archived   │
            │ (promoting)  │    │  (terminal) │
            └──────────────┘    └─────────────┘
                (terminal)

Terminal states: Won, Lost, Archived

Cascade on Tender state change (BR-094):

Tender →Effect on Estimates
WonThe one submitted Estimate is kept (remains Submitted). All other Estimates under the Tender are archived. Kept Estimate is promoted to project (outside Estimate scope).
LostAll Estimates under the Tender transition to Archived
ArchivedAll Estimates under the Tender transition to Archived

5. Validation / Invariants

  1. Client mandatory. Every Tender has exactly one Client (Company with Client role). BR-090.
  2. At least one Estimate. Every Tender has one or more Estimates (BR-091).
  3. State enum. Tender status ∈ {Active, Submitted, Won, Lost, Archived}.
  4. Cascade on Won. When Tender → Won, exactly one Estimate is kept (the submitted one); all others → Archived. If no submitted Estimate exists, this is an error state.
  5. Terminal states non-reversible. Once a Tender reaches Won/Lost/Archived, manual transitions are blocked.
  6. Tender Program optional. tender_program_id may be null (BR-100).
  7. Unique identification. number is free-text and may collide; not enforced unique.

6. Worked Examples

Example 1 — Base Case, Alternative, and Strategy Estimates (three variants)

A Tender for a commercial office refurbishment with three submission strategies:

Tender: "Acme Corp Refurb"
  number: TND-2026-042
  client_id: <Company "Acme Corp">
  location: "North Tower, 42 Main St"
  tender_due_date: 2026-05-15
  status: Active

  Estimate A: "Base Case" (estimate_number: "1")
    lead_estimator_id: <User "Alice">
    status: In Progress
    Contents: Standard scope, core trades, no premium finishes
    Headings: Demolition, Structural, Fit-out, Services
    Items: 45 schedule items + internal build-up

  Estimate B: "Alternative Premium" (estimate_number: "alt")
    lead_estimator_id: <User "Bob">
    status: In Progress
    Contents: Base scope + premium finishes, upgraded materials
    Headings: same structure as A
    Items: 48 schedule items

  Estimate C: "Strategy Fast-Track" (estimate_number: "fast")
    lead_estimator_id: <User "Charlie">
    status: In Progress
    Contents: Phased delivery; core works Phase 1, finishes Phase 2
    Headings: Phase 1 structure, Phase 2 structure
    Items: 52 items (broken across phases)

Tender state flow:
  1. Active: Alice, Bob, Charlie build independently. No cross-collaboration at Item level (different branches).
  2. Lead reviews → Estimate A & B → Reviewed state. Estimate C still In Progress.
  3. Decision: Submit Estimate A (Base Case) to client → Publisher output generated → Tender → Submitted, Estimate A → Submitted (locked).
  4. Estimates B & C remain In Progress (not submitted).
  5. Client accepts Base Case → Tender → Won.
  6. Cascade: Estimate A stays Submitted. Estimates B & C automatically → Archived.

Result: Tender complete. Estimate A (Base Case, locked) retained; B & C archived but recoverable.

Example 2 — Tender Lost; All Estimates Archived

A Tender for bridge works that fails to win:

Tender: "Interstate Bridge Retrofit"
  number: TND-2026-015
  client_id: <Company "State Highways Authority">
  location: "Bridge span 7, Route 3"
  tender_due_date: 2026-06-01
  status: Active

  Estimate "Main Bid" (estimate_number: "rev a")
    lead_estimator_id: <User "David">
    status: Submitted (locked) [was submitted yesterday]
    Items: 120 items across 8 heading groups (earthworks, structures, finishes, etc.)

Tender state flow:
  1. Estimate submitted → Tender → Submitted.
  2. Waiting for client decision...
  3. Client notifies: project awarded to competitor.
  4. Tender → Lost (manual transition).
  5. Cascade: Estimate → Archived.
  6. Result: Tender now read-only. All Estimates read-only. Archive available for historical reference / retrospective.

Users can still view the Estimate and its Items (audit trail, learning), but cannot edit.