eletrotupi / tcc/ thesis/chapters/architecture.texc901c35af9c84b6a29e5185545ced1129f33b8f4
22.0 KB | 439 lines Raw
1
\chapter{Arquitetura e Funcionamento do Sistema}
2

3
Como delineado as tecnologias no capítulo anterior, aqui se apresenta a
4
arquitetura, demonstrando como todas as tecnologias apresentadas acima se
5
conectam e conversam entre si.
6

7
\begin{figure}[h]
8
\centering
9
\caption{Arquitetura e elementos do Sistema}
10
\label{fig:arch}
11
\includegraphics[width=0.9\linewidth]{arch-v2.png}
12
\source{Elaborado pelo autor (2026)}
13
\end{figure}
14

15
Três planos compõem a arquitetura representada na Figura~\ref{fig:arch} ---
16
cliente, \textit{back-end} e infraestrutura ---, lidos da esquerda para a
17
direita. O aplicativo móvel comunica-se exclusivamente com a API por
18
HTTPS/JSON e mantém no dispositivo apenas o estado efêmero da interface e um
19
cache local dos dados já consultados; validação, autorização e regras de
20
domínio ficam concentradas no servidor. A API é a única porta de entrada para
21
os dados: acessa o PostgreSQL por meio do Prisma, grava avatares no
22
armazenamento de objetos e delega o trabalho que não precisa bloquear a
23
resposta ao usuário a filas no Valkey, consumidas por \textit{workers}
24
independentes. São esses \textit{workers} que enviam e-mails e notificações e
25
recalculam os indicadores, mantendo a API livre de tarefas de longa duração.
26

27
Essa organização tem como principal força a separação de responsabilidades em
28
torno de um contrato único: como o cliente só conhece a API, mudanças internas
29
no banco, nas filas ou nos serviços externos não o afetam, e a autenticação por
30
JWT permite que a API permaneça sem estado, reiniciável sem perda de sessão. O
31
desacoplamento por filas também torna o registro de um humor uma operação
32
curta, independente do custo de recalcular indicadores ou disparar
33
notificações. Em contrapartida, a topologia é deliberadamente monolítica e
34
vertical: todos os componentes são implantados em um único servidor por meio do
35
Docker Compose, sem replicação horizontal da API ou separação física entre
36
banco, fila e \textit{workers}. Isso significa que o trabalho pesado dos
37
\textit{workers} compete por CPU e memória com o atendimento das requisições, e
38
que a disponibilidade do conjunto equivale à disponibilidade desse único
39
\textit{host}. Trata-se de um \textit{trade-off} coerente com o porte do
40
projeto, mas que delimita seu principal limite de escalabilidade.
41

42
Este capítulo detalha o funcionamento de algumas funcionalidades
43
desenvolvidas durante o projeto. Apenas algumas funcionalidades mais
44
chaves são abordadas neste capítulo, como o registro de humor, o vínculo
45
de um gatilho, os indicadores, o registro de atividades e, por fim, a
46
exportação de dados e a geração de relatórios.
47

48
\section{Processo de Login}
49

50
Logo ao abrir o aplicativo, o usuário é redirecionado para a tela de
51
login. A tela em si é relativamente simples, e contém os campos de
52
email e senha. Existe aqui um elemento proposital: uma forma de
53
garantir um certo nível de anonimato, em que o usuário não precisa se
54
identificar com um nome ou número de telefone, tampouco ativar a conta
55
através de uma plataforma de terceiro, como Google ou Facebook.
56

57
Isso se dá, em especial, por dois motivos. Primeiro, o uso de uma tecnologia de
58
autenticação, como por exemplo, \textit{OAuth} \cite{Hardt:2012} exigiria uma
59
conexão com plataformas de terceiro, que poderiam então rastrear quais usuários
60
têm acesso a qual aplicativo --- algo que é fartamente documentado na literatura
61
sobre os mecanismos usados por tais plataformas para rastrear e monitorar o
62
acesso a dados de usuários, com o fim de vender e monetizar essas informações.
63

