BMAD-METHOD/docs/jus-ia-project/architecture.md

40 KiB

stepsCompleted inputDocuments workflowType project_name user_name date lastStep status completedAt
1
2
3
4
5
6
7
8
prd.md
product-brief.md
ux-design-specification.md
research.md
brainstorm.md
architecture Jus IA Start Kit Gabriel Vaz 2026-03-08 8 complete 2026-03-08

Architecture Decision Document — Jus IA Start Kit

Documento construído colaborativamente para garantir que agentes de IA implementem de forma consistente.


Project Context Analysis

Requirements Overview

Functional Requirements:

O PRD define 31 requisitos funcionais (FR1-FR31) organizados em 6 categorias:

Categoria FRs Implicação Arquitetural
Task Selection & Navigation FR1-FR5 Roteamento com deep links, seleção hierárquica (tipo → área → subtipo)
Guided Flow (Deterministic) FR6-FR10 Engine de fluxo condicional, 10 templates de perguntas, validação server-side
AI Contextual Refinement FR11-FR14 Endpoint LLM backend, loading states, resposta assíncrona
Prompt Assembly & Delivery FR15-FR19 Template engine para montagem de prompt, URL builder com encoding
URL Overflow Handling FR20-FR22 Detecção de limite de caracteres, fallback copy-paste
Sharing & Distribution FR23-FR24 OG tags dinâmicas por rota, deep links compartilháveis
Analytics & Tracking FR25-FR29 Client-side analytics, tracking de funil, contagem de redirects
Edge Cases & Fallbacks FR30-FR31 Handling de fluxos não disponíveis, sugestão de alternativas

Non-Functional Requirements:

Categoria NFRs Impacto Arquitetural
Performance NFR1-NFR3 MPA leve, <5s em 3G, loading state para LLM
Security NFR4-NFR6 Zero persistência, sem auth, sem cookies de sessão, logs sanitizados
Integration NFR7-NFR9 URL parametrizada para Jus IA, validação de limite, fallback idêntico
Compatibility NFR10-NFR12 Evergreen browsers, mobile-first, OG tags para WhatsApp

Scale & Complexity:

  • Primary domain: Web application (MPA)
  • Complexity level: Medium — stateless, sem persistência de dados, sem auth
  • Estimated architectural components: ~8 (router, flow engine, template renderer, LLM client, prompt builder, URL builder, analytics, OG tags)
  • Unique constraint: Zero data retention — dados transitam pelo backend apenas durante refinamento IA e são descartados

Technical Constraints & Dependencies

Constraint Impacto
Stateless by design Sem banco de dados, sem sessão server-side, sem cache de estado do usuário
URL limit ~2000 chars Prompt montado deve caber na URL ou acionar fallback copy-paste
LLM latency Refinamento contextual tem latência de 2-5s — requer loading state
Mobile-first MPA Cada tela é um page load — performance de HTML/CSS é crítica
Zero auth Sem login, sem cookies de sessão, sem tracking de identidade
Jus IA URL format Formato fixo: ia.jusbrasil.com.br/conversa?q=...&send
10 flow types MVP Templates de prompt por área do direito requerem expertise jurídica

Cross-Cutting Concerns Identified

  1. Data Transit Security: Dados do caso passam pelo backend para refinamento IA — devem ser descartados após resposta, sem logs de conteúdo
  2. Progressive Enhancement: Base funcional sem JS (MPA form submit), JS para melhorias (validação inline, copy-to-clipboard, transições)
  3. Analytics: Único estado persistente — client-side tracking em todas as páginas do fluxo
  4. OG Tags: Dinâmicas por rota para preview correto no WhatsApp
  5. Error Handling: Retry automático para LLM, fallback graceful para URL overflow
  6. Performance: Bundle CSS mínimo (Tailwind purged), HTML semântico leve, sem JS framework pesado

Starter Template Evaluation

Primary Technology Domain

MPA (Multi Page Application) — server-rendered HTML com Tailwind CSS. Não é SPA, não é SSR com hydration. Cada page load é um HTML completo gerado no servidor.

Starter Options Considered

Opção Tipo Avaliação
Next.js Full-stack React SSR Overkill — traz React, hydration, e complexidade desnecessária para um MPA de 5 telas
Express + EJS/Pug MPA clássico Node.js Simples, leve, MPA nativo. Sem overhead de framework frontend
Fastify + Nunjucks MPA rápido Node.js Melhor performance que Express, templates flexíveis, plugin ecosystem
Hono Edge-first web framework Ultralight, funciona em Cloudflare Workers/Vercel Edge, mas menos maduro para MPA templates
Python Flask + Jinja2 MPA Python Maduro mas equipe prefere ecossistema Node/TypeScript

Selected Starter: Fastify + Nunjucks + Tailwind CSS

