<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Aluisio Amorim C.</title>
    <description>The latest articles on Forem by Aluisio Amorim C. (@aluisiodev).</description>
    <link>https://forem.com/aluisiodev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F579257%2Fb053578b-e7b8-427e-9b9c-0e7ad268c356.jpeg</url>
      <title>Forem: Aluisio Amorim C.</title>
      <link>https://forem.com/aluisiodev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aluisiodev"/>
    <language>en</language>
    <item>
      <title>O que é IA Generativa? Um Glossário de Termos Essenciais</title>
      <dc:creator>Aluisio Amorim C.</dc:creator>
      <pubDate>Tue, 19 Nov 2024 14:27:33 +0000</pubDate>
      <link>https://forem.com/bem-te-vi/o-que-e-ia-generativa-um-glossario-de-termos-essenciais-eof</link>
      <guid>https://forem.com/bem-te-vi/o-que-e-ia-generativa-um-glossario-de-termos-essenciais-eof</guid>
      <description>&lt;p&gt;Nos últimos anos, a Inteligência Artificial Generativa tem se tornado um dos avanços tecnológicos mais comentados. Capaz de criar texto, imagens, áudio e até vídeos de forma autônoma, essa tecnologia impacta as mais diversas indústrias. Para compreender como a IA generativa funciona, é essencial conhecer os principais conceitos que a impulsionam.&lt;/p&gt;




&lt;h2&gt;
  
  
  LLM (Large Language Model)
&lt;/h2&gt;

&lt;p&gt;LLM, ou Large Language Model, refere-se a um modelo de linguagem de grande escala, treinado em vastos conjuntos de dados textuais. Esses modelos, como GPT, Claude ou Llama, são compostos de bilhões ou até trilhões de parâmetros, o que lhes confere uma capacidade impressionante de gerar texto coerente, traduzir linguagens, responder a perguntas complexas e muito mais. O tamanho do modelo é um fator crucial para sua eficácia, pois modelos maiores tendem a capturar mais nuances da linguagem e gerar saídas mais sofisticadas.&lt;/p&gt;

&lt;p&gt;Atualmente, quando falamos de IA generativa, usualmente estamos nos referindo ao poder de geração de texto desses LLMs, que são fundação para aplicações como o Chat GPT.&lt;/p&gt;

&lt;p&gt;O LLM é o &lt;em&gt;Transformer&lt;/em&gt; altamente treinado, que compreende e gera séries de &lt;em&gt;tokens&lt;/em&gt; sofisticadas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transformer
&lt;/h2&gt;

&lt;p&gt;O Transformer é a arquitetura de rede neural que revolucionou o campo do processamento de linguagem natural (NLP). Introduzido no artigo “Attention is All You Need” de 2017, ele é a base para os grandes modelos de linguagem, como GPT, BERT e outros. Ao contrário de arquiteturas anteriores, como redes recorrentes (RNNs), o Transformer utiliza o mecanismo de &lt;strong&gt;atenção&lt;/strong&gt;, que o permite capturar dependências de longo prazo, ou seja, considerar o conteúdo relevante de qualquer parte do texto. Sobretudo, esta arquitetura permite processamento paralelo, o que torna possível treinar modelos tão grandes em um “curto” período.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token
&lt;/h2&gt;

&lt;p&gt;No contexto de LLMs, um token é uma unidade básica de texto. Pode ser uma palavra, parte de uma palavra ou até mesmo um símbolo, dependendo de como o modelo é treinado. A geração de texto pelo modelo ocorre token por token, com a previsão de qual será o próximo baseada nos anteriores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedding
&lt;/h2&gt;

&lt;p&gt;Um embedding, no contexto de processamento de linguagem natural, é a representação numérica do token em um espaço vetorial, em outras palavras, um embedding é um vetor. O que significa dizer que os embeddings são responsáveis por capturar relações sintáticas e semânticas entre os tokens. Por exemplo, os embeddings das palavras “rei” e “príncipe” estão mais próximos do que os embeddings de “rei” e “Python”, permitindo assim, a geração de texto contextualizado e coeso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inferência
&lt;/h2&gt;

&lt;p&gt;Na IA generativa, a inferência refere-se ao processo de utilizar um modelo treinado para prever o próximo token em uma sequência de texto. Durante a inferência, o modelo analisa o contexto fornecido pelos tokens anteriores e gera previsões baseadas nos padrões aprendidos durante o treinamento. A qualidade dessa inferência determina a fluidez, coerência e relevância do texto gerado. Para tarefas como escrita automática ou diálogos, essa capacidade inferencial é o núcleo do funcionamento dos modelos de linguagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Janela de Contexto (Context Window)
&lt;/h2&gt;

