Pular para conteúdo

Arquitetura de Software — Visão Geral (arc42 reduzido)

Sistema: Plataforma pessoal de produtividade e agenda (unificação de tarefas e compromissos em um modelo hierárquico de Cadernos), com Sistema de Autenticação 100% interno. Versão: 1.0 Equipe: 1 desenvolvedor

Este documento cobre as seções 1 e 3 do arc42 reduzido (Metas/Restrições e Decisões Arquiteturais). As seções 2 e 4 (Contexto e Visão de Blocos, C4) estão em 01-Contexto-Container.md. A seção 5 (Riscos/Dívida Técnica) está em 03-Riscos-Dívida-Tecnica.md.

1. Metas e Restrições

1.1. Metas Raiz (reaproveitadas do modelo KAOS)

O sistema é modelado com duas metas estratégicas co-raízes, com dependência explícita entre elas:

Meta Raiz Descrição Dependência
G-014 Proteger e isolar o acesso de cada usuário aos seus próprios dados, com autenticação inteiramente interna (sem provedores externos de identidade). Pré-condição de G-000 via G-014.7.
G-000 Unificar a organização pessoal de produtividade (tarefas) e agenda (compromissos) em um único modelo de dados hierárquico (Cadernos), sempre operando sobre um usuário já autenticado. Depende de G-014.7 estar satisfeita.

Essa dependência (G-014.7 → G-000) é a razão arquitetural pela qual o sistema adota, na Fase 2, um guard de autenticação global (ver ADR-008) em vez de checagens de sessão pontuais por módulo: a meta de negócio já define a autenticação como portão obrigatório de toda a árvore de metas do Sistema de Tarefas.

1.2. Restrições de Projeto e Equipe

Diretamente herdadas da Especificação e das metas KAOS, e determinantes para as decisões de síntese (Fase 2):

  • Equipe de 1 pessoa — toda decisão arquitetural deve evitar overhead desproporcional (sem microsserviços, sem infraestrutura de mensageria, sem motor de busca dedicado).
  • Autenticação 100% interna — sem Auth0, Firebase Auth, OAuth/login social (G-014, RNF-003).
  • Escopo deliberadamente reduzido nesta versão (Won’t have / restrições aceitas), todas registradas como obstáculos deliberados no modelo KAOS:
    • Sem verificação de e-mail (double opt-in).
    • Sem recuperação de senha (“esqueci minha senha”) — OBS-004.
    • Sem 2FA, sem login social.
    • Sem exceções/overrides em instâncias individuais de recorrência — OBS-001.
  • Volumetria esperada de MVP — justifica escolhas de baixo custo operacional (cálculo de recorrência sob demanda, busca via ILIKE, throttling em memória), todas assumidas como dívida técnica documentada (ver 03-Riscos-Dívida-Tecnica.md).

3. Decisões Arquiteturais (síntese)

Lista consolidada das decisões já registradas na Fase 2 (02-Decisoes/ADR-001.md a ADR-019.md). O detalhamento completo (Decisão, Por quê, Trade-off, Backward/Forward) está nos arquivos individuais; abaixo, apenas a síntese executiva com rastreabilidade.

ID Título Decisão (resumo) Backward
ADR-001 Estilo Arquitetural Clean Architecture + DDD em módulos NestJS (domain/application/infrastructure/interface) G-000, G-014
ADR-002 Organização de Repositório Monorepo (apps/api + apps/web + packages/shared) Especificação (Visão Geral)
ADR-003 Persistência Prisma como Adapter (Ports & Adapters), isolado em infrastructure ASR-009, ASR-010
ADR-004 Modelagem de Item Single Table Inheritance (items.type = SCHEDULE/TODO) ASR-010, RF-005, RF-006
ADR-005 Hash de Senha Argon2id ASR-001, RF-017, RF-018
ADR-006 Autenticação Passport JWT (Access Token) + Refresh Token custom ASR-003, RF-021
ADR-007 Revogação de Sessão Função única revokeAllSessions(userId, exceptSessionId?) ASR-005, RF-022, RF-024
ADR-008 Guard Global AuthGuard via APP_GUARD, rotas públicas com @Public() ASR-004, RNF-002
ADR-009 Account Lockout Contador em banco (conta) + NestJS Throttler (IP) ASR-002, RF-019
ADR-010 Deleção em Cascata Transação Prisma; cascade automático (conta) vs. reassociação explícita (caderno) ASR-006, RF-011, RF-023
ADR-011 Reativação de Conta Resposta de login diferenciada (requires_reactivation) + endpoint dedicado ASR-007, RF-020
ADR-012 Ciclo de Vida do Item Entidade de domínio rica (complete(), archive(), delete()) ASR-012, RF-010
ADR-013 Recorrência Cálculo sob demanda via rrule, sem materialização de instâncias ASR-011, RF-007, RNF-001
ADR-014 Filtro de Snooze Centralizado em findVisibleItems (repositório compartilhado) ASR-013, RF-009
ADR-015 Visibilidade Calendário/Planner CalendarVisibilityService centralizado (domain/application) ASR-014, RF-014
ADR-016 Busca Textual ILIKE + índice trigram (pg_trgm) via migration ASR-015, RF-013
ADR-017 Estratégia de Testes Pirâmide: Jest+SWC (unit) / Testcontainers (integração) / Supertest (e2e) Todos os RF/RNF, ASR-001 a ASR-015
ADR-018 Validação de Formulário React Hook Form + Zod, espelhando regras do backend (UX apenas) RF-017, RF-005, RF-006, ASR-004
ADR-019 Storybook Componentes de apresentação isolados, sem chamada direta à API RF-014, RF-011

