Skip to main content

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:

  1. ScenarioId has been removed from Energy, Reaction, Quality, Status models
  2. Energy model simplified to global settings only (pump properties removed)
  3. LinkProperty and NodeProperty models created for generic property storage
  4. Pump, Valve, Tank properties moved to LinkProperty/NodeProperty tables

📊 Scope Summary

CategoryCountEffortPriority
DTOs to Update2 (Energy, Reaction)1-2 hours🔴 HIGH
DTOs to Keep3 (Pump, Valve, Tank)0 hours✅ No change
Controllers to Update5 (Energy, Reaction, Pump, Valve, Tank)6-8 hours🔴 HIGH
New Controllers0-2 (optional)0-3 hours🟢 OPTIONAL
New DTOs0-2 (optional)0-1 hours🟢 OPTIONAL
TestingAll endpoints2-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 properties
  • UpdateEnergyRequest - 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 ScenarioId
  • UpdateReactionRequest - 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, EPattern properties, 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:

  • Status property 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:

  • InitQual and BulkCoeff removed from Tank model
  • MixingModel handled 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

ControllerChangesPriorityEffort
EnergyControllerRemove ScenarioId, pump properties🔴 HIGH1 hour
ReactionControllerRemove ScenarioId🔴 HIGH30 min
PumpControllerJOIN LinkProperty, embed in DTO🔴 HIGH2 hours
ValveControllerJOIN LinkProperty, embed in DTO🔴 HIGH1 hour
TankControllerJOIN NodeProperty, embed in DTO🔴 HIGH2 hours
QualityControllerRemove ScenarioId, query NodeProperty🟡 MEDIUM1 hour
StatusControllerRemove ScenarioId, query LinkProperty🟡 MEDIUM1 hour
LeakageControllerRemove ScenarioId🟡 MEDIUM30 min
EmitterControllerRemove ScenarioId🟡 MEDIUM30 min
OptionsControllerRemove ScenarioId (if exists)🟡 MEDIUM30 min
TimeParametersControllerRemove ScenarioId (if exists)🟡 MEDIUM30 min
ReportControllerRemove ScenarioId (if exists)🟡 MEDIUM30 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:

  1. Energy Endpoint:

    • GET /api/energy → Returns single global record
    • POST /api/energy → Creates global settings only
    • Verify no ScenarioId, no pump properties
  2. 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
  3. NodeProperties Endpoint:

    • GET /api/en2/nodeproperties?nodeId=T-1 → Returns tank properties
    • GET /api/en2/nodeproperties?propertyId=4 → Returns all INITQUAL properties
  4. 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)

  1. ✅ Update EnergyDto (remove ScenarioId, pump properties)
  2. ✅ Update ReactionDto (remove ScenarioId)
  3. ✅ Create LinkPropertyDto
  4. ✅ Create NodePropertyDto

Day 3: New Controllers

  1. ✅ Create LinkPropertiesController
  2. ✅ Create NodePropertiesController
  3. ✅ Test basic CRUD operations

Day 4: Update Existing Controllers

  1. ✅ Update EnergyController
  2. ✅ Update ReactionController
  3. ⚠️ Assess Quality/Status/Leakage/Emitter controllers
  4. ✅ Update any other controllers with ScenarioId

Day 5: Testing & Documentation

  1. ✅ Integration testing
  2. ✅ Update Swagger documentation
  3. ✅ Update API documentation
  4. ✅ Update CHANGELOG

Rollback Plan

If issues arise:

  1. Keep old DTOs - Create new DTOs with "V2" suffix
  2. Version endpoints - /api/v2/energy, etc.
  3. Gradual migration - Support both old and new for transition period

Breaking Changes

⚠️ These are BREAKING CHANGES for API consumers:

  1. Energy endpoint:

    • No longer accepts/returns ScenarioId
    • No longer accepts/returns PumpId, PumpPrice, PumpPattern, PumpEfficiency
    • Returns single global record (or very few records)
  2. Reaction endpoint:

    • No longer accepts/returns ScenarioId
  3. 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

  1. Create feature branch: feature/api-model-redesign
  2. Start with DTOs: Low risk, high value
  3. Create new controllers: Independent, can be tested separately
  4. Update existing controllers: Higher risk, careful testing
  5. Integration testing: End-to-end validation
  6. Code review: Team review before merge
  7. Deploy to dev: Test in development environment
  8. Frontend coordination: Ensure frontend adapts
  9. 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 ✅