&lt;p&gt;A janela de contexto é a quantidade de texto ou tokens que um modelo de linguagem pode processar de uma vez. A janela de contexto define o número de tokens que podem ser considerados simultaneamente para gerar uma resposta. Se o contexto for muito longo e exceder o limite da janela, o modelo não poderá levar em conta a totalidade da informação passada. A escolha de uma janela de contexto adequada é essencial para garantir que o modelo tenha informações suficientes para tomar decisões precisas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Habilidades Emergentes
&lt;/h2&gt;

&lt;p&gt;As habilidades emergentes referem-se a comportamentos ou capacidades inesperadas que os modelos de IA exibem à medida que se tornam maiores e mais complexos. Essas habilidades não foram explicitamente programadas, mas emergem naturalmente durante o processo de treinamento em grandes volumes de dados. Um exemplo é a capacidade de resolver problemas matemáticos complexos ou gerar código em linguagens de programação específicas. Esses fenômenos demonstram o poder dos LLMs para aprender padrões além das intenções dos desenvolvedores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treinamento
&lt;/h2&gt;

&lt;p&gt;O treinamento de um modelo envolve ajustar seus parâmetros por meio da exposição a grandes quantidades de dados. Para modelos de linguagem generativa, o treinamento consiste em alimentar o modelo com vastos conjuntos de dados de texto, permitindo que ele aprenda padrões e contextos. Durante o processo, o modelo passa por muitas iterações, ajustando seus pesos e viéses com base em erros anteriores, para melhorar sua capacidade de prever o próximo token em uma sequência de texto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine-tuning
&lt;/h2&gt;

&lt;p&gt;O fine-tuning é o processo de ajustar um modelo já treinado para tarefas específicas. Por exemplo, após o treinamento geral em um vasto conjunto de dados, um modelo pode ser refinado para tarefas como geração de e-mails ou atendimento ao cliente em um domínio específico. O fine-tuning permite que um modelo genérico seja especializado para contextos mais específicos, sem precisar começar o treinamento do zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompts
&lt;/h2&gt;

&lt;p&gt;Um prompt é a entrada inicial fornecida a um modelo de linguagem generativa para gerar uma resposta. É a “semente” que desencadeia o processo de geração de texto. O design do prompt é crucial para obter resultados satisfatórios. Dependendo de como o prompt é estruturado, o modelo pode produzir respostas muito diferentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Viés (Bias)
&lt;/h2&gt;

&lt;p&gt;No contexto dos modelos de IA, o termo bias refere-se a um parâmetro que influencia a forma como o modelo aprende e generaliza. Esse tipo de bias, na matemática das redes neurais, ajuda a ajustar o modelo para que ele possa capturar melhor os padrões nos dados de treinamento e alcançar maior precisão nas previsões. Essencialmente, ele atua como uma constante que permite ao modelo se adaptar mais facilmente a um conjunto de dados, tornando a aprendizagem mais eficiente e flexível. Esse tipo de parâmetro bias não está diretamente relacionado a influências culturais ou sociais, mas ao ajuste de pesos para otimizar a capacidade do modelo em realizar tarefas preditivas com menor erro.&lt;/p&gt;

&lt;p&gt;No entanto, o termo bias também refere-se ao viés presente nos dados e, por consequência, nas respostas geradas pelo modelo. Esse viés surge dos padrões contidos nos dados de treinamento, que podem refletir preconceitos e estereótipos humanos. Quando exposto a dados enviesados, um modelo de IA pode gerar saídas que perpetuam ou até amplificam preconceitos, resultando em textos racistas, sexistas ou de outra forma prejudiciais. Isso ocorre porque o modelo aprende com grandes quantidades de dados reais, que podem carregar vieses culturais, históricos e sociais. Combater esses vieses exige um trabalho cuidadoso de seleção e tratamento dos dados, além de ajustes no próprio processo de treinamento para minimizar outputs indesejáveis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alucinação (Hallucination)
&lt;/h2&gt;

