Pular para conteúdo

Arquitetura de Software — Decisões ASRs

Versão: 1.0 Escopo: Documento único contendo todos os ASRs do projeto.

Requisitos de CRUD simples e baixo risco (ex.: RF-004, RF-008, RF-012, RF-015, RF-016) foram deliberadamente deixados de fora, por não gerarem decisão arquitetural própria.

Sistema de Autenticação

ASR-001

  • < Backward: RF-017, RF-018
  • Preocupação: Armazenamento e comparação de senha são pontos de falha crítica de segurança — qualquer erro de implementação (hash fraco, comparação de texto puro, ausência de salt) compromete todas as contas do sistema.
  • Decisão rápida: Usar algoritmo de hashing adequado a senhas (bcrypt ou Argon2) com salt individual por usuário, via biblioteca madura da linguagem escolhida; nunca logar, comparar ou trafegar a senha em texto puro em nenhuma camada.

ASR-002

  • < Backward: RF-019
  • Preocupação: A proteção contra força bruta exige contagem de tentativas falhas e bloqueio temporário por conta, sem degradar a performance do fluxo de login legítimo.
  • Decisão rápida: Contador de tentativas persistido junto ao registro do usuário (coluna dedicada) para o volume esperado do MVP, com TTL de bloqueio (ex.: 15 min) resolvido por timestamp, evitando dependência de infraestrutura extra (Redis) nesta versão.

ASR-003

  • < Backward: RF-021
  • Preocupação: O modelo híbrido de sessão (Access Token JWT stateless + Refresh Token opaco persistido) é a espinha dorsal de segurança de todo o sistema e precisa suportar múltiplas sessões por dispositivo com revogação granular.
  • Decisão rápida: Tabela sessions armazenando apenas o hash do refresh token, associada a user_id e device/user-agent; Access Token JWT curto (~15 min) nunca persistido; ambos transportados via cookie httpOnly, Secure, SameSite.

ASR-004

  • < Backward: RNF-002
  • Preocupação: A exigência de sessão válida é transversal a toda operação sobre Cadernos, Itens e Sub-itens — trata-se do portão de segurança de todo o Sistema de Tarefas, não de uma regra isolada de um módulo.
  • Decisão rápida: Implementar um único middleware/guard de autenticação aplicado globalmente às rotas protegidas, validando o Access Token antes de qualquer handler de negócio ser executado, evitando checagem de sessão duplicada por endpoint.

ASR-005

  • < Backward: RF-022, RF-024
  • Preocupação: Desativação de conta e troca de senha disparam revogação em massa de sessões, mas com uma diferença sutil e propensa a erro: a troca de senha preserva a sessão corrente, a desativação encerra todas.
  • Decisão rápida: Centralizar a lógica em uma função única revokeAllSessions(userId, exceptSessionId?), reutilizada pelos dois fluxos, para evitar duas implementações divergentes do mesmo mecanismo.

ASR-006

  • < Backward: RF-023, RF-011
  • Preocupação: Deleção de dados tem dois comportamentos distintos e sensíveis a inconsistência: exclusão de conta é cascata total, enquanto exclusão de Caderno preserva itens movendo-os para a Inbox — se não forem transacionais, ambos os fluxos arriscam dados órfãos.
  • Decisão rápida: Toda operação de deleção com efeito em cascata deve rodar em uma transação de banco (ACID); usar ON DELETE CASCADE no schema para exclusão de conta, e lógica de aplicação explícita (reassociação, não cascade) para exclusão de Caderno.

ASR-007

  • < Backward: RF-020, RF-018
  • Preocupação: O endpoint de login precisa tratar um terceiro caminho além de sucesso/falha — credenciais válidas em conta Desativada não podem gerar sessão direta nem erro genérico, exigindo um estado intermediário de confirmação.
  • Decisão rápida: Login retorna um código de resposta distinto (ex.: requires_reactivation) em vez de token quando a conta está desativada; endpoint de reativação separado (POST /user/reactivate) só então libera a emissão da sessão.

ASR-008

  • < Backward: RNF-003
  • Preocupação: A ausência deliberada de verificação de e-mail, recuperação de senha, login social e 2FA reduz a superfície de integração externa do MVP, mas implica que perda de senha é irrecuperável nesta versão.
  • Decisão rápida: Não integrar provedores de e-mail/OAuth nesta versão; registrar a ausência de “esqueci minha senha” como risco de produto aceito, a ser tratado em 03-Riscos-Dívida-Tecnica.md na Fase 3.

