Ir para o conteúdo

Arquitetura e tecnologias

A arquitetura da aplicação é similar a de outros projetos que utilizam uma estrutura de diretórios baseados em Clean Architecture, mas a arquitetura seguida é a Model-View-ViewModel (MVVM), com distinções em subcamadas para os modelos. No lado do servidor, a arquitetura é monolítica, com um único banco de dados e acesso centralizado aos serviços de autenticação, armazenamento e etc.

Já as tecnologias utilizadas foram escolhidas com base nas seguintes restrições de domínio e de recursos:

  • Tempo limitado: por isso utilizamos bibliotecas de interface de usuário com componentes e Design System já estruturados, e também utilizamos plataformas de BaaS (Back-End as a Service) para maior foco no desenvolvimento da aplicação móvel.
  • Relacionamento complexo entre entidades: com agrupamento de múltiplas entidades por uma área temática, além da presença de formulários reutilizáveis em diferentes contextos, o que faz necessário que uma mesma alternativa de uma questão tenha diferentes valores para cada contexto.
  • Presença de dados que necessitam de atualizações assíncronas: entre as funcionalidades descritas nas Histórias de Usuário estão dicas personalizadas para usuários e rotinas semanais. Pensando na escalabilidade, uso em diferentes plataformas e experiência de usuário, existe a necessidade que atualizações nesses dados ocorram de forma assíncrona no lado do servidor.

Agrupamento de Funcionalidades

As principais funcionalidades da aplicação, definidas nas Histórias de Usuário se dividem nos seguintes temas:

graph LR

subgraph Comparacao[Comparação]
    c1[Comparar consumo esperado com real] 
    c2[Comparar consumo com o de outros usuários]
end


subgraph Consumo

    c3[Estimar pegada de carbono]
    c4[Estimar consumo de energia]
    c5[Estimar consumo de água]
    c6[Controlar o consumo real de energia] --> c1
    c6 --> c2
    c7[Controlar o consumo real de água] --> c1
    c7 --> c2
end
subgraph Histórico
    h1[Gráficos de consumo de energia]
    h2[Gráfico de pegada de carbono]
    h3[Gráfico de consumo de água]
    h4[Histórico de consumo de água]
    h5[Histórico de consumo de energia]
    h6[Histórico de consumo de água]

    h1 --> h4
    h2 --> h5
    h3 --> h6
end

subgraph Rotina
    r[Controle de rotina]
    t[Tarefas semanais]

    t --> r
end

subgraph "Ação Coletiva"
    g[Gerenciar ações]
    p[Participar de ações]
end

subgraph Dicas
    d[Dicas personalizadas para usuários]
end
Press "Alt" / "Option" to enable Pan & Zoom

Back-End

graph LR
    A["API REST"] --Armazena e manipula tabelas-->  B
    A --Adiciona e manipula imagens--> C
    D --Provê credenciais--> A

    subgraph Supabase
        direction LR

        C --Guarda referências às imagens--> B[("Database")]
        D --Provê permissões de linhas e colunas--> B
        C@{ shape: lin-cyl, label: "Supabase Storage" }
        D["Supabase Auth"]
    end
Press "Alt" / "Option" to enable Pan & Zoom

Banco de dados