Rationale for Selection:

  1. Performance: Fastify é ~2x mais rápido que Express em benchmarks. Para MPA com loading de LLM, cada ms conta
  2. MPA nativo: Nunjucks templates renderizam HTML server-side sem JS client-side — exatamente o modelo MPA
  3. TypeScript first: Fastify tem suporte nativo a TypeScript com type providers
  4. Plugin ecosystem: Fastify plugins para static files, form body, cors, rate limiting
  5. Tailwind integration: CSS build separado do runtime — Tailwind compila para CSS estático servido como asset
  6. Boring technology: Fastify é estável (v5+), bem documentado, usado em produção em escala
  7. Lightweight: Sem React, sem Vue, sem hydration, sem virtual DOM. HTML puro + CSS + JS progressivo

Initialization Command:

mkdir jus-ia-start-kit && cd jus-ia-start-kit
npm init -y
npm install fastify @fastify/static @fastify/formbody @fastify/view nunjucks
npm install -D typescript @types/node tailwindcss @tailwindcss/cli
npx tsc --init
npx tailwindcss init

Architectural Decisions Provided by Starter:

Language & Runtime:

  • TypeScript 5.x com Node.js 22 LTS
  • ESM modules (type: "module" no package.json)
  • Strict mode TypeScript

Styling Solution:

  • Tailwind CSS v4+ com configuração customizada de design tokens
  • CSS compilado como asset estático (não inline)
  • Purge em produção para bundle mínimo

Build Tooling:

  • TypeScript compiler (tsc) para build do server
  • Tailwind CLI para build do CSS
  • npm scripts para development e production

Testing Framework:

  • Vitest para unit tests (compatível com TypeScript ESM nativo)
  • Playwright para E2E tests (mobile viewport testing)

Code Organization:

  • Feature-based modules (cada fluxo jurídico como módulo)
  • Templates Nunjucks separados por tela
  • Shared partials para componentes reutilizáveis

Development Experience:

  • Fastify com --watch para hot reload do server
  • Tailwind com --watch para hot reload do CSS
  • TypeScript em modo watch

Note: Project initialization usando este comando deve ser a primeira story de implementação.


Core Architectural Decisions

Decision Priority Analysis

Critical Decisions (Block Implementation):

  1. Server framework e template engine (Fastify + Nunjucks)
  2. Flow engine pattern (state machine por fluxo)
  3. LLM integration pattern (server-side proxy)
  4. Prompt assembly strategy (template composition)
  5. URL builder e overflow detection

Important Decisions (Shape Architecture): 6. Form state management across MPA pages 7. Analytics integration approach 8. OG tags generation strategy 9. Error handling e retry patterns

Deferred Decisions (Post-MVP):

  • CDN e caching strategy (premature optimization)
  • Rate limiting detalhado (monitorar antes de otimizar)
  • A/B testing infrastructure (v2)

Data Architecture

Decisão: Zero Persistence — In-Memory Only

Aspecto Decisão
Database Nenhum. Sem banco de dados no MVP
Session state Hidden form fields + URL query params entre pages
Flow state Dados acumulados via hidden inputs em cada form submit (MPA pattern)
LLM context Montado server-side a cada request a partir dos form data recebidos
Analytics Client-side (GA4 ou Plausible) — não passa pelo backend

Rationale: O produto é stateless by design (NFR4-NFR6). Dados do caso existem apenas durante a sessão do browser. Cada page load do MPA recebe os dados acumulados via hidden form fields e os passa adiante. Sem cookies, sem localStorage para dados do caso.

Form State Pattern:

Tela 1 → form submit → Tela 2 (hidden inputs com dados da Tela 1)
                        → form submit → Tela 3 (hidden inputs com dados das Telas 1+2)
                                         → ...até Preview

Authentication & Security

Decisão: Zero Auth

Aspecto Decisão
Authentication Nenhuma. Sem login, sem cadastro
Authorization Nenhuma. Todas as rotas são públicas
Data protection Dados transitam via form POST, não ficam na URL (exceto deep links de entrada)
LLM security Backend sanitiza input antes de enviar ao LLM. Sem log de conteúdo jurídico
CSRF Token CSRF em forms para prevenir submissions maliciosas
Rate limiting Básico por IP no endpoint LLM para prevenir abuso

Rationale: NFR6 explicitamente define "não há autenticação, cookies de sessão ou tracking de identidade". O único ponto de segurança é o endpoint LLM (prevenir abuso) e sanitização de inputs (prevenir injection).

API & Communication Patterns

Decisão: Server-Side LLM Proxy — Sem API Pública

Aspecto Decisão
External API Nenhuma API pública exposta. O produto é um MPA, não uma API
LLM communication Server-side: Fastify route handler → LLM provider SDK → response
LLM provider OpenAI API (GPT-4o-mini para custo-benefício) ou Anthropic Claude Haiku
Request format Form POST do browser → Fastify handler monta context → chama LLM → renderiza template
Error handling Retry 1x automático. Se falhar: renderiza template de erro com botão retry
Response format HTML renderizado (Nunjucks template) — não JSON