&lt;p&gt;No contexto de modelos de IA generativa, alucinação refere-se ao fenômeno em que o modelo gera informações falsas, incoerentes ou não fundamentadas nos dados fornecidos. Isso ocorre porque os LLMs não têm acesso direto a fatos ou à realidade durante o processo de geração; eles simplesmente seguem padrões aprendidos no treinamento para prever o próximo token. &lt;/p&gt;

&lt;p&gt;Por exemplo, um modelo pode inventar nomes de livros, criar citações inexistentes ou afirmar informações factualmente incorretas como verdadeiras. Alucinações podem ser problemáticas, especialmente em aplicações críticas como saúde, direito, educação, ou seguro onde a precisão é essencial. &lt;/p&gt;

&lt;p&gt;Minimizar alucinações exige melhorias contínuas nos processos de treinamento, maior supervisão humana e, em muitos casos, a integração com sistemas que validem os outputs gerados pelo modelo. O design de prompts claros e específicos também ajuda a mitigar esse comportamento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guard Rails
&lt;/h2&gt;

&lt;p&gt;Guard rails referem-se a mecanismos implementados para limitar o comportamento dos modelos de IA generativa, garantindo que suas respostas sejam seguras, éticas e alinhadas aos objetivos pretendidos. Esses mecanismos são projetados para prevenir o uso indevido, reduzir outputs prejudiciais, e proteger contra alucinações ou vieses problemáticos.&lt;/p&gt;

&lt;p&gt;Os guard rails podem ser implementados em várias formas, incluindo:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filtros de conteúdo&lt;/strong&gt;: Bloqueiam respostas inadequadas, como discurso de ódio ou informações perigosas.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validação de saídas&lt;/strong&gt;: Integração com sistemas externos para verificar fatos ou assegurar a precisão de respostas.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitação de contexto&lt;/strong&gt;: Restringe o escopo do modelo para tópicos relevantes à aplicação.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instruções específicas no treinamento&lt;/strong&gt;: Ajustam os dados de treinamento e o fine-tuning para moldar o comportamento do modelo.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um exemplo comum de guard rail é a configuração de um modelo para evitar responder perguntas fora de um domínio específico, como o contexto de seguros que estamos inseridos.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;"Os limites de minha linguagem são os limites de meu mundo."&lt;br&gt;&lt;br&gt;
— &lt;em&gt;Ludwig Wittgenstein&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dominar o vocabulário técnico da área prepara o terreno para estudos mais aprofundados.&lt;/p&gt;

&lt;p&gt;O intuito desse texto é se tornar um glossário do time da bem-te-vi, compartilhado com a comunidade. Sinta-se a vontade para sugerir adições e edições.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referência
&lt;/h3&gt;

&lt;p&gt;Bouchard, Louis-Francois, and Louie Peters. Building LLMs for Production. Towards AI, 2024.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing end-to-end encryption (E2EE) to a Planning Poker game</title>
      <dc:creator>Aluisio Amorim C.</dc:creator>
      <pubDate>Tue, 02 Apr 2024 14:12:27 +0000</pubDate>
      <link>https://forem.com/qwikens/implementing-end-to-end-encryption-e2ee-to-a-planning-poker-game-1hoi</link>
      <guid>https://forem.com/qwikens/implementing-end-to-end-encryption-e2ee-to-a-planning-poker-game-1hoi</guid>
      <description>&lt;p&gt;&lt;a href="https://www.mountaingoatsoftware.com/agile/planning-poker" rel="noopener noreferrer"&gt;Planning Poker®&lt;/a&gt; is a consensus-based technique for agile estimating. It is a fun and engaging way for teams to apply relative estimates to planned work. In this blog post, we're diving into how we can enhance the security of Planning Poker sessions using end-to-end encryption (E2EE).&lt;/p&gt;

&lt;p&gt;The code of the Qwikens &lt;strong&gt;Free Planning Poker&lt;/strong&gt; application is open-source. 🚀🥳 &lt;br&gt;&lt;br&gt;
Take a look at the repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/qwikens/planning-poker" rel="noopener noreferrer"&gt;https://github.com/qwikens/planning-poker&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is End-to-End Encryption?
&lt;/h3&gt;

&lt;p&gt;End-to-End Encryption (E2EE) is a method of secure communication that prevents third-parties from accessing data while it's transferred from one end system or device to another. In E2EE, the data is encrypted on the sender's system or device and only the recipient is able to decrypt it. Nobody in between, be it internet service providers, hackers, or even the &lt;code&gt;platform provider itself&lt;/code&gt;, can read it or tamper with it.&lt;/p&gt;