64
Essa preocupação não é hipotética: um estudo que interceptou o tráfego de rede
65
de 36 dos aplicativos mais populares de saúde mental (depressão e cessação de
66
tabagismo) encontrou transmissão de dados a pelo menos um terceiro em 92\%
67
deles, sendo que 81\% enviavam dados especificamente a serviços operados por
68
Google ou Facebook --- e apenas 59\% desses casos declaravam esse
69
compartilhamento em política de privacidade \cite{Huckvale2019}.
70

71
Um estudo posterior, focado exclusivamente em 27 aplicativos de saúde
72
mental mais populares da Google Play Store, confirmou o mesmo padrão e
73
o caracterizou formalmente como uma ameaça:
74

75
\begin{quote}
76
  A maioria dos aplicativos representa ameaças relacionadas à rastreabilidade,
77
  à identificação e à detecção. Isso constitui um risco, pois  alguns terceiros
78
  podem rastrear, reidentificar e detectar as ações e os dados dos usuários. A
79
  falta de conscientização também está relacionada a essas ameaças, uma vez que
80
  os aplicativos não explicam (por exemplo, na política de privacidade) os
81
  riscos que a publicidade direcionada representa para pessoas com problemas
82
  mentais, bem como o risco de reidentificação e divulgação de condições de
83
  saúde mental (por exemplo, ansiedade, depressão).
84
  \cite[p.~3, tradução nossa]{Iwaya:22}
85
\end{quote}
86

87
Como os próprios autores resumem, a mera vinculação de um usuário a um
88
aplicativo de saúde mental já pode revelar que essa pessoa possui uma condição
89
psicológica --- seja ansiedade, depressão, ou, no caso de um aplicativo como o
90
Nexo, Transtorno Afetivo Bipolar ---, tornando usuários desses aplicativos
91
particularmente vulneráveis a esse tipo de exposição \cite{Iwaya:22}.
92

93
No caso do Nexo, essa cadeia de inferência é especialmente
94
sensível: a presença do aplicativo na lista de apps instalados de um usuário,
95
associada ao seu identificador publicitário, permitiria a uma plataforma como a
96
Meta inferir uma possível condição de saúde mental do usuário para fins de
97
segmentação de anúncios, sem que este tenha conhecimento ou consentimento
98
explícito disso.
99

100
Segundo, e retomando a proposta de oferecer ao usuário a possibilidade
101
de \textit{self-service}, aquele que decidisse manter uma instância
102
própria do aplicativo não precisaria de uma conta em uma plataforma de
103
terceiro, nem se cadastrar nelas.
104

105
\begin{figure}[H]
106
\centering
107
\caption{Tela de login}
108
\label{fig:screenshot-login}
109
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-login.jpeg}
110
\source{Elaborado pelo autor (2026)}
111
\end{figure}
112

113
Por fim, destaca-se aqui que, conforme mencionado anteriormente na
114
modelagem de casos de uso (figura \ref{fig:use-cases}), ao realizar o
115
login pela primeira vez é enviado um email com um código de
116
verificação, seguindo a lógica dos \textit{magic links}. Isso adiciona
117
uma camada extra de segurança, garantindo que apenas o usuário que
118
solicitou o login possa acessar a conta.
119

120
\section{Página de Consulta de Registros}
121

122
A tela inicial é a tela nomeada apenas como ``Novo''. A proposta aqui
123
é ser a tela de cadastro rápido de um humor, e também é a tela que
124
visualmente mais destoa das demais. O usuário é apresentado com três
125
seções distintas:
126

127
\begin{itemize}
128
    \item Cadastro rápido de um humor
129
    \item Entre ontem e hoje
130
    \item Registros recentes
131
\end{itemize}
132

133
Respectivamente: uma seção em que o usuário é convidado a ``escolher
134
um humor'' e iniciar o processo de registro de uma nova entrada; a
135
seção em que são apresentados os indicadores de nível de energia
136
acumulado entre o dia anterior e o dia atual, além da média de sono do
137
dia comparada com a do dia anterior; e, por fim, a listagem dos dez
138
últimos registros de humor cadastrados pelo usuário.
139

