> For the complete documentation index, see [llms.txt](https://docs.flexbase.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flexbase.in/solution-structure/getting-started/features/rest-services/soft-delete-example.md).

# Soft Delete Example

## Overview

This document demonstrates the complete **Soft Delete flow** using the **SoftDeleteShipping** feature from the EBusiness application. The flow starts with a DELETE request to the controller and ends with event publishing and subscriber processing. Soft delete marks the entity as deleted without physically removing it from the database.

## Complete Flow Architecture

```
DELETE Request → Controller → Service → PreBus Plugins → Command Handler → RESTClient → External System
                                                                                    ↓
Response ← Controller ← Service ← Command Handler ← RESTClient ← External System
```

### **Detailed Flow Breakdown**

```
1. DELETE Request
   ↓
2. Controller (API Entry Point)
   ↓
3. Service Layer (Business Orchestration)
   ↓
4. PreBus Processing (Validation Pipeline)
   ├── SoftDeleteShippingSequence (Plugin Registration)
   ├── SoftDeleteShippingDataPacket (Validation Context)
   └── IsValidShippingForSoftDelete Plugin (Business Rules)
   ↓
5. Command Handler (RESTClient Integration)
   ├── Internal DTO → Request DTO Mapping
   ├── RESTClient Call to External System
   └── Response DTO Processing
   ↓
6. Event Publishing (Asynchronous Processing)
   ↓
7. Subscribers (Side Effects)
```

## Step-by-Step Implementation

### 1. **API Controller** - The Entry Point

**File**: `ShippingController_SoftDeleteShipping.cs`

```csharp
[HttpDelete()]
[Route("SoftDeleteShipping/{id}")]
[ProducesResponseType(typeof(BadRequestResult), 400)]
[ProducesResponseType(typeof(string), 200)]
public async Task<IActionResult> SoftDeleteShipping(string id)
{
    SoftDeleteShippingDto dto = new SoftDeleteShippingDto();
    dto.Id = id;
    return await RunService(200, dto, _processShippingService.SoftDeleteShipping);
}
```

**What Happens:**

* **HTTP Method**: `DELETE /api/Shipping/SoftDeleteShipping/{id}`
* **Input**: Shipping ID from URL parameter
* **DTO Creation**: Creates `SoftDeleteShippingDto` with the ID
* **Action**: Calls the service layer to process the soft delete
* **Response**: HTTP 200 OK with success status

### 2. **Service Layer** - Business Orchestration

**File**: `ProcessShippingService_SoftDeleteShipping.cs`

```csharp
public async Task<CommandResult> SoftDeleteShipping(SoftDeleteShippingDto dto)
{
    var packet = await ProcessBusinessRuleSequence<SoftDeleteShippingDataPacket, SoftDeleteShippingSequence, SoftDeleteShippingDto, FlexAppContextBridge>(dto);

    if (packet.HasError)
    {
        return new CommandResult(Status.Failed, packet.Errors());
    }
    else
    {
        dto.SetGeneratedId(_pkGenerator.GenerateKey());
        SoftDeleteShippingCommand cmd = new SoftDeleteShippingCommand
        {
            Dto = dto,
        };

        await ProcessCommand(cmd);

        CommandResult cmdResult = new CommandResult(Status.Success);

        SoftDeleteShippingResultModel outputResult = new SoftDeleteShippingResultModel();
        cmdResult.result = outputResult;
        return cmdResult;
    }
}
```

**What Happens:**

* **PreBus Processing**: Executes business rule sequences (plugins)
* **Validation**: Processes business rule sequences
* **ID Generation**: Generates unique key for tracking
* **Command Creation**: Creates `SoftDeleteShippingCommand` with DTO
* **Command Processing**: Calls the command handler
* **Result**: Returns success status

### 2.1. **PreBus Business Rule Sequence** - Validation Pipeline

**File**: `SoftDeleteShippingSequence.cs`

```csharp
public class SoftDeleteShippingSequence : FlexiBusinessRuleSequenceBase<SoftDeleteShippingDataPacket>
{
    public SoftDeleteShippingSequence()
    {
        this.Add<IsValidShippingForSoftDelete>(); 
    }
}
```

**What Happens:**

* **Plugin Registration**: Registers validation plugins in execution order
* **Sequential Processing**: Executes plugins one by one
* **Error Collection**: Collects validation errors from all plugins
* **Early Exit**: Stops processing if any plugin fails

### 2.2. **PreBus Data Packet** - Validation Context

**File**: `SoftDeleteShippingDataPacket.cs`

```csharp
public partial class SoftDeleteShippingDataPacket : FlexiFlowDataPacketWithDtoBridge<SoftDeleteShippingDto, FlexAppContextBridge>
{
    protected readonly ILogger<SoftDeleteShippingDataPacket> _logger;

    public SoftDeleteShippingDataPacket(ILogger<SoftDeleteShippingDataPacket> logger)
    {
        _logger = logger;
    }

    #region "Properties
    //Models and other properties goes here
    #endregion
}
```

**What Happens:**

* **Context Container**: Holds DTO and application context
* **Error Collection**: Collects validation errors from plugins
* **Data Sharing**: Allows plugins to share data during validation
* **Logging**: Provides logging capabilities for plugins

### 2.3. **PreBus Validation Plugin** - Business Rules

**File**: `IsValidShippingForSoftDelete.cs`

```csharp
public partial class IsValidShippingForSoftDelete : FlexiBusinessRuleBase, IFlexiBusinessRule<SoftDeleteShippingDataPacket>
{
    public override string Id { get; set; } = "3a1cd5b1fa98b4c63378de9607706082";
    public override string FriendlyName { get; set; } = "IsValidShippingForSoftDelete";

    protected readonly ILogger<IsValidShippingForSoftDelete> _logger;
    protected readonly RepoFactory _repoFactory;

    public IsValidShippingForSoftDelete(ILogger<IsValidShippingForSoftDelete> logger, RepoFactory repoFactory)
    {
        _logger = logger;
        _repoFactory = repoFactory;
    }

    public virtual async Task Validate(SoftDeleteShippingDataPacket packet)
    {
        //Uncomment the below line if validating against a db data using your repo
        //_repoFactory.Init(packet.Dto);

        //If any validation fails, uncomment and use the below line of code to add error to the packet
        //packet.AddError("key", "ErrorMessage");

        await Task.CompletedTask; //If you have any await in the validation, remove this line
    }
}
```

**What Happens:**

* **Business Rule Validation**: Implements specific validation logic
* **Database Access**: Can access repository for data validation
* **Error Reporting**: Adds errors to the data packet if validation fails
* **Async Support**: Supports asynchronous validation operations
* **Dependency Injection**: Receives logger and repository factory

### 3. **Command Handler** - RESTClient Integration

**File**: `SoftDeleteShippingHandler.cs`

```csharp
public partial class SoftDeleteShippingHandler : ISoftDeleteShippingHandler
{
    protected string EventCondition = "";
    protected readonly ILogger<SoftDeleteShippingHandler> _logger;
    protected readonly IFlexHost _flexHost;
    protected ShippingRESTClient _restClient;
    protected FlexAppContextBridge? _flexAppContext;

    public SoftDeleteShippingHandler(ILogger<SoftDeleteShippingHandler> logger, IFlexHost flexHost, ShippingRESTClient restClient)
    {
        _logger = logger;
        _flexHost = flexHost;
        _restClient = restClient;
    }

    public virtual async Task Execute(SoftDeleteShippingCommand cmd, IFlexServiceBusContext serviceBusContext)
    {
        // Convert internal DTO to Request DTO
        SoftDeleteShippingRequestDto requestParams = new SoftDeleteShippingRequestDto
        {
            Id = cmd.Dto.Id,
            DeletionReason = cmd.Dto.DeletionReason ?? "User requested soft deletion",
            SoftDeleteFlag = true
        };

        // Call external REST service
        var response = await _restClient.SoftDeleteShipping(requestParams);

        // Process response
        if (response.IsSuccessStatusCode)
        {
            var responseContent = await response.Content.ReadAsStringAsync();
            var responseDto = JsonConvert.DeserializeObject<SoftDeleteShippingResponseDto>(responseContent);
            
            _logger.LogDebug("Shipping soft deleted successfully with external ID: {ExternalId}", responseDto?.Id);
            
            // Set success condition for event firing
            EventCondition = "CONDITION_ONSUCCESS";
        }
        else
        {
            _logger.LogError("Failed to soft delete shipping. Status: {StatusCode}", response.StatusCode);
            EventCondition = "CONDITION_ONFAILED";
        }

        await this.Fire(EventCondition, serviceBusContext);
    }
}
```

**What Happens:**

* **DTO Mapping**: Converts internal DTO to Request DTO for external system
* **RESTClient Call**: Calls external shipping service via RESTClient
* **Response Processing**: Handles success/failure responses from external system
* **Logging**: Logs success/failure of external service call
* **Event Publishing**: Fires events based on external service result

### 4. **Domain Model** - Business Logic

**File**: `Shipping/SoftDeleteShipping.cs`

```csharp
public virtual Shipping SoftDeleteShipping(SoftDeleteShippingCommand cmd)
{
    Guard.AgainstNull("Shipping model cannot be empty", cmd);

    this.Id = cmd.Dto.Id;
    this.SetSoftDeleted();

    //Set your appropriate SetSoftDeleted for the inner object here

    return this;
}
```

**What Happens:**

* **Validation**: Guards against null commands
* **ID Assignment**: Sets the shipping ID from DTO
* **State Management**: Marks entity as soft deleted
* **Child Objects**: Processes child object soft deletions

### 5. **NServiceBus Handler** - Message Processing

**File**: `SoftDeleteShippingNsbHandler.cs`

```csharp
public class SoftDeleteShippingNsbHandler : NsbCommandHandler<SoftDeleteShippingCommand>
{
    readonly ILogger<SoftDeleteShippingNsbHandler> _logger;
    readonly IFlexHost _flexHost;
    readonly ISoftDeleteShippingHandler _handler;

    public SoftDeleteShippingNsbHandler(ILogger<SoftDeleteShippingNsbHandler> logger, IFlexHost flexHost, ISoftDeleteShippingHandler handler)
    {
        _logger = logger;
        _flexHost = flexHost;
        _handler = handler;
    }

    public override async Task Handle(SoftDeleteShippingCommand message, IMessageHandlerContext context)
    {
        _logger.LogTrace($"Executing {nameof(SoftDeleteShippingNsbHandler)}");

        await _handler.Execute(message, new NsbHandlerContextBridge(context));
    }
}
```

**What Happens:**

* **Message Reception**: Receives `SoftDeleteShippingCommand` from message bus
* **Logging**: Logs handler execution
* **Delegation**: Calls the actual command handler
* **Context Bridge**: Converts NServiceBus context to FlexBase context

### 6. **Event Publishing** - Asynchronous Processing

**Event**: `ShippingSoftDeletedEvent` (if implemented)

```csharp
public class ShippingSoftDeletedEvent : FlexEventBridge<FlexAppContextBridge>
{
    // Event data is automatically populated by FlexBase
}
```

**What Happens:**

* **Event Creation**: FlexBase creates event with shipping data
* **Message Bus**: Event is published to message bus
* **Subscriber Notification**: All subscribers are notified

### 7. **Event Subscribers** - Side Effects

**File**: `NotifyLogisticsOnShippingSoftDeleted.cs` (if implemented)

```csharp
public partial class NotifyLogisticsOnShippingSoftDeleted : INotifyLogisticsOnShippingSoftDeleted
{
    protected readonly ILogger<NotifyLogisticsOnShippingSoftDeleted> _logger;
    protected string EventCondition = "";

    public NotifyLogisticsOnShippingSoftDeleted(ILogger<NotifyLogisticsOnShippingSoftDeleted> logger)
    {
        _logger = logger;
    }

    public virtual async Task Execute(ShippingSoftDeletedEvent @event, IFlexServiceBusContext serviceBusContext)
    {
        _flexAppContext = @event.AppContext;

        //TODO: Write your business logic here:
        // - Update logistics systems
        // - Notify carriers of cancellation
        // - Update analytics
        // - Archive related data

        await this.Fire<NotifyLogisticsOnShippingSoftDeleted>(EventCondition, serviceBusContext);
    }
}
```

**What Happens:**

* **Event Reception**: Receives `ShippingSoftDeletedEvent` from message bus
* **Side Effects**: Executes business logic (logistics updates, notifications, etc.)
* **Additional Events**: Can fire more events if needed

## Data Transfer Objects (DTOs)

### **Input DTO**: `SoftDeleteShippingDto`

```csharp
public partial class SoftDeleteShippingDto : DtoBridge 
{
    public string Id { get; set; }
    
    // Optional: Reason for soft delete
    public string DeletionReason { get; set; }
}
```

### **Command**: `SoftDeleteShippingCommand`

```csharp
public class SoftDeleteShippingCommand : FlexCommandBridge<SoftDeleteShippingDto, FlexAppContextBridge>
{
    // Command data is automatically populated by FlexBase
}
```

## Key Differences from Hard Delete

### **Soft Delete vs Hard Delete Characteristics**

| Aspect               | Soft Delete                    | Hard Delete                  |
| -------------------- | ------------------------------ | ---------------------------- |
| **Data Persistence** | ✅ Data remains in database     | ❌ Data physically removed    |
| **Recovery**         | ✅ Can be restored              | ❌ Cannot be recovered        |
| **Audit Trail**      | ✅ Complete history maintained  | ❌ History lost               |
| **Performance**      | ✅ Fast (just flag update)      | ✅ Fast (row deletion)        |
| **Storage**          | ❌ Uses more storage            | ✅ Frees storage              |
| **Queries**          | ❌ Need to filter deleted items | ✅ No filtering needed        |
| **Business Rules**   | ✅ Can validate before delete   | ✅ Can validate before delete |

### **Soft Delete-Specific Features**

1. **Data Preservation**: Entity remains in database with deleted flag
2. **Recovery**: Can be restored if needed
3. **Audit Trail**: Maintains complete history
4. **Query Filtering**: Queries must filter out soft-deleted items
5. **Business Logic**: Can implement complex deletion rules

### **Soft Delete Pattern Benefits**

* **Data Safety**: No accidental data loss
* **Compliance**: Meets regulatory requirements for data retention
* **Audit Trail**: Complete history of all operations
* **Recovery**: Can restore deleted data if needed
* **Business Rules**: Can implement complex deletion logic

## Flow Summary

### **Synchronous Flow (Immediate Response)**

1. **DELETE Request** → Controller receives request with ID
2. **Service Processing** → Business orchestration and PreBus validation
3. **PreBus Plugins** → Sequential validation of business rules
4. **Command Handler** → Data processing and soft delete
5. **Domain Logic** → Business rules and state management
6. **Response** → HTTP 200 OK with success status

### **Asynchronous Flow (Event Processing)**

1. **Event Publishing** → ShippingSoftDeletedEvent published to message bus
2. **Subscriber Processing** → NotifyLogisticsOnShippingSoftDeleted executes
3. **Side Effects** → Logistics updates, carrier notifications, analytics

## Query Filtering for Soft Deleted Items

### **Standard Query Filtering**

```csharp
// In query handlers, always filter out soft deleted items
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Always exclude soft deleted items
    query = query.Where(s => !s.IsSoftDeleted);
    
    // Add other filtering logic here
    
    return query;
}
```

### **Include Soft Deleted Items (Admin Queries)**

```csharp
// For admin queries that need to see soft deleted items
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Only include soft deleted items if specifically requested
    if (_params.IncludeSoftDeleted == true)
    {
        // Don't filter out soft deleted items
    }
    else
    {
        query = query.Where(s => !s.IsSoftDeleted);
    }
    
    return query;
}
```

## Key Benefits

* **Data Safety**: No accidental data loss
* **Compliance**: Meets regulatory requirements
* **Audit Trail**: Complete history of operations
* **Recovery**: Can restore deleted data
* **Business Rules**: Complex deletion logic support
* **Event-Driven**: Notifies other systems of deletions
* **Testable**: Each component can be tested independently
* **Maintainable**: Clear separation of concerns

***

**This SoftDeleteShipping example demonstrates how FlexBase enables clean, maintainable, and scalable soft delete operations with proper validation, data preservation, and event-driven architecture!** 🚀