&lt;p&gt;The principle behind E2EE is that it uses cryptographic keys to encrypt and decrypt the data. Only the communicating users possess the keys to unlock and read the messages. This ensures that the data remains confidential and integral, providing a secure channel for communication over potentially insecure networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples of E2EE in Use
&lt;/h3&gt;

&lt;p&gt;One of the most well-known examples of E2EE in use today is WhatsApp. WhatsApp encrypts messages in a way that even WhatsApp servers cannot decrypt them. This means that when you send a message, photo, video, or file, everything is encrypted automatically, and only the recipient can decrypt and view the message.&lt;/p&gt;

&lt;p&gt;Other notable examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signal&lt;/strong&gt;: A messaging app that is widely regarded for its state-of-the-art end-to-end encryption for voice calls, video calls, and instant messaging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram&lt;/strong&gt;: Offers optional end-to-end encrypted secret chats that are not stored on their servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ProtonMail&lt;/strong&gt;: An email service that secures emails with end-to-end encryption, meaning that even ProtonMail cannot access the content of your emails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These examples highlight the growing importance and implementation of E2EE in various forms of digital communication, ensuring privacy and security for users worldwide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why E2EE?
&lt;/h3&gt;

&lt;p&gt;Our infrastructure already provides a secure channel for communication (TLS/SSL), so why do we need E2EE?&lt;/p&gt;

&lt;p&gt;While TLS/SSL secures the communication between the client and the server, it does not protect the data once it reaches the server. This means that the data is decrypted on the server and can potentially be accessed by the service provider or malicious actors who gain access to the server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More information about TLS/SSL: &lt;br&gt; &lt;a href="https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/" rel="noopener noreferrer"&gt;https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are worried about the Planning Poker issues being exposed to the Qwikens's infrastructure, we want to ensure that the issues remains confidential even when it's stored on the server. This is where E2EE comes into play. By encrypting the data on the client-side before it's sent to the server, we can ensure that only the intended recipient can decrypt and access the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  E2EE in Planning Poker
&lt;/h3&gt;

&lt;p&gt;This is not a trivial task, since we are working with a real-time collaborative tool, we need to ensure that the encryption and decryption process does not introduce significant latency or complexity to the user experience.&lt;/p&gt;

&lt;p&gt;The first point to consider is that we are dealing with a group of participants. So, it is not enough to encrypt the data with the recipient's public key, as this would only allow the recipient to decrypt the data.&lt;/p&gt;

&lt;p&gt;We need to encrypt the data with the public keys of all participants, so that all participants can decrypt the data.&lt;/p&gt;

&lt;p&gt;The second point to consider is that we are dealing with a real-time application. This means that we need to ensure that the encryption and decryption process is fast enough to keep up with the pace of the planning poker game. We need to carefully consider the encryption algorithm and key size to ensure that the process is efficient and secure.&lt;/p&gt;

&lt;p&gt;Based on these &lt;strong&gt;constraints&lt;/strong&gt;, we had to analyze some approaches.&lt;/p&gt;

&lt;h4&gt;
  
  
  Peer-to-peer encryption
&lt;/h4&gt;

&lt;p&gt;Each participant encrypts the data with the public keys of all participants and sends the encrypted data to all participants. This approach is not scalable, as the number of messages grows quadratically with the number of participants.&lt;/p&gt;

&lt;p&gt;In the context of Planning Poker, where the number of participants is relatively small, this approach could be feasible. However, it introduces additional complexity and overhead, as each participant needs to encrypt the data multiple times and create multiple issues. This could lead to synchronization issues and potential performance problems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Shared key
&lt;/h4&gt;

&lt;p&gt;All participants share a &lt;strong&gt;symmetric key&lt;/strong&gt; that is used to encrypt and decrypt the data. This approach is simpler and more efficient, as it avoids the need to encrypt the data multiple times and create multiple encrypted issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When creating a room, the client generates a key and shares it with all participants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although this approach is simpler and more efficient, since the data is encrypted with a single key, there are two main drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single point of failure&lt;/strong&gt;: If the key is compromised, all data is exposed. This means that the security of the system relies on the secrecy of the key;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Key management&lt;/strong&gt;: Since all participants share the same key, there is a risk that the key could be lost or compromised. This could lead to data loss or exposure. Also, the key is a huge string, so it is not easy to share.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A possible solution is to share the key within the URL, as a query parameter, but this results in a very long URL, which is not ideal, since it could be truncated by some services (like Google Meet, for example).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Hybrid approach
&lt;/h4&gt;

