Core Concepts
ForgeX is built around a hierarchical data model that mirrors the natural structure of construction bids. Understanding these core concepts will help you work faster and build more accurate estimates.
The ForgeX Hierarchy
In plain English:
- A Client can have many Bids
- A Bid contains multiple Scopes (work areas)
- Each Scope contains Items across 6 modules
- Items roll up to Scope costs
- Scopes roll up to the Bid total
1. Clients
Clients represent the companies or individuals you're bidding for.
Key Fields
| Field | Description | Example |
|---|---|---|
| Company Name | Client organization | "ABC Construction" |
| Contact Name | Primary contact | "John Smith" |
| Contact email | "john@abc.com" | |
| Phone | Contact phone | "(281) 555-1234" |
| Address | Client address | "123 Main St, Houston, TX" |
Usage
- Create clients once, reuse across multiple bids
- Track bid history per client
- Filter bids by client in the dashboard
Set up clients before creating bids. You can't create a bid without selecting a client.
2. Bids
Bids are the top-level container for an entire construction estimate. Each bid represents a unique project opportunity.
Key Fields
| Field | Type | Description |
|---|---|---|
jobName | String | Project name (e.g., "Memorial Park Expansion") |
location | String | Job site location |
bidNumber | String | Unique identifier (e.g., "B-2025-001") |
clientId | Reference | Link to Client |
status | Enum | Bid lifecycle stage |
taxExempt | Boolean | Whether bid is tax-exempt |
perDiemEnabled | Boolean | Include per diem for crew |
overheadPercent | Number | Bid-level overhead % |
profitPercent | Number | Bid-level profit % |
Bid Status Lifecycle
Bids progress through these statuses:
| Status | Description | Editable? |
|---|---|---|
| DRAFT | Initial state, work in progress | ✅ Full access |
| SUBMITTED | Sent to client for review | ⚠️ ADMIN/ESTIMATOR only |
| NEGOTIATION | Under discussion with client | ⚠️ ADMIN/ESTIMATOR only |
| AWARDED | Won! Converts to project (Phase 2) | ❌ Read-only |
| LOST | Did not win | ❌ Read-only |
| COMPLETED | Project fully completed | ❌ Read-only |
Only DRAFT bids can be deleted. Once submitted, bids are permanent for audit purposes.
Bid-Level Settings
Tax Exemption
When taxExempt = true:
- Taxable materials are excluded from tax calculations
- Non-taxable items (labor, equipment rentals) are unaffected
- The tax line disappears from bid summaries
Per Diem
When perDiemEnabled = true:
- Adds daily per diem costs for crew members
- Configured via Global Variables
- Scales with labor days
Overhead & Profit
- Overhead: Applied after all module markups (default from Global Variables)
- Profit: Applied after overhead (default from Global Variables)
- Can be overridden per bid for custom margins
3. Scopes
Scopes represent distinct work areas or phases within a bid. Think of them as logical groupings of estimation items.
Examples of Scopes
- "Foundation" - All foundation work
- "Parking Lot" - Parking area construction
- "Sidewalks" - Sidewalk and walkways
- "Driveway" - Driveway slab
- "Retaining Wall North" - Specific wall section
Key Fields
| Field | Type | Description |
|---|---|---|
name | String | Scope name (unique within bid) |
shape | Enum | SLAB, FOOTING, WALL, CYLINDER |
multiplier | Number | Repeat factor (default: 1) |
parentScopeId | Reference | Link to parent scope (optional) |
Scope Multiplier
The multiplier is a powerful feature for repeated identical areas:
- Example
- Calculation
Scenario: 5 identical garage slabs
Without multiplier:
- Create 5 separate scopes
- Duplicate all items 5 times
- Hard to maintain consistency
With multiplier:
- Create 1 scope: "Garage Slab"
- Set multiplier:
5 - All costs automatically scale ×5
// Individual item total
itemCost = calculateItemCost(item)
// Scope total (all items)
scopeSubtotal = sum(allItemCosts)
// Apply multiplier
scopeTotalCost = scopeSubtotal * multiplier
Result: Change multiplier from 5 to 6, and all costs update instantly.
Multiplier applies to ALL items in the scope. If areas differ (e.g., different dimensions or rebar), use separate scopes.
Parent-Child Scope Linking
Scopes can be linked in a parent-child relationship to inherit properties:
Inheritance:
- Child scopes inherit dimensions/materials from parent
- Changes to parent propagate to children
- Reduces duplication for complex structures
Use case: Grade beams with multiple piers — define the grade beam once, create child scopes for each pier that inherit base properties.
4. Modules (Estimation Items)
ForgeX provides 6 specialized modules for estimating different cost categories. Each module has unique fields and calculations.
Module Overview
| Module | Purpose | Auto-Calculations |
|---|---|---|
| Concrete | Slabs, footings, walls, cylinders | Square feet, cubic yards, rebar pounds |
| Labor | Crew hours and wages | FICA, FUTA, SUTA, dependent roles, auto costs |
| Equipment | Rentals and owned equipment | Fuel charges, delivery fees, insurance |
| Materials | Supplies and consumables | Waste factors, tax |
| Subcontractor | Third-party services | Buffer markup |
| Misc | Other costs | Direct cost entry |
Concrete Module
Shapes: SLAB, FOOTING, WALL, CYLINDER
Key Fields:
- Dimensions:
length,width,depth(ordiameterfor cylinders) - Rebar:
slabRebarSize,slabRebarOnCenter,slabRebarOrientation - Mix design (from Pricing catalog)
- Waste percentage
Auto-Calculations:
// Square feet (for slabs/walls)
squareFeet = length * width
// Cubic yards
cubicYards = (length * width * (depth/12)) / 27
// Rebar pounds (based on size, spacing, area)
rebarPounds = calculateRebarPounds(size, spacing, area)
rebarWithWaste = rebarPounds * (1 + wastePercent/100)
// Costs
concreteCost = cubicYards * mixPricePerCY
rebarCost = rebarWithWaste * rebarPricePerPound
// Total
totalCost = concreteCost + rebarCost + tax
Auto-Materialization: When enabled, concrete items automatically create Material items for:
- Concrete (based on cubic yards)
- Rebar (based on pounds)
This prevents double-counting — material items linked via sourceConcreteItemId are excluded from material cost rollup.
Labor Module
Key Fields:
role: Job role (Finisher, Laborer, Operator, etc.)quantity: Number of workershoursPerDay: Hours per worker per daydays: Number of daysratePerHour: Hourly wage
Auto-Calculations:
// Base cost
baseCost = quantity * hoursPerDay * days * ratePerHour
// Soft costs (payroll taxes)
ficaAmount = baseCost * ficaRate
futaAmount = baseCost * futaRate
sutaAmount = baseCost * sutaRate
// Auto costs (if vehicles specified)
autoDepreciation = baseCost * autoDepreciationRate
autoFuel = baseCost * autoFuelRate
autoInsurance = baseCost * autoInsuranceRate
// Total
totalCost = baseCost + fica + futa + suta + autoCosts
Dependent Roles: The system automatically calculates supervision needs:
- Ops Coordinator: 5% of skilled labor hours (max 40 hrs)
- Labor Foreman: 1 per 10 skilled laborers
- Junior Foreman: 1 per 5 laborers
These are read-only and update automatically when labor items change.
Equipment Module
Key Fields:
name: Equipment name (from catalog or manual)rentalType: DAILY, WEEKLY, MONTHLYquantity: Number of unitsduration: Duration in daysrate: Rental rate per period
Auto-Calculations:
// Base rental cost
baseRentalCost = quantity * duration * ratePerUnit
// Fuel charge (not applicable to formwork)
fuelCharge = quantity * days * fuelChargePerDay
// Delivery fee (not charged if "on previous equipment")
deliveryFee = onPrevious ? 0 : deliveryFee
// Truck haul costs (formwork only)
trucksCost = truckCount * truckHaulCost
// Total
totalCost = baseRentalCost + fuelCharge + deliveryFee + trucksCost + tax
Materials Module
Key Fields:
name: Material name (from catalog or manual)quantity: Quantity neededunit: Unit of measure (EA, LF, SF, CY, etc.)unitCost: Cost per unitwastePercentage: Waste factor (e.g., 10 = 10%)isTaxable: Whether item is taxable
Auto-Calculations:
// Adjusted quantity (with waste)
adjustedQuantity = quantity * (1 + wastePercent/100)
// Base cost
baseCost = adjustedQuantity * unitCost
// Tax (if not exempt and isTaxable)
taxAmount = (bid.taxExempt || !isTaxable) ? 0 : baseCost * taxRate
// Total
totalCost = baseCost + taxAmount
Waste applies to total quantity, not unit cost. This ensures accurate material tracking.
Subcontractor Module
Key Fields:
name: Service namevendor: Vendor/companyquantity: Quantityunit: Unit of measureunitCost: Cost per unitbuffer: Markup percentage
Auto-Calculations:
// Subtotal
subtotal = quantity * unitCost
// Apply buffer (markup)
totalCost = subtotal * (1 + buffer/100)
Pump Catalog: ForgeX includes a pump catalog with 122 entries:
- Vendor, pump type, reach
- Volume rate ($/CY), hourly rate, travel fee, minimum hours
Select from catalog, and rates auto-populate.
Misc Module
Key Fields:
name: Descriptionquantity: QuantityunitCost: Cost per unit
Calculation:
totalCost = quantity * unitCost
Simple direct cost entry for items that don't fit other modules (permits, testing, etc.).
5. Pricing Items
Pricing Items are the catalog of materials, equipment, and rates used throughout the system.
What They Include
| Category | Examples |
|---|---|
| Concrete Mixes | 3000 PSI, 4000 PSI, 5000 PSI, Flowable fill |
| Rebar | #3, #4, #5, #6, #7, #8 (price per pound) |
| Equipment | Skid steer, excavator, mixer, compactor |
| Materials | Wire mesh, vapor barrier, stakes, anchor bolts |
| Pump Services | Concrete pumps (122 vendors/types) |
| Joint Saw Rates | Green saw, demo saw |
Two-Tier System
- Global Pricing Items - Default catalog for all bids
- Bid-Specific Overrides - Custom pricing for specific bids
Lookup priority:
// Check for bid-specific override first
bidPricingItem = BidPricingItem.findByBidAndKey(bidId, key)
// Fall back to global catalog
if (!bidPricingItem) {
pricingItem = PricingItem.findByKey(key)
}
return bidPricingItem || pricingItem
Use case for overrides: Client negotiated special pricing on concrete mix. Create a bid-specific override without changing the global catalog.
Pricing Fields
| Field | Description |
|---|---|
key | Unique identifier (e.g., "CONCRETE_3000PSI") |
value | Numeric value (price, rate, etc.) |
unit | Unit of measure (CY, LB, EACH, etc.) |
category | CONCRETE, REBAR, EQUIPMENT, MATERIAL, PUMP, etc. |
isActive | Whether item is available for use |
6. Global Variables
Global Variables store system-wide configuration values used in calculations across all bids.
Variable Categories
- Tax Rates
- Labor Soft Costs
- Auto Costs
- Module Markups
- Bid-Level
- Equipment
- Misc
- Concrete_Tax_Rate: Sales tax on concrete (default: 8.25%)
- Rebar_Tax_Rate: Sales tax on rebar (default: 8.25%)
- Material_Tax_Rate: Sales tax on materials (default: 8.25%)
- Equipment_Tax_Rate: Sales tax on equipment rentals (default: 8.25%)
- FICA_Rate: Federal Insurance Contributions Act (default: 7.65%)
- FUTA_Rate: Federal Unemployment Tax (default: 0.6%)
- SUTA_Rate: State Unemployment Tax (default: 2.7%)
- Auto_Depreciation_Rate: Vehicle depreciation per labor dollar (default: 3%)
- Auto_Fuel_Rate: Fuel cost per labor dollar (default: 2%)
- Auto_Insurance_Rate: Vehicle insurance per labor dollar (default: 1.5%)
Workers Compensation (WC):
- Labor_WC, Equipment_WC, Materials_WC, Subcontractor_WC, Misc_WC
Overhead:
- Labor_Overhead, Equipment_Overhead, Materials_Overhead, Subcontractor_Overhead, Misc_Overhead
Profit:
- Labor_Profit, Equipment_Profit, Materials_Profit, Subcontractor_Profit, Misc_Profit
GL Pollution:
- Labor_GL_Pollution, Equipment_GL_Pollution, Materials_GL_Pollution, etc.
- Overhead_Percent: Default bid overhead (default: 10%)
- Profit_Percent: Default bid profit (default: 15%)
- Fuel_Charge_Per_Day: Daily fuel charge for equipment (default: $25)
- Rental_Insurance_Percent: Insurance rate for rentals (default: 2%)
- Per_Diem_Rate: Daily per diem for crew (default: $50)
- Green_Saw_Rate: Green concrete saw rate ($/LF)
- Demo_Saw_Rate: Demo saw rate ($/LF)
Variable Structure
| Field | Description |
|---|---|
key | Unique identifier (e.g., "FICA_Rate") |
value | Numeric value (stored as decimal, e.g., 7.65 for 7.65%) |
category | TAX, LABOR, OVERHEAD, PROFIT, etc. |
description | Human-readable description |
defaultValue | System default (used if no bid override) |
Bid-Specific Overrides
Just like Pricing Items, Global Variables support bid-specific overrides:
// Check for bid-specific variable override
bidVariable = BidGlobalVariable.findByBidAndKey(bidId, "FICA_Rate")
// Fall back to global default
if (!bidVariable) {
globalVariable = GlobalVariable.findByKey("FICA_Rate")
}
return bidVariable?.value || globalVariable.value
Use case: Special project with different overhead/profit margins — override for that bid only.
Cost Rollup Flow
Understanding how costs flow through the system is crucial:
Step-by-Step
Each module calculates its own item cost based on inputs:
- Concrete: CY + rebar pounds
- Labor: Hours * rate + soft costs
- Equipment: Rental + fuel + delivery
- Materials: Quantity + waste
- Subcontractor: Quantity * rate + buffer
- Misc: Quantity * unit cost
Sum all items within the scope by module type:
scope.concreteCost = Σ ConcreteItem.totalCost
scope.laborCost = Σ LaborItem.totalCost
...
scope.totalCost = sum of all modules * multiplier
Sum all scopes by module type:
bid.concreteCost = Σ Scope.concreteCost
bid.laborCost = Σ Scope.laborCost
...
Apply WC, overhead, profit, and GL pollution to each module:
hardCost = bid.laborCost
wcAmount = hardCost * Labor_WC
overheadAmount = hardCost * Labor_Overhead
profitAmount = (hardCost + wc + overhead) * Labor_Profit
glAmount = (hardCost + wc + overhead + profit) * Labor_GL_Pollution
laborCostWithMarkups = hardCost + wc + overhead + profit + gl
Repeat for all modules.
Apply final bid-level overhead and profit:
subtotal = sum of all modules with markups
overheadAmount = subtotal * bid.overheadPercent
profitAmount = (subtotal + overhead) * bid.profitPercent
totalCost = subtotal + overheadAmount + profitAmount
All calculations are automatic. You never manually calculate costs — ForgeX updates them in real-time as you edit items.
Key Takeaways
Hierarchy Matters
Client → Bid → Scope → Items is the structure. Organize your bids logically with clear scope names.
Use Multipliers
Don't duplicate scopes for identical areas. Use the multiplier field to scale costs automatically.
Leverage Catalogs
Use Pricing Items and Pump Catalog instead of manual entry. They're pre-configured and accurate.
Understand Rollup
Items → Scopes → Bid. Each level applies markups. Know where overhead/profit come from.
Tax Exemption
Set taxExempt at the bid level. It filters taxable items from all modules.
Auto-Materialization
Enable auto-add to Materials for concrete items. Prevents double-counting via sourceConcreteItemId.