Executando verificação de segurança...
1

Depois da nossa conversa inicial, decidi atualizar o exemplo pra ficar mais fácil de visualizar a ideia enquanto um mecanismo de compensação a nível de negócio, ao invés de estar associado à camada de dados. Isso porque, na camada de dados, a reconciliação vai certamente cair nas complicações que você muito bem colocou. Já na camada de negócios, seria o mesmo que delegar uma atualização em alto nível.
Não resolve todos os casos, mas pode ser o suficiente para alguns cenários.

graph TB
    %% Client Layer
    subgraph CLIENT ["🌐 CLIENT LAYER"]
        HTTP["HTTP Requests<br/>GET /health<br/>GET /users<br/>POST /users<br/>PUT /users/:email<br/>POST /users/:email/rollback"]
    end

    %% Presentation Layer
    subgraph PRESENTATION ["📡 PRESENTATION LAYER"]
        APP["Express App<br/>(index.ts)<br/>+ Pino Logger"]
        ROUTES["Routes Handler<br/>(routes.ts)"]
    end

    %% Use Case Layer (Refactored)
    subgraph USECASE ["🎯 USE CASE LAYER"]
        USERSUSECASES["UsersUseCases Class<br/>• createUser()<br/>• updateUser()<br/>• listUsers()<br/>• rollbackUser()"]
        SNAPSUSECASES["SnapshotsUseCases Class<br/>• createSnapshot()<br/>• getSnapshot()"]
        USECASEINSTANCE["Singleton Instance<br/>(use-case/users/index.ts)"]
    end

    %% Repository Layer
    subgraph REPOSITORY ["🗄️ REPOSITORY LAYER"]
        USERREPOINTF["UsersRepository<br/>Interface"]
        USERREPO["UsersRepositoryInMemory<br/>(Implementation)"]
        SNAPREPOINTF["SnapshotRepository<br/>Interface"]
        SNAPREPO["SnapshotRepositoryInMemoryImpl<br/>(Implementation)"]
    end

    %% Entity Layer
    subgraph ENTITY ["📊 ENTITY LAYER"]
        USER["User Interface<br/>{name: string, email: string}"]
        SNAPSHOT["Snapshot Interface<br/>{entity_id: string, entity: string, data: string}"]
    end

    %% Data Storage
    subgraph STORAGE ["💾 DATA STORAGE"]
        USERMAP["In-Memory Map<string, User><br/>User Storage<br/>+ Duplicate Prevention"]
        SNAPMAP["In-Memory Map<string, Snapshot><br/>Snapshot Storage<br/>Key: 'entity@entity_id'"]
    end

    %% Communication Flow
    HTTP --> APP
    APP --> ROUTES
    
    ROUTES --> USECASEINSTANCE
    USECASEINSTANCE --> USERSUSECASES
    
    USERSUSECASES --> USERREPOINTF
    USERREPOINTF --> USERREPO
    
    USERSUSECASES --> SNAPSUSECASES
    SNAPSUSECASES --> SNAPREPOINTF
    SNAPREPOINTF --> SNAPREPO

    USERREPO --> USER
    SNAPREPO --> SNAPSHOT

    USERREPO --> USERMAP
    SNAPREPO --> SNAPMAP

    %% Dependency Injection
    USECASEINSTANCE -.->|"Dependency Injection"| USERREPO
    USERSUSECASES -.->|"Composition"| SNAPSUSECASES
    SNAPSUSECASES -.->|"Dependency Injection"| SNAPREPO

    %% Enhanced Features
    USERREPO -.->|"Duplicate Check"| USERMAP
    SNAPREPO -.->|"Composite Key Storage"| SNAPMAP

    %% Styling for high contrast
    classDef clientStyle fill:#000000,stroke:#ffffff,stroke-width:3px,color:#ffffff
    classDef presentationStyle fill:#2d3748,stroke:#ffffff,stroke-width:2px,color:#ffffff
    classDef usecaseStyle fill:#4a5568,stroke:#ffffff,stroke-width:2px,color:#ffffff
    classDef repositoryStyle fill:#718096,stroke:#000000,stroke-width:2px,color:#000000
    classDef entityStyle fill:#e2e8f0,stroke:#000000,stroke-width:2px,color:#000000
    classDef storageStyle fill:#ffffff,stroke:#000000,stroke-width:3px,color:#000000

    class HTTP clientStyle
    class APP,ROUTES presentationStyle
    class USERSUSECASES,SNAPSUSECASES,USECASEINSTANCE usecaseStyle
    class USERREPOINTF,USERREPO,SNAPREPOINTF,SNAPREPO repositoryStyle
    class USER,SNAPSHOT entityStyle
    class USERMAP,SNAPMAP storageStyle

No código ficou assim:

class UsersUseCases {
  private snapshotsUseCases: SnapshotsUseCases;
  private _ENTITY = 'user';

  constructor(private readonly usersRepository: UsersRepository) {
    this.snapshotsUseCases = new SnapshotsUseCases(new SnapshotRepositoryInMemoryImpl());
  }

  createUser(user: User) {
    this.usersRepository.store(user);
  }

  updateUser(user: User) {
    const currentState = this.usersRepository.findByEmail(user.email);

    if (currentState) {
      this.snapshotsUseCases.createSnapshot({
        entity: this._ENTITY,
        entity_id: user.email,
        data: JSON.stringify(currentState)
      });
    }

    this.usersRepository.update(user);
  }

  listUsers() {
    return this.usersRepository.list();
  }

  rollbackUser(email: string) {
    const previousState = this.snapshotsUseCases.getSnapshot(this._ENTITY, email);
    if (previousState) {
      const user = JSON.parse(previousState.data) as User;
      this.updateUser(user);
    }
  }
}
Carregando publicação patrocinada...