&lt;p&gt;What about a hybrid approach? 🤔&lt;/p&gt;

&lt;p&gt;The idea is to combine the benefits of both approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not need to share keys "manually";&lt;/li&gt;
&lt;li&gt;Do not need to maintain multiple encrypted issues state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is to use a &lt;strong&gt;symmetric key&lt;/strong&gt; to encrypt the data, but the key is encrypted with the public keys of all participants. This way, only the participants can decrypt the key and access the data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When creating a room, the user generates a pair of keys (public and private) and shares the public key;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates a RSA key pair using a specified bit length.
 * @returns An object containing the PEM encoded public and private keys.
 * @example
 * const keyPair = generateKeyPair();
 * console.log(keyPair.publicKey); // PEM encoded public key
 * console.log(keyPair.privateKey); // PEM encoded private key
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateKeyPair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rsa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateKeyPair&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicKeyToPem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;privateKeyToPem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;b&gt;&lt;br&gt;
A key point here is to generate the key pair inside a &lt;code&gt;Promise&lt;/code&gt;. Generating the key pair synchronously could block the JS event loop's main thread, causing the application to freeze. By using a &lt;code&gt;Promise&lt;/code&gt;, we ensure that the key pair is generated asynchronously, outside the main thread, and the application remains responsive.&lt;br&gt;
&lt;/b&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#never_blocking" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#never_blocking&lt;/a&gt;&lt;br&gt;
&lt;b&gt;&lt;br&gt;
For the sake of simplicity, we are using a 2048-bit RSA key pair. This is a common key size for RSA encryption and provides a good balance between security and performance. However, the key size can be adjusted based on the desired level of security and performance.&lt;br&gt;
&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user also generates a symmetric key and encrypts it with its own public key;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates a symmetric key using a specified bit length.
 * @param {number} [bitLength=256] - The bit length for the symmetric key. Default is 256 bits.
 * @returns {string} The generated symmetric key, base64 encoded.
 * @example
 * const symmetricKey = generateSymmetricKey();
 * console.log(symmetricKey); // Base64 encoded symmetric key
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateSymmetricKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bitLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bitLength&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBytesSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When any participant enters the room, the new participant generates a pair of keys and shares the public key;&lt;/li&gt;
&lt;li&gt;Then, any of the current participants encrypts the symmetric key with the new participant's public key and sends it to the server;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Encrypts a message using a given public key.
 * @param message - The plaintext message to be encrypted.
 * @param publicKey - The PEM encoded public key used for encryption.
 * @returns The encrypted message, base64 encoded.
 * @example
 * const encryptedMessage = asymmetricEncrypt("Hello, world!", publicKey);
 * console.log(encryptedMessage); // Encrypted and base64 encoded message
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asymmetricEncrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicKeyRsa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publicKeyFromPem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;publicKeyRsa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeUtf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;With the encrypted symmetric key in hands, the new participant can decrypt it with its private key and access the data;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Decrypts an encrypted message using a given private key.
 * @param encryptedMessage - The encrypted message, base64 encoded.
 * @param privateKey - The PEM encoded private key used for decryption.
 * @returns The decrypted plaintext message.
 * @example
 * const decryptedMessage = asymmetricDecrypt(encryptedMessage, privateKey);
 * console.log(decryptedMessage); // Decrypted plaintext message
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asymmetricDecrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;encryptedMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;privateKeyObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pki&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;privateKeyFromPem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;privateKeyObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeUtf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decrypted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The application needs to handle two states: &lt;code&gt;issues&lt;/code&gt; and &lt;code&gt;decryptedIssues&lt;/code&gt;;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Issue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;storyPoints&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;createdBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issuesState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decryptedIssuesState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Each issue is encrypted with the symmetric key before being sent to the server;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Encrypts a message using a symmetric key.
 * @param message - The plaintext message to be encrypted.
 * @param symmetricKey - The base64 encoded symmetric key used for encryption.
 * @returns The encrypted message, base64 encoded.
 * @example
 * const encryptedMessage = symmetricEncrypt("Hello, world!", symmetricKey);
 * console.log(encryptedMessage); // Encrypted and base64 encoded message
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;symmetricEncrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;symmetricKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;symmetricKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBytesSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Initialization vector&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-CBC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeUtf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBytes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedMessageWithIv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedMessageWithIv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When the &lt;code&gt;issues&lt;/code&gt; state is synchronized, the client decrypts the issues with the symmetric key and updates the &lt;code&gt;decryptedIssues&lt;/code&gt; state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Decrypts an encrypted message using a symmetric key.
 * @param encryptedMessage - The encrypted message, base64 encoded.
 * @param symmetricKey - The base64 encoded symmetric key used for decryption.
 * @returns The decrypted plaintext message.
 * @example
 * const decryptedMessage = symmetricDecrypt(encryptedMessage, symmetricKey);
 * console.log(decryptedMessage); // Decrypted plaintext message
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;symmetricDecrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;encryptedMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;symmetricKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;symmetricKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedBytesWithIv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encryptedBytesWithIv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encryptedBytesWithIv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDecipher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-CBC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encryptedBytes&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;forge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeUtf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBytes&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Diffie–Hellman key exchange
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Diffie–Hellman key exchange is a mathematical method of securely exchanging cryptographic keys over a public channel and was one of the first public-key protocols.&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Diffie–Hellman key exchange is a method for securely exchanging cryptographic keys over a public channel. It allows two parties to agree on a shared secret key without exchanging the key directly. This is achieved by each party generating a public-private key pair and exchanging public keys. The shared secret key is then derived from the combination of the private key and the other party's public key.&lt;/p&gt;

