From 65e8127261e4cdb5d2cf778c06e7ebf03ca46f2a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 8 Mar 2026 22:46:40 +0000 Subject: [PATCH] Complete Architecture Decision Document (Steps 1-8) Architecture for Jus IA Start Kit: Fastify + Nunjucks + Tailwind CSS MPA. Key decisions: zero persistence, server-side LLM proxy, progressive enhancement, feature-based organization, hidden form fields for state. Includes implementation patterns, project structure, and validation. https://claude.ai/code/session_01CvrcMDqfCKWV2hC3xpRbx3 --- docs/jus-ia-project/architecture.md | 956 ++++++++++++++++++++++++++++ 1 file changed, 956 insertions(+) create mode 100644 docs/jus-ia-project/architecture.md diff --git a/docs/jus-ia-project/architecture.md b/docs/jus-ia-project/architecture.md new file mode 100644 index 000000000..336a8f6d2 --- /dev/null +++ b/docs/jus-ia-project/architecture.md @@ -0,0 +1,956 @@ +--- +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