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á em03-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 (ver03-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 |