| 1 | \chapter{Tecnologias}
|
| 2 |
|
| 3 | Este capítulo apresenta as principais tecnologias empregadas no desenvolvimento
|
| 4 | do aplicativo, organizadas de acordo com a camada da arquitetura em que
|
| 5 | atuam: front-end, back-end e infraestrutura/persistência de dados.
|
| 6 |
|
| 7 | \section{Front-end}
|
| 8 |
|
| 9 | \subsection{React Native}
|
| 10 |
|
| 11 | React Native é um \textit{framework} de código aberto, mantido pela Meta, que
|
| 12 | permite o desenvolvimento de aplicativos móveis multiplataforma a partir de
|
| 13 | uma única base de código escrita em JavaScript/TypeScript, utilizando
|
| 14 | componentes que são traduzidos para elementos nativos tanto no iOS quanto no
|
| 15 | Android \citep{reactnative:2026}.
|
| 16 |
|
| 17 | A escolha do React Native se justifica pelo escopo reduzido da equipe de
|
| 18 | desenvolvimento (um único desenvolvedor) e facilidade de conhecimento e
|
| 19 | manutenção, sem trazer, para este projeto, benefícios que justifiquem esse
|
| 20 | custo adicional. Além disso, o ecossistema maduro do React Native oferece
|
| 21 | ampla disponibilidade de bibliotecas para funcionalidades já previstas no
|
| 22 | aplicativo, como notificações locais e gráficos.
|
| 23 |
|
| 24 | \subsection{Zustand}
|
| 25 |
|
| 26 | Zustand é uma biblioteca leve de gerenciamento de estado para aplicações
|
| 27 | React e React Native, que dispensa a estrutura verbosa de \textit{providers}
|
| 28 | e \textit{reducers} tipicamente associada a bibliotecas como Redux
|
| 29 | \citep{zustand:2026}.
|
| 30 |
|
| 31 | Ela foi escolhida para gerenciar o estado efêmero da aplicação (por exemplo,
|
| 32 | dados de formulários em preenchimento ou estados de navegação temporários)
|
| 33 | por sua API minimalista e baixo \textit{overhead} de configuração, adequada a um
|
| 34 | projeto de escopo individual em que a complexidade adicional de soluções
|
| 35 | mais robustas de gerenciamento de estado não se justifica.
|
| 36 |
|
| 37 | \section{Back-end}
|
| 38 |
|
| 39 | \subsection{Express.js}
|
| 40 |
|
| 41 | Express.js é um \textit{framework} minimalista para aplicações web em
|
| 42 | Node.js, amplamente utilizado para a construção de APIs \textit{REST},
|
| 43 | oferecendo uma camada fina de abstração sobre o roteamento de requisições HTTP e
|
| 44 | \textit{middlewares} \citep{express:2026}.
|
| 45 |
|
| 46 | Sua adoção se deve à simplicidade e à flexibilidade não opinativa do
|
| 47 | \textit{framework}, que permite estruturar a API de acordo com as
|
| 48 | necessidades específicas do projeto, sem impor convenções rígidas de
|
| 49 | arquitetura, além de sua ampla documentação e maturidade no ecossistema
|
| 50 | Node.js.
|
| 51 |
|
| 52 | \subsection{Zod}
|
| 53 |
|
| 54 | Zod é uma biblioteca de validação e definição de esquemas de dados para
|
| 55 | TypeScript, que permite declarar formatos esperados de entrada (como corpos
|
| 56 | de requisição) e inferir automaticamente os tipos estáticos correspondentes
|
| 57 | \citep{zod:2026}.
|
| 58 |
|
| 59 | Zod foi escolhido para validar os dados recebidos pela API antes de seu
|
| 60 | processamento, garantindo que registros de humor, sono e demais entradas do
|
| 61 | usuário estejam em conformidade com o formato esperado. A inferência
|
| 62 | automática de tipos a partir dos esquemas evita a duplicação de definições de
|
| 63 | tipo entre a camada de validação e o restante do código TypeScript do
|
| 64 | back-end.
|
| 65 |
|
| 66 | \subsection{Valkey e BullMQ}
|
| 67 |
|
| 68 | Valkey é um banco de dados em memória, do tipo chave-valor, criado como
|
| 69 | \textit{fork} de código aberto do Redis, mantido sob a governança da Linux
|
| 70 | Foundation \citep{valkey:2026}. BullMQ é uma biblioteca para gerenciamento de
|
| 71 | filas de tarefas em Node.js, construída sobre bancos de dados compatíveis com
|
| 72 | o protocolo Redis \citep{bullmq:2026}.
|
| 73 |
|
| 74 | A combinação das duas ferramentas foi adotada para o processamento paralelo
|
| 75 | e assíncrono de tarefas que não precisam bloquear a resposta imediata da API,
|
| 76 | como o disparo de notificações programadas e o processamento de indicadores
|
| 77 | a partir do histórico de registros do usuário. A escolha do Valkey em
|
| 78 | específico, e não do Redis diretamente, se deve à mudança de licenciamento do
|
| 79 | Redis em 2024, que passou a restringir certos usos comerciais; o Valkey
|
| 80 | mantém compatibilidade total de protocolo, permanecendo sob licença
|
| 81 | permissiva de código aberto.
|
| 82 |
|
| 83 | \section{Infraestrutura e Persistência de Dados}
|
| 84 |
|
| 85 | \subsection{PostgreSQL}
|
| 86 |
|
| 87 | PostgreSQL é um sistema gerenciador de banco de dados relacional, de código
|
| 88 | aberto, reconhecido por sua conformidade com o padrão SQL, robustez e suporte
|
| 89 | a tipos de dados avançados \citep{postgresql:2026}.
|
| 90 |
|
| 91 | Sua escolha se justifica pela natureza estruturada e relacional dos dados do
|
| 92 | domínio da aplicação (registros de humor associados a usuários, horários,
|
| 93 | gatilhos e categorias), que se beneficia das garantias de integridade
|
| 94 | referencial e das transações ACID oferecidas por um banco relacional
|
| 95 | maduro, em detrimento de soluções não relacionais.
|
| 96 |
|
| 97 | \subsection{Prisma}
|
| 98 |
|
| 99 | Prisma é um \textit{Object-Relational Mapper} (ORM) para o ecossistema
|
| 100 | Node.js/TypeScript, que gera automaticamente um cliente de acesso ao banco de
|
| 101 | dados tipado a partir de um esquema declarativo, além de oferecer um sistema
|
| 102 | de migrações versionadas \citep{prisma:2026}.
|
| 103 |
|
| 104 | O Prisma foi escolhido por permitir a manutenção do esquema do banco de dados
|
| 105 | de forma versionada e sincronizada com o código da aplicação, reduzindo a
|
| 106 | chance de divergência entre a estrutura do banco e as entidades manipuladas
|
| 107 | pelo back-end, além de prover checagem de tipos em tempo de compilação para
|
| 108 | as consultas realizadas.
|
| 109 |
|
| 110 | \section{Implantação e Automação}
|
| 111 |
|
| 112 | \subsection{Docker e Docker Compose}
|
| 113 |
|
| 114 | Docker é uma plataforma de conteinerização que permite empacotar uma
|
| 115 | aplicação e suas dependências em uma unidade isolada e portátil, capaz de ser
|
| 116 | executada de forma consistente em diferentes ambientes \citep{docker:2026}. O
|
| 117 | Docker Compose é uma ferramenta complementar que permite definir e orquestrar
|
| 118 | múltiplos contêineres --- e as relações entre eles --- por meio de um único
|
| 119 | arquivo de configuração declarativo \citep{dockercompose:2026}.
|
| 120 |
|
| 121 |
|
| 122 | No projeto, o Docker Compose é utilizado tanto no ambiente de desenvolvimento
|
| 123 | quanto no ambiente de produção para orquestrar os serviços de banco de dados
|
| 124 | (PostgreSQL), armazenamento em memória (Valkey) e da própria API, garantindo
|
| 125 | que as versões e configurações desses serviços sejam idênticas entre as
|
| 126 | máquinas de desenvolvimento e o servidor de produção.
|
| 127 |
|
| 128 | O uso de \textit{healthchecks} em conjunto com a diretiva
|
| 129 | \texttt{depends\_on} e a condição \texttt{service\_healthy} assegura
|
| 130 | que a API só seja iniciada após o banco de dados e o Valkey estarem de
|
| 131 | fato prontos para aceitar conexões, evitando falhas de inicialização
|
| 132 | por condição de corrida (\textit{race condition}), como ilustrado no
|
| 133 | Código~\ref{lst:healthcheck-compose}.
|
| 134 |
|
| 135 | \begin{lstlisting}[caption={Configuração de \textit{healthcheck} do Valkey e de dependência condicional da API no \texttt{docker-compose.yml}}, label={lst:healthcheck-compose}]
|
| 136 | valkey:
|
| 137 | image: valkey/valkey:9.0-alpine
|
| 138 | healthcheck:
|
| 139 | test: ["CMD", "valkey-cli", "ping"]
|
| 140 | interval: 10s
|
| 141 | timeout: 5s
|
| 142 | retries: 5
|
| 143 | start_period: 5s
|
| 144 |
|
| 145 | api:
|
| 146 | build: ./api
|
| 147 | depends_on:
|
| 148 | valkey:
|
| 149 | condition: service_healthy
|
| 150 | db:
|
| 151 | condition: service_healthy
|
| 152 | \end{lstlisting}
|
| 153 |
|
| 154 | \sourcecode{Elaborado pelo autor (2026)}
|
| 155 |
|
| 156 | A adoção do Docker se justifica, no contexto de uma aplicação de saúde
|
| 157 | mental de código aberto, pelo objetivo de garantir a reprodutibilidade do
|
| 158 | ambiente de execução: qualquer pessoa que clone o repositório --- seja para
|
| 159 | contribuir com o projeto, auditar seu funcionamento ou realizar sua própria
|
| 160 | implantação --- consegue reproduzir o ambiente completo sem depender de
|
| 161 | configurações manuais específicas do sistema operacional hospedeiro, o que
|
| 162 | reforça o caráter \textit{self-service} do projeto.
|
| 163 |
|
| 164 | \subsection{GitHub Actions}
|
| 165 |
|
| 166 | GitHub Actions é uma plataforma de integração e entrega contínuas (CI/CD)
|
| 167 | nativa do GitHub, que permite a definição de fluxos de trabalho automatizados
|
| 168 | --- disparados por eventos como \textit{push} ou \textit{pull request} ---
|
| 169 | descritos de forma declarativa em arquivos YAML \citep{githubactions:2026}.
|
| 170 |
|
| 171 | No projeto, o fluxo de trabalho de CI/CD é dividido em três etapas
|
| 172 | sequenciais e dependentes entre si. A primeira etapa (\texttt{test}) sobe um
|
| 173 | serviço efêmero de PostgreSQL e executa a suíte de testes automatizados da
|
| 174 | API a cada \textit{push} ou \textit{pull request} que modifique arquivos do
|
| 175 | diretório da API.
|
| 176 |
|
| 177 | A segunda etapa (\texttt{build-and-push}), condicionada ao
|
| 178 | sucesso da primeira e restrita a eventos de \textit{push}, constrói a imagem
|
| 179 | Docker de produção da API e a publica no GitHub Container Registry (GHCR),
|
| 180 | com marcação automática pelo SHA do \textit{commit} e, condicionalmente, pela
|
| 181 | tag \texttt{latest} quando o \textit{push} ocorre na \textit{branch}
|
| 182 | \texttt{master}.
|
| 183 |
|
| 184 | Por último, a terceira etapa (\texttt{deploy-production}), restrita à
|
| 185 | \textit{branch} \texttt{master}, conecta-se ao servidor de produção via SSH e
|
| 186 | realiza a atualização do serviço da API por meio da atualização da tag da
|
| 187 | imagem no arquivo \texttt{.env} e da recriação do contêiner correspondente
|
| 188 | via Docker Compose.
|
| 189 |
|
| 190 | Esse processo elimina a necessidade de intervenção manual para a maior
|
| 191 | parte do ciclo de implantação, restringindo a ação humana direta sobre o
|
| 192 | servidor de produção a situações excepcionais, o que reduz a superfície de
|
| 193 | erro humano e aumenta a confiabilidade do processo de entrega de novas
|
| 194 | versões da aplicação.
|
| 195 |
|
| 196 | \subsection{Ansible}
|
| 197 |
|
| 198 | Ansible é uma ferramenta de automação de infraestrutura que permite
|
| 199 | descrever, de forma declarativa e idempotente, o estado desejado de um ou
|
| 200 | mais servidores, dispensando a necessidade de um agente instalado na máquina
|
| 201 | gerenciada, uma vez que se comunica com ela via SSH \citep{ansible:2026}.
|
| 202 |
|
| 203 | No escopo deste projeto, o papel do Ansible é ortogonal ao do Docker Compose
|
| 204 | e ao do GitHub Actions: enquanto estes automatizam, respectivamente, a
|
| 205 | orquestração dos serviços da aplicação e o ciclo de integração e entrega
|
| 206 | contínuas, o Ansible é responsável exclusivamente pelo provisionamento
|
| 207 | inicial do servidor de produção, executado uma única vez --- ou sempre que um
|
| 208 | novo servidor precisar ser provisionado. Esse provisionamento consiste em:
|
| 209 | (1) criar o usuário dedicado à aplicação; (2) adicionar a chave pública SSH
|
| 210 | utilizada pelo GitHub Actions para se autenticar no servidor durante a etapa
|
| 211 | de implantação; (3) criar os diretórios da aplicação com as permissões
|
| 212 | adequadas; e (4) instalar o Docker no servidor. A cópia do arquivo de
|
| 213 | variáveis de ambiente de produção (\texttt{.env.production}), por conter
|
| 214 | segredos e credenciais sensíveis, é deliberadamente mantida como uma etapa
|
| 215 | manual, não automatizada, e não é versionada no repositório.
|
| 216 |
|
| 217 | A separação entre o provisionamento inicial (\textit{Ansible}), a orquestração de
|
| 218 | execução (\textit{Docker Compose}) e a automação do ciclo de
|
| 219 | entrega (\textit{GitHub Actions}) reflete uma decisão arquitetural:
|
| 220 | cada ferramenta atua em uma camada distinta e bem delimitada do processo
|
| 221 | de implantação, o que favorece a reprodutibilidade de todo o processo,
|
| 222 | do zero, por qualquer pessoa que deseje hospedar sua própria instância da aplicação.
|
| 223 |
|
| 224 | Essa preocupação é particularmente relevante no contexto de um
|
| 225 | aplicativo de saúde mental de código aberto: ao reduzir a dependência
|
| 226 | de serviços proprietários de implantação (\textit{walled gardens}) e
|
| 227 | ao documentar e automatizar o processo de provisionamento, o projeto
|
| 228 | favorece um modelo mais alinhado aos princípios de privacidade e de
|
| 229 | autonomia sobre os dados dos usuários, permitindo que instituições ou
|
| 230 | indivíduos preocupados com a confidencialidade de dados sensíveis de
|
| 231 | saúde mental hospedem e controlem sua própria instância da aplicação.
|