&lt;p&gt;In the context of Planning Poker, the Diffie–Hellman key exchange could be used to establish a shared symmetric key between all participants. This would eliminate the need for a single point of failure.&lt;/p&gt;

&lt;p&gt;The problem with this approach is that it does not solve the problem of &lt;code&gt;N * M&lt;/code&gt; issues being created, where N is the number of players and M is the number of issues.&lt;br&gt;
The secret key now is the combination of pairs of keys, so the application needs to handle a &lt;code&gt;issuesState&lt;/code&gt;for each pair of keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of E2EE in Planning Poker
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: Ensures that issues remain confidential among the participants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Protects against potential eavesdropping or data breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust&lt;/strong&gt;: Builds trust among team members, knowing that their issues are secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next steps and Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Room IDs&lt;/strong&gt;: A UUID is secure enough to be the room identifier?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key size&lt;/strong&gt;: What is the ideal key size for the symmetric key and the RSA key pair?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: How to ensure that the encryption and decryption process is fast enough to keep up with the pace of the Planning Poker game?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RSA vs. ECC&lt;/strong&gt;: Should we consider using Elliptic Curve Cryptography (ECC) instead of RSA for key generation? ECC is known for its shorter key lengths and faster performance compared to RSA. RSA is more widely used and supported, but the key-pair generation and encryption/decryption process can be really slow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this article, we have explored the concept of end-to-end encryption (E2EE) and its potential application in Planning Poker. We have discussed the importance of E2EE in ensuring privacy, security, and trust among team members.&lt;/p&gt;

&lt;p&gt;We have also examined the challenges of implementing E2EE in a real-time collaborative tool like Planning Poker, such as the need to encrypt data with the public keys of all participants and the need to ensure that the encryption and decryption process is fast enough to keep up with the pace of the game.&lt;/p&gt;

&lt;p&gt;We have proposed a hybrid approach that combines the benefits of both symmetric and asymmetric encryption. This approach involves using a symmetric key to encrypt the data, but the key is encrypted with the public keys of all participants. This ensures that only the participants can decrypt the key and access the data, eliminating the need for a single point of failure and reducing the complexity of key management.&lt;/p&gt;

&lt;p&gt;However, there are still many considerations and potential challenges to address, such as the choice of key size, the performance of the encryption and decryption process, and the choice between RSA and ECC for key generation.&lt;/p&gt;

&lt;p&gt;In conclusion, while E2EE can significantly enhance the security of Planning Poker, its implementation requires careful consideration and planning. It is not a one-size-fits-all solution, but rather a tool that can be tailored to meet the specific needs and constraints of each application.&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>e2ee</category>
      <category>planning</category>
      <category>scrum</category>
    </item>
    <item>
      <title>How to Successfully Integrate with Legacy APIs Using NodeJS</title>
      <dc:creator>Aluisio Amorim C.</dc:creator>
      <pubDate>Mon, 11 Dec 2023 18:20:08 +0000</pubDate>
      <link>https://forem.com/aluisiodev/how-to-successfully-integrate-with-legacy-apis-using-nodejs-3kbf</link>
      <guid>https://forem.com/aluisiodev/how-to-successfully-integrate-with-legacy-apis-using-nodejs-3kbf</guid>
      <description>&lt;p&gt;Hello, I'm Aluisio, a software engineer with a rich history of integrating with Brazilian banks, insurance companies, and ERPs.&lt;/p&gt;

