API Model Redesign Implementation Plan
🎯 KEY STRATEGY: Hide Implementation, Expose Domain
DECISION: Frontend will NOT know about LinkProperty/NodeProperty tables.
APPROACH:
- ✅ Pump/Valve/Tank DTOs KEEP all their properties (InitStatus, InitSetting, HCurve, etc.)
- ✅ Controllers JOIN LinkProperty/NodeProperty tables and map to DTO fields
- ✅ Frontend code doesn't change - same API contract, different implementation
- ⚠️ Generic property endpoints are OPTIONAL - only for advanced admin tools
WHY:
- Frontend works with domain concepts (Pump, Valve, Tank), not database tables
- Better encapsulation - database schema is hidden
- Simpler frontend code - one API call per resource
- Standard REST practice - resources, not tables
- Backward compatible - similar API contract
Overview
This document outlines the specific changes required to dwd-api-aspnet to support the EN2Models redesign where:
- ScenarioId has been removed from Energy, Reaction, Quality, Status models
- Energy model simplified to global settings only (pump properties removed)
- LinkProperty and NodeProperty models created for generic property storage
- Pump, Valve, Tank properties moved to LinkProperty/NodeProperty tables
📊 Scope Summary
| Category | Count | Effort | Priority |
|---|---|---|---|
| DTOs to Update | 2 (Energy, Reaction) | 1-2 hours | 🔴 HIGH |
| DTOs to Keep | 3 (Pump, Valve, Tank) | 0 hours | ✅ No change |
| Controllers to Update | 5 (Energy, Reaction, Pump, Valve, Tank) | 6-8 hours | 🔴 HIGH |
| New Controllers | 0-2 (optional) | 0-3 hours | 🟢 OPTIONAL |
| New DTOs | 0-2 (optional) | 0-1 hours | 🟢 OPTIONAL |
| Testing | All endpoints | 2-3 hours | 🔴 HIGH |
| TOTAL (Required) | 9-13 hours | ||
| TOTAL (with Optional) | 9-17 hours |
Phase 1: DTO Updates (4-6 hours)
1.1 EnergyDto.cs ✅ Priority 1
File: Models/DTOs/EnergyDto.cs
Changes Required:
Remove Properties:
// ❌ DELETE - ScenarioId no longer exists
public int? ScenarioId { get; set; }
// ❌ DELETE - Pump-specific properties removed from Energy model
public string? PumpId { get; set; }
public double? PumpPrice { get; set; }
public string? PumpPattern { get; set; }
public string? PumpEfficiency { get; set; }
Keep Properties:
// ✅ KEEP - Global settings only
public int Id { get; set; }
public double? GlobalPrice { get; set; }
public string? GlobalPattern { get; set; }
public double? GlobalEfficiency { get; set; }
public double? DemandCharge { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? ModifiedAt { get; set; }
Also Update:
CreateEnergyRequest- Remove ScenarioId, PumpId, pump propertiesUpdateEnergyRequest- Remove PumpId, pump properties
Note: Pump energy properties (ECost, ECurve, EPattern) are now in Pump model as properties. They'll be accessed via the Pump endpoint or new LinkProperties endpoint.
1.2 ReactionDto.cs ✅ Priority 1
File: Models/DTOs/ReactionDto.cs
Changes Required:
Remove:
// ❌ DELETE - ScenarioId no longer exists
public int? ScenarioId { get; set; }
Keep:
// ✅ KEEP - All other properties remain
public int Id { get; set; }
public double? BulkOrder { get; set; }
public double? WallOrder { get; set; }
public double? TankOrder { get; set; }
public double? GlobalBulk { get; set; }
public double? GlobalWall { get; set; }
public double? LimitingPotential { get; set; }
public double? RoughnessCorrelation { get; set; }
// ... etc
Also Update:
CreateReactionRequest- Remove ScenarioIdUpdateReactionRequest- No ScenarioId to remove
1.3 QualityDto.cs ✅ Priority 2
File: Models/DTOs/QualityDto.cs
Changes Required:
Remove:
// ❌ DELETE - ScenarioId no longer exists
public int? ScenarioId { get; set; }
Keep:
// ✅ KEEP - All other properties
public int Id { get; set; }
public string NodeId { get; set; }
public double? InitialQuality { get; set; }
// ... etc
Note: Quality values are now in NodeProperty table. This DTO might need to be deprecated or repurposed.
1.4 StatusDto.cs ✅ Priority 2
File: Models/DTOs/StatusDto.cs
Changes Required:
Remove:
// ❌ DELETE - ScenarioId no longer exists
public int? ScenarioId { get; set; }
Keep:
// ✅ KEEP - All other properties
public int Id { get; set; }
public string LinkId { get; set; }
public string? StatusValue { get; set; }
// ... etc
Note: Status values are now in LinkProperty table. This DTO might need to be deprecated or repurposed.
1.5 LeakageDto.cs ✅ Priority 2
File: Models/DTOs/LeakageDto.cs
Changes Required:
Remove:
// ❌ DELETE - ScenarioId if it exists
public int? ScenarioId { get; set; }
Note: Leakage values are now in LinkProperty table. This DTO might need to be deprecated or repurposed.
1.6 EmitterDto.cs ✅ Priority 2
File: Models/DTOs/EmitterDto.cs
Changes Required:
Remove:
// ❌ DELETE - ScenarioId if it exists
public int? ScenarioId { get; set; }
Note: Emitter values are now in NodeProperty table. This DTO might need to be deprecated or repurposed.
1.7 PumpDto.cs ⚠️ Assessment Needed
File: Models/DTOs/PumpDto.cs
Current State: Check if it contains pump-specific energy properties
Possible Changes:
- If it has
ECost,ECurve,EPatternproperties, these are now in Pump model (kept) - If it has
InitStatus,InitSetting,Pattern,HCurve- these may need to be removed or handled differently
Action: Read file and assess
1.8 ValveDto.cs ⚠️ Assessment Needed
File: Models/DTOs/ValveDto.cs
Current State: Check if it contains Status property
Possible Changes:
Statusproperty removed from Valve model- May need to add property collection or reference
Action: Read file and assess
1.9 TankDto.cs ⚠️ Assessment Needed
File: Models/DTOs/TankDto.cs
Current State: Check if it contains InitQual, BulkCoeff, MixingModel properties
Possible Changes:
InitQualandBulkCoeffremoved from Tank modelMixingModelhandled by TankMixing table
Strategy: NO CHANGES NEEDED
Tank properties (InitQual, BulkCoeff) stored in NodeProperty table will be embedded in TankDto. MixingModel is already handled by TankMixing table (separate model, already working).
Action: Controller will JOIN NodeProperty and map to DTO fields
Phase 2: New DTOs (OPTIONAL - Skip for Now)
DECISION: Skip creating LinkPropertyDto/NodePropertyDto unless needed for advanced tools.
Note: These DTOs are optional - only needed if you want generic property endpoints for advanced scenarios.
2.1 LinkPropertyDto.cs ⚠️ OPTIONAL
File: Models/DTOs/LinkPropertyDto.cs
Use Case: Only for advanced property editor tools, not for normal frontend operations
Create New:
using System.ComponentModel.DataAnnotations;
namespace DwdApiAspNet.Models.DTOs
{
/// <summary>
/// Data Transfer Object for LinkProperty entities.
/// Represents generic link properties stored by PropertyId (EPANET enum values).
/// </summary>
public class LinkPropertyDto
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gets or sets the link identifier.
/// </summary>
[Required]
[StringLength(31)]
public string LinkId { get; set; }
/// <summary>
/// Gets or sets the property identifier (EN_LinkProperty enum value).
/// </summary>
[Required]
public int PropertyId { get; set; }
/// <summary>
/// Gets or sets the property name (for display).
/// </summary>
public string? PropertyName { get; set; }
/// <summary>
/// Gets or sets the property value.
/// </summary>
[Required]
public double PropertyValue { get; set; }
/// <summary>
/// Gets or sets the creation timestamp.
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// Gets or sets the last modification timestamp.
/// </summary>
public DateTime? ModifiedAt { get; set; }
}
/// <summary>
/// Request model for creating/updating link properties.
/// </summary>
public class UpsertLinkPropertyRequest
{
[Required]
[StringLength(31)]
public string LinkId { get; set; }
[Required]
public int PropertyId { get; set; }
[Required]
public double PropertyValue { get; set; }
}
}
2.2 NodePropertyDto.cs ✅ NEW
File: Models/DTOs/NodePropertyDto.cs
Create New:
using System.ComponentModel.DataAnnotations;
namespace DwdApiAspNet.Models.DTOs
{
/// <summary>
/// Data Transfer Object for NodeProperty entities.
/// Represents generic node properties stored by PropertyId (EPANET enum values).
/// </summary>
public class NodePropertyDto
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gets or sets the node identifier.
/// </summary>
[Required]
[StringLength(31)]
public string NodeId { get; set; }
/// <summary>
/// Gets or sets the property identifier (EN_NodeProperty enum value).
/// </summary>
[Required]
public int PropertyId { get; set; }
/// <summary>
/// Gets or sets the property name (for display).
/// </summary>
public string? PropertyName { get; set; }
/// <summary>
/// Gets or sets the property value.
/// </summary>
[Required]
public double PropertyValue { get; set; }
/// <summary>
/// Gets or sets the creation timestamp.
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// Gets or sets the last modification timestamp.
/// </summary>
public DateTime? ModifiedAt { get; set; }
}
/// <summary>
/// Request model for creating/updating node properties.
/// </summary>
public class UpsertNodePropertyRequest
{
[Required]
[StringLength(31)]
public string NodeId { get; set; }
[Required]
public int PropertyId { get; set; }
[Required]
public double PropertyValue { get; set; }
}
}
2.3 PropertyMetadataDto.cs ✅ NEW (Optional)
File: Models/DTOs/PropertyMetadataDto.cs
Purpose: Provide metadata about available properties (for UI dropdowns, etc.)
namespace DwdApiAspNet.Models.DTOs
{
/// <summary>
/// Metadata about an EPANET property.
/// </summary>
public class PropertyMetadataDto
{
public int PropertyId { get; set; }
public string PropertyName { get; set; }
public string Description { get; set; }
public string Unit { get; set; }
public double? DefaultValue { get; set; }
public string Category { get; set; } // "Link" or "Node"
}
}
Phase 3: New Controllers (2-3 hours) - OPTIONAL
Note: These controllers are optional - only create if you need generic property access for admin tools.
3.1 LinkPropertiesController.cs ⚠️ OPTIONAL (Low Priority)
File: Controllers/EN2/LinkPropertiesController.cs
Use Case: For property editors, bulk operations, admin tools
Endpoints:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using DwdApiAspNet.Models.DTOs;
using EN2Models;
namespace DwdApiAspNet.Controllers.EN2
{
/// <summary>
/// Controller for managing link properties.
/// </summary>
[ApiController]
[Route("api/en2/[controller]")]
public class LinkPropertiesController : ControllerBase
{
private readonly EN2PostgresContext.EN2PostgresContext _context;
public LinkPropertiesController(EN2PostgresContext.EN2PostgresContext context)
{
_context = context;
}
/// <summary>
/// Gets all link properties, optionally filtered by LinkId and/or PropertyId.
/// </summary>
/// <param name="linkId">Optional link identifier filter</param>
/// <param name="propertyId">Optional property identifier filter</param>
[HttpGet]
public async Task<ActionResult<IEnumerable<LinkPropertyDto>>> GetLinkProperties(
[FromQuery] string? linkId = null,
[FromQuery] int? propertyId = null)
{
var query = _context.LinkProperties.AsQueryable();
if (!string.IsNullOrEmpty(linkId))
query = query.Where(lp => lp.LinkId == linkId);
if (propertyId.HasValue)
query = query.Where(lp => lp.PropertyId == propertyId.Value);
var properties = await query.ToListAsync();
return Ok(properties.Select(MapToDto));
}
/// <summary>
/// Gets a specific link property by ID.
/// </summary>
[HttpGet("{id}")]
public async Task<ActionResult<LinkPropertyDto>> GetLinkProperty(int id)
{
var property = await _context.LinkProperties.FindAsync(id);
if (property == null)
return NotFound();
return Ok(MapToDto(property));
}
/// <summary>
/// Gets all properties for a specific link.
/// </summary>
[HttpGet("link/{linkId}")]
public async Task<ActionResult<IEnumerable<LinkPropertyDto>>> GetPropertiesByLink(string linkId)
{
var properties = await _context.LinkProperties
.Where(lp => lp.LinkId == linkId)
.ToListAsync();
return Ok(properties.Select(MapToDto));
}
/// <summary>
/// Creates or updates a link property.
/// </summary>
[HttpPost]
public async Task<ActionResult<LinkPropertyDto>> UpsertLinkProperty(
[FromBody] UpsertLinkPropertyRequest request)
{
var existing = await _context.LinkProperties
.FirstOrDefaultAsync(lp =>
lp.LinkId == request.LinkId &&
lp.PropertyId == request.PropertyId);
if (existing != null)
{
// Update existing
existing.PropertyValue = request.PropertyValue;
existing.ModifiedAt = DateTime.UtcNow;
}
else
{
// Create new
var newProperty = new LinkProperty(
request.LinkId,
request.PropertyId,
request.PropertyValue);
_context.LinkProperties.Add(newProperty);
}
await _context.SaveChangesAsync();
var result = existing ?? await _context.LinkProperties
.FirstOrDefaultAsync(lp =>
lp.LinkId == request.LinkId &&
lp.PropertyId == request.PropertyId);
return Ok(MapToDto(result));
}
/// <summary>
/// Deletes a link property.
/// </summary>
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteLinkProperty(int id)
{
var property = await _context.LinkProperties.FindAsync(id);
if (property == null)
return NotFound();
_context.LinkProperties.Remove(property);
await _context.SaveChangesAsync();
return NoContent();
}
private LinkPropertyDto MapToDto(LinkProperty entity)
{
return new LinkPropertyDto
{
Id = entity.Id,
LinkId = entity.LinkId,
PropertyId = entity.PropertyId,
PropertyName = GetPropertyName(entity.PropertyId),
PropertyValue = entity.PropertyValue,
CreatedAt = entity.CreatedAt,
ModifiedAt = entity.ModifiedAt
};
}
private string GetPropertyName(int propertyId)
{
// Map PropertyId to friendly name
// Could use EnumMappingService or dictionary
return ((Epanet2Wrapper.EN_LinkProperty)propertyId).ToString();
}
}
}
3.2 NodePropertiesController.cs ✅ NEW
File: Controllers/EN2/NodePropertiesController.cs
Endpoints: (Similar structure to LinkPropertiesController)
// GET /api/en2/nodeproperties?nodeId={id}&propertyId={propId}
// GET /api/en2/nodeproperties/{id}
// GET /api/en2/nodeproperties/node/{nodeId}
// POST /api/en2/nodeproperties
// DELETE /api/en2/nodeproperties/{id}
Phase 4: Controller Updates - PRIMARY WORK (6-8 hours)
This is the main work - updating existing controllers to join and embed properties.
4.0 General Pattern for Asset Controllers
For all asset controllers (Pump, Valve, Tank), follow this pattern:
[HttpGet("{id}")]
public async Task<ActionResult<PumpDto>> GetPump(string id)
{
// 1. Get the core entity
var pump = await _context.Pumps.FirstOrDefaultAsync(p => p.Id == id);
if (pump == null) return NotFound();
// 2. Get all properties for this entity
var properties = await _context.LinkProperties
.Where(lp => lp.LinkId == id)
.ToDictionaryAsync(lp => lp.PropertyId, lp => lp.PropertyValue);
// 3. Map to DTO, embedding properties
return Ok(MapToDto(pump, properties));
}
private PumpDto MapToDto(Pump pump, Dictionary<int, double> properties)
{
return new PumpDto
{
Id = pump.Id,
FromNode = pump.FromNode,
ToNode = pump.ToNode,
// Embed properties from LinkProperty table
InitStatus = GetIntProperty(properties, EN_LinkProperty.EN_INITSTATUS),
InitSetting = GetProperty(properties, EN_LinkProperty.EN_INITSETTING),
Pattern = GetIntProperty(properties, EN_LinkProperty.EN_LINKPATTERN),
HCurve = GetIntProperty(properties, EN_LinkProperty.EN_PUMP_HCURVE),
ECurve = GetIntProperty(properties, EN_LinkProperty.EN_PUMP_ECURVE),
ECost = GetProperty(properties, EN_LinkProperty.EN_PUMP_ECOST),
EPattern = GetIntProperty(properties, EN_LinkProperty.EN_PUMP_EPAT),
CreatedAt = pump.CreatedAt,
ModifiedAt = pump.ModifiedAt
};
}
// Helper methods
private double? GetProperty(Dictionary<int, double> props, EN_LinkProperty prop)
{
return props.TryGetValue((int)prop, out var value) ? value : null;
}
private int? GetIntProperty(Dictionary<int, double> props, EN_LinkProperty prop)
{
return props.TryGetValue((int)prop, out var value) ? (int)value : null;
}
Phase 4: Controller Updates (3-4 hours)
4.1 EnergyController.cs ✅ Priority 1
File: Controllers/EN2/EnergyController.cs
Changes Required:
Update MapToDto:
private EnergyDto MapToDto(Energy entity)
{
return new EnergyDto
{
Id = entity.Id,
// ❌ REMOVE: ScenarioId = entity.ScenarioId,
GlobalPrice = entity.GlobalPrice,
GlobalPattern = entity.GlobalPattern,
GlobalEfficiency = entity.GlobalEfficiency,
DemandCharge = entity.DemandCharge,
// ❌ REMOVE: PumpId = entity.PumpId,
// ❌ REMOVE: PumpPrice = entity.PumpPrice,
// ❌ REMOVE: PumpPattern = entity.PumpPattern,
// ❌ REMOVE: PumpEfficiency = entity.PumpEfficiency,
CreatedAt = entity.CreatedAt,
ModifiedAt = entity.ModifiedAt
};
}
Update GET methods:
// Should return single global record or very few records
[HttpGet]
public async Task<ActionResult<IEnumerable<EnergyDto>>> GetEnergyParameters()
{
// No ScenarioId filter needed - there's only one global record
var energyParameters = await _context.Energy.ToListAsync();
return Ok(energyParameters.Select(MapToDto));
}
Update POST/PUT methods:
[HttpPost]
public async Task<ActionResult<EnergyDto>> CreateEnergyParameters(
[FromBody] CreateEnergyRequest request)
{
var energy = new Energy(); // No ScenarioId parameter
energy.GlobalPrice = request.GlobalPrice;
energy.GlobalPattern = request.GlobalPattern;
energy.GlobalEfficiency = request.GlobalEfficiency;
energy.DemandCharge = request.DemandCharge;
// ❌ REMOVE: No pump properties
_context.Energy.Add(energy);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetEnergyParameters),
new { id = energy.Id }, MapToDto(energy));
}
4.2 ReactionController.cs ✅ Priority 1
File: Controllers/EN2/ReactionController.cs
Changes Required:
- Update
MapToDto- Remove ScenarioId - Update POST method - Remove ScenarioId parameter
- No query filter changes needed (Reaction is still complex model)
4.3 QualityController.cs ⚠️ Assessment Needed
File: Controllers/EN2/QualityController.cs
Decision:
- Keep controller for backward compatibility?
- Deprecate and redirect to NodePropertiesController?
- Quality data is now in NodeProperty table
Recommendation: Keep but update to query NodeProperty table where PropertyId=4
Summary of Controller Updates
| Controller | Changes | Priority | Effort |
|---|---|---|---|
| EnergyController | Remove ScenarioId, pump properties | 🔴 HIGH | 1 hour |
| ReactionController | Remove ScenarioId | 🔴 HIGH | 30 min |
| PumpController | JOIN LinkProperty, embed in DTO | 🔴 HIGH | 2 hours |
| ValveController | JOIN LinkProperty, embed in DTO | 🔴 HIGH | 1 hour |
| TankController | JOIN NodeProperty, embed in DTO | 🔴 HIGH | 2 hours |
| QualityController | Remove ScenarioId, query NodeProperty | 🟡 MEDIUM | 1 hour |
| StatusController | Remove ScenarioId, query LinkProperty | 🟡 MEDIUM | 1 hour |
| LeakageController | Remove ScenarioId | 🟡 MEDIUM | 30 min |
| EmitterController | Remove ScenarioId | 🟡 MEDIUM | 30 min |
| OptionsController | Remove ScenarioId (if exists) | 🟡 MEDIUM | 30 min |
| TimeParametersController | Remove ScenarioId (if exists) | 🟡 MEDIUM | 30 min |
| ReportController | Remove ScenarioId (if exists) | 🟡 MEDIUM | 30 min |
Total: 11-12 hours
4.4 StatusController.cs ⚠️ Assessment Needed
File: Controllers/EN2/StatusController.cs
Decision:
- Keep controller for backward compatibility?
- Deprecate and redirect to LinkPropertiesController?
- Status data is now in LinkProperty table
Recommendation: Keep but add note that data is in LinkProperty table
4.5 LeakageController.cs ⚠️ Assessment Needed
File: Controllers/EN2/LeakageController.cs
Same as Status/Quality - assess deprecation vs. keeping
4.6 EmitterController.cs ⚠️ Assessment Needed
File: Controllers/EN2/EmitterController.cs
Same as Status/Quality - assess deprecation vs. keeping
4.7 OptionsController.cs ⚠️ Check for ScenarioId
File: Controllers/EN2/OptionsController.cs
Action: Check if Options model has ScenarioId, remove if present
4.8 TimeParametersController.cs ⚠️ Check for ScenarioId
File: Controllers/EN2/TimeParametersController.cs
Action: Check if TimeParameters model has ScenarioId, remove if present
4.9 ReportController.cs ⚠️ Check for ScenarioId
File: Controllers/EN2/ReportController.cs
Action: Check if Report model has ScenarioId, remove if present
Phase 5: Testing & Validation (2-3 hours)
5.1 Unit Tests (Optional)
Create tests for:
- LinkPropertiesController
- NodePropertiesController
- Updated EnergyController
- Updated DTOs
5.2 Integration Tests
Test Scenarios:
Energy Endpoint:
- GET /api/energy → Returns single global record
- POST /api/energy → Creates global settings only
- Verify no ScenarioId, no pump properties
LinkProperties Endpoint:
- GET /api/en2/linkproperties?linkId=Pump-1 → Returns pump properties
- GET /api/en2/linkproperties?propertyId=19 → Returns all HCURVE properties
- POST → Creates/updates property
NodeProperties Endpoint:
- GET /api/en2/nodeproperties?nodeId=T-1 → Returns tank properties
- GET /api/en2/nodeproperties?propertyId=4 → Returns all INITQUAL properties
Backward Compatibility:
- Test Quality, Status, Leakage, Emitter endpoints still work
- Verify data comes from correct tables
5.3 Manual Testing Checklist
- Swagger UI shows updated endpoints
- All GET endpoints return data
- POST/PUT work without ScenarioId
- No compilation errors
- No runtime exceptions
- Response DTOs match expected structure
Implementation Order
Day 1-2: DTOs (Priority 1)
- ✅ Update EnergyDto (remove ScenarioId, pump properties)
- ✅ Update ReactionDto (remove ScenarioId)
- ✅ Create LinkPropertyDto
- ✅ Create NodePropertyDto
Day 3: New Controllers
- ✅ Create LinkPropertiesController
- ✅ Create NodePropertiesController
- ✅ Test basic CRUD operations
Day 4: Update Existing Controllers
- ✅ Update EnergyController
- ✅ Update ReactionController
- ⚠️ Assess Quality/Status/Leakage/Emitter controllers
- ✅ Update any other controllers with ScenarioId
Day 5: Testing & Documentation
- ✅ Integration testing
- ✅ Update Swagger documentation
- ✅ Update API documentation
- ✅ Update CHANGELOG
Rollback Plan
If issues arise:
- Keep old DTOs - Create new DTOs with "V2" suffix
- Version endpoints - /api/v2/energy, etc.
- Gradual migration - Support both old and new for transition period
Breaking Changes
⚠️ These are BREAKING CHANGES for API consumers:
Energy endpoint:
- No longer accepts/returns ScenarioId
- No longer accepts/returns PumpId, PumpPrice, PumpPattern, PumpEfficiency
- Returns single global record (or very few records)
Reaction endpoint:
- No longer accepts/returns ScenarioId
Quality, Status, Leakage, Emitter:
- May be deprecated in favor of LinkProperties/NodeProperties
Mitigation:
- Document breaking changes
- Provide migration guide
- Consider versioned endpoints
- Coordinate with frontend team
Success Criteria
✅ Phase Complete When:
- All DTOs updated and compile
- New controllers created and functional
- Existing controllers updated
- No ScenarioId references remain
- All tests pass
- Documentation updated
- Frontend team notified of changes
Next Steps
- Create feature branch:
feature/api-model-redesign - Start with DTOs: Low risk, high value
- Create new controllers: Independent, can be tested separately
- Update existing controllers: Higher risk, careful testing
- Integration testing: End-to-end validation
- Code review: Team review before merge
- Deploy to dev: Test in development environment
- Frontend coordination: Ensure frontend adapts
- Production deployment: Coordinated release
Document Status: READY FOR IMPLEMENTATION 🚀
Owner: API Team Estimated Duration: 2-3 days (12-17 hours) Dependencies: efcorelibraries and epanetconsolecore updates complete ✅