--- stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8] inputDocuments: - prd.md - product-brief.md - ux-design-specification.md - research.md - brainstorm.md workflowType: 'architecture' project_name: 'Jus IA Start Kit' user_name: 'Gabriel Vaz' date: '2026-03-08' lastStep: 8 status: 'complete' completedAt: '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:** ```bash 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:** ```typescript // Dados acumulados entre telas via hidden inputs interface FlowState { area: string; // "trabalhista" subtipo: string; // "horas-extras" step: number; // Current step number responses: Record; // All responses so far } ``` **LLM Request Format:** ```typescript interface LlmRefinementRequest { systemPrompt: string; // Template por área/subtipo caseContext: Record; // Respostas coletadas maxQuestions: number; // Limitar perguntas de refinamento (2-3) } ``` **LLM Response Format:** ```typescript interface LlmRefinementResponse { questions: Array<{ id: string; text: string; type: "select" | "multiselect" | "text"; options?: string[]; // Para select/multiselect placeholder?: string; // Para text }>; } ``` **Prompt Output Format:** ```typescript 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:** ```typescript 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:** ```typescript // 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:** ```html ``` ### 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:** ```typescript // ✅ Correto — flow step handler seguindo o pattern export async function handleStep(req: FastifyRequest, reply: FastifyReply) { const flowState = parseFlowState(req.body as Record); 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:** ```typescript // ❌ 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 = () => ; // 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** - [x] Project context thoroughly analyzed (31 FRs, 12 NFRs) - [x] Scale and complexity assessed (medium, stateless MPA) - [x] Technical constraints identified (URL limit, zero persistence, LLM latency) - [x] Cross-cutting concerns mapped (security, analytics, progressive enhancement) **✅ Architectural Decisions** - [x] Critical decisions documented with versions (Fastify 5.x, Node 22 LTS, Tailwind v4+) - [x] Technology stack fully specified (Fastify + Nunjucks + Tailwind + TypeScript) - [x] Integration patterns defined (LLM proxy, URL redirect, client-side analytics) - [x] Performance considerations addressed (MPA light, Tailwind purged, minimal JS) **✅ Implementation Patterns** - [x] Naming conventions established (kebab-case files, camelCase code, snake_case templates) - [x] Structure patterns defined (feature-based, co-located tests) - [x] Communication patterns specified (form POST → handler → template render) - [x] Process patterns documented (error handling, loading, sanitization) **✅ Project Structure** - [x] Complete directory structure defined with all files - [x] Component boundaries established (routes, services, flows, templates) - [x] Integration points mapped (LLM API, Jus IA redirect, analytics) - [x] 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