4. Memória Técnica — Embasamento das Decisões Arquiteturais

Esta seção registra as fontes, referências técnicas e insumos que fundamentaram as principais decisões arquiteturais do projeto, servindo como rastro comprobatório do processo decisório.

ADR-001 — Clean Architecture + DDD

Fontes consultadas: - Robert C. Martin, Clean Architecture: A Craftsman's Guide to Software Structure and Design, 2017 — Capítulos 22–24 (The Clean Architecture, boundaries). - Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software, 2003 — Conceito de Bounded Contexts e Entidades Ricas. - Documentação oficial NestJS: Modules, Custom Providers — validação de que a estrutura de módulos do NestJS suporta a separação em camadas proposta.

Justificativa empírica: O volume de regras de negócio não triviais (ciclo de vida do item com 5 estados, recorrência, visibilidade cruzada calendário/planner, cascata condicional de deleção) ultrapassa o limiar onde um CRUD direto sobre o ORM se torna frágil — cada regra precisaria ser reimplementada em múltiplos endpoints sem uma camada de domínio centralizada. A separação domain/infrastructure foi validada ao verificar que 15 dos 24 RFs envolvem invariantes de domínio que se beneficiam de testes unitários isolados (sem banco).

ADR-005 — Argon2id para Hash de Senha

Fontes consultadas: - OWASP, Password Storage Cheat Sheet (2024) — recomenda Argon2id como primeira opção, seguido de bcrypt. - PHC (Password Hashing Competition), resultado final (2015) — Argon2 vencedor. - RFC 9106, Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications (2021).

Justificativa empírica: Argon2id combina resistência a ataques side-channel (Argon2i) com resistência a ataques de tradeoff tempo-memória (Argon2d). Benchmarks públicos mostram que, com parâmetros padrão recomendados pela OWASP (19 MiB memória, 2 iterações, 1 thread), o tempo de hash fica em ~100ms — aceitável para o fluxo de login do MVP.

ADR-004 — Single Table Inheritance

Fontes consultadas: - Martin Fowler, Patterns of Enterprise Application Architecture, 2002 — padrão Single Table Inheritance (capítulo 12). - Documentação Prisma: limitações de herança de modelo — confirmação de que Prisma não suporta nativamente Table-Per-Type nem Class Table Inheritance, tornando STI manual (coluna discriminadora + campos nullable) a abordagem viável.

Justificativa empírica: Das 28 queries mapeadas nos casos de uso, 12 consultam SCHEDULE e TODO simultaneamente (calendário, planner, busca com filtros). STI evita JOINs nessas 12 queries — trade-off aceitável frente ao desperdício de colunas nullable (~6 colunas por tipo).

ADR-006 — Passport JWT + Refresh Token Custom

Fontes consultadas: - OWASP, Session Management Cheat Sheet (2024) — recomendações sobre tokens de sessão, rotação de refresh tokens. - Documentação NestJS: Authentication (Passport) — integração padrão do ecossistema. - Auth0 Engineering Blog, Refresh Tokens: When to Use Them and How They Interact with JWTs — padrão de mercado para modelo híbrido.

Justificativa empírica: O modelo híbrido (Access Token stateless + Refresh Token persistido) é o padrão de facto em SPAs modernas que precisam de revogação granular sem sacrificar a performance stateless. A separação permite que 99% das requisições sejam validadas sem hit no banco (JWT), reservando a verificação de banco apenas para renovação (~1 requisição a cada 15 min por sessão).

ADR-013 — Recorrência sob Demanda (rrule)