Data Flow:

Browser → POST form data → Fastify handler
  → Monta contexto do caso a partir dos form fields
  → Chama LLM API com prompt de sistema + contexto
  → Recebe perguntas de refinamento da IA
  → Renderiza template Nunjucks com perguntas
  → Retorna HTML ao browser

Prompt Assembly Flow:

Browser → POST com todas as respostas → Fastify handler
  → Combina template de prompt (por área/subtipo) + respostas do advogado
  → Gera prompt final otimizado para Jus IA
  → Verifica tamanho do prompt (< ~1800 chars para URL encoding safety)
  → Se cabe: gera URL parametrizada
  → Se não cabe: renderiza template com copy-paste fallback
  → Retorna HTML de preview ao browser

Frontend Architecture

Decisão: MPA com Progressive Enhancement

Aspecto Decisão
Rendering 100% server-side (Nunjucks templates). Zero client-side rendering
JavaScript Progressive enhancement only. Produto funciona sem JS
State management Hidden form fields (zero client-side state)
Routing Fastify routes — cada tela é uma rota do servidor
Components Nunjucks partials/macros — reutilizáveis no server
CSS Tailwind CSS compilado como asset estático
Icons Heroicons como SVG inline nos templates

Progressive Enhancement (JS opcional):

Feature Sem JS Com JS
Form submit Normal page reload Fetch + DOM swap (opcional)
Validation Server-side após submit Inline validation ao sair do campo
Copy to clipboard Selecionar texto manualmente Botão "Copiar" com navigator.clipboard
Chip selection Radio buttons styled Click handler + visual feedback
Loading state Page load normal Skeleton shimmer animation

JS Bundle Strategy:

  • Um arquivo app.js mínimo (~5KB gzipped) com progressive enhancements
  • Sem framework JS (sem React, Vue, Alpine, HTMX)
  • Vanilla JS com módulos ES nativos do browser
  • Carregado com defer para não bloquear render

Infrastructure & Deployment

Decisão: Single Container Deploy — Railway ou Render

Aspecto Decisão
Hosting Railway.app ou Render.com — PaaS simples com deploy por git push
Container Single Node.js container (Fastify serve tudo: HTML, CSS, JS, assets)
CDN Cloudflare free tier como proxy — caching de assets estáticos
Domain Custom domain (ex: startkit.jusia.com.br ou similar)
SSL Automático via PaaS + Cloudflare
CI/CD GitHub Actions → build TypeScript + Tailwind → deploy via git push
Monitoring PaaS built-in metrics + Sentry free tier para error tracking
Logging Structured JSON logs via Fastify logger (pino). Sem log de conteúdo jurídico
Environment .env para LLM API key, analytics IDs, feature flags mínimos

Rationale: Produto lean, zero banco de dados, single container. PaaS é a abordagem mais simples que funciona. Sem Kubernetes, sem microservices, sem Docker Compose. Um container Node.js que serve tudo.

Scaling Strategy (se necessário):

  • PaaS auto-scaling horizontal (Railway/Render suportam)
  • Cloudflare cacheia assets estáticos (CSS, JS, imagens, fonts)
  • LLM é o bottleneck — scaling depende do budget de inferência

Decision Impact Analysis

Implementation Sequence:

  1. Project setup (Fastify + TypeScript + Tailwind + Nunjucks)
  2. Template system (layouts, partials, design tokens)
  3. Routing e deep links
  4. Flow engine (1 fluxo trabalhista completo)
  5. LLM integration (refinamento contextual)
  6. Prompt assembly + URL builder
  7. Preview + redirect + copy fallback
  8. Analytics integration
  9. OG tags
  10. Expand para 10 fluxos

Cross-Component Dependencies:

  • Flow engine depende de templates Nunjucks + routing
  • LLM integration depende de flow engine (monta contexto a partir das respostas)
  • Prompt assembly depende de LLM integration + flow engine
  • URL builder depende de prompt assembly
  • Preview depende de URL builder (decide se redirect ou copy fallback)

Implementation Patterns & Consistency Rules

Pattern Categories Defined

12 áreas onde agentes IA poderiam fazer escolhas diferentes identificadas e resolvidas.

Naming Patterns

File & Directory Naming:

  • Arquivos: kebab-case.ts (ex: flow-engine.ts, prompt-builder.ts)
  • Diretórios: kebab-case/ (ex: legal-flows/, template-helpers/)
  • Templates: kebab-case.njk (ex: chip-selector.njk, preview-card.njk)
  • Tests: *.test.ts co-located (ex: prompt-builder.test.ts ao lado de prompt-builder.ts)

Route Naming:

  • Rotas de fluxo: /:area/:subtipo (ex: /trabalhista/horas-extras)
  • Kebab-case, sem acentos, lowercase
  • Rotas internas: /flow/:area/:subtipo/step/:stepNumber
  • POST endpoints: mesma rota que GET (form submission)