&lt;p&gt;In this article, I'll share my experience and guide you through the process of seamless integration. For instructional purposes, I'll exaggerate partner inefficiencies, but it's crucial to tailor these strategies to your unique context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document Everything
&lt;/h2&gt;

&lt;p&gt;When embarking on the integration journey, the initial step is to request documentation. However, the reality is that &lt;strong&gt;not every company excels at documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uncertainty looms over the structure of responses.&lt;/li&gt;
&lt;li&gt;The configuration of the POST body remains a mystery.&lt;/li&gt;
&lt;li&gt;Required parameters are shrouded in ambiguity.&lt;/li&gt;
&lt;li&gt;The meanings of various fields are unclear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The solution? Write your documentation!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Begin by selecting your preferred platform for API development (e.g., Postman, Insomnia), then create a collection and commence drafting your requests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If feasible, consider importing the requests provided by your partner.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffu7je4hh1ngh5uh7d6tu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffu7je4hh1ngh5uh7d6tu.png" alt="Postman printscreen" width="670" height="469"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Create a Dedicated Section for Your Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Establish a dedicated section for your documentation, whether it's a &lt;a href="https://docs.github.com/pt/communities/documenting-your-project-with-wikis/about-wikis" rel="noopener noreferrer"&gt;Wiki&lt;/a&gt; within your repository, a 'docs' folder in your monorepo, a page on Notion, or any other suitable platform.&lt;/p&gt;

&lt;p&gt;This documentation should encompass the following key components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs&lt;/strong&gt;: Include links to the partner's documentation. This serves as a quick reference for your team to access essential information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contacts&lt;/strong&gt;: Documenting available contacts is crucial. Specify people's names and their respective positions. This not only provides clarity on the support network but also ensures that in the absence of the designated integration contact, another developer can seamlessly take over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Working Requests&lt;/strong&gt;: Compile a comprehensive list of all endpoints that are functional and yield valuable data for your business. Each entry in this list should include a detailed description (as interpreted by your team) of the endpoint, its required parameters, and a breakdown of each response field. For any unknown fields, mark them with a 'TODO,' and ensure that the relevant partner contacts are activated for swift resolution.&lt;/p&gt;

&lt;p&gt;This structured documentation will significantly enhance your integration process, fostering clarity and efficiency within your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write an RFC (Request for Comments)
&lt;/h2&gt;

&lt;p&gt;Consider initiating the integration process by drafting a Request for Comments (RFC). Refer to the concept of &lt;a href="https://pt.wikipedia.org/wiki/Request_for_Comments" rel="noopener noreferrer"&gt;RFC&lt;/a&gt; for guidance. Emphasize the importance of maintaining clean and well-documented code to facilitate comprehension and collaboration among developers working on the integration.&lt;/p&gt;

&lt;p&gt;Conduct a thorough evaluation of existing integrations within your team's codebase. Identify commonalities, potential areas for abstraction, and opportunities for optimization such as concurrency and batch processing. Advocate for &lt;strong&gt;asynchronous and efficient communication&lt;/strong&gt;, providing practical implementation suggestions along with code examples.&lt;/p&gt;

&lt;p&gt;Once your team aligns on the integration strategy, proceed to the coding phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mock the API
&lt;/h2&gt;

&lt;p&gt;In my experience, achieving a &lt;strong&gt;quality delivery is inseparable from rigorous testing&lt;/strong&gt;. Begin by creating test scenarios, especially when integrating with complex systems like ERPs.&lt;/p&gt;

&lt;p&gt;Consider a hypothetical scenario where data from a list of companies within an ERP needs to be retrieved. As a personal recommendation, leverage tools like &lt;a href="https://github.com/mswjs/msw" rel="noopener noreferrer"&gt;MSW&lt;/a&gt; for top-level mocks, which can significantly enhance the testing process.&lt;/p&gt;

