<?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: Proesc</title>
    <description>The latest articles on Forem by Proesc (@proesc).</description>
    <link>https://forem.com/proesc</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%2Forganization%2Fprofile_image%2F8170%2Faee75d7d-41c6-471f-8e2b-7ae87a37aaf6.png</url>
      <title>Forem: Proesc</title>
      <link>https://forem.com/proesc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/proesc"/>
    <language>en</language>
    <item>
      <title>Como criei um dashboard estratégico com Streamlit usando dados do Jira (sendo Product Owner)</title>
      <dc:creator>Aline Daher</dc:creator>
      <pubDate>Wed, 15 Jan 2025 20:03:46 +0000</pubDate>
      <link>https://forem.com/proesc/como-criei-um-dashboard-estrategico-com-streamlit-usando-dados-do-jira-sendo-product-owner-igj</link>
      <guid>https://forem.com/proesc/como-criei-um-dashboard-estrategico-com-streamlit-usando-dados-do-jira-sendo-product-owner-igj</guid>
      <description>&lt;p&gt;Como Product Owner, meu papel é atuar como um facilitador de decisões estratégicas, ajudando a liderança e o time a alcançar seus objetivos com base em dados precisos e acionáveis. No meu dia a dia, identifiquei uma necessidade crítica: acessar informações detalhadas e personalizadas sobre o desempenho do time técnico, composto por profissionais de dados, desenvolvedores, infraestrutura, UX e PMs.&lt;/p&gt;

&lt;p&gt;A abordagem tradicional de obter essas informações diretamente no Jira provou ser recorrente, pouco escalável e custosa, principalmente pela dependência de aplicativos adicionais da plataforma. Diante desse cenário, resolvi criar o Tech Reports, um ambiente personalizado que me permite coletar métricas específicas e gerar relatórios sob medida, adaptados às demandas tanto do time quanto da liderança.&lt;/p&gt;

&lt;p&gt;Essa iniciativa vai além das atribuições tradicionais da minha função, mas trouxe um impacto significativo ao meu trabalho. Com o Tech Reports, consegui otimizar processos, reduzir custos e, mais importante, garantir que dados confiáveis e relevantes estejam sempre disponíveis como base para decisões estratégicas.&lt;/p&gt;

&lt;p&gt;Confira os tópicos que abordaremos hoje: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Por que criar uma solução própria?&lt;/li&gt;
&lt;li&gt;Relatórios no ambiente&lt;/li&gt;
&lt;li&gt;Ferramentas e tecnologias&lt;/li&gt;
&lt;li&gt;Código em ação&lt;/li&gt;
&lt;li&gt;Impacto no time e na liderança&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vou explicar como esse projeto foi estruturado, os relatórios que implementei e o impacto que ele teve na equipe e na liderança.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que criar uma solução própria?&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Embora o Jira ofereça ótimos recursos, nem todos atendem às necessidades específicas de times ou lideranças. Alguns impedimentos me motivaram a criar o &lt;strong&gt;Tech Reports&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Custos adicionais:&lt;/strong&gt; Muitos relatórios ou dashboards no Jira requerem plugins pagos.&lt;br&gt;
&lt;strong&gt;Falta de personalização:&lt;/strong&gt; As visões disponíveis nem sempre atendem às necessidades do time ou da liderança.&lt;br&gt;
&lt;strong&gt;Tarefas repetitivas:&lt;/strong&gt; Criação e gestão de sprints em múltiplos boards tomavam um tempo precioso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A solução? Uma ferramenta personalizada que integra a API do Jira com dashboards interativos criados com Streamlit e Plotly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relatórios no ambiente &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Os relatórios do Tech Reports foram desenvolvidos para trazer uma visão abrangente e detalhada das sprints e da capacidade das equipes. Aqui estão os principais relatórios e suas funcionalidades:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quantitativo da sprint&lt;/strong&gt;&lt;br&gt;
Apresenta uma visão geral das tarefas da sprint, categorizando-as em: &lt;em&gt;total, tarefas planejadas e tarefas não planejadas&lt;/em&gt;. &lt;br&gt;
Esta segmentação permite compreender rapidamente o panorama da sprint em termos de volume e organização.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entrega planejada vs não planejada&lt;/strong&gt;&lt;br&gt;
Compara a entrega de tarefas planejadas com as tarefas não planejadas, destacando a proporção entre elas. Esse comparativo ajuda a visualizar o equilíbrio entre demandas planejadas e urgências.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resolução da sprint&lt;/strong&gt;&lt;br&gt;
Exibe o percentual de tarefas em cada status, oferecendo uma visão geral do progresso e da conclusão das atividades durante a sprint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tarefas não planejadas por setor&lt;/strong&gt;&lt;br&gt;
Analisa quais setores são responsáveis por originar o maior número de tarefas não planejadas, ajudando a identificar padrões e oportunidades de melhoria no planejamento.&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%2Fycgwm7oednqj1ncozk3l.gif" 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%2Fycgwm7oednqj1ncozk3l.gif" alt="Image description" width="1919" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visão por squad&lt;/strong&gt;&lt;br&gt;
Detalha a distribuição de issues por membro do time, incluindo o status atual de cada tarefa, com uma visualização colorida para facilitar a identificação rápida.&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%2Frrs66ta0amqn9yciq31g.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%2Frrs66ta0amqn9yciq31g.png" alt="Image description" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capacidade do squad&lt;/strong&gt;&lt;br&gt;
Apresenta a capacidade de trabalho de cada membro em horas estimadas, destacando potenciais sobrecargas ou subutilização de recursos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medição de horas trabalhadas e horas planejadas&lt;/strong&gt;&lt;br&gt;
Realiza a comparação entre as horas planejadas e as horas efetivamente trabalhadas por cada integrante da equipe, identificando desvios nas estimativas e na execução.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disponibilidade da equipe por sprint&lt;/strong&gt;&lt;br&gt;
Mostra a capacidade remanescente de cada membro com base em um limite padrão de 75 horas por sprint, facilitando o gerenciamento de recursos e a alocação de novas tarefas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Taxa de utilização&lt;/strong&gt;&lt;br&gt;
Indica a proporção de utilização de cada membro da equipe em relação à capacidade máxima estipulada, permitindo monitorar o ritmo de trabalho.&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%2Fs7fexelq3eu6kgx7rov5.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%2Fs7fexelq3eu6kgx7rov5.png" alt="Image description" width="750" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribuição de esforço por cargo&lt;/strong&gt;&lt;br&gt;
Fornece uma visão detalhada da divisão do esforço entre diferentes cargos dentro da sprint, com base no total de horas dedicadas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribuição de esforço por issue&lt;/strong&gt;&lt;br&gt;
Apresenta a alocação percentual de issues por responsável, utilizando estimativas de horas como métrica principal, permitindo analisar a carga de trabalho individual de forma precisa.&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%2Fr9lynw8fqf20k0s4fzkx.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%2Fr9lynw8fqf20k0s4fzkx.png" alt="Image description" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Ferramentas e Tecnologias &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Essas foram as ferramentas e bibliotecas que usei para dar vida ao projeto:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Streamlit:&lt;/strong&gt; &lt;em&gt;Framework para criar dashboards web de forma simples e rápida.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Requests:&lt;/strong&gt; &lt;em&gt;Para consumir e manipular dados da API do Jira.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Pandas:&lt;/strong&gt; &lt;em&gt;Para transformar e estruturar os dados.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Plotly:&lt;/strong&gt; &lt;em&gt;Para criar gráficos e visualizações interativas.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Streamlit-authenticator:&lt;/strong&gt; &lt;em&gt;Controle de acesso e autenticação de usuários.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Python-dotenv:&lt;/strong&gt; &lt;em&gt;Gerenciamento de variáveis sensíveis, como tokens de API.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Psycopg2:&lt;/strong&gt; &lt;em&gt;Conexão com banco de dados PostgreSQL&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Openpyxl:&lt;/strong&gt; &lt;em&gt;Manipulação de relatórios em Excel.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Boto3:&lt;/strong&gt; &lt;em&gt;Integração com AWS para armazenar arquivos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nota: É necessário instalar o Streamlit antes de iniciar o projeto. Confira a &lt;a href="https://docs.streamlit.io/" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt; para instruções de instalação.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Código em ação &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;1. Configurando a autenticação com a API do Jira&lt;/strong&gt;&lt;br&gt;
Antes de acessar os dados, configuramos a autenticação usando as credenciais armazenadas em variáveis de ambiente. Essas credenciais são codificadas em base64 para serem enviadas como parte do cabeçalho das requisições.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import base64
import os
from dotenv import load_dotenv