Code Naming:

  • Variáveis e funções: camelCase (ex: buildPrompt, flowConfig)
  • Types e interfaces: PascalCase (ex: FlowStep, LegalArea)
  • Constants: UPPER_SNAKE_CASE (ex: MAX_URL_LENGTH, LLM_TIMEOUT_MS)
  • Template variables: snake_case nos Nunjucks (ex: {{ area_direito }}, {{ tipo_tarefa }})

Nunjucks Specifics:

  • Macros: camelCase (ex: {% macro chipSelector(options) %})
  • Blocks: camelCase (ex: {% block pageContent %})
  • Partials: prefixo _ (ex: _stepper-progress.njk)

Structure Patterns

Project Organization: Feature-based com shared core.

src/
├── server.ts              # Entry point — Fastify setup
├── config/                # Configuration loading
├── routes/                # Fastify route handlers
│   ├── home.ts            # Landing page route
│   └── flow.ts            # Flow routes (/:area/:subtipo/...)
├── flows/                 # Flow definitions (per legal area)
│   ├── types.ts           # Shared flow types
│   ├── trabalhista/       # Trabalhista flows
│   │   ├── horas-extras.ts
│   │   ├── rescisao-indireta.ts
│   │   └── ...
│   └── civel/             # Cível flows
│       ├── cobranca.ts
│       └── ...
├── services/              # Business logic services
│   ├── flow-engine.ts     # Core flow execution logic
│   ├── llm-client.ts      # LLM API client
│   ├── prompt-builder.ts  # Prompt assembly from responses
│   └── url-builder.ts     # URL generation + overflow detection
├── templates/             # Nunjucks templates
│   ├── layouts/
│   │   └── base.njk       # Base layout (head, body, scripts)
│   ├── pages/
│   │   ├── home.njk       # Landing page
│   │   ├── flow-step.njk  # Generic flow step page
│   │   ├── preview.njk    # Preview + redirect page
│   │   └── error.njk      # Error page
│   └── partials/
│       ├── _stepper-progress.njk
│       ├── _chip-selector.njk
│       ├── _preview-card.njk
│       ├── _legal-badge.njk
│       ├── _loading-state.njk
│       ├── _copy-fallback.njk
│       └── _og-tags.njk
├── public/                # Static assets
│   ├── css/
│   │   └── app.css        # Compiled Tailwind output
│   ├── js/
│   │   └── app.js         # Progressive enhancement JS
│   └── images/
│       └── og-default.png # Default OG image
└── utils/                 # Shared utilities
    ├── sanitize.ts        # Input sanitization
    ├── analytics.ts       # Analytics event helpers
    └── og-tags.ts         # OG tag generation

Test Organization: Co-located com source.

src/services/flow-engine.ts
src/services/flow-engine.test.ts    # Unit test ao lado
src/services/prompt-builder.ts
src/services/prompt-builder.test.ts
tests/                              # E2E tests separados
├── e2e/
│   ├── flow-trabalhista.spec.ts
│   ├── flow-civel.spec.ts
│   └── url-overflow.spec.ts
└── fixtures/
    ├── flow-responses.ts           # Mock responses para testes
    └── llm-responses.ts            # Mock LLM responses

Format Patterns

Form Data Format:

// Dados acumulados entre telas via hidden inputs
interface FlowState {
  area: string;          // "trabalhista"
  subtipo: string;       // "horas-extras"
  step: number;          // Current step number
  responses: Record<string, string | string[]>;  // All responses so far
}

LLM Request Format:

interface LlmRefinementRequest {
  systemPrompt: string;           // Template por área/subtipo
  caseContext: Record<string, string>;  // Respostas coletadas
  maxQuestions: number;           // Limitar perguntas de refinamento (2-3)
}

LLM Response Format:

interface LlmRefinementResponse {
  questions: Array<{
    id: string;
    text: string;
    type: "select" | "multiselect" | "text";
    options?: string[];           // Para select/multiselect
    placeholder?: string;         // Para text
  }>;
}

Prompt Output Format:

interface AssembledPrompt {
  text: string;                   // Prompt completo para Jus IA
  legalReferences: string[];      // ["art. 59 CLT", "Súmula 85 TST"]
  charCount: number;              // Contagem de caracteres
  fitsInUrl: boolean;             // charCount <= MAX_URL_LENGTH
  encodedUrl?: string;            // URL completa se fitsInUrl
}

Error Format:

interface AppError {
  code: string;                   // "LLM_TIMEOUT" | "LLM_ERROR" | "INVALID_FLOW"
  message: string;                // Mensagem para o usuário (pt-BR)
  retryable: boolean;             // Se o botão retry deve aparecer
}

Communication Patterns

Request-Response Pattern (MPA):

  • Browser envia form POST → Fastify handler processa → Retorna HTML
  • Sem WebSocket, sem SSE, sem polling
  • Loading state para LLM: client-side JS mostra skeleton enquanto form submits (progressive enhancement)

