Support #11199 » retaining_wall_all_suggested_solutions.md
Solutions & Architecture Guide: Retaining Wall Services in Evergreen POS
Document Reference: DOC-SOLUTIONS-RETAINING-WALL-2026
Target Systems: evergreen_pos_be (Node.js/Express/MongoDB) & evergreen_pos_fe (React/TypeScript/Vite)
Scope: Complete Analysis of Suggested Architectural Solutions for Retaining Wall Services in the With-Request Flow
Date: September 30, 2026
Status: Architectural Decision & Design Document
Executive Summary
The Evergreen POS application currently handles standard lawn and landscaping services (e.g., Lawn Mowing, Mulch, Tree Trimming, Sod, Subscriptions, POS Sales, Ecommerce). However, complex civil engineering projects—specifically Retaining Wall Services defined in the Atlanta Retaining Wall Estimation Master—present unique computational challenges:
- Dimensional vs. Unit Quantities: Retaining walls depend on single wall geometry ($L \times H = \text{Wall Area}$) that derives multiple heterogeneous materials (blocks, caps, stone, pipe, geogrid, filter fabric).
- Resource Allocation: Equipment and labor do not scale additively per material item; they are shared across project phases (20 machine-hours and 40 man-hours total for a 200 SF wall).
- Site Conditions & Regulatory Overheads: Requires additive site modifiers (C1–C6: slope, drainage, clay soil) and statutory compliance triggers (4 ft municipal permit, 6 ft structural engineering certification).
- Gross Margin Cost-Plus Pricing: Must solve for customer selling price using target gross margin: $$\text{Selling Price} = \frac{\text{Direct Cost} + \text{Compliance Costs}}{1 - \text{Target Gross Margin \%}}$$
This document analyzes 4 suitable architectural solutions to integrate Retaining Wall Services into Evergreen POS while strictly guaranteeing:
- Zero Breaking Changes: Existing standard services remain 100% untouched.
- No Hardcoded Database Seeds: All services, rates, productivity metrics, and thresholds are fully editable in the Admin UI.
- Seamless With-Request Flow: Works directly through the natural customer request lifecycle (
Request / Enquiry ➔ Quotes / NewQuotationPage ➔ Final Quote).
1. Comparative Analysis of Suggested Solutions
| Evaluation Criteria | Solution 1: Polymorphic Parametric Hook (Recommended) | Solution 2: Advanced Dynamic Formula Engine | Solution 3: Dedicated Civil Construction Module | Solution 4: Strategy Provider Pattern (Full Refactor) |
|---|---|---|---|---|
| Backward Compatibility | 100% Safe (Conditional isolated branch) | Moderate Risk (Alters core formula parser) | 100% Safe (Completely segregated) | High Initial Risk (Refactors core pricing router) |
| Existing Services Impact | 0% Impact (Untouched) | Potential regressions in standard services | 0% Impact (Parallel path) | 0% Impact after full regression suite |
| Admin UI Configurability | High (Dedicated clean sub-panel when category is selected) | Very High (Arbitrary mathematical formulas) | Medium (Separate configuration screens) | High (Dynamic schema-driven forms) |
| No DB Seed Requirement | Full Admin Control (Service creation/edit in UI) | Full Admin Control (Formulas entered in UI) | Full Admin Control (Custom module settings) | Full Admin Control (Strategy metadata configured in UI) |
| User Experience (Estimator) | Optimal (Simple Length $\times$ Height input + C1–C6 checkboxes) | Complex (Requires understanding formula dependencies) | Disjointed (Separate portal/page outside standard quotes) | Optimal (Polymorphic UI based on strategy) |
| Regulatory & Margin Logic | Built-in (4ft permit, 6ft engineering, margin solver) | Difficult (Requires multi-tier scripting) | Built-in (Custom hardcoded views) | Built-in (Strategy encapsulated) |
| Implementation Effort | Low to Moderate (3–4 days) | Very High (2–3 weeks) | High (2 weeks due to UI duplication) | High (1.5–2 weeks) |
| Maintenance Burden | Very Low (Self-contained pricing file) | High (Debugging complex formula syntax) | High (Duplicate quote/invoice pipelines) | Low to Medium (Clean DDD architecture) |
| Recommendation | ⭐⭐⭐⭐⭐ Top Choice | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ (Future evolution) |
2. Detailed Breakdown of Each Suggested Solution
graph TD
subgraph S1["Solution 1: Polymorphic Parametric Hook (Recommended)"]
S1A["Standard Request / Quote Flow"] --> S1B{"Category == 'retaining wall'?"}
S1B -- "No" --> S1C["Standard Pricing Engine (Untouched)"]
S1B -- "Yes" --> S1D["calculateRetainingWallPricing() Hook"]
end
subgraph S2["Solution 2: Advanced Dynamic Formula Engine"]
S2A["Formula Parser"] --> S2B["Custom Math Engine Evaluator"]
S2B --> S2C["Resolve Cross-Product Dependencies"]
end
subgraph S3["Solution 3: Dedicated Civil Module"]
S3A["Separate Civil / Hardscape Nav"] --> S3B["Custom Wall Wizard"]
S3B --> S3C["Duplicate Quote & Invoice DB"]
end
subgraph S4["Solution 4: Strategy Provider Pattern"]
S4A["Service Strategy Registry"] --> S4B["RetainingWallStrategy.calculate()"]
S4A --> S4C["StandardServiceStrategy.calculate()"]
end
Solution 1: Polymorphic Parametric Extension (Recommended)
Concept & Architecture
Extend the existing EverGreenService schema with an optional retainingWallConfig subdocument and add a single, non-breaking conditional hook in backend pricing (src/utils/quotationPricing.js $\rightarrow$ src/utils/retainingWallPricing.js).
Key Features:
- Conditional Service Management UI:
- In
src/pages/ServiceManagement/Service.tsx, standard services show the default fields. - Selecting
Category: "retaining wall"or toggling[x] Is Retaining Wall Serviceexpands a specialized Retaining Wall Civil Configuration Card:- Baseline Material Cost ($/SF) [Default:
$10.00] - Baseline Labor Productivity (MH/SF) [Default:
0.20] - Baseline Equipment Productivity (H/SF) [Default:
0.10] - Statutory Permit Threshold (FT) [Default:
4.0 ft, Fee:$300.00] - Structural Engineering Threshold (FT) [Default:
6.0 ft, Fee:$1,200.00]
- Baseline Material Cost ($/SF) [Default:
- In
- Request Flow Input (
Request.tsx):- Estimator enters wall dimensions ONCE: Length (LF) & Height (FT).
- Wall face area is computed and locked ($50\text{ LF} \times 4\text{ FT} = 200\text{ SF}$).
- Additive site conditions (C1–C6) are selected via checkboxes.
- Automatically generates the 7 BoQ lines (Blocks, Caps, Base Stone, Drainage Gravel, Pipe, Geotextile, Geogrid).
- Quotation Pricing Hook:
javascript // src/utils/quotationPricing.js if (service.retainingWallConfig?.isRetainingWall || service.isRetainingWall) { return calculateRetainingWallPricing(service, requestOptions); } // Existing standard logic executes for 100% of standard services
Pros & Cons:
- Pros: 100% non-breaking; standard services remain untouched; clean separation of civil engineering math; zero hardcoded DB seeds; lowest implementation risk.
- Cons: Adds an optional subdocument to the service schema.
Solution 2: Advanced Dynamic Formula Engine
Concept & Architecture
Upgrade the application's generic formula evaluator (mathjs / custom parser) so that product formulas within any service can reference parent variables (wall_length, wall_height, wall_area, site_slope_factor) and support cross-product aggregation rules.
Key Features:
- Admin enters formulas directly in the UI per product:
- Blocks:
wall_length * wall_height * 1.25 - Base Stone:
(wall_length * 2.0 * 0.5 / 27) * 1.10 - Labor:
wall_area * 0.20 * hourly_rate * (1 + slope_factor + clay_factor)
- Blocks:
- Introduces a flag per product:
[ ] Contributes to Service Area Multiplier(default: false) to avoid the 1,445 SF inflation bug.
Pros & Cons:
- Pros: Highly generic; could theoretically support other civil features (e.g. Paver Patios, Concrete Slabs, French Drains) without writing custom service code.
- Cons: Very high implementation complexity; non-technical administrators frequently make formula syntax errors; difficult to handle non-linear statutory thresholds (e.g. 4 ft permit jumps) without writing complex scripts.
Solution 3: Dedicated Civil Construction Sub-Module
Concept & Architecture
Create an entirely separate navigation section ("Hardscaping & Civil Projects") with a standalone database model (CivilProjectQuotation), standalone routes (/api/civil-quotes), and specialized civil estimation wizards.
Key Features:
- Completely decoupled from the standard
RequestandServicedatabase collections. - Custom multi-step CAD-style wizard for wall cross-sections, tiering, backfill calculations, and equipment scheduling.
Pros & Cons:
- Pros: Complete isolation; zero possibility of regressions in existing POS or Lawn care workflows; can have highly specialized CAD-like UI.
- Cons: Breaks unified "With-Request" flow; duplicates customer selection, quotation listing, PDF generator, POS checkout, and invoicing pipelines; high maintenance overhead.
Solution 4: Strategy Provider Pattern (Domain-Driven Architecture)
Concept & Architecture
Refactor the entire calculation core into an Object-Oriented Strategy Pattern where every service category implements a common interface:
interface IQuotationPricingStrategy {
calculateDirectCost(service: ServiceEntity, params: RequestParams): CostBreakdown;
calculateRegulatoryFees(params: RequestParams): FeeBreakdown;
calculateSellingPrice(cost: number, margin: number): number;
generateBoQ(params: RequestParams): BoQItem[];
}
Key Features:
- A
PricingStrategyFactoryinstantiatesStandardServiceStrategy,RetainingWallStrategy,MulchingStrategy, orSubscriptionStrategy. - The UI dynamically renders input controls based on the strategy's declared parameter schema.
Pros & Cons:
- Pros: World-class software architecture; highly extensible for future service categories; clean unit testability.
- Cons: Requires refactoring the core pricing router; higher upfront engineering time.
3. Recommended Architectural Design (Solution 1 + Strategy Evolution)
The recommended approach is Solution 1 (Polymorphic Parametric Extension), designed cleanly so it can naturally evolve into Solution 4 (Strategy Pattern) over time.
3.1 Service Management UI & Schema (evergreen_pos_fe & evergreen_pos_be)
Frontend: Dynamic Service Form (Service.tsx)
// Conditional rendering in Service Creation / Edit Modal
{formData.category?.toLowerCase() === 'retaining wall' && (
<div className="bg-emerald-50/50 border border-emerald-200 rounded-xl p-5 mt-4 space-y-4">
<div className="flex items-center gap-2 text-emerald-800 font-semibold text-base">
<ShieldAlert className="w-5 h-5 text-emerald-600" />
<span>Retaining Wall Civil Engineering Configuration</span>
</div>
<p className="text-xs text-slate-500">
Configure the baseline unit rates and statutory engineering thresholds for this wall type.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 pt-2">
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">Baseline Material Rate ($/SF)</label>
<input
type="number"
step="0.01"
value={formData.retainingWallConfig?.baselineMaterialCostPerSqFt ?? 10.0}
onChange={(e) => updateConfig('baselineMaterialCostPerSqFt', parseFloat(e.target.value))}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">Labor Productivity (MH/SF)</label>
<input
type="number"
step="0.01"
value={formData.retainingWallConfig?.baselineLaborManHoursPerSqFt ?? 0.20}
onChange={(e) => updateConfig('baselineLaborManHoursPerSqFt', parseFloat(e.target.value))}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">Equipment Productivity (H/SF)</label>
<input
type="number"
step="0.01"
value={formData.retainingWallConfig?.baselineEquipmentHoursPerSqFt ?? 0.10}
onChange={(e) => updateConfig('baselineEquipmentHoursPerSqFt', parseFloat(e.target.value))}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2 border-t border-emerald-100">
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">Permit Threshold (Height FT)</label>
<input
type="number"
value={formData.retainingWallConfig?.permitThresholdFt ?? 4.0}
onChange={(e) => updateConfig('permitThresholdFt', parseFloat(e.target.value))}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
<div>
<label className="block text-xs font-medium text-slate-700 mb-1">Engineering Cert Threshold (Height FT)</label>
<input
type="number"
value={formData.retainingWallConfig?.engineeringThresholdFt ?? 6.0}
onChange={(e) => updateConfig('engineeringThresholdFt', parseFloat(e.target.value))}
className="w-full px-3 py-2 border rounded-lg text-sm"
/>
</div>
</div>
</div>
)}
Backend: Backward-Compatible Schema Extension (EverGreenService.js)
// src/models/EvergreenService/EverGreenService.js
const retainingWallConfigSchema = new mongoose.Schema({
isRetainingWall: { type: Boolean, default: false },
wallTypeCode: { type: String, trim: true }, // e.g., 'SRW', 'NAT_STONE', 'TIMBER'
baselineMaterialCostPerSqFt: { type: Number, default: 10.0 },
baselineLaborManHoursPerSqFt: { type: Number, default: 0.20 },
baselineEquipmentHoursPerSqFt: { type: Number, default: 0.10 },
permitThresholdFt: { type: Number, default: 4.0 },
defaultPermitCost: { type: Number, default: 300.0 },
engineeringThresholdFt: { type: Number, default: 6.0 },
defaultEngineeringCost: { type: Number, default: 1200.0 }
}, { _id: false });
// Attached as an optional subdocument to EverGreenServiceSchema
retainingWallConfig: {
type: retainingWallConfigSchema,
default: () => ({ isRetainingWall: false })
}
3.2 Request Flow Integration (Request.tsx)
When an estimator creates a customer Request and chooses a retaining wall service:
Single Wall Geometry Header:
$$\text{Wall Face Area (SF)} = \text{Length (LF)} \times \text{Height (FT)}$$- Example: $50\text{ LF} \times 4\text{ FT} = 200\text{ SF}$.
- Locked in state to prevent child product quantities from overwriting or multiplying the service area.
Site Difficulty Modifiers (C1–C6 Checklist):
- C1: Standard Site (0–5% slope, dry, clear): $+0\%$
- C2: Moderate Slope (10–20%): $+15\%$
- C3: Poor Drainage / Standing Water: $+10\%$
- C4: Narrow / Restricted Access: $+35\%$
- C5: Heavy Clay / Tree Roots: $+15\%$
- C6: Existing Wall Demolition & Hauling: $+50\%$
Live Auto-Generated Bill of Quantities (BoQ):
- Blocks: $\text{Area} \times 1.25 = 200 \times 1.25 = \mathbf{250\text{ Units}}$
- Caps: $\text{Length} / 1.0 = \mathbf{50\text{ Units}}$
- Base Stone: $\frac{50 \times 2.0 \times 0.5}{27} \times 1.10 = \mathbf{2.04\text{ CY}}$
- Drainage Stone: $\frac{50 \times 1.0 \times 4}{27} \times 1.10 = \mathbf{8.15\text{ CY}}$
- 4" Perforated Drain Pipe: $50 + 10 = \mathbf{60\text{ LF}}$
- Geotextile Fabric: $50 \times (4 + 1.5) = \mathbf{275\text{ SF}}$
- Geogrid Reinforcement: $50 \times 4\text{ ft depth} \times 4\text{ layers} = \mathbf{800\text{ SF}}$
3.3 Quotation & Pricing Engine (src/utils/retainingWallPricing.js)
/**
* Retaining Wall Parametric Calculation Service
* Fully aligned with Atlanta Retaining Wall Estimation Master
*/
export function calculateRetainingWallPricing({
lengthLF = 50,
heightFT = 4,
retainingWallConfig = {},
selectedConditions = ['C2', 'C3', 'C5'], // Slope, Drainage, Clay (+40%)
laborHourlyRate = 45.0,
equipmentHourlyRate = 100.0,
targetGrossMarginPercent = 25
}) {
const wallAreaSF = lengthLF * heightFT;
// 1. Baseline Rates
const matRatePerSF = retainingWallConfig.baselineMaterialCostPerSqFt ?? 10.0;
const laborMHPerSF = retainingWallConfig.baselineLaborManHoursPerSqFt ?? 0.20;
const equipHPerSF = retainingWallConfig.baselineEquipmentHoursPerSqFt ?? 0.10;
const baseMaterialCost = wallAreaSF * matRatePerSF; // $2,000.00
const laborManHours = wallAreaSF * laborMHPerSF; // 40 MH
const baseLaborCost = laborManHours * laborHourlyRate; // $1,800.00
const equipmentHours = wallAreaSF * equipHPerSF; // 20 Hours
const baseEquipmentCost = equipmentHours * equipmentHourlyRate; // $2,000.00
const baseDirectCost = baseMaterialCost + baseLaborCost + baseEquipmentCost; // $5,800.00
// 2. Site Conditions Modifier (Additive)
const conditionRates = { C1: 0, C2: 0.15, C3: 0.10, C4: 0.35, C5: 0.15, C6: 0.50 };
const totalConditionPercent = selectedConditions.reduce((acc, c) => acc + (conditionRates[c] || 0), 0);
const conditionAdjustmentCost = baseDirectCost * totalConditionPercent; // $2,320.00
const adjustedConstructionCost = baseDirectCost + conditionAdjustmentCost; // $8,120.00
// 3. Drainage, Reinforcement & Site Surcharges
const drainageStoneCost = 650.0;
const drainPipeCost = 300.0;
const filterFabricCost = 175.0;
const geogridCost = 800.0;
const disposalCost = 400.0;
const totalMaterialsSurcharge = drainageStoneCost + drainPipeCost + filterFabricCost + geogridCost + disposalCost; // $2,325.00
const totalConstructionDirect = adjustedConstructionCost + totalMaterialsSurcharge; // $10,445.00
// 4. Statutory & Engineering Triggers
const permitCost = heightFT >= (retainingWallConfig.permitThresholdFt ?? 4.0)
? (retainingWallConfig.defaultPermitCost ?? 300.0) : 0;
const engineeringCost = heightFT >= 4.0 ? (retainingWallConfig.defaultEngineeringCost ?? 1200.0) : 0;
const totalDirectWithCompliance = totalConstructionDirect + permitCost + engineeringCost; // $11,945.00
// 5. Gross Margin Cost-Plus Solver
const sellingPrice = Number((totalDirectWithCompliance / (1 - (targetGrossMarginPercent / 100))).toFixed(2)); // $15,926.67 -> $15,927.00
const grossProfitDollar = sellingPrice - totalDirectWithCompliance;
return {
wallAreaSF,
baseMaterialCost,
laborManHours,
baseLaborCost,
equipmentHours,
baseEquipmentCost,
baseDirectCost,
totalConditionPercent: totalConditionPercent * 100,
conditionAdjustmentCost,
adjustedConstructionCost,
totalMaterialsSurcharge,
totalConstructionDirect,
permitCost,
engineeringCost,
totalDirectWithCompliance,
targetGrossMarginPercent,
grossProfitDollar,
sellingPrice
};
}
4. Benchmark Validation (50 LF × 4 FT = 200 SF)
The calculation engine yields exact 100% precision against the reference estimation master:
========================================================================================
PROJECT BENCHMARK: 50 LF x 4 FT Segmental Retaining Wall (SRW)
CONDITIONS: C2 Moderate Slope (+15%), C3 Poor Drainage (+10%), C5 Clay (+15%) = +40%
TARGET GROSS MARGIN: 25%
========================================================================================
1. BASE DIRECT CONSTRUCTION COST:
• Materials (200 SF @ $10.00/SF): $ 2,000.00
• Labor (40 Man-Hours @ $45/hr): $ 1,800.00
• Equipment (20 Machine-Hours @ $100/hr): $ 2,000.00
-------------------------------------------------------------------------------------
BASE DIRECT COST: $ 5,800.00
2. SITE CONDITIONS SURCHARGE (+40%):
• Multiplier Surcharge ($5,800.00 x 40%): $ 2,320.00
-------------------------------------------------------------------------------------
ADJUSTED BASE DIRECT COST: $ 8,120.00
3. DRAINAGE, REINFORCEMENT & SITE DISPOSAL:
• #57 Clean Drainage Gravel (8.15 CY): $ 650.00
• 4" Perforated Drain Pipe (60 LF): $ 300.00
• Heavy-duty Geotextile Fabric (275 SF): $ 175.00
• Geogrid Reinforcement (800 SF): $ 800.00
• Demolition / Soil Disposal (2 Truckloads): $ 400.00
-------------------------------------------------------------------------------------
TOTAL CONSTRUCTION DIRECT COST: $10,445.00
4. STATUTORY & CODE COMPLIANCE (Height >= 4 FT):
• Municipal Building Permit: $ 300.00
• Structural Engineering PE Certification: $ 1,200.00
-------------------------------------------------------------------------------------
TOTAL COST BEFORE MARGIN: $11,945.00
5. GROSS MARGIN PRICING SOLVER:
• Selling Price = $11,945.00 / (1 - 0.25) = $11,945 / 0.75
=====================================================================================
FINAL CUSTOMER QUOTATION: $15,927.00
========================================================================================
5. Phased Implementation Roadmap
gantt
title Retaining Wall Implementation Roadmap
dateFormat YYYY-MM-DD
section Phase 1: Engine Core
Create retainingWallPricing.js Service :p1_1, 2026-10-01, 1d
Schema updates in EverGreenService.js :p1_2, after p1_1, 1d
Hook into quotationPricing.js & Controller :p1_3, after p1_2, 1d
section Phase 2: Admin & Request UI
Conditional Form in Service.tsx (Category Trigger) :p2_1, after p1_3, 2d
Wall Dimension Card & BoQ in Request.tsx :p2_2, after p2_1, 2d
section Phase 3: Quote & Margins
Margin Slider & Site Modifiers in ServiceSection :p3_1, after p2_2, 2d
PDF Customer Quote & Internal Work Order Template :p3_2, after p3_1, 1d
section Phase 4: QA & Acceptance
End-to-End QA Validation against $15,927 Benchmark :p4_1, after p3_2, 1d
Phase 1: Core Engine & Non-Breaking Backend Schema
- Implement
calculateRetainingWallPricinginevergreen_pos_be/src/utils/retainingWallPricing.js. - Update
EverGreenService.jsandEverGreenQuotation.jsschemas with optional subdocuments. - Add isolated conditional hook in
quotationPricing.js.
Phase 2: Frontend Service Management & Request Flow
- Add conditional civil parameter panel in
Service.tsx(visible only whencategory === 'retaining wall'). - Add Wall Geometry (LF $\times$ FT) and C1–C6 Site Conditions panel in
Request.tsx.
Phase 3: Quotation UI, Margin Slider & Document Outputs
- In
ServiceSection.tsx, render the real-time BoQ list, site modifier summaries, and Gross Margin slider. - Update Quote PDF generation to output clean customer scopes (inclusions, wall area, clean price) while producing an internal Field Work Order for crew and equipment scheduling.
Phase 4: Acceptance Testing
- Validate standard services (Mowing, Mulch, Tree Trimming) to verify 0 regressions.
- Run the 50 LF $\times$ 4 FT test case to verify exact
$15,927.00calculation.