package team import ( "github.com/damirmukimov/city_resource_graph/models/params" ) // TeamMember represents a single team member with role and salary. type TeamMember struct { Role string `json:"role" yaml:"role"` // e.g., "backend_engineer", "frontend_engineer" Salary float64 `json:"salary" yaml:"salary"` // Annual salary in EUR } // TeamComposition defines team composition for a given year. type TeamComposition struct { BackendEngineers int `json:"backend_engineers" yaml:"backend_engineers"` // Number of backend engineers FrontendEngineers int `json:"frontend_engineers" yaml:"frontend_engineers"` // Number of frontend engineers DevOpsEngineers int `json:"devops_engineers" yaml:"devops_engineers"` // Number of DevOps engineers DataEngineers int `json:"data_engineers" yaml:"data_engineers"` // Number of data engineers CTO int `json:"cto" yaml:"cto"` // Number of CTOs (typically 1) BDSales int `json:"bd_sales" yaml:"bd_sales"` // Number of BD/Sales managers DomainExperts int `json:"domain_experts" yaml:"domain_experts"` // Number of domain experts CustomerSuccess int `json:"customer_success" yaml:"customer_success"` // Number of customer success Operations int `json:"operations" yaml:"operations"` // Number of operations staff Total int `json:"total" yaml:"total"` // Total team size } // Salaries defines annual salary for each role. type Salaries struct { BackendEngineer float64 `json:"backend_engineer" yaml:"backend_engineer"` // Annual salary in EUR FrontendEngineer float64 `json:"frontend_engineer" yaml:"frontend_engineer"` // Annual salary in EUR DevOpsEngineer float64 `json:"devops_engineer" yaml:"devops_engineer"` // Annual salary in EUR DataEngineer float64 `json:"data_engineer" yaml:"data_engineer"` // Annual salary in EUR CTO float64 `json:"cto" yaml:"cto"` // Annual salary in EUR BDSales float64 `json:"bd_sales" yaml:"bd_sales"` // Annual salary in EUR DomainExpert float64 `json:"domain_expert" yaml:"domain_expert"` // Annual salary in EUR CustomerSuccess float64 `json:"customer_success" yaml:"customer_success"` // Annual salary in EUR Operations float64 `json:"operations" yaml:"operations"` // Annual salary in EUR } // DefaultSalaries returns default salaries for each role. func DefaultSalaries() Salaries { return Salaries{ BackendEngineer: 100000, // €100k/year FrontendEngineer: 100000, // €100k/year DevOpsEngineer: 100000, // €100k/year DataEngineer: 100000, // €100k/year CTO: 120000, // €120k/year BDSales: 100000, // €100k/year DomainExpert: 90000, // €90k/year CustomerSuccess: 70000, // €70k/year Operations: 70000, // €70k/year } } // CalculateTeamCosts computes total personnel costs for a team composition. func CalculateTeamCosts(composition TeamComposition, salaries Salaries) float64 { var total float64 total += float64(composition.BackendEngineers) * salaries.BackendEngineer total += float64(composition.FrontendEngineers) * salaries.FrontendEngineer total += float64(composition.DevOpsEngineers) * salaries.DevOpsEngineer total += float64(composition.DataEngineers) * salaries.DataEngineer total += float64(composition.CTO) * salaries.CTO total += float64(composition.BDSales) * salaries.BDSales total += float64(composition.DomainExperts) * salaries.DomainExpert total += float64(composition.CustomerSuccess) * salaries.CustomerSuccess total += float64(composition.Operations) * salaries.Operations return total } // CalculateTeamCostsFromParams computes team costs using params structure. // This bridges the old CostParams (engineers count + salary) to new team structure. func CalculateTeamCostsFromParams(year int, p *params.Params, salaries Salaries) (float64, TeamComposition) { // Get total engineers from params totalEngineers := p.Costs.Engineers.GetYear(year) // Default distribution (can be overridden in params.yaml) composition := TeamComposition{ BackendEngineers: int(float64(totalEngineers) * 0.5), // 50% backend FrontendEngineers: int(float64(totalEngineers) * 0.25), // 25% frontend DevOpsEngineers: int(float64(totalEngineers) * 0.125), // 12.5% DevOps DataEngineers: int(float64(totalEngineers) * 0.125), // 12.5% data CTO: 1, // 1 CTO BDSales: 1, // 1 BD/Sales DomainExperts: 2, // 2 domain experts CustomerSuccess: 0, // 0 initially, grows over time Operations: 0, // 0 initially } // Adjust to match total engineers (distribute remaining) allocated := composition.BackendEngineers + composition.FrontendEngineers + composition.DevOpsEngineers + composition.DataEngineers if allocated < totalEngineers { // Add remaining to backend engineers composition.BackendEngineers += totalEngineers - allocated } composition.Total = totalEngineers + composition.CTO + composition.BDSales + composition.DomainExperts + composition.CustomerSuccess + composition.Operations // Calculate costs totalCost := CalculateTeamCosts(composition, salaries) return totalCost, composition } // GetYearlyTeamComposition returns team composition for a given year. // This can be extended to read from params.yaml if team structure is defined there. func GetYearlyTeamComposition(year int, p *params.Params) TeamComposition { salaries := DefaultSalaries() _, composition := CalculateTeamCostsFromParams(year, p, salaries) // Adjust based on year (team grows over time) if year >= 2 { composition.CustomerSuccess = 1 // Add customer success in year 2+ } if year >= 3 { composition.Operations = 1 // Add operations in year 3+ } return composition }