Template Rendering Pattern:

// Todos os handlers seguem este padrão
async function handleFlowStep(request: FastifyRequest, reply: FastifyReply) {
  const flowState = parseFlowState(request.body);
  const stepConfig = getStepConfig(flowState.area, flowState.subtipo, flowState.step);

  // Se step precisa de LLM refinement
  if (stepConfig.requiresLlm) {
    const refinement = await llmClient.refine(flowState);
    return reply.view("pages/flow-step.njk", { flowState, questions: refinement.questions });
  }

  return reply.view("pages/flow-step.njk", { flowState, questions: stepConfig.questions });
}

Analytics Pattern:

<!-- Em cada template, antes do </body> -->
<script>
  // Analytics events disparados no client
  trackEvent('flow_step_view', { area: '{{ area }}', subtipo: '{{ subtipo }}', step: {{ step }} });
</script>

Process Patterns

Error Handling:

  • LLM timeout (>10s): retry automático 1x. Se falhar: renderiza error.njk com "Não conseguimos analisar seu caso agora" + botão retry
  • Invalid flow (área/subtipo não existe): renderiza error.njk com "Este fluxo ainda não está disponível" + links para fluxos disponíveis
  • Form validation error: re-renderiza a mesma tela com mensagens de erro inline
  • Uncaught errors: Sentry captura + renderiza página genérica de erro

Loading State Pattern:

  • Sem JS: form submit → page load normal (browser mostra spinner nativo)
  • Com JS: intercepta form submit → mostra skeleton/shimmer → fetch → substitui conteúdo
  • Microcopy de loading: "Analisando seu caso..." (nunca "Carregando...")

Input Sanitization:

  • Todos os inputs de texto: strip HTML tags, trim whitespace, limit length (500 chars)
  • Valores de select/chip: validar contra opções permitidas (whitelist)
  • Não salvar raw input em logs — apenas metadata (área, subtipo, step number)

Enforcement Guidelines

All AI Agents MUST:

  1. Seguir o naming pattern: arquivos kebab-case, variáveis camelCase, constants UPPER_SNAKE_CASE
  2. Nunca persistir dados do caso em disco, banco, ou logs
  3. Usar Nunjucks partials para componentes — nunca duplicar HTML
  4. Manter progressive enhancement: tudo funciona sem JS
  5. Sanitizar inputs antes de qualquer processamento
  6. Usar o pattern de FlowState para acumular respostas entre telas
  7. Tratar erros de LLM com retry 1x + fallback para página de erro
  8. Incluir analytics tracking em toda tela do fluxo

Pattern Examples

Good Examples:

// ✅ Correto — flow step handler seguindo o pattern
export async function handleStep(req: FastifyRequest, reply: FastifyReply) {
  const flowState = parseFlowState(req.body as Record<string, string>);
  const config = getStepConfig(flowState.area, flowState.subtipo, flowState.step);
  return reply.view("pages/flow-step.njk", { flowState, ...config });
}

// ✅ Correto — template usando partials
// pages/flow-step.njk
{% extends "layouts/base.njk" %}
{% block pageContent %}
  {% include "partials/_stepper-progress.njk" %}
  {% for question in questions %}
    {% if question.type == "select" %}
      {{ chipSelector(question) }}
    {% endif %}
  {% endfor %}
{% endblock %}

Anti-Patterns:

// ❌ Errado — persistindo dados do caso
await db.insert('user_cases', { data: flowState.responses });

// ❌ Errado — logando conteúdo jurídico
logger.info('User response:', flowState.responses);

// ❌ Errado — client-side rendering
const App = () => <FlowStep questions={questions} />;  // Sem React!

// ❌ Errado — naming inconsistente
const UserFlowState = {};  // Deveria ser flowState (camelCase)
const flow_engine = {};    // Deveria ser flowEngine (camelCase)

Project Structure & Boundaries

Complete Project Directory Structure