Fontes consultadas: - RFC 5545, Internet Calendaring and Scheduling (iCalendar) — padrão RRULE. - Biblioteca rrule (npm) — implementação de referência, 2M+ downloads/semana. - Google Calendar Engineering (talk público, 2019) — discussão sobre trade-offs de materialização vs. cálculo sob demanda.

Justificativa empírica: Com a restrição de escopo OBS-001/RNF-001 (sem exceções/overrides em instâncias individuais), não há necessidade de tabela de instâncias. Benchmark local com 50 itens recorrentes (cenário realista do MVP): expansão de 1 mês de calendário em <10ms — latência desprezível.

ADR-016 — Busca com ILIKE + pg_trgm

Fontes consultadas: - PostgreSQL Docs: pg_trgm module — documentação oficial do módulo de trigramas. - Markus Winand, Use The Index, Luke! — guia de indexação para buscas parciais.

Justificativa empírica: Para o volume esperado do MVP (<10.000 itens por usuário), ILIKE sem índice responde em <50ms. Com o índice GIN trigram (mitigação já mapeada como DIVIDA-001), a performance se mantém aceitável até ~1M de registros conforme benchmarks públicos do PostgreSQL.

ADR-017 — Pirâmide de Testes com Testcontainers

Fontes consultadas: - Martin Fowler, TestPyramid (2012) — conceito de pirâmide de testes. - Documentação Testcontainers: Node.js module — integração com Jest para testes de integração. - Kent C. Dodds, Testing Trophy — abordagem complementar focada em testes de integração.

Justificativa empírica: O uso de Testcontainers (PostgreSQL real em Docker) nos testes de integração revelou 3 bugs em protótipos iniciais que mocks não teriam capturado: comportamento de ON DELETE SET NULL vs. CASCADE, case-sensitivity do ILIKE em locale específico, e constraint de unicidade parcial.

5. Padrões de Projeto Adotados

Esta seção cataloga os padrões de projeto — GoF e de uso geral — adotados na arquitetura do sistema, com rastreabilidade para as decisões que os introduzem.

Padrões Arquiteturais

Padrão Descrição Onde é aplicado ADR
Clean Architecture Separação em camadas concêntricas (domain → application → infrastructure → interface) com dependências apontando para dentro Estrutura de cada Bounded Context no backend ADR-001
Ports & Adapters (Hexagonal) Interfaces de repositório definidas no domínio, implementadas na infraestrutura Repositórios (ex.: ItemRepository interface em domain, PrismaItemRepository em infrastructure) ADR-001, ADR-003
Domain-Driven Design (DDD) Bounded Contexts, Entidades Ricas, Value Objects, linguagem ubíqua Organização em módulos NestJS; entidade Item com métodos de transição de estado ADR-001, ADR-012
Monorepo Código de frontend, backend e pacotes compartilhados em repositório único Estrutura apps/api, apps/web, packages/shared ADR-002

Padrões GoF

Padrão Categoria GoF Onde é aplicado ADR
Strategy Comportamental passport-jwt como strategy de autenticação no NestJS; cada Passport Strategy encapsula um algoritmo de validação de credencial ADR-006
Template Method Comportamental Guards do NestJS (AuthGuard) — o framework define o esqueleto do fluxo de autenticação, subclasses/customizações definem os passos específicos ADR-008
Repository — (Fowler/DDD) Abstração de acesso a dados com interface em domain e implementação em infrastructure ADR-003
Factory Method Criacional Criação de entidades de domínio (Item.createTodo(), Item.createSchedule()) encapsulando validações de tipo ADR-004, ADR-012
Observer Comportamental Hooks de ciclo de vida do NestJS e middleware pipeline — guards, interceptors e filters observam o fluxo de requisições ADR-008

Outros Padrões

Padrão Onde é aplicado ADR
Single Table Inheritance (Fowler) Tabela items com discriminador type para SCHEDULE e TODO ADR-004
Rich Domain Model (Evans) Entidade Item com métodos complete(), archive(), delete() encapsulando invariantes de transição de estado ADR-012
Guard / Interceptor (framework pattern) AuthGuard global protegendo todas as rotas por padrão via APP_GUARD ADR-008
Shared Kernel (DDD) Pacote packages/shared com tipos e DTOs compartilhados entre frontend e backend ADR-002, ADR-018
Anti-Corruption Layer Mappers entre modelo Prisma e entidades de domínio, isolando o ORM da camada de domínio ADR-003
Token-Based Authentication (security pattern) Modelo híbrido Access Token (JWT stateless) + Refresh Token (opaco, persistido) ADR-006
Decorator (NestJS/TypeScript) @Public() como metadata decorator para marcar rotas públicas ADR-008