140
\begin{figure}[H]
141
\centering
142
\caption{Tela de Consulta de Registros}
143
\label{fig:screenshot-consulta-registros}
144
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-initial-page.jpeg}
145
\source{Elaborado pelo autor (2026)}
146
\end{figure}
147

148
Aqui já é introduzido ao usuário um padrão de organização e hierarquia:
149
todos os elementos centrais são organizados em \textit{cards}, exibidos
150
em no máximo duas colunas. Também é introduzido, caso o usuário já
151
possua registros de humor cadastrados, o padrão pelo qual esses
152
registros são resumidos em todas as seções do aplicativo: geralmente
153
um ícone, um título e alguma informação adicional em destaque.
154

155
\section{Criação de Registros de Humor}
156

157
Nesta seção, o usuário pode criar novos registros de humor, escolhendo
158
entre uma lista de opções pré-definidas. O humor selecionado na tela
159
anterior é mostrado aqui, e o usuário é convidado a julgar, em uma
160
escala de 1 a 10, como se sente em relação aos níveis de energia,
161
estresse e ansiedade, respectivamente.
162

163
\begin{figure}[H]
164
\centering
165
\caption{Criação de Registros de Humor}
166
\label{fig:screenshot-consulta-humor}
167
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-create-mood.jpeg}
168
\source{Elaborado pelo autor (2026)}
169
\end{figure}
170

171
Naturalmente, é uma questão difícil de responder --- e, como o próprio
172
aplicativo procura deixar claro, é importante que seja um momento
173
reflexivo, não necessariamente preciso.
174

175
O usuário pode adicionar uma anotação sobre aquele registro em
176
específico, padrão que se repete em outras telas do aplicativo.
177

178
Por fim, o usuário pode escolher o que compõe aquele registro, ou
179
seja, selecionar emoções e estados/sentimentos que sente naquele
180
momento. É apresentada uma listagem mista desses elementos, na qual o
181
usuário seleciona os que mais se aplicam a ele e atribui um nível de
182
intensidade para cada um. Aqui a escala é menor e mais simples, visando
183
facilitar a escolha e o julgamento do usuário, entre ``Leve'',
184
``Moderado'' e ``Intenso'', conforme a figura
185
\ref{fig:screenshot-add-components}.
186

187
\begin{figure}[H]
188
\centering
189
\caption{Adicionando sentimentos/emoções}
190
\label{fig:screenshot-add-components}
191
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-add-components.jpeg}
192
\source{Elaborado pelo autor (2026)}
193
\end{figure}
194

195
Ao concluir esse processo e salvar, é apresentada ao usuário uma tela
196
de confirmação, na qual ele pode, opcionalmente, vincular o registro a
197
um gatilho específico --- que pode ter ocorrido antes de ele salvar o
198
registro --- ou criar um novo gatilho. O projeto novamente se ancora no
199
EMA, enriquecendo o registro de humor com mais contexto sobre o que
200
aconteceu.
201

202
\begin{figure}[H]
203
\centering
204
\caption{Vinculando um humor com um gatilho}
205
\label{fig:screenshot-link-mood-trigger}
206
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-link-mood-with-trigger.jpeg}
207
\source{Elaborado pelo autor (2026)}
208
\end{figure}
209

210
Em seguida, o usuário pode indicar o impacto que aquele gatilho
211
exerceu sobre o registro de humor em questão. Novamente, trata-se de
212
uma estimativa subjetiva, sem pretensão de precisão.
213

214
\begin{figure}[H]
215
\centering
216
\caption{Avaliando o impacto de um gatilho no humor}
217
\label{fig:screenshot-assess-trigger-mood-impact}
218
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-link-mood-assess-impact.jpeg}
219
\source{Elaborado pelo autor (2026)}
220
\end{figure}
221

222
Por fim, vale mencionar que, após esse processo, é enfileirado
223
internamente um \textit{background job} que recalcula, sob demanda, o
224
indicador de energia daquele dia, apresentado na figura
225
\ref{fig:screenshot-consulta-registros}. Diferentemente deste, os
226
indicadores semanais --- como a correlação entre sono e energia,
227
descrita na seção \ref{sec:insights} --- não são recalculados a cada
228
registro individual, sendo processados apenas pelo job semanal
229
agendado (seção \ref{sec:insights}).
230