jus-ia-start-kit/
├── README.md
├── package.json
├── tsconfig.json
├── tailwind.config.ts
├── .env.example
├── .env
├── .gitignore
├── .github/
│   └── workflows/
│       ├── ci.yml                    # Lint + test + build
│       └── deploy.yml                # Deploy to Railway/Render
│
├── src/
│   ├── server.ts                     # Fastify entry point
│   ├── config/
│   │   ├── index.ts                  # Config loader from env
│   │   ├── flows.ts                  # Flow registry (all 10 flows)
│   │   └── constants.ts              # MAX_URL_LENGTH, LLM_TIMEOUT_MS, etc.
│   │
│   ├── routes/
│   │   ├── home.ts                   # GET / — landing page
│   │   ├── flow.ts                   # GET/POST /:area/:subtipo/... — flow routes
│   │   └── health.ts                 # GET /health — health check
│   │
│   ├── flows/
│   │   ├── types.ts                  # FlowConfig, FlowStep, Question types
│   │   ├── trabalhista/
│   │   │   ├── index.ts              # Trabalhista area config
│   │   │   ├── horas-extras.ts       # Flow: horas extras
│   │   │   ├── horas-extras.test.ts
│   │   │   ├── rescisao-indireta.ts  # Flow: rescisão indireta
│   │   │   ├── rescisao-indireta.test.ts
│   │   │   ├── dano-moral.ts         # Flow: dano moral
│   │   │   ├── acumulo-funcao.ts     # Flow: acúmulo de função
│   │   │   └── contestacao.ts        # Flow: contestação trabalhista
│   │   └── civel/
│   │       ├── index.ts              # Cível area config
│   │       ├── cobranca.ts           # Flow: cobrança
│   │       ├── indenizacao.ts        # Flow: indenização
│   │       ├── obrigacao-fazer.ts    # Flow: obrigação de fazer
│   │       ├── contestacao.ts        # Flow: contestação cível
│   │       └── contrato.ts           # Flow: contrato revisão
│   │
│   ├── services/
│   │   ├── flow-engine.ts            # Core flow logic
│   │   ├── flow-engine.test.ts
│   │   ├── llm-client.ts             # LLM API client (OpenAI/Anthropic)
│   │   ├── llm-client.test.ts
│   │   ├── prompt-builder.ts         # Prompt assembly from responses
│   │   ├── prompt-builder.test.ts
│   │   ├── url-builder.ts            # URL generation + overflow detection
│   │   └── url-builder.test.ts
│   │
│   ├── templates/
│   │   ├── layouts/
│   │   │   └── base.njk              # Base HTML layout
│   │   ├── pages/
│   │   │   ├── home.njk              # Landing: "O que você precisa?"
│   │   │   ├── select-area.njk       # Seleção de área do direito
│   │   │   ├── select-subtipo.njk    # Seleção de subtipo
│   │   │   ├── flow-step.njk         # Tela genérica de perguntas
│   │   │   ├── loading.njk           # Loading state (noscript fallback)
│   │   │   ├── preview.njk           # Preview + redirect/copy
│   │   │   ├── not-available.njk     # Fluxo não disponível
│   │   │   └── error.njk             # Erro genérico
│   │   └── partials/
│   │       ├── _stepper-progress.njk # Componente: barra de progresso
│   │       ├── _chip-selector.njk    # Componente: seleção por chips
│   │       ├── _preview-card.njk     # Componente: card do preview
│   │       ├── _legal-badge.njk      # Componente: badge jurídico
│   │       ├── _loading-state.njk    # Componente: loading skeleton
│   │       ├── _copy-fallback.njk    # Componente: copy + link
│   │       ├── _og-tags.njk          # OG meta tags
│   │       ├── _hidden-state.njk     # Hidden inputs com flow state
│   │       ├── _analytics.njk        # Analytics script snippet
│   │       └── _back-button.njk      # Botão voltar
│   │
│   ├── public/
│   │   ├── css/
│   │   │   └── app.css               # Tailwind compiled output
│   │   ├── js/
│   │   │   └── app.js                # Progressive enhancement
│   │   ├── images/
│   │   │   ├── og-default.png        # OG image padrão
│   │   │   ├── og-trabalhista.png    # OG image trabalhista
│   │   │   └── og-civel.png          # OG image cível
│   │   └── favicon.ico
│   │
│   └── utils/
│       ├── sanitize.ts               # Input sanitization
│       ├── sanitize.test.ts
│       ├── parse-flow-state.ts       # Parse hidden form fields
│       ├── parse-flow-state.test.ts
│       └── og-tags.ts                # OG tag data by route
│
├── tests/
│   ├── e2e/
│   │   ├── happy-path.spec.ts        # Fluxo completo trabalhista
│   │   ├── deep-links.spec.ts        # Deep link entry points
│   │   ├── url-overflow.spec.ts      # Overflow fallback
│   │   ├── back-navigation.spec.ts   # Browser back preserva estado
│   │   └── no-js.spec.ts             # Funciona sem JavaScript
│   └── fixtures/
│       ├── flow-responses.ts         # Mock form data
│       └── llm-responses.ts          # Mock LLM API responses
│
├── prompts/                           # Prompt templates (não é código)
│   ├── system/
│   │   ├── trabalhista-refinement.md  # System prompt para refinamento trabalhista
│   │   └── civel-refinement.md        # System prompt para refinamento cível
│   └── templates/
│       ├── trabalhista-horas-extras.md    # Template de prompt final
│       ├── trabalhista-rescisao-indireta.md
│       └── ...                        # Um por fluxo
│
└── Dockerfile                         # Container para deploy

Architectural Boundaries

API Boundaries:

  • Nenhuma API pública. O produto é um MPA — browser fala com Fastify via form POST
  • Único ponto de integração externo: LLM API (OpenAI/Anthropic) chamado server-side
  • Único ponto de saída: redirect para ia.jusbrasil.com.br/conversa?q=...&send