&lt;p&gt;Prioritizing testing not only ensures the reliability of your integration but also streamlines the development workflow, ultimately leading to a more robust and maintainable codebase.&lt;/p&gt;

&lt;p&gt;So, firstly, setup your handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setupServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Describe network behavior with request handlers.&lt;/span&gt;
  &lt;span class="c1"&gt;// Tip: move the handlers into their own module and&lt;/span&gt;
  &lt;span class="c1"&gt;// import it across your browser and Node.js setups!&lt;/span&gt;
  &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/companies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f8dd058f-9006-4174-8d49-e3086bc39c21&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tradeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`My Test Company`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8ac96078-6434-4959-80ed-cc834e7fef61&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tradeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`My Test Company 2`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Enable request interception.&lt;/span&gt;
&lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// Reset handlers so that each test could alter them&lt;/span&gt;
&lt;span class="c1"&gt;// without affecting other, unrelated tests.&lt;/span&gt;
&lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resetHandlers&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// Don't forget to clean up afterwards.&lt;/span&gt;
&lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create your test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gets companies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your function to fetch the endpoint data (it can use fetch,&lt;/span&gt;
    &lt;span class="c1"&gt;// axios, etc).&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;companies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCompanies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;companies&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f8dd058f-9006-4174-8d49-e3086bc39c21&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tradeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Test Company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8ac96078-6434-4959-80ed-cc834e7fef61&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tradeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Test Company 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Type the API
&lt;/h2&gt;

&lt;p&gt;After creating the test cases, the next crucial step is to define the types for your API endpoints. I highly recommend leveraging &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;Zod&lt;/a&gt;💫 for its exceptional type safety and developer experience (DX).&lt;/p&gt;

&lt;p&gt;An innovative approach is to &lt;strong&gt;integrate GPT into this process&lt;/strong&gt;. Here's how:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt469170ibqwxsduf2mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt469170ibqwxsduf2mn.png" alt="GPT Prompt" width="512" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Having integrated with endpoints featuring over 80 fields in the response, the time-saving potential of GPT becomes truly apparent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Response:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0y6rdv0504is3es129j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0y6rdv0504is3es129j.png" alt="GPT response" width="690" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wonderful, GPT saved us a lot of time, right?&lt;/p&gt;

&lt;p&gt;One remarkable advantage of using Zod schemas is that they are &lt;strong&gt;not strict&lt;/strong&gt;. In cases where certain fields, like &lt;code&gt;foo&lt;/code&gt;, are not pertinent, Zod allows for their effortless removal. This flexibility ensures that your schema definitions remain concise and directly aligned with your specific needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Zod schema without `foo`&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCompaniesResponseSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// Improved schema definition&lt;/span&gt;
    &lt;span class="na"&gt;tradeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// A company cannot have less than 0 employees&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Response type&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetCompaniesResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;getCompaniesResponseSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that you can improve GPT responses with some &lt;a href="https://en.wikipedia.org/wiki/Prompt_engineering" rel="noopener noreferrer"&gt;prompt engineering&lt;/a&gt; to add restrictions, descriptions, and possible meanings for each field, in the schema definition.&lt;br&gt;
Feel free to explore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, use the schema to parse the responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Gets companies list
 *
 * @example
 *   const companies = await getCompanies();
 *
 * @throws {ZodError} If parsing fails (response is not valid)
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCompanies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GetCompaniesResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-api.com/companies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getCompaniesResponseSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Definitions of Done
&lt;/h2&gt;

&lt;p&gt;As the integration process progresses, it's imperative to establish clear conditions for its conclusion. Ideally, these criteria should be aligned even before the initiation of RFCs, ensuring a cohesive and well-orchestrated development journey.&lt;/p&gt;

&lt;p&gt;However, the final stage of delivery is the "Definitions of Done". It encapsulates all the necessary conditions for integration completion. These conditions encompass every integration requirement, essentially encapsulating all the data required for resolving the targeted problem.&lt;/p&gt;

&lt;p&gt;Once these defined requirements are met, &lt;strong&gt;the integration achieves its state of readiness&lt;/strong&gt;. These "Definitions of Done" serve as a comprehensive checklist, assuring that every aspect of the integration is not only functional but also aligned with the broader objectives it aims to address.&lt;/p&gt;

&lt;p&gt;In essence, the clarity provided by these conclusive criteria ensures that the integration is not only technically sound but also effectively solves the targeted problem, contributing to a &lt;strong&gt;successful and impactful project delivery&lt;/strong&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