231
\section{Indicadores}\label{sec:insights}
232

233
Nessa tela é apresentado um conjunto de indicadores construídos a partir
234
dos registros de humor, sono e gatilho do usuário. Diferente das demais
235
telas do aplicativo, que operam sobre dados em tempo real, os indicadores
236
são artefatos pré-computados: um \textit{worker} assíncrono (\textit{BullMQ})
237
percorre semanalmente todos os usuários ativos e enfileira, para cada
238
um, um conjunto de \textit{jobs} --- um por tipo de indicador --- que
239
processam a janela dos últimos sete dias e persistem o resultado em uma
240
tabela dedicada. Vale notar que nem todos os indicadores seguem esse
241
fluxo agendado: os indicadores diários (energia e sono) são recalculados
242
sob demanda, no momento em que o usuário registra um novo humor ou
243
sessão de sono, enquanto os indicadores semanais dependem
244
exclusivamente do \textit{job} de \textit{fan-out} de segunda-feira.
245

246
O aplicativo móvel apenas consulta esse resultado já
247
calculado, o que evita repetir cálculos custosos a cada abertura da tela
248
e desacopla a lógica analítica do restante da API.
249

250
\begin{figure}[H]
251
\centering
252
\caption{Tela de indicadores}
253
\label{fig:screenshot-insights}
254
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-insights.jpeg}
255
\source{Elaborado pelo autor (2026)}
256
\end{figure}
257

258
% TODO: referenciar EMA / momentary assessment como justificativa da janela de 7 dias
259

260
São três os indicadores semanais exibidos: tendência de humor, correlação
261
entre sono e energia, e padrão de gatilhos.
262

263
\begin{itemize}
264
    \item \textbf{Tendência de humor}: compara a média de humor da
265
    primeira metade da semana com a da segunda metade, expressando a
266
    diferença como uma variação percentual. O resultado é classificado
267
    como melhora, piora ou estabilidade a partir de uma margem de $\pm10\%$.
268

269
    \item \textbf{Correlação entre sono e energia}: relaciona a duração
270
    do sono de uma noite com o nível de energia relatado na manhã
271
    seguinte, através do coeficiente de correlação de Pearson. Exige um
272
    mínimo de observações pareadas para ser calculado --- caso contrário,
273
    o indicador simplesmente não é exibido.
274

275
    \item \textbf{Padrão de gatilhos}: identifica a categoria de gatilho
276
    mais frequente na semana e expressa sua predominância como percentual
277
    do total de registros.
278
\end{itemize}
279

280
É intencional, na figura \ref{fig:screenshot-insights}, que o bloco de
281
``Energia'' apareça vazio: o cálculo da correlação depende da existência
282
simultânea de registros de sono \emph{e} de humor em quantidade mínima,
283
e no período retratado o usuário ainda não havia acumulado dados
284
suficientes de ambos os tipos. Optou-se por não exibir uma correlação
285
calculada com poucos pontos, preferindo comunicar a ausência de dado a
286
apresentar um número pouco confiável.
287

288
O bloco maior no topo da tela, o ``Resumo Semanal'', condensa os
289
indicadores mais centrais --- média de sono do período e um rótulo de
290
humor (``Estável'', no exemplo). Esse rótulo, no entanto, é o elemento
291
mais delicado de toda a funcionalidade. Embora exista uma fórmula capaz
292
de produzir uma classificação de estabilidade a partir da variância dos
293
registros de humor, atribuir esse tipo de afirmação a um usuário ---
294
especialmente em um aplicativo que é utilizado por pessoas com
295
Transtorno Afetivo Bipolar, para quem uma leitura equivocada de
296
``estabilidade'' pode mascarar justamente o início de um episódio ---
297
exige um embasamento mais cuidadoso do que uma regra estatística
298
simples. Por esse motivo, o rótulo apresentado nesta versão do
299
aplicativo é estático (não deriva de fato do cálculo de estabilidade) e
300
a funcionalidade pode ser inteiramente desabilitada pelo usuário nas
301
configurações. A decisão de manter ou não uma afirmação automatizada
302
desse tipo, e sob quais critérios, permanece um ponto em aberto que
303
mereceria revisão de literatura específica antes de ser tratado como
304
funcionalidade definitiva.
305