Component Boundaries:

Componente Responsabilidade Não pode
Routes Receber request, parsear form data, chamar services, renderizar template Conter lógica de negócio
Flow Engine Determinar próximo step, validar respostas, decidir se precisa LLM Acessar LLM diretamente
LLM Client Comunicar com API do LLM, retry, timeout handling Conhecer fluxos jurídicos
Prompt Builder Montar prompt final a partir de template + respostas Comunicar com LLM
URL Builder Gerar URL parametrizada, detectar overflow Conhecer conteúdo jurídico
Templates Renderizar HTML a partir de dados Conter lógica de negócio
Flows Definir perguntas, validações, e metadata por fluxo jurídico Acessar serviços externos

Data Flow:

[Browser] → POST form data
    ↓
[Route Handler] → Parse form data → FlowState
    ↓
[Flow Engine] → Determina próximo step
    ↓ (se precisa IA)
[LLM Client] → Chama API → Perguntas de refinamento
    ↓
[Route Handler] → Renderiza template com perguntas
    ↓
[Browser] ← HTML response

--- No step final: ---

[Flow Engine] → Todas respostas coletadas
    ↓
[Prompt Builder] → Monta prompt final + legal references
    ↓
[URL Builder] → Gera URL ou detecta overflow
    ↓
[Route Handler] → Renderiza preview template
    ↓
[Browser] → Click "Gerar no Jus IA →" → Redirect

Requirements to Structure Mapping

FR1-FR5 (Task Selection & Navigation):

  • src/routes/home.ts + src/routes/flow.ts — routing e deep links
  • src/templates/pages/home.njk + select-area.njk + select-subtipo.njk

FR6-FR10 (Guided Flow):

  • src/flows/ — definição dos 10 fluxos por área/subtipo
  • src/services/flow-engine.ts — engine de execução
  • src/templates/pages/flow-step.njk + partials

FR11-FR14 (AI Refinement):

  • src/services/llm-client.ts — comunicação com LLM
  • prompts/system/ — system prompts por área
  • src/templates/partials/_loading-state.njk

FR15-FR22 (Prompt Assembly & Delivery):

  • src/services/prompt-builder.ts — montagem do prompt
  • src/services/url-builder.ts — URL + overflow
  • prompts/templates/ — templates de prompt por fluxo
  • src/templates/pages/preview.njk + _preview-card.njk + _copy-fallback.njk

FR23-FR24 (Sharing & Distribution):

  • src/utils/og-tags.ts + src/templates/partials/_og-tags.njk
  • Deep links via routing em src/routes/flow.ts

FR25-FR29 (Analytics):

  • src/templates/partials/_analytics.njk — script tag em todas as páginas
  • Client-side tracking (GA4 ou Plausible)

FR30-FR31 (Edge Cases):

  • src/templates/pages/not-available.njk
  • Flow engine retorna fluxos disponíveis quando subtipo não existe

Integration Points

Internal Communication:

  • Route handlers chamam services via import direto (sem message bus, sem events)
  • Services são stateless functions — recebem dados, retornam resultado
  • Templates recebem dados via reply.view() — sem state management

External Integrations:

Integração Método Configuração
LLM API HTTP REST (OpenAI SDK / Anthropic SDK) LLM_API_KEY env var
Jus IA redirect URL parametrizada no browser Hardcoded format no url-builder
Analytics Client-side script tag ANALYTICS_ID env var
Error tracking Sentry SDK server-side SENTRY_DSN env var

Architecture Validation Results

Coherence Validation

Decision Compatibility: Todas as decisões tecnológicas são compatíveis e formam um stack coeso:

  • Fastify (server) + Nunjucks (templates) + Tailwind (CSS) = MPA clássico com tooling moderno
  • TypeScript unifica linguagem server + build tools
  • Sem conflitos de dependência — stack mínimo sem overlapping

Pattern Consistency:

  • Naming patterns consistentes (kebab-case arquivos, camelCase código, snake_case templates)
  • Todos os handlers seguem o mesmo padrão: parse → process → render
  • Progressive enhancement aplicado uniformemente: tudo funciona sem JS

Structure Alignment:

  • Feature-based organization (flows/trabalhista/, flows/civel/) alinha com os 10 fluxos do PRD
  • Separação clara: routes (HTTP) → services (lógica) → templates (apresentação)
  • Tests co-located facilitam manutenção por feature

Requirements Coverage Validation

Functional Requirements Coverage:

Categoria FRs Suporte Arquitetural
Task Selection FR1-FR5 Routes + deep links + templates
Guided Flow FR6-FR10 Flow engine + flow configs (10 flows)
AI Refinement FR11-FR14 LLM client + loading state
Prompt Assembly FR15-FR19 Prompt builder + URL builder
URL Overflow FR20-FR22 URL builder overflow detection + copy fallback
Sharing FR23-FR24 OG tags + deep links
Analytics FR25-FR29 Client-side analytics em todas as páginas
Edge Cases FR30-FR31 Not-available page + flow suggestions