Sistema de Tarefas

ASR-009

  • < Backward: RF-001, RF-002, RF-003
  • Preocupação: A hierarquia Caderno → Item → Sub-item, incluindo o estado transitório “Inbox” (item sem caderno), é a fundação estrutural de todo o modelo de dados do sistema.
  • Decisão rápida: Coluna notebook_id nullable na tabela de Item (nulo = Inbox); Sub-item com FK obrigatória e não nulável para o Item pai do tipo TODO, sem tabela de junção N:N (proibindo reaproveitamento).

ASR-010

  • < Backward: RF-005, RF-006
  • Preocupação: O Item unificado com dois subtipos (SCHEDULE e TODO), com campos e regras distintas, é consultado por praticamente todos os módulos (Calendário, Planner, Todo List, Busca) — a escolha de modelagem impacta todas essas queries.
  • Decisão rápida: Single Table Inheritance — uma única tabela items com coluna discriminadora type e campos específicos por tipo nulináveis, priorizando simplicidade de joins nas visões unificadas em detrimento de algum desperdício de colunas nulas.

ASR-011

  • < Backward: RF-007, RNF-001
  • Preocupação: Recorrência (diária/semanal/mensal) é um problema clássico de alto risco técnico — a escolha entre materializar instâncias ou calculá-las sob demanda impacta diretamente performance e complexidade de query.
  • Decisão rápida: Calcular ocorrências sob demanda (regra + data base + data de término), sem tabela de instâncias materializadas — decisão simplificada pela restrição deliberada de RNF-001 (sem exceções/overrides), que eliminaria a necessidade dessa tabela de qualquer forma.

ASR-012

  • < Backward: RF-010
  • Preocupação: O ciclo de vida do item (Inbox → Ativo → Concluído → Arquivado; Deletado a partir de qualquer estado) é uma máquina de estados consumida por múltiplos módulos, com regra crítica de que o arquivamento nunca pode ser automático.
  • Decisão rápida: Enum de status persistido no banco; validação das transições permitidas centralizada em um único service/use-case de domínio, não replicada em cada endpoint que manipula itens.

ASR-013

  • < Backward: RF-009
  • Preocupação: O Snooze sobrepõe uma condição temporária de visibilidade ao estado Ativo — toda listagem (Todo List, Planner, Busca) precisa respeitar esse filtro adicional, com risco de inconsistência se a regra for reimplementada em cada módulo.
  • Decisão rápida: Campo snoozed_until na tabela de itens; filtro de visibilidade “não expirado” centralizado em uma camada de repositório/query compartilhada por todos os módulos de listagem.

ASR-014

  • < Backward: RF-014
  • Preocupação: As regras de exibição cruzada entre Calendário e Planner Diário (SCHEDULE sempre visível; TODO visível no calendário só com horário ou due date; TODO sem data só no planner) formam uma lógica de negócio não trivial, compartilhada entre módulos e propensa a divergência entre frontend e backend.
  • Decisão rápida: Centralizar essa lógica de “visibilidade por visão” em uma única camada de query/service no backend, consumida por todos os endpoints de calendário e planner, evitando duplicação condicional no frontend.

ASR-015

< Backward: RF-013 Preocupação: A busca textual por título (restrita aos itens do tipo TODO) tem baixo risco de lentidão considerando a volumetria inicial do MVP. Contudo, o uso de operadores de correspondência parcial sem indexação apropriada força o banco a realizar Full Table Scans, o que degradará a performance severamente à medida que a base de dados crescer. Decisão: Utilizar o operador nativo contains (que opera como ILIKE) do Prisma ORM para viabilizar o desenvolvimento rápido do MVP. A adoção de motores de busca dedicados e complexos, está descartada nesta fase por ser desproporcional ao escopo, infraestrutura e custos do MVP. Trade-off / Mitigação: A ausência inicial de índices otimizados para busca de texto parcial é aceita como uma dívida técnica consciente. O caminho de evolução arquitetural já está mapeado: assim que a volumetria exigir maior performance, a mitigação será feita no nível do banco de dados (PostgreSQL) por meio da criação de um índice GIN com pg_trgm (trigramas) utilizando uma Raw Migration do Prisma, mantendo a simplicidade da infraestrutura.