--- title: Serviço de histórico tags: Análise Cloud --- # Serviço de histórico A ideia é criar um serviço para persistr o histórico de todos os campos, unindo os campos standards e os personalizados. Uma request quando chega no heimdall é gerado um id pra ela para podermos identifica-la em qualquer ponto, esse id é passado para as requests internas que fazemos tbm. Sendo assim podemos utilizar esse id para unir os dados de históricos dos serviços standards e do btb. Basicamente cada serviço fica responsavel por fazer a diff de seus dados e enviar ao serviço de histórico passando o request id que gerou essas diffs, o serviço de histórico por sua vez une todas as diffs que chegarem para a mesma request id. ## Base de dados ``` sql CREATE TABLE revision ( id uuid NOT NULL, request_id uuid NOT NULL, "date" timestamptz NOT NULL, user_id uuid NOT NULL, user_name varchar(255) NOT NULL, system_version varchar(64) NOT NULL, history_type varchar(20) NOT NULL, origin varchar(20) NOT NULL, "version" int4 NULL, updated_at timestamptz NOT NULL, created_at timestamptz NOT NULL, external_id varchar(255) NULL, PRIMARY KEY (id) ); CREATE TABLE entity_state ( id uuid NOT NULL, "version" int4 NULL, external_id varchar NULL, revision_id uuid NOT NULL, previous_entity_state_id uuid NULL, sequence_record_changing int4 NOT NULL, service varchar(20) NOT NULL, event_type varchar(20) NOT NULL, entity varchar(100) NOT NULL, record_id uuid NOT NULL, record_text_identifier varchar(255) NOT NULL, state jsonb NOT NULL, parent_id uuid NULL, parent_name varchar(100) NULL, updated_at timestamptz NOT NULL, created_at timestamptz NOT NULL, PRIMARY KEY (id), FOREIGN KEY (previous_entity_state_id) REFERENCES entity_state(id) ON UPDATE RESTRICT ON DELETE RESTRICT, FOREIGN KEY (revision_id) REFERENCES revision(id) ON UPDATE RESTRICT ON DELETE RESTRICT ); CREATE TABLE history_comment ( id uuid NOT NULL, "comment" varchar(4000) NOT NULL, record_id uuid NOT NULL, "version" int4 NULL, updated_at timestamptz NOT NULL, created_at timestamptz NOT NULL, external_id varchar(255) NULL, service varchar(20) NOT NULL, entity varchar(80) NOT NULL, revision_id uuid NOT NULL, deleted bool NOT NULL DEFAULT false, PRIMARY KEY (id), FOREIGN KEY (revision_id) REFERENCES revision(id) ); CREATE TABLE history_system_event ( id uuid NOT NULL, revision_id uuid NOT NULL, event varchar(80) NULL, event_type varchar(40) NOT NULL, event_args jsonb, message varchar(255), record_id uuid NOT NULL, service varchar(20) NOT NULL, entity varchar(80) NOT NULL, "version" int4 NULL, updated_at timestamptz NOT NULL, created_at timestamptz NOT NULL, external_id varchar(255) NULL, PRIMARY KEY (id), FOREIGN KEY (revision_id) REFERENCES revision(id) ON UPDATE RESTRICT ON DELETE RESTRICT ); ``` ## API ### Fluxo ```mermaid sequenceDiagram participant Heimdall participant Router participant Customer participant BTB participant Mensageria participant Historic Heimdall->>Router: Adiciona request id Router->>Customer: Chama serviço standard Customer->>Customer: Recebe dados standards, gera o diff deles e persiste no banco local Customer->>Mensageria: Envia mensagem com o id do registro de histórico que deve ser consultado Router->>BTB: Chama o btb BTB->>BTB: Recebe dados personalizados, gera o diff deles e persiste no banco local BTB->>Mensageria: Envia mensagem com o id do registro de histórico que deve ser consultado Historic->>Mensageria: Consulta mensagns a serem processadas Historic->>Customer: Consulta registro de histórico com o id passado na mensagem Historic->>Historic: Persiste o registro de histórico cos campos standards Historic->>BTB: Consulta registro de histórico com o id passado na mensagem Historic->>Historic: Atualiza o registro de histórico dos campos standards fazendo merge com os campos customizados ``` ### Post de histórico */histories/{service}/{entity}/* ```jsonql= { "revision": { "requestId": "", "date": "", "userId": "", "userName": "", "systemVersion": "", "historyType": "", "origin": "", "entityStaties": [{ "externalId": "", "revisionId": "", "previousEntityStateId": "", "sequenceRecordChanging": "", "eventType": "", "recordId": "", "recordTextIdentifier": "", "state": {}, "parentId": "", "parentName": "", }] } ``` Ao receber esses dados deve ser verificado se ja existe uma revisão para o registro, caso não exista deve ser persistido os registros, caso contrário deve ser apenas mergeado o state unindo os dados. Para verificar se um registro existe deve ser utilizado as seguinte informações: * requestId * service * entity * recordId ### Post de comentários Comentários geram uma revisão própria e são vinculados à uma entidade através de seu Id */comments/{service}/{entity}/{recordId}* ```jsonql= { "historyComment": { "comment": "Este é um exemplo de comentário de oportunidade." } } ``` ### Get Lista todos os acontecimentos relacionados à um entidade específica, estes acontecimentos são: - Auditorias - Comentários - Eventos de Sistema */histories/{service}/{entity}/{recordId}* ```jsonql= { "items": [ { "user": { "id": "27801f26-9bef-4bc1-b5bc-ee922499dd59", "name": "Administrador" }, "date": "2019-01-11T20:14:23.503Z", "historyType": "AUDIT" } ], "count": 1, "firstRow": 0, "page": 0, "pageSize":1 } ``` ## Audit A proposta é alterar a lib existente [audit](https://gitlab.wssim.com.br/cloud/audit) hoje para que ao invés de persistir os registros essa lib deve gerar as mensagens com as diffs para que o serviço de histórico consuma e persista. Além disso parte do que essa lib faz hoje o serviço de histórico que irá fornecer tirando essas responsabilidades da lib, sendo elas: * End point de comentários (que hoje fica em [Histories](https://gitlab.wssim.com.br/cloud/audit#gerando-coment%C3%A1rios)) * End point de pesquisa ([Search](https://gitlab.wssim.com.br/cloud/audit#filtros)) ### End-points para accesso do histórico Fica como responsabilidade do audit expor end-point que seja possivel configurar (via desenvolvimento) e expor para acesso do usuario os registros do histório ### Sync Para registros que venham de mobile o histórico deve ser gerado a partir da sync. Para esses casos o id da sync deve ser utilizado como request id ja que os serviços são sincronizados na mesma request. Comentários podem ser criados no mobile e sincronizados normalmente. A sync deve ser feita a partir do serviço da entidade, ou seja, vai ser um proxy para o histórico. Isso para poder ser aplicado os fitros corretos de sincronização. ## Serviços standards Os serviços deverão implementar a lib audit que fará a auditoria e enviará os dados para o serviço de histórico. Alem de servirem como proxy para manipular comentários e consultar os resgistros de histórico. ### Telas As telas ficam por responsabilidade de cada serviço implementar e exibir os registros de histórico da melhor forma para o contexto de cada funcionalidade. Atualmente existe um componente responsavel por fazer isso. Esse componente deve ser alterado para possibilitar a exibição de campos personalizados. Hoje esse componente somente internacionaliza os nomes dos campos conforme passado para ele, ele deve passar a verificar se é um campo que standard e nesse caso internacionalizar, caso contrario assumir o label passado para ele. ### Serviços com histórico ja implementados Será nescessário replicar todos os registros. Como as entidades são basicamente a mesma não deve ser um problema porém deve-se tomar cuidado para migrar a qual serviço pertence o registro. ## BTB No primeiro momento o BTB vai gerar apenas histórico do data lake de entidade standards, ou seja, não será gerado histórico de alteração de metada dados e nem histórico de entidades customs. Para isso o btb irá enviar as alterações de data lake utilizando o serviço e nome da entidade standard. O BTB irá utilizar uma lib nossa pra fazer a diff do JSON, após isso iremos converter o resultado retornado dessa lib na estrutura esperada pelo Javers e persistir. A partir desse ponto segue o mesmo fluxo que serviços standards, ou seja, gera uma mensagem para o serviço centralizador consumir.