Non-Functional Requirements Coverage:

NFR Requisito Suporte
NFR1 <5s em 3G MPA leve, Tailwind purged, sem JS framework
NFR2 Loading state LLM Loading template + progressive enhancement
NFR3 Transições sem delay MPA page loads nativos
NFR4 Zero persistência Sem DB, hidden form fields only
NFR5 Sem log de conteúdo Sanitize + log metadata only
NFR6 Sem auth/cookies/tracking Zero auth architecture
NFR7-NFR9 URL format Jus IA URL builder com formato específico
NFR10-NFR12 Browsers + mobile + OG Tailwind responsive + OG tags

Implementation Readiness Validation

Decision Completeness:

  • Todas as decisões críticas documentadas com versões (Fastify 5.x, Node 22 LTS, Tailwind v4+)
  • Patterns de implementação com exemplos concretos de código
  • Consistência rules enforceable (naming, structure, process)

Structure Completeness:

  • Diretório completo com todos os arquivos mapeados
  • Cada FR mapeado para arquivos específicos
  • Boundaries claros entre componentes

Pattern Completeness:

  • Naming patterns cobrem arquivos, rotas, código, e templates
  • Error handling definido para todos os cenários (LLM, validation, not found)
  • Data flow documentado end-to-end

Gap Analysis Results

Nenhum gap crítico identificado.

Gaps importantes (não bloqueiam MVP):

  1. Prompt templates (em prompts/) requerem expertise jurídica para construção — não é decisão arquitetural, mas é dependência de conteúdo
  2. LLM provider final (OpenAI vs Anthropic) pode ser decidido durante implementação baseado em custo/qualidade
  3. Analytics provider (GA4 vs Plausible) decisão pode ser deferida

Nice-to-have (pós-MVP):

  • Health check endpoint mais robusto (readiness probe)
  • Structured logging com correlation IDs
  • Feature flags para rollout gradual de novos fluxos

Architecture Completeness Checklist

Requirements Analysis

  • Project context thoroughly analyzed (31 FRs, 12 NFRs)
  • Scale and complexity assessed (medium, stateless MPA)
  • Technical constraints identified (URL limit, zero persistence, LLM latency)
  • Cross-cutting concerns mapped (security, analytics, progressive enhancement)

Architectural Decisions

  • Critical decisions documented with versions (Fastify 5.x, Node 22 LTS, Tailwind v4+)
  • Technology stack fully specified (Fastify + Nunjucks + Tailwind + TypeScript)
  • Integration patterns defined (LLM proxy, URL redirect, client-side analytics)
  • Performance considerations addressed (MPA light, Tailwind purged, minimal JS)

Implementation Patterns

  • Naming conventions established (kebab-case files, camelCase code, snake_case templates)
  • Structure patterns defined (feature-based, co-located tests)
  • Communication patterns specified (form POST → handler → template render)
  • Process patterns documented (error handling, loading, sanitization)

Project Structure

  • Complete directory structure defined with all files
  • Component boundaries established (routes, services, flows, templates)
  • Integration points mapped (LLM API, Jus IA redirect, analytics)
  • Requirements to structure mapping complete (all 31 FRs mapped)

Architecture Readiness Assessment

Overall Status: READY FOR IMPLEMENTATION

Confidence Level: High — stack simples, decisões claras, zero ambiguidade arquitetural

Key Strengths:

  1. Simplicidade radical: MPA + hidden form fields + server-side rendering. Sem complexidade acidental
  2. Zero persistence: Sem banco, sem sessão, sem cache = zero infraestrutura de dados para manter
  3. Progressive enhancement: Funciona sem JS — robustez máxima para mobile entre audiências
  4. Feature-based organization: Cada fluxo jurídico é um módulo isolado — fácil expandir para novos fluxos
  5. Patterns claros: Agentes IA têm examples concretos de código correto vs. anti-patterns

Areas for Future Enhancement:

  1. Service Worker para PWA offline (pós-MVP)
  2. Edge deployment (Cloudflare Workers) para latência menor
  3. A/B testing de templates de prompt
  4. Integração bidirecional com Jus IA

Implementation Handoff

AI Agent Guidelines:

  • Follow all architectural decisions exactly as documented
  • Use implementation patterns consistently across all components
  • Respect project structure and boundaries
  • Refer to this document for all architectural questions
  • Never persist case data — this is a non-negotiable security requirement
  • Always maintain progressive enhancement — everything must work without JS

First Implementation Priority:

  1. npm init + install dependencies + TypeScript + Tailwind setup
  2. Base layout template (base.njk) with design tokens from UX spec
  3. Home route + landing page template
  4. One complete flow (trabalhista/horas-extras) end-to-end
  5. LLM integration for contextual refinement
  6. Prompt builder + URL builder + preview
  7. Expand to remaining 9 flows