erDiagram
    user["Usuário"] {
        int id PK
        string name
        string email
        string password
    }
    action["Ação"] {
        int id PK
        datetime start_date
        datetime end_date
        string objective
    }
    action_media["Mídia de ação"] {
        int id PK
        blob file "Armazenado em um serviço diferente"
    }

    form["Formulário"] {
        int id PK
        date answered_date 
        blob file "Armazenado em um serviço diferente"
    }
    area["Área"] {
        int id PK
        string nome UK
    }
    question["Questão"] {
        int id PK
        string name
        string description
        blob file "Armazenado em um serviço diferente"
    }
    dependent_question["Questão Dependente"] {
        int id PK
    }
    question_value["Valor da Questão"] {
        int id pk
        enum unit 
        float quantity
        datetime time_period
    }
    question_answer["Resposta da Questão"] {
        int id pk
    }
    consumption["Consumo"] {
        int id PK
        float quantity
        string unit
        date measurement_date 
        datetime time_period
    }
    routine_meta["Dados da rotina"] {
        int id PK
    }
    routine["Rotina"] {
        datetime start_date
        datetime end_date
    }
    activity["Atividade"] {
        int id PK
        enum frequency 
        enum weekday
    }
    activity_meta["Dados da atividade"] {
        int id PK
        string name
        string description
    }
    tip["Dica"] {
        int id PK
        string name 
        string description
    }

    user ||--o{ action : Cria
    user }|--o{ action : Participa
    action ||--o{ action_media: Possui

    area ||--|{ consumption : "Relacionada a"
    consumption ||--|| form : "Calculado por" 
    user || --o{ consumption : "Mediu"
    question }|--|| area : "Relacionadas à"
    question }|--|{ form : "Estão em"
    question_answer ||--|{ question_value : "Possui"
    question ||--|{ question_value: "Possui"
    question ||--o{ dependent_question: "Possui"
    dependent_question }|--|{ form: "Estão em"
    dependent_question || -- |{ question_answer: "Depende de"
    form ||--|{ question_answer : "Possui"

    tip }|--o{ user : "Sugeridas para"
    tip }|--|{ area : "Pertencem a"

    user ||--|| routine_meta : "Possui"
    routine_meta ||--|{ activity_meta : "Possui"
    routine ||--|| routine_meta : "Descrita por"
    routine }|--|{ activity : "Possui várias"
    activity }|--|| activity_meta : "Descritas por"
    activity }|--|| area : "Situadas em"
Press "Alt" / "Option" to enable Pan & Zoom

Aplicação Mobile

O principal produto consiste de uma aplicação móvel nativa para Android. Essa aplicação atua como cliente do servidor descrito acima. Essa aplicação está sendo desenvolvida com a linguagem Kotlin, que é atualmente a recomendação da Google para o desenvolvimento Android. Abaixo estão incluídas descrições detalhadas das camadas da aplicação, da comunicação entre elas e as bibliotecas utilizadas em cada uma.

Camadas

graph LR
    subgraph presentation
        ui
        components --Combinados em páginas completas--> ui 
        theme --Define estilos--> ui
        theme --Define estilos-->components
        viewmodel --Mantém o estado de uma página--> ui

    end

    presentation --Representa objetos--> domainmodel

    repository --Controla os dados--> viewmodel
    service --Interage com interfaces externas --> viewmodel



    subgraph domain 
       domainmodel["model"]
    end

    subgraph service


    end

    subgraph repository
        repomodel["model"]
    end

    subgraph exceptions

    end

    exceptions --Define erros específicos--> repository 
    exceptions --Define erros específicos--> service

    subgraph utils
        mapper --Fornece conversões de--> domainmodel --Para--> repomodel
        mapper --Fornece conversões de--> repomodel --Para--> domainmodel

    end

    subgraph di["di (Dependency Injection)"]
        servicemodule
        repomodule
    end
        servicemodule --Fornece--> service
        repomodule --Fornece--> repository
Press "Alt" / "Option" to enable Pan & Zoom

Tecnologias

Interface de Usuário (presentation)

A interface de usuário é criada com a biblioteca Jetpack Compose e outros pacotes auxiliares (e.g. navigation-compose), seguindo os padrões do Material 3. As telas completas são definidas no pacote subpacote ui e componentes individuais em components . O tema de cores foi criado com o plugin Material Theme Builder do Figma e é definido subpacote theme.

Dentro do subpacote viewmodel estão os ViewModels, responsáveis por armazenar os dados da tela e encapsular o contato destas com serviços e repositórios. Idealmente, cada tela está vinculada a um único ViewModel.

Serviços (service)

Os serviços são interfaces externas utilizadas pelo sistema, como autenticação e notificações, podem ser acessados por interfaces de Rede, como HTTP, ou por serviços do Android (Foreground, Background, Broadcast, etc).

Um serviço pode ser utilizado diretamente por um ViewModel, como no caso da autenticação, em que o estado do login e as ações realizadas são repassadas da interação do usuário para o ViewModel e depois para um serviço específico.

Atualmente, os serviços utilizados estão presentes no Supabase, sendo a autenticação o principal.

Repositórios (repository)

A camada de repositório é responsável por interfaces externas que representam/integram bancos de dados, como bancos de dados locais ou operações CRUD acessadas por APIs REST. No momento, a interface de banco de dados planejada será acessada através da API REST do Supbase, consumida através do Retrofit.

No subpacote model estão modelos específicos de uma implementação de banco de dados, que necessitam de conversão para modelos do domínio.

Utilitários (utils)

A camada de utilitários é compartilhada através de outras e é usada principalmente para processamentos locais ou mapeamento de entidades, no subpacote mapper estão as interfaces e classes responsáveis por converter modelos do domínio para modelos de outras camadas bidirecionalmente.

A serialização de objetos será implementada com a biblioteca Moshi e é utilizada nesse mapeamento, nos casos em que um objeto precise ser enviado em um formato JSON.

Injeção de Dependência (di)

A injeção de dependência na aplicação é gerenciada com a biblioteca Hilt, onde os módulos (objetos Kotlin) contendo os métodos para retornar implementações concretas das interfaces são definidos por camada, então todas as injeções da camada de repositórios estarão em um arquivo RepositoryModule.kt, da mesma forma com serviços e outras implementações.