306
% TODO: literatura sobre riscos de auto-monitoramento automatizado de humor / mood-tracking apps e TAB
307

308
\section{Histórico}\label{sec:history-analysis}
309

310
Nessa tela é apresentado o histórico consolidado de registros de humor,
311
sono, gatilho e ações de cuidado (como sessões de terapia), organizados
312
cronologicamente e agrupados por dia, conforme a figura
313
\ref{fig:screenshot-history}. O usuário pode ainda filtrar a listagem por
314
categoria (``Humor'', ``Sono'', ``Gatilho'' e ``Ações de Cuidado''),
315
reduzindo o volume de informação exibida.
316

317
\begin{figure}[H]
318
\centering
319
\caption{Tela de Histórico}
320
\label{fig:screenshot-history}
321
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-history.jpeg}
322
\source{Elaborado pelo autor (2026)}
323
\end{figure}
324

325
Como os quatro tipos de dado residem em recursos distintos da API, a
326
tela consulta os respectivos \textit{endpoints} em paralelo e, em
327
seguida, processa o resultado no próprio aplicativo. Para isso, é
328
utilizado um pequeno serviço que atua como \textit{mapper}, transformando
329
os dados de cada \textit{endpoint} em um formato comum, apresentado no
330
código \ref{lst:history-card}.
331

332
\newpage
333

334
\begin{lstlisting}[caption={Formato comum da tela de histórico}, label={lst:history-card}]
335
export type HistoryCard = {
336
  id: string; // "<category>-<id>" to avoid collisions
337
  category: HistoryCategory;
338
  subtype?: CareActionSubtype; // only set when category === "care_action"
339
  timestamp: string; // ISO string -- used for sorting and display
340
  title: string;
341
  summary: string;
342
  badge?: HistoryBadge;
343
  raw: MoodEntry | SleepRecord | Trigger | CareAction;
344
};
345
\end{lstlisting}
346

347
Após a normalização, os quatro conjuntos de dados são combinados em uma
348
única lista ordenada pelo campo \texttt{timestamp} e reagrupados por dia
349
para exibição, conforme visto na figura \ref{fig:screenshot-history}, nos
350
cabeçalhos ``terça-feira, 14 de julho'' e ``segunda-feira, 13 de julho''.
351
Essa unificação é proposital: ao invés de apresentar quatro telas
352
separadas por tipo de dado, o histórico busca reconstruir uma narrativa
353
única do dia do usuário, aproximando-se do princípio de \textit{Ecological
354
Momentary Assessment} já mencionado anteriormente --- o contexto de um
355
registro de humor (por exemplo, o gatilho ``Interno'' registrado três
356
minutos antes, na mesma figura) fica visualmente próximo do evento que
357
possivelmente o motivou.
358

359
A propriedade \texttt{raw} armazena o dado original, permitindo que a
360
listagem redirecione o usuário para a tela de detalhe correta ao tocar em
361
um card, independentemente da categoria. Já a propriedade \texttt{badge}
362
reaproveita o mesmo mecanismo já descrito na seção de indicadores: para
363
um registro de sono, sinaliza se a duração foi insuficiente; para um
364
registro de humor, destaca a dimensão mais relevante daquele registro
365
(como ``Ansiedade alta'' na figura \ref{fig:screenshot-history}); para um
366
gatilho, indica sua categoria, e assim por diante.
367

368
\section{Exportação de Dados e Relatórios}\label{sec:export-report}
369

