14 KiB
Estimating Extension Design
Date: 2026-03-13
Related workbook: samples/CGIBreakdown_Template/Template_CGI-Breakdown+Calc_25Dez_V0.976_251212_beta_LCR-Update.xlsx
Purpose: Canonical design, field mapping, and implementation plan for a browser-based estimating system in CapaKraken.
Executive Summary
The workbook is not a simple calculator. It is a full estimating and pricing system with:
- project and commercial assumptions
- scope breakdown for shots and assets
- roster and rate lookups
- phased effort and cost calculations
- management summaries
- downstream export sheets
CapaKraken can support this, but not by copying Excel cell logic into the browser. The right implementation is a dedicated estimating bounded context with:
- a wizard for first-pass estimate creation
- a workspace for iterative revisions
- a typed calculation pipeline
- live linkage to CapaKraken resources and roles
- immutable snapshots for auditability
Design Principles
1. Do not emulate Excel
The workbook contains very large formula surfaces, including roughly 823k formula cells in CALC_AUX alone. Rebuilding that as browser spreadsheet emulation would preserve the current maintenance problem instead of solving it.
The replacement should be:
- typed
- stage-based
- versioned
- testable
- explainable
2. Reuse the current platform where it already fits
Useful existing CapaKraken primitives:
Resourcefor roster, rates, skills, availability, and dynamic metadataProjectfor schedule, budget, and project linkageRolefor assignment and capability alignment- blueprint-driven fields for temporary bridge data where first-class models do not yet exist
3. Keep estimating separate from operational staffing
Estimating answers:
- what work is assumed
- what rates and policies apply
- what cost, price, and margin result
Operational planning answers:
- who is actually assigned
- when capacity is consumed
- how delivery is staffed in reality
DemandRequirement and Assignment are downstream execution data, not the primary estimating store.
Product Shape
Estimate Wizard
The wizard should generate the first complete draft through structured steps:
- Opportunity and project shell
- Scope breakdown
- Commercial assumptions
- Staffing strategy
- Rate and resource matching
- Financial review
- Export and approval
Estimate Workspace
After the wizard, the user should move into a workspace with tabs:
OverviewScope BreakdownAssumptionsRates & ResourcesStaffing / PhasingFinancialsExportsVersion Compare
This replaces the giant spreadsheet with a clearer domain-oriented UI.
Workbook Domains
The analyzed workbook combines several distinct domains:
- input and assumption sheets such as
ProjectInfo,Shots&Assets_Breakdown,ratesBreakdown, andRessource Roster MASTER - reference catalogs such as
ExperienceAdjust,Packages,IT Rate card,machine_rates,FX, andRates ACN - derived engine sheets such as
Calculation,CALC_AUX,4Dispo,SAP Phasing, andMMP Import - management and reporting views such as
Overview_*,Cockpit,Analytics, andPer Year
That mix is exactly why the app needs separated models for assumptions, scope, demand, rates, snapshots, outputs, and exports.
Proposed Domain Model
New bounded context: Estimating
| Model | Purpose |
|---|---|
Estimate |
Top-level estimate container tied to a project or opportunity |
EstimateVersion |
Versioning, options, baselines, approvals, and locked commercial states |
EstimateAssumption |
Structured commercial, tax, pricing, and scenario inputs |
ScopeItem |
Scope rows imported or authored from the breakdown sheet |
ScopeEffortRule |
Rules that turn scope into discipline effort |
EstimateDemandLine |
Normalized effort lines with phasing and pricing attributes |
RateCard |
Versioned pricing and cost catalog |
RateCardLine |
Attribute-based rate resolution entries |
ResourceCostSnapshot |
Immutable copy of roster/rate facts used by one estimate version |
EstimateMetric |
Persisted derived totals for fast reads and auditability |
EstimateExport |
Stored export artifacts and serializer metadata |
Reuse strategy
| Existing model | Reuse level | How it fits |
|---|---|---|
Project |
Direct |
Parent linkage, timeline context, budget bridge |
Resource |
Direct |
Roster, chapter, role, LCR/UCR, skill and availability context |
Role |
Direct |
Demand-line role alignment and staffing suggestions |
DemandRequirement / Assignment |
Downstream |
Planning handoff target after estimate approval |
dynamicFields / blueprints |
Bridge only |
Short-term bridge for unmigrated metadata, not core estimate storage |
Mapping Strategy
Mapping legend
Direct: already maps to an existing first-class CapaKraken fieldBridge: can be bridged short-term, but should move to estimating modelsDerived: calculate it, do not persist it as manual source dataNew Model: requires estimating schema
Project and commercial inputs
| Workbook field | Current target | Status | Recommended target |
|---|---|---|---|
| Project Name | Project.name |
Direct |
keep on Project, mirror into Estimate.name |
| Opportunity ID | project dynamic field | Bridge |
Estimate.opportunityId |
| Timeframe From / To | Project.startDate / Project.endDate |
Direct |
default estimate context from project |
| Currency | project/resource bridge only | Bridge |
Estimate.baseCurrency |
| Contract Owner / Business Unit / Service Group | none | New Model |
EstimateAssumption.* |
| Pricing Structure | partly Project.orderType |
Bridge |
EstimateAssumption.pricingStructure |
| Revenue Timing / Recognition | none | New Model |
EstimateAssumption.* |
| Sales Tax / Billing Arrears / Payment Terms | none | New Model |
EstimateAssumption.* |
| Contingency / Capital Charge / Mgmt Fee policies | none | New Model |
EstimateAssumption.* |
Scope breakdown inputs
| Workbook field | Current target | Status | Recommended target |
|---|---|---|---|
| Row sequence, type, package | none | New Model |
ScopeItem.sequenceNo, scopeType, packageCode |
| Description, scene, page, location | coarse project notes only | New Model |
ScopeItem.* |
| Assumptions / comments | none | New Model |
ScopeItem.assumptionCategory, internalComments |
| Resolution / FPS / aspect / shot length | project dynamic fields only | Bridge |
ScopeItem.technicalSpec JSON |
| Frame count / count / unit mode | limited bridge only | Bridge |
ScopeItem.frameCount, count, unitMode |
| Discipline effort columns | none | New Model |
generated EstimateDemandLine rows |
| Total costs on the breakdown sheet | none | Derived |
EstimateMetric |
Resource, rate, and lookup data
| Workbook field | Current target | Status | Recommended target |
|---|---|---|---|
| Roster employee/name | Resource.displayName / eid |
Bridge |
link to Resource plus snapshot source text |
| UCR / LCR | Resource.ucrCents / lcrCents |
Direct |
direct reuse plus snapshot |
| FTE | indirect only | Bridge |
ResourceCostSnapshot.fte |
| Level / work type / area | dynamic fields only | Bridge |
normalize later, snapshot now |
| Location / country | dynamic bridge only | Bridge |
snapshot + demand-line attributes |
| Rates ACN / rate breakdown / machine / FX | none | New Model |
RateCard, RateCardLine, FX/rule tables |
| Experience adjustments | none | New Model |
rate adjustment rules |
Calculation, phasing, and exports
| Workbook field group | Current target | Status | Recommended target |
|---|---|---|---|
| Calculation line items | none | New Model |
EstimateDemandLine |
| Named resource references | Assignment.resourceId via planning handoff |
Direct |
linked demand line + resource snapshot |
| Dates, hours, bill code, org unit, economic profile | none | New Model |
EstimateDemandLine.* |
| Monthly spread | none | New Model |
EstimateDemandLine.monthlySpread |
Weekly phasing (4Dispo) |
none | Derived |
generated projection view |
CALC_AUX transformed outputs |
none | Derived |
derived from demand lines and snapshots |
MMP Import / external export sheets |
none | New Model |
serializer output + EstimateExport |
| Cockpit / analytics totals | none | Derived |
persisted EstimateMetric rows |
Browser Architecture
Calculation engine
Implement a typed calculation pipeline in packages/engine:
- validate assumptions and scope
- resolve effort rules into demand lines
- resolve roster/rate snapshots
- calculate phased costs, prices, and metrics
- materialize outputs for UI and export
This should be deterministic and test-first. Manual overrides must be explicit and traceable.
Resource-connected behavior
The browser system can stay dynamic and resource-connected if it uses two data modes at once:
- live links to
ResourceandRolefor current matching and suggestion UX - immutable snapshots on
EstimateVersionfor pricing, auditability, and approval history
That prevents old approved estimates from changing when roster rates or metadata are edited later.
Implementation Plan
Phase 1. Schema and contracts
- add
Estimate,EstimateVersion,EstimateAssumption,ScopeItem,EstimateDemandLine,RateCard,RateCardLine,ResourceCostSnapshot,EstimateMetric, andEstimateExport - define DTOs and use cases in
packages/application - create engine contracts and test fixtures
Phase 2. Wizard and workspace
- build the estimate wizard
- add estimate workspace routes and tabs
- support import from workbook-derived source data where useful
Phase 3. Calculation and pricing
- implement rule engine for scope-to-effort conversion
- add rate resolution and cost/price calculations
- persist metrics and audit trail
Phase 4. Resource linkage and planning handoff
- connect demand lines to resources, roles, and availability
- add staffing suggestions from current CapaKraken data
- support conversion from approved estimate demand into downstream planning entities
Phase 5. Exports and approvals
- generate external export formats
- add version compare, lock, approval, and audit views
Current Status
This is no longer design-only.
Implemented baseline in the current codebase:
- estimating Prisma schema and enums
- shared estimate types and validation schemas
- engine-level summary metric helper
- application-layer estimate creation and retrieval use-cases
- estimate API router registration
- estimates list route and first estimate creation wizard
- estimate workspace detail route with overview, assumptions, scope, staffing, versions, and exports tabs
- working-draft editor for overview, assumptions, scope, and staffing
- version submit, approve, and locked revision-cloning actions
- export artifact scaffolding with stored serializer metadata records
- format-specific export generation with stored payloads for JSON, CSV, XLSX, SAP, and MMP
- live resource-linked staffing rows that can sync current CapaKraken rates and persist estimate-version snapshots
- explicit live-vs-manual rate mode metadata on demand lines, with server-side recalculation before metrics are persisted
- read-only and draft workspace visibility for manual overrides versus live resource snapshots
- project snapshot persistence on estimate versions
- approved-version planning handoff into downstream
DemandRequirementandAssignmentrecords, with estimate lineage metadata - scope import from XLSX in the estimate wizard
- financials tab in the estimate workspace with summary cards, cost-to-price bridge, chapter breakdown, and monthly phasing
- rate cards with per-client association and client filter in the admin UI
Still open:
- estimate templates and cloning for recurring project types
- richer version comparison (side-by-side diff of demand lines and metrics)
- approval email notifications
- scope-to-effort rule engine (currently manual demand lines only)
- rate adjustment rules and experience multipliers
Planning Handoff Model
The demand/assignment persistence split is complete. The legacy Allocation table has been dropped.
Current behavior
Approved estimate versions hand off like this:
- one
DemandRequirementis created per normalized estimate demand line - if a linked resource is valid, an
Assignmentis created linked to that demand - if no valid resource is available, the demand stays open with the suggested resource stored in metadata
- estimate provenance is preserved on both records through
estimateHandoffmetadata
Estimate-to-planning mapping
| Estimate source | DemandRequirement target | Assignment target | Notes |
|---|---|---|---|
Estimate.projectId + approved version |
projectId |
projectId |
direct |
EstimateDemandLine.id |
metadata.estimateHandoff.estimateDemandLineId |
same | provenance |
EstimateDemandLine.name |
role or demand title |
copied display metadata | readable context |
EstimateDemandLine.roleId |
roleId |
optional copied roleId | direct when present |
EstimateDemandLine.resourceId |
metadata.suggestedResourceId when open |
resourceId when assigned |
demand vs assignment split eliminates nullable-resource ambiguity |
EstimateDemandLine.hours + project window |
hoursPerDay, percentage, headcount |
hoursPerDay, percentage |
reused derivation logic |
EstimateDemandLine.fte |
headcount |
not needed | demand owns quantity |
| rate and price totals | metadata snapshot | metadata snapshot | preserve auditability |
| staffing attributes / monthly spread | metadata | metadata | direct carry-over |
The workbook mapping is feasible. The estimating product covers wizard creation, workspace editing, version management, export generation, and planning handoff. Remaining work focuses on templates, richer comparison, and the scope-to-effort rule engine.