// Carrega variáveis de ambiente
load_dotenv()

// Configuração de credenciais 

jira_username = os.getenv("JIRA_USERNAME")
jira_api_token = os.getenv("JIRA_API_TOKEN")
jira_domain = os.getenv("JIRA_DOMAIN") 

// Codifica as credenciais para autenticação

jira_credentials = f"{jira_username}:{jira_api_token}"
jira_encoded_credentials = base64.b64encode(jira_credentials.encode()).decode("utf-8")

// Cabeçalhos para requisições
def get_jira_headers():
    return {
        "Authorization": f"Basic {jira_encoded_credentials}",
        "Content-Type": "application/json"
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dica:&lt;/strong&gt; Certifique-se de configurar suas variáveis de ambiente corretamente no arquivo .env com as seguintes informações:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JIRA_USERNAME=seu_usuario
JIRA_API_TOKEN=seu_token
JIRA_DOMAIN=seu_dominio.atlassian.net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Coletando sprints e issues&lt;/strong&gt;&lt;br&gt;
Usei a API para buscar todas as sprints ativas e fechadas de um board específico. Isso permite que o sistema exiba opções dinâmicas no dashboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@st.cache_data(show_spinner=False)
def get_all_sprints_for_board(board_id):
    headers = get_jira_headers()
    url = f"https://{jira_domain}/rest/agile/1.0/board/{board_id}/sprint?state=all"
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        sprints = response.json().get("values", [])
        return sorted(sprints, key=lambda x: x.get("startDate", ""), reverse=True)
    else:
        st.error("Erro ao buscar sprints.")
        return []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa abordagem organiza as sprints em ordem cronológica, permitindo que o dashboard exiba dados recentes primeiro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Processando e visualizando dados&lt;/strong&gt;&lt;br&gt;
Para transformar as informações das tarefas em insights úteis, criamos um DataFrame usando Pandas. Em seguida, utilizamos Plotly para visualizações interativas. Aqui está um exemplo de gráfico de pizza que mostra a distribuição de esforço por cargo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@st.cache_data(show_spinner=False)
def process_issues_by_role(df):
    // Agrupa tarefas por cargo e ajusta horas
    df['Role'] = df['Assignee'].apply(assign_role)
    role_hours = df.groupby('Role')['Time Estimate'].sum().reset_index()
    return role_hours

// Exibição do gráfico
fig_role = px.pie(
    role_hours,
    names='Role',
    values='Time Estimate',
    title="Distribuição de Esforço por Cargo",
    width=800,
    height=600
)
st.plotly_chart(fig_role)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Medindo capacidade e utilização&lt;/strong&gt;&lt;br&gt;
Um dos dashboards mais úteis é o de capacidade. Ele compara as horas planejadas e trabalhadas por cada membro da equipe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fig_hours = px.bar(
    df_hours,
    x="Assignee",
    y=["Horas Planejadas", "Horas Trabalhadas"],
    barmode="group",
    title="Medição de Horas Planejadas vs Trabalhadas",
)
st.plotly_chart(fig_hours)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Dica: Defina uma capacidade máxima por sprint (exemplo: 75 horas por membro) para calcular a disponibilidade restante de cada integrante do time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Impacto no time e na liderança&lt;/strong&gt; &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Com o Tech Reports, consegui criar uma visão detalhada sobre o time técnico, englobando desde a capacidade de entrega até a performance em sprints. Alguns dos principais benefícios incluem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tomada de decisão baseada em dados:&lt;/strong&gt; &lt;em&gt;A liderança agora tem informações claras e precisas para orientar decisões estratégicas.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Maior visibilidade:&lt;/strong&gt; &lt;em&gt;Os gráficos permitem uma análise detalhada da saúde das sprints, da capacidade do time e do impacto das demandas.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Identificação de gargalos:&lt;/strong&gt; &lt;em&gt;Relatórios específicos, como o de tarefas não planejadas por setor, ajudam a entender os pontos críticos do fluxo de trabalho.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Planejamento mais preciso:&lt;/strong&gt; &lt;em&gt;A análise de capacidade e disponibilidade garante que o planejamento seja baseado em dados reais e não em suposições.&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Maior eficiência operacional:&lt;/strong&gt; &lt;em&gt;A automatização de tarefas e a organização visual economizam tempo e reduzem custos com ferramentas adicionais.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Essas melhorias não apenas economizaram tempo, mas também aumentaram a eficiência e a precisão nas discussões de progresso e prioridades.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O Tech Reports é uma solução que integra dados, automação e visualizações interativas para transformar a forma como a equipe técnica e a liderança trabalham. Ao fornecer métricas claras, insights detalhados e automações inteligentes, ele se tornou um aliado indispensável para melhorar o planejamento e a execução de projetos.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Construindo um monolito moderno com Inertia.js</title>
      <dc:creator>Luma Montes</dc:creator>
      <pubDate>Fri, 03 Jan 2025 20:31:56 +0000</pubDate>
      <link>https://forem.com/proesc/construindo-um-monolito-moderno-com-inertiajs-1j1k</link>
      <guid>https://forem.com/proesc/construindo-um-monolito-moderno-com-inertiajs-1j1k</guid>
      <description>&lt;p&gt;Recentemente tive uma experiência com Inertia Js em um projeto, e fiquei impressionada com a facilidade que foi o desenvolvimento! Neste artigo, vou falar um pouquinho sobre como o Inertia funciona e seus benefícios.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o Inertia.js?
&lt;/h2&gt;

&lt;p&gt;O Inertia JS é uma nova abordagem criada pra facilitar o desenvolvimento de monolitos modernos. Ele tem uma forte relação com o ecossistema Laravel, mas também pode ser usado em outros frameworks de backend.  Um projeto com Inertia.js é bem parecido com os projetos em PHP, a diferença é que o frontend agora é em React (ou Vue). O inertia.js atua fazendo a comunicação entre o seu frontend e seu backend, substituindo a necessidade por uma API, por exemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que usar o Inertia.js?
&lt;/h2&gt;

&lt;p&gt;Seu objetivo de negócio e o seu time são alguns dos pontos a levar em consideração! Em projetos onde os times de frontend e backend são separados ou há integração entre diferentes negócios ou empresas, faz sentido dividir o sistema em serviços ou projetos independentes.&lt;/p&gt;

&lt;p&gt;Em contrapartida, um só time com poucos desenvolvedores que precisariam ser multidisciplinares, trabalhando tanto no código frontend quando backend o tempo todo, fez bastante sentido em utilizar o inertia pra entregar o projeto sem grandes complexidades que os microserviços trazem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como funciona?
&lt;/h2&gt;

&lt;p&gt;O Inertia.js elimina a necessidade de uma API tradicional. Você pode enviar dados do backend diretamente para o frontend como parâmetros em uma resposta, e o frontend usa esses dados para renderizar componentes. Para realizar a instalação, você pode seguir os passos da documentação:&lt;a href="https://inertiajs.com/server-side-setup" rel="noopener noreferrer"&gt;https://inertiajs.com/server-side-setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aqui adicionei um exemplo simples:&lt;/p&gt;

&lt;p&gt;Definição de rota:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// web.php&lt;/span&gt;
&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/books'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BooksController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criação de lógica no controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;//BooksController.php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inertia\Inertia&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BooksController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Inertia&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Books/Index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'books'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$books&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;Renderização da sua view usando React e Typescript:&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;// resources/js/Pages/Books/Index.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usePage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Book&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;number&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BooksIndex&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePage&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Book&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="p"&gt;))}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;E pronto! Esse é um exemplo simples do funcionamento do inertia, quem já vem do desenvolvimento em PHP percebe que é bem parecido com as blades do PHP (tirando o fato de ser React/Vue).&lt;/p&gt;

&lt;p&gt;Nesse exemplo acima, o hook &lt;code&gt;usePage&lt;/code&gt; do Inertia é usado pra puxar as informações que mandamos como lá no controller. Além disso, alguns dos principais utilitários disponíveis são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;useRemember&lt;/strong&gt;: Armazena dados entre navegações de página.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WhenVisible&lt;/strong&gt;: Componente usado como forma de só carregar dados quando um elemento se torna vísivel na página&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deferred&lt;/strong&gt;: Permite você adie o carragamento de determinados nados da ágina até depois da renderização inicial, especialment usando em casos onde parte dos dados não são imediatamente necessárias no primeiro carregamento&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link&lt;/strong&gt;: Componente usado para navegação, similar ao  do React Router&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Logicamente, tudo depende dos requisitos do seu projeto e do seu time. Mas o Inertia é uma ótima ferramenta que vem crescendo e se desenvolvendo cada vez mais no ecossistema laravel, uma ótima pedida pra projetos monolitos com PHP e com frameworks modernos como React/Vue para trazer uma melhor experiência para os usuários. A seguir o link da documentação, que foi base para este artigo, recomendo a leitura para conhecer mais sobre o Inertia:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://inertiajs.com/" rel="noopener noreferrer"&gt;https://inertiajs.com/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Iniciando em React</title>
      <dc:creator>Lucas Edilson</dc:creator>
      <pubDate>Fri, 10 May 2024 13:13:05 +0000</pubDate>
      <link>https://forem.com/proesc/iniciando-em-react-1cd3</link>
      <guid>https://forem.com/proesc/iniciando-em-react-1cd3</guid>
      <description>&lt;p&gt;Para quem curte trabalhar com interfaces interativas o conhecimento de React é de grande ajuda para o desenvolvimento dessas interfaces. Se você utiliza redes sociais com frequência, principalmente do ecossistema do Facebook, já percebeu que partes determinadas da tela têm comportamentos especifícos e independentes do restante da aplicação. Um exemplo disso seriam os anúncios que são exibidos nas aplicações.&lt;/p&gt;

&lt;p&gt;Tentando identificar a melhor forma de lidar com esse tipo de funcionalidade, a equipe de desenvolvedores do Facebook desenvolveu uma forma muito específica de lidar com as informações exibidas e a atualização dessas pequenas partes da aplicação: o React.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o React?
&lt;/h2&gt;

&lt;p&gt;O React é uma biblioteca de JavaScript focada na construção de interfaces altamente interativas, ou seja, se trata de um conjunto de linhas de código em JavaScript criados pela comunidade, que podem ser reutilizados em diversos projetos.&lt;/p&gt;

&lt;p&gt;Indo um pouco além, várias empresas de tecnologia, como por exemplo o Instagram, a Netflix, o Airbnb e o Twitter, utilizam o React em suas aplicações web e mobile.&lt;/p&gt;

&lt;p&gt;Isso indica que existe uma boa variedade de oportunidades de mercado em diferentes tipos de empresas que se utilizam do React. Fora isso, o React é uma biblioteca de código aberto, o que significa que ele tem uma comunidade ativa de desenvolvedores que contribuem constantemente com códigos e recursos para ajudar a melhorar a tecnologia.&lt;/p&gt;

&lt;h6&gt;
  
  
  React é um framework?
&lt;/h6&gt;

&lt;p&gt;Não, o React não é um framework, ele é uma biblioteca utilizada para criação de de interfaces. Dito isso, ele é utilizado em vários frameworks como por exemplo o Remix, Next.js, RedwoodJS e Blitz.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  SPA x SSR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SPA&lt;/strong&gt; ou &lt;strong&gt;single page application&lt;/strong&gt; é uma forma em que a aplicação web é carregada em uma única página, atualizada dinamicamente conforme o usuário interage com a aplicação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSR&lt;/strong&gt; ou &lt;strong&gt;server side rendering&lt;/strong&gt; é uma técnica de renderização em que o servidor processa a solicitação do usuário e envia uma página HTML completa de volta ao navegador. Ou seja, antes de a página ser exibida no navegador, todo o processamento necessário já foi feito no servidor.&lt;/p&gt;

&lt;p&gt;A principal diferença entre SSR e SPA é aonde a página é renderizada. Enquanto no SSR, a página é renderizada no servidor antes de ser enviada para o navegador, já no SPA, a renderização ocorre no navegador, conforme o usuário interage com a aplicação. Um destaque importante é que o SPA é melhor para a experiência do usuário, pois evita um desgaste com o recarregamento de várias telas consecutivas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs4p35ptss4kg8xuywlg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs4p35ptss4kg8xuywlg.png" alt="Image description" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Iniciando um projeto em React
&lt;/h2&gt;

&lt;h6&gt;
  
  
  Ferramentas:
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="//nodejs.org"&gt;Node&lt;/a&gt; instalado no computador.&lt;/li&gt;
&lt;li&gt;Um gerenciador de pacotes chamado npm, ele vem incluído automaticamente na sua instalação do Node.&lt;/li&gt;
&lt;li&gt;Um bom editor de código para trabalhar nos arquivos do projeto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para criar um novo projeto em React, podemos usar a ferramenta npx. Ela nos possibilita na utilização do pacote &lt;code&gt;create-react-app&lt;/code&gt; sem ter de instalá-lo primeiro no seu computador.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app meu-app-do-react&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Após isso, o projeto será criado no seu computador e para iniciar ele basta utilizar o seguinte comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsj2fiju7n2ebv9i1pi0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsj2fiju7n2ebv9i1pi0.png" alt="Image description" width="712" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Componentes e Propriedades
&lt;/h2&gt;

&lt;h6&gt;
  
  
  # Componentes no React
&lt;/h6&gt;

&lt;p&gt;Os componentes são blocos de construção fundamentais para qualquer aplicação React. Eles são a representação de partes isoladas da interface do usuário e variam em tamanho e complexidade.&lt;br&gt;
A modularização de componentes no React nos permite criar e reutilizar eles de maneira eficiente.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;function MeuComponente(props) {&lt;br&gt;
  return &amp;lt;div&amp;gt;Olá, {props.nome}!&amp;lt;/div&amp;gt;;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  # Propriedades no React
&lt;/h6&gt;

&lt;p&gt;As propriedades, normalmente abreviadas como &lt;strong&gt;props&lt;/strong&gt;, são um mecanismo fundamental para passar dados de um componente pai para um componente filho. Ou seja, permite que os componentes sejam preenchidas de maneiras dinamicas e sejam facilmente reutilizáveis dentro do código.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;function MeuComponente(props) {&lt;br&gt;
  return &amp;lt;div&amp;gt;Olá, {props.nome}!&amp;lt;/div&amp;gt;;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Boas práticas de Product Owner no time de tecnologia</title>
      <dc:creator>Aline Daher</dc:creator>
      <pubDate>Thu, 11 Apr 2024 02:13:44 +0000</pubDate>
      <link>https://forem.com/proesc/boas-praticas-de-product-owner-no-time-de-tecnologia-an7</link>
      <guid>https://forem.com/proesc/boas-praticas-de-product-owner-no-time-de-tecnologia-an7</guid>
      <description>&lt;p&gt;No ambiente acelerado e muitas vezes complicado das equipes de tecnologia, o papel do Product Owner é um catalisador sem o qual todos os esforços não serão suficientes. Atuando como o elo entre os objetivos do negócio e os detalhes técnicos, o Product Owner é necessário para garantir que sua equipe não apenas cumpra as expectativas, mas as supere. É por isso que este artigo busca compartilhar um conjunto de dicas e abordagens para Product Owners que desejam aprimorar sua contribuição para as equipes de tecnologia. Desde técnicas de interação diárias que garantam o bom funcionamento, este guia será útil para Product Owners em qualquer etapa de sua carreira. Dito isto vamos mergulhar nas estratégias que podem transformar a forma como você lidera e contribui para o seu time de tecnologia!&lt;/p&gt;

&lt;p&gt;Confira os tópicos que abordaremos hoje: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Intercalação de Daily Top Down e Round Robin

&lt;ul&gt;
&lt;li&gt;Acompanhamento via Dashboard&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Revisão Contínua do Backlog&lt;/li&gt;
&lt;li&gt;Checklist de Refinamento&lt;/li&gt;
&lt;li&gt;
Análise de Indicadores: Identificando Travas e Oportunidades &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas estratégias foram vistas, estudadas e aplicadas por mim, que sou atualmente Product Owner na Proesc.com, com base nas leituras dos livros "Sprint a Sprint" de Mary Provinciatto e Paulo Caroli, bem como "Product Backlog Building" de Fábio Aguiar e Paulo Caroli. Ambas as obras fornecem insights valiosos e práticas recomendadas que serviram de fundamento para os tópicos que exploraremos, garantindo uma abordagem fundamentada e eficaz para o papel do Product Owner em equipes de tecnologia.&lt;/p&gt;

&lt;h1&gt;
  
  
  Intercalação de Daily Top Down e Round Robin &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;A estratégia de intercalar as dailys com abordagens Top Down e Round Robin atende à necessidade de acompanhar o progresso e o sucesso na conclusão de tarefas pelos desenvolvedores. Esse método é essencial para identificar rapidamente se é necessária a redistribuição de conhecimentos dentro da equipe, a fim de otimizar as entregas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Acompanhamento via Dashboard: &lt;a&gt;&lt;/a&gt; Para complementar, o uso de um dashboard individualizado, mostrando todas as tarefas e o índice de conclusão na sprint, permite um acompanhamento preciso e visual do progresso. Esse recurso visual é crucial para identificar, em tempo real, onde a equipe está prosperando e onde pode precisar de ajustes ou realocação de recursos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo de dashboard que utilizo:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2dypf3jnw9s1e10i3z9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2dypf3jnw9s1e10i3z9.png" alt="Image description" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Legenda
Top Down: Visão geral do progresso em relação às metas da sprint, onde cada colaborador irá divulgar sua ferramenta de acompanhamento e atualizar a equipe como está o status de cada task

Round Robin: Discussão detalhada do progresso individual e desafio, baseado no padrão: 
1. O que fiz ontem?
2. O que farei hoje?
3. Tive/Estou tendo alguma dificuldade?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Revisão Contínua do Backlog &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Mantenha o backlog limpo: Certifique-se de que cada item esteja atualizado, claro e diretamente vinculado aos objetivos de longo prazo. Elimine ou redefina tarefas que não serão abordadas nas próximas cinco sprints para evitar confusão e a transformação do backlog em um mero inventário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alinhamento estratégico: Garanta que as tarefas contribuam para os OKRs e o roadmap, revisando e ajustando regularmente o backlog para refletir mudanças estratégicas ou prioridades.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Checklist de refinamento &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Antes de uma tarefa ser levantada para a sprint, ela deve passar por um checklist rápido para garantir sua prontidão, baseado em três pilares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Informações Completas: Verifique se a tarefa tem todas as informações necessárias para execução.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Épico Selecionado: Confirme se a tarefa está associada a um épico específico.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Viabilidade de Conclusão: Avalie se a tarefa pode ser concluída dentro de uma sprint.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se todos esses critérios forem atendidos, o item está pronto para a sprint. Caso contrário, deve permanecer no backlog para ser atualizado pelo responsável de produto e posteriormente reavaliado pelo Product Owner.&lt;/p&gt;

&lt;p&gt;Exemplo de Template para descrição de tarefa:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsrmn3lw33fqtemzwqvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsrmn3lw33fqtemzwqvp.png" alt="Image description" width="753" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Análise de Indicadores: Identificando Travas e Oportunidades &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Para além das dailys, o Product Owner deve realizar análises periódicas de indicadores que reflitam o progresso da equipe. Esta análise estratégica dos dados permite identificar não só os gargalos na entrega, mas também oportunidades de otimização. Ações como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Acompanhamento Direto: Engajar-se diretamente com desenvolvedores que enfrentam desafios, oferecendo suporte e direcionamento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Promoção de Pair Programming: Incentivar a colaboração entre desenvolvedores, especialmente em tarefas complexas, para compartilhar conhecimentos e habilidades.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Esclarecimento de Dúvidas: Disponibilizar-se para resolver quaisquer questões sobre a especificidade e funcionamento das tarefas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estas iniciativas visam não apenas desbloquear obstáculos pontuais mas também aumentar a eficiência da equipe como um todo, elevando a taxa de conclusão das tarefas, tanto em nível micro quanto macro, ao longo das sprints.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Espero que este artigo sirva como um recurso valioso para os Product Owners em busca de excelência da mesma forma que foi gratificante para mim escrevê-lo, ajudando-os a liderar suas equipes na criação de produtos excepcionais.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>Fluxo de autenticação no React Native usando Expo Router</title>
      <dc:creator>Luma Montes</dc:creator>
      <pubDate>Sun, 18 Feb 2024 05:33:32 +0000</pubDate>
      <link>https://forem.com/proesc/fluxo-de-autenticacao-no-react-native-usando-expo-router-61h</link>
      <guid>https://forem.com/proesc/fluxo-de-autenticacao-no-react-native-usando-expo-router-61h</guid>
      <description>&lt;p&gt;Quem já trabalhou com rotas com Expo ou React Native, sabe que o React Navigation é a forma padrão de lidar com navegação! No entanto, conforme mais telas você vai criando no seu app, o código utilizado pode ficar bem grande, com processos manuais que precisam de muitas linhas de código para serem feitos. Logo, o time do Expo lançou uma novidade: Expo Router, uma alternativa ao React Navigation para roteamento e navegação com React Native. &lt;/p&gt;

&lt;p&gt;Esse post irá mostrar como criar um fluxo de autenticação com Expo Router no seu app React Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
 Principais funcionalidades do Expo Router:
&lt;/li&gt;
&lt;li&gt;
 Pré-requisitos
&lt;/li&gt;
&lt;li&gt;
 Exemplo de código

&lt;ul&gt;
&lt;li&gt;  1 - Crie um contexto de autenticação
&lt;/li&gt;
&lt;li&gt;
 2 - Adicione o arquivo app/_layout.tsx
&lt;/li&gt;
&lt;li&gt;
 3 - Crie a tela de login
&lt;/li&gt;
&lt;li&gt;
 4 - Adicione a lógica de autenticação no arquivo app/(auth)/_layout.tsx
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

 Conclusão &lt;/li&gt;

&lt;/ul&gt;

&lt;h6&gt;
  
  
  generated with &lt;a href="https://summaryze-forem.vercel.app/" rel="noopener noreferrer"&gt;Summaryze Forem 🌱&lt;/a&gt;
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Principais funcionalidades do Expo Router:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nativo&lt;/strong&gt;: Construído em cima do React Navigation, a navegação do Expo Router é nativa e otimizada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compartilhável&lt;/strong&gt;: Toda tela do seu aplicativo é automaticamente configurada com deep linking. Tornando qualquer rota do seu aplicativo compartilhável com links, como por exemplo, um link de redirecionamento de uma notificação, não sendo necessário configurar manualmente quais telas são acessíveis por links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline-first&lt;/strong&gt;: Os aplicativos são armazenados em cache e executados de forma offline first, com atualizações automáticas quando você publica uma nova versão.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Expo Router trás um conceito de &lt;em&gt;file based routing&lt;/em&gt;, ou seja, as rotas da aplicação refletem a estrutura dos arquivos criados na pasta &lt;code&gt;/app&lt;/code&gt;. Parecido, por exemplo, com a estrutura do Next.js.&lt;/p&gt;

&lt;p&gt;Quando um arquivo é criado na pasta app, automaticamente se torna uma rota no app. Logo, diferentemente do React Navigation, todas as stacks (ou rotas) do seu app já ficam publicas e disponíveis para navegação! Além disso, as navegações para diferentes telas podem ser feitas usando um elemento &lt;code&gt;&amp;lt;Link href='/nome-da-rota'&lt;/code&gt;, por exemplo. bem parecido com o que fazemos na web. Você pode usar um router.replace('nome-da-rota') para definir globalmente o redirecionamento de rota, além de rotas dinâmicas, criação de grupos de rotas e muito mais. 🤯&lt;/p&gt;

&lt;h2&gt;
  
  
  Pré-requisitos
&lt;/h2&gt;

&lt;p&gt;Para o exemplo a seguir, você pode clonar o projeto para reproduzir o exemplo.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

git clone git@github.com:lumamontes/expo-router-auth.git


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instale as dependências do projeto:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx expo &lt;span class="nb"&gt;install&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;E rode o projeto:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx expo start


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Mas, caso queira criar um projeto do zero, você pode seguir os passos originais do &lt;a href="https://docs.expo.dev/router/installation/#quick-start" rel="noopener noreferrer"&gt;Expo Router&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo de código
&lt;/h2&gt;

&lt;p&gt;Agora, vamos a um exemplo no código! Vamos implementar um fluxo de autenticação utilizando o Expo Router para navegação. Vamos analisar a estrutura do projeto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FsEF6S5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FsEF6S5o.png" alt="Pasted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alguns pontos chaves para entender o Expo Router:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Todos os arquivos que estão na pasta &lt;code&gt;/app&lt;/code&gt; serão rotas (com exceção de arquivos "especiais", que irei comentar abaixo!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_layout.tsx&lt;/code&gt;: O expo router possibilita a criação de &lt;em&gt;Layout routes&lt;/em&gt;, elementos que são compartilhados entre diversas telas, como uma header. No caso do arquivo app/_layout.tsx, ele é um layout que será compartilhado entre todas as telas dentro da pasta &lt;code&gt;/app&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pastas &lt;code&gt;(auth)&lt;/code&gt; e &lt;code&gt;(tags)&lt;/code&gt;: são grupos de rotas do Expo Router, que são usados para organizar as rotas do app. Você pode adicionar quantos grupos quiser. Grupos também são bons para organizar seções do app. No exemplo a seguir, temos &lt;strong&gt;app/(auth)&lt;/strong&gt; que irá ter as telas para usuários autenticados. Um ponto interessante é que os grupos não afetam a url, ou seja, um arquivo localizado na pasta &lt;code&gt;app/(auth)/nome-do-arquivo.tsx&lt;/code&gt; não terá a url &lt;code&gt;app/(auth)/nome-do-arquivo&lt;/code&gt;, mas sim &lt;code&gt;app/nome-do-arquivo&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ctx.tsx&lt;/code&gt;: é um contexto de autenticação, que irá centralizar algumas informações globais como a sessão do usuário, a função de logar e deslogar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;+not-found.tsx&lt;/code&gt;: é uma rota que será acessada quando nenhuma outra rota for encontrada.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Logo, o nosso app irá possui duas camadas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotas para usuários autenticados (todo o conteúdo do grupo (auth))&lt;/li&gt;
&lt;li&gt;Rotas para usuários não autenticados (somente a tela de login)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para fazer essa separação entre a camada de usuários autenticados e não autenticados, é possível criar um contexto que vai definir essas regras de negócio:&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - Crie um contexto de autenticação
&lt;/h3&gt;

&lt;p&gt;Esse contexto irá centralizar algumas informações e lógicas globais como a sessão do usuário, a função de signIn e signOut.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

iimport React from "react";
import { useStorageState } from "./useStorageState";

const AuthContext = React.createContext&amp;lt;{
  signIn: () =&amp;gt; void;
  signOut: () =&amp;gt; void;
  session?: string | null;
  isLoading: boolean;
}&amp;gt;({
  signIn: () =&amp;gt; null,
  signOut: () =&amp;gt; null,
  session: null,
  isLoading: false,
});

// This hook can be used to access the user info.
export function useSession() {
  const value = React.useContext(AuthContext);
  return value;
}

export function SessionProvider(props: React.PropsWithChildren) {
  const [[isLoading, session], setSession] = useStorageState("session");
  return (
    &amp;lt;AuthContext.Provider
      value={{
        signIn: () =&amp;gt; {
          // Add your login logic here
          // For example purposes, we'll just set a fake session in storage
          setSession("John Doe");
        },
        signOut: () =&amp;gt; {
          setSession(null);
        },
        session,
        isLoading,
      }}
    &amp;gt;
      {props.children}
    &amp;lt;/AuthContext.Provider&amp;gt;
  );
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A função &lt;code&gt;signIn&lt;/code&gt; irá salvar a sessão do usuário, nesse caso, uma simples string 'John Doe', e a função &lt;code&gt;signOut&lt;/code&gt; irá remover a sessão alterando esse valor para null.&lt;/p&gt;

&lt;p&gt;Para finalidade de testes, a função signIn não irá ter nenhum tipo de validação, sempre que ela for chamada, o usuário será autenticado. No entanto, em um app real, você pode adicionar a lógica de login do seu app fazendo uma requisição para uma API, por exemplo.&lt;/p&gt;

&lt;p&gt;Um ponto importante é que iremos salvar essas informações de sessão do usuário no storage do dispositivo, para que o usuário não precise logar toda vez que abrir o app.&lt;/p&gt;

&lt;p&gt;Para isso, utilizaremos o hook &lt;code&gt;useStorageState&lt;/code&gt; que retornar um estado e uma função para alterar esse estado, salvar e recuperar as informações do storage do dispositivo utilizando a biblioteca &lt;code&gt;expo-secure-store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Esse hook é composto por três funções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A função &lt;code&gt;useAsyncState&lt;/code&gt; irá retornar um estado e uma função para alterar esse estado, mas com um estado inicial de loading, que será true, e o valor inicial, que será null.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import * as SecureStore from "expo-secure-store";
import * as React from "react";
import { Platform } from "react-native";

type UseStateHook&amp;lt;T&amp;gt; = [[boolean, T | null], (value: T | null) =&amp;gt; void];

function useAsyncState&amp;lt;T&amp;gt;(
  initialValue: [boolean, T | null] = [true, null]
): UseStateHook&amp;lt;T&amp;gt; {
  return React.useReducer(
    (
      state: [boolean, T | null],
      action: T | null = null
    ): [boolean, T | null] =&amp;gt; [false, action],
    initialValue
  ) as UseStateHook&amp;lt;T&amp;gt;;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setStorageItemAsync&lt;/code&gt;: que irá salvar ou deletar um item no storage do dispositivo, dependendo do valor passado.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export async function setStorageItemAsync(key: string, value: string | null) {
  if (value == null) {
    await SecureStore.deleteItemAsync(key);
  } else {
    await SecureStore.setItemAsync(key, value);
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useStorageState&lt;/code&gt;: que irá retornar um estado e uma função para alterar esse estado, salvando e recuperando as informações do storage do dispositivo utilizando a biblioteca &lt;code&gt;expo-secure-store&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export function useStorageState(key: string): UseStateHook&amp;lt;string&amp;gt; {
  const [state, setState] = useAsyncState&amp;lt;string&amp;gt;();

  React.useEffect(() =&amp;gt; {
    SecureStore.getItemAsync(key).then((value) =&amp;gt; {
      setState(value);
    });
  }, [key]);

  const setValue = React.useCallback(
    (value: string | null) =&amp;gt; {
      setState(value);
      setStorageItemAsync(key, value);
    },
    [key]
  );

  return [state, setValue];
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Logo, se eu usar o hook dessa forma: useStorageState('session'), ele irá retornar: isLoading, session e setSession.&lt;/p&gt;

&lt;p&gt;Mas se eu usasse dessa forma: useStorageState('user'), ele irá retornar: isLoading, user e setUser, por exemplo.&lt;/p&gt;

&lt;p&gt;Podemos então entender que o useStorageState é um hook genérico que irá retornar um estado e uma função para alterar esse estado, salvando e recuperando as informações do storage do dispositivo utilizando a biblioteca &lt;code&gt;expo-secure-store&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Adicione o arquivo app/_layout.tsx
&lt;/h3&gt;

&lt;p&gt;Esse arquivo é um layout que será compartilhado entre todas as telas do app. Nele, podemos:&lt;/p&gt;

&lt;h4&gt;
  
  
  - Definir a rota inicial do app
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export const unstable_settings = {
  initialRouteName: "login",
};


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Essa simples linha de código irá garantir que a rota inicial do nosso app será sempre 'login', ou seja, o componente presente no arquivo de login.tsx!&lt;/p&gt;

&lt;h4&gt;
  
  
  - Adicionar o nosso contexto por volta de todo o seu app
&lt;/h4&gt;

&lt;p&gt;Ele irá apenas retornar o children, que será a stack do grupo &lt;code&gt;(auth)&lt;/code&gt; ou a tela de login, dependendo se o usuário está autenticado ou não. Para isso, usaremos o &lt;code&gt;&amp;lt;Slot&amp;gt;&lt;/code&gt; do Expo Router, que é um elemento que irá renderizar o "children" da rota atual:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import { Slot } from "expo-router";
import { SessionProvider } from "./ctx";

export default function RootLayoutNav() {
  return (
    &amp;lt;SessionProvider&amp;gt;
      &amp;lt;Slot /&amp;gt;
    &amp;lt;/SessionProvider&amp;gt;
  );
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3 - Crie a tela de login
&lt;/h3&gt;

&lt;p&gt;Na tela de login, que será o arquivo &lt;code&gt;app/login.tsx&lt;/code&gt;, você pode adicionar a lógica de login do seu app, como um formulário de email e senha. No nosso caso, vamos somente um botão que irá logar o usuário no app.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

export default function Login() {
  const { signIn } = useSession();
  const handleLogin = () =&amp;gt; {
    signIn();
    //Antes de navegar, tenha certeza de que o usuário está autenticado
    router.replace("/");
  };

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Button title="Login" onPress={handleLogin} /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso irá redirecionar para &lt;code&gt;(auth)/\_layout.tsx&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  4 - Adicione a lógica de autenticação no arquivo &lt;code&gt;app/(auth)/\_layout.tsx&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Esse arquivo é um layout que será compartilhado entre todas as telas do app no grupo (auth), ou seja, todas as telas que precisam de autenticação para serem acessadas. Nele, podemos adicionar a lógica de autenticação do app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Se o usuário não possuir sessão, redirecionar para a tela de login&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caso o usuário tenha sessão, retornar a stack do grupo &lt;code&gt;(tabs)&lt;/code&gt;, que contém o restante das telas do app.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const { session } = useSession();

if (!session) {
  return &amp;lt;Redirect href="/login" /&amp;gt;;
}

return (
  &amp;lt;Stack&amp;gt;
    &amp;lt;Stack.Screen name="(tabs)" options={{ headerShown: false }} /&amp;gt;

    &amp;lt;Stack.Screen name="modal" options={{ presentation: "modal" }} /&amp;gt;
  &amp;lt;/Stack&amp;gt;
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Assim, ao clicar para login e ser redirecionado com sucesso, o usuário irá ter acesso a tela &lt;code&gt;app/(auth)/(tabs)/index.tsx&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;E caso o usuário não esteja autenticado, ele será redirecionado para a tela de login, completando um fluxo básico de autenticação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Fazendo um comparativo com React Navigation, acredito que o Expo Router é bem acessível e fácil de entender, principalmente pra quem vem do desenvolvimento de frontend web.&lt;/p&gt;

&lt;p&gt;Onde no React Navigation, várias funcionalidades eram feitas de forma manual, como a criação das rotas, a configuração de deep linking, entre outras, esses processos super importantes são feitos já automaticamente pelo Expo Router, deixando o código bem mais limpo. Pelo fato de ser file based routing, a estrutura do projeto fica bem mais organizada, e a navegação entre telas é bem mais simples, com a utilização do elemento &lt;code&gt;&amp;lt;Link href='/nome-da-rota'&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;No geral, acredito que o Expo Router é uma ótima ferramenta para quem está começando a desenvolver apps com react native, ou para quem já tem experiência com react native e quer otimizar o tempo de desenvolvimento e manter uma navegação de fácil implementação. Estarei utilizando nos meus novos projetos com Expo 🚀&lt;/p&gt;

&lt;p&gt;Segue o link do projeto no github, caso queira testar o código:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lumamontes/expo-router-auth" rel="noopener noreferrer"&gt;Expo Router Auth&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>mobile</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