370
Além das telas de consulta e análise, o Nexo oferece duas formas de
371
levar os dados para fora do aplicativo: a exportação integral dos
372
registros, em formato aberto, e a geração de um relatório resumido em
373
PDF. Ambas materializam o princípio de soberania dos dados discutido nos
374
capítulos anteriores --- princípio reforçado pelo questionário, em que a
375
maioria dos respondentes atribuiu nota máxima à importância de ter
376
controle total sobre as próprias informações. A diferença entre as duas
377
reside no propósito: a exportação devolve a totalidade dos dados em um
378
formato legível e processável, enquanto o relatório condensa um período
379
específico em um documento pronto para ser guardado ou compartilhado com
380
um profissional de saúde.
381

382
A exportação é acionada na tela de configurações, na opção ``Exportar
383
Meus Dados''. Antes de disparar o processo, o aplicativo pede uma
384
confirmação e informa que o arquivo será enviado para o e-mail cadastrado
385
--- um lembrete explícito de que aquela operação retira dados do
386
dispositivo e os entrega por um canal externo.
387

388
% TODO: adicionar screenshot da tela de exportação (modal de confirmação)
389

390
Do ponto de vista técnico, a solicitação enfileira um \textit{job}
391
assíncrono na mesma infraestrutura de filas descrita na
392
seção~\ref{sec:insights}. O \textit{worker} percorre todas as entidades
393
associadas ao usuário --- perfil, humores e seus componentes, sono,
394
gatilhos e seus vínculos, ações de cuidado, medicamentos, consultas,
395
atividades e os indicadores já calculados --- e serializa cada uma em um
396
arquivo CSV próprio, com os rótulos traduzidos e os valores enumerados
397
convertidos para texto legível. Os arquivos são compactados em um único
398
\textit{zip}, acompanhados de um manifesto com a data de geração, e o
399
pacote é anexado a um e-mail enviado ao usuário; em caso de falha, um
400
e-mail de erro é disparado em seu lugar. O resultado é uma exportação
401
completa e portátil: nenhum campo é omitido ou agregado, de modo que o
402
usuário pode reimportar os dados em outra ferramenta ou auditá-los
403
diretamente --- alinhado à exigência de portabilidade levantada nos
404
requisitos não funcionais.
405

406
O relatório, por sua vez, é gerado sob demanda a partir da tela
407
``Relatório'', acessível também pelas configurações. O usuário escolhe um
408
período --- por meio de atalhos de 7, 30 ou 90 dias, ou um intervalo
409
personalizado limitado a 90 dias --- e aciona ``Gerar relatório''.
410

411
\begin{figure}[H]
412
\centering
413
\caption{Tela de geração de relatório}
414
\label{fig:screenshot-report}
415
\includegraphics[width=0.70\textwidth,height=0.60\textheight,keepaspectratio]{screenshot-report-initial.png}
416
\source{Elaborado pelo autor (2026)}
417
\end{figure}
418

419
O servidor reúne os registros de humor do período e os renderiza em um
420
PDF intitulado ``Relatório de Humor e Bem-Estar'', produzido com
421
\textit{@react-pdf/renderer} e devolvido ao aplicativo, que o oferece
422
pela folha de compartilhamento nativa do sistema --- permitindo salvá-lo
423
ou enviá-lo a um terapeuta. O documento é dividido em duas páginas: a
424
primeira traz uma visão geral (total de \textit{check-ins}, humor
425
predominante e dias rastreados), a distribuição percentual de cada humor
426
e um mapa de calor diário; a segunda lista os sentimentos e emoções mais
427
frequentes, com a intensidade média, e o registro detalhado dos
428
\textit{check-ins}, com os níveis de ansiedade, estresse e energia.
429

430
Cabe registrar, contudo, que o relatório desta versão cobre apenas os
431
dados de humor. A intenção original era incorporar também o sono, as
432
atividades e os padrões de gatilho --- inclusive a correlação entre sono
433
e energia já calculada nos indicadores ---, mas essa ampliação foi
434
adiada para uma versão futura. Como consequência, o relatório atual
435
complementa, mas não substitui, a exportação integral: para uma visão
436
completa de todos os tipos de dado, o usuário ainda recorre ao
437
\textit{zip} de CSV.
438

439
\FloatBarrier