From 608f37edc6b0296073d2cd271087ed85be79a38a Mon Sep 17 00:00:00 2001 From: Bruno OS Date: Fri, 24 Jul 2026 19:37:20 +0000 Subject: [PATCH] docs: create Codigos/GPT-2 --- Codigos/GPT-2.md | 997 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 997 insertions(+) create mode 100644 Codigos/GPT-2.md diff --git a/Codigos/GPT-2.md b/Codigos/GPT-2.md new file mode 100644 index 0000000..84a3cde --- /dev/null +++ b/Codigos/GPT-2.md @@ -0,0 +1,997 @@ +--- +title: Gpt 2 +description: +published: true +date: 2026-07-24T19:37:15.466Z +tags: +editor: markdown +dateCreated: 2026-07-24T19:37:15.466Z +--- + +# Guia de Estudo: Meu GPT v2 em LXC no Proxmox + +Este documento descreve como evoluir o projeto original para uma aplicacao web multiusuario com: + +- cadastro e login; +- usuarios salvos em banco de dados; +- historico de conversas; +- upload de arquivos; +- controle de consumo e custo por usuario; +- painel administrativo; +- hospedagem em um container LXC no Proxmox. + +> Importante: a aplicacao usa a **OpenAI API**, cuja cobranca e separada da assinatura do ChatGPT. A chave da API pertence ao administrador da aplicacao e deve permanecer somente no servidor. + +## 1. Resultado esperado + +O usuario acessa a aplicacao pelo navegador, cria uma conta ou entra com seu login e conversa com o GPT. As conversas ficam salvas e podem ser abertas novamente. O usuario pode anexar arquivos e consultar seu consumo. + +O administrador pode: + +- ativar e desativar usuarios; +- definir limite mensal individual; +- consultar consumo por usuario; +- consultar quantidade de tokens e custo estimado; +- impedir novas chamadas quando o limite for atingido; +- escolher quais modelos ficam disponiveis. + +## 2. Arquitetura proposta + +```text +Navegador + | + | HTTPS + v +Nginx no LXC + | + v +Next.js + |-- telas React + |-- login e sessoes + |-- API de chat + |-- API de upload + |-- regras de limite + | + |----------> PostgreSQL + | |-- usuarios + | |-- conversas + | |-- mensagens + | |-- anexos + | |-- consumo + | + |----------> armazenamento privado no LXC + | |-- arquivos enviados + | + `----------> OpenAI Responses API + |-- respostas do modelo + |-- leitura de arquivos compativeis + `-- contagem de tokens +``` + +## 3. Tecnologias escolhidas e por que usa-las + +### Next.js e React + +O Next.js continua sendo a aplicacao principal. Ele permite criar as telas e as rotas de backend no mesmo projeto. + +O React cuida das partes interativas da tela: + +- lista de conversas; +- envio de mensagens; +- indicador de resposta; +- selecao e upload de arquivos; +- tela de consumo. + +### TypeScript + +O TypeScript reduz erros ao definir claramente o formato de usuarios, mensagens, anexos e registros de consumo. + +Exemplo: + +```ts +type Message = { + id: string; + role: "USER" | "ASSISTANT"; + content: string; +}; +``` + +### PostgreSQL + +O PostgreSQL sera o banco de dados. Ele e adequado para dados relacionados, por exemplo: + +- um usuario possui varias conversas; +- uma conversa possui varias mensagens; +- uma mensagem pode possuir varios anexos; +- cada chamada da API gera um registro de consumo. + +Para estudo e para uma instalacao pequena, o PostgreSQL pode rodar no mesmo LXC. Em um ambiente maior, pode ser movido para outro container. + +### Prisma ORM + +O Prisma faz a comunicacao entre o TypeScript e o PostgreSQL. + +Em vez de escrever SQL para cada operacao, o projeto pode usar: + +```ts +const conversations = await prisma.conversation.findMany({ + where: { userId }, + orderBy: { updatedAt: "desc" }, +}); +``` + +As migrations do Prisma tambem registram as alteracoes feitas na estrutura do banco. + +### Auth.js + +O Auth.js sera responsavel pelo fluxo de autenticacao e pela sessao do usuario. Neste projeto: + +- o usuario informa e-mail e senha; +- a aplicacao procura o usuario no PostgreSQL; +- a senha e comparada com o hash salvo; +- uma sessao assinada identifica o usuario nas proximas requisicoes. + +A senha nunca deve ser salva em texto puro. Use `bcryptjs` ou `argon2` para gerar o hash. + +### Armazenamento de arquivos + +Na primeira versao, os arquivos podem ser armazenados em uma pasta privada do LXC: + +```text +/var/lib/meu-gpt/uploads +``` + +Essa pasta nao deve ficar dentro de `public/`, pois isso permitiria tentar acessar o arquivo diretamente por URL. + +Os metadados ficam no PostgreSQL, mas o conteudo fica no disco. Mais tarde, o armazenamento pode ser trocado por MinIO ou outro servico compativel com S3. + +### Nginx, PM2 e HTTPS + +- **Nginx** recebe os acessos HTTPS e encaminha para o Next.js. +- **PM2** mantem o processo do Next.js em execucao. +- **Certbot e Let's Encrypt** fornecem o certificado HTTPS. + +## 4. Estrutura sugerida do projeto + +```text +meu-gpt/ +|-- app/ +| |-- (auth)/ +| | |-- login/page.tsx +| | `-- cadastro/page.tsx +| |-- (app)/ +| | |-- chat/[conversationId]/page.tsx +| | |-- configuracoes/page.tsx +| | `-- consumo/page.tsx +| |-- admin/ +| | |-- usuarios/page.tsx +| | `-- consumo/page.tsx +| `-- api/ +| |-- auth/[...nextauth]/route.ts +| |-- register/route.ts +| |-- conversations/route.ts +| |-- conversations/[id]/messages/route.ts +| |-- upload/route.ts +| `-- admin/users/[id]/route.ts +|-- components/ +|-- lib/ +| |-- auth.ts +| |-- prisma.ts +| |-- openai.ts +| |-- permissions.ts +| |-- pricing.ts +| `-- storage.ts +|-- prisma/ +| `-- schema.prisma +|-- private-uploads/ +|-- middleware.ts +|-- .env +`-- package.json +``` + +Em producao, use `/var/lib/meu-gpt/uploads` em vez de `private-uploads/`. + +## 5. Modelo de dados + +O modelo abaixo e um ponto de partida. Ele pode ser ajustado durante a implementacao. + +```prisma +enum UserRole { + USER + ADMIN +} + +enum UserStatus { + ACTIVE + BLOCKED +} + +enum MessageRole { + USER + ASSISTANT + SYSTEM +} + +enum UsageStatus { + SUCCESS + ERROR +} + +model User { + id String @id @default(cuid()) + name String + email String @unique + passwordHash String + role UserRole @default(USER) + status UserStatus @default(ACTIVE) + monthlyLimitUsd Decimal @default(5.00) @db.Decimal(12, 4) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + conversations Conversation[] + usageRecords UsageRecord[] + attachments Attachment[] +} + +model Conversation { + id String @id @default(cuid()) + userId String + title String @default("Nova conversa") + model String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + archivedAt DateTime? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + messages Message[] + usageRecords UsageRecord[] + + @@index([userId, updatedAt]) +} + +model Message { + id String @id @default(cuid()) + conversationId String + role MessageRole + content String @db.Text + openaiResponseId String? + createdAt DateTime @default(now()) + conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) + attachments Attachment[] + + @@index([conversationId, createdAt]) +} + +model Attachment { + id String @id @default(cuid()) + userId String + messageId String? + originalName String + storedName String + mimeType String + sizeBytes Int + sha256 String + openaiFileId String? + createdAt DateTime @default(now()) + deletedAt DateTime? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + message Message? @relation(fields: [messageId], references: [id], onDelete: SetNull) + + @@index([userId, createdAt]) +} + +model UsageRecord { + id String @id @default(cuid()) + userId String + conversationId String? + model String + inputTokens Int @default(0) + cachedInputTokens Int @default(0) + outputTokens Int @default(0) + reasoningTokens Int @default(0) + totalTokens Int @default(0) + costUsd Decimal @default(0) @db.Decimal(18, 8) + status UsageStatus + requestId String? + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + conversation Conversation? @relation(fields: [conversationId], references: [id], onDelete: SetNull) + + @@index([userId, createdAt]) +} +``` + +## 6. Instalacao no LXC + +### Recursos recomendados + +Para poucos usuarios: + +```text +Sistema: Debian 12 ou Ubuntu 24.04 +CPU: 2 a 4 cores +RAM: 4 GB +Disco: 30 GB ou mais +Container nao privilegiado: sim +Inicializar no boot: sim +``` + +O tamanho do disco depende principalmente dos uploads e dos backups. + +### Instalar os pacotes + +```bash +apt update +apt upgrade -y +apt install -y curl git nginx postgresql postgresql-contrib ca-certificates +``` + +Instale uma versao LTS do Node.js compativel com as versoes atuais do Next.js e do Prisma escolhidas no momento da instalacao. + +Confirme: + +```bash +node -v +npm -v +psql --version +``` + +### Criar banco e usuario + +Entre no PostgreSQL: + +```bash +sudo -u postgres psql +``` + +Execute, substituindo a senha: + +```sql +CREATE USER meu_gpt_user WITH ENCRYPTED PASSWORD 'COLOQUE_UMA_SENHA_FORTE'; +CREATE DATABASE meu_gpt OWNER meu_gpt_user; +\q +``` + +O PostgreSQL pode continuar aceitando conexoes somente do proprio LXC. + +### Instalar dependencias do projeto + +Dentro da pasta do projeto: + +```bash +npm install openai next-auth bcryptjs zod +npm install prisma @prisma/client +npm install -D @types/bcryptjs +``` + +Bibliotecas opcionais: + +```bash +npm install file-type +``` + +`zod` valida os dados recebidos. `file-type` ajuda a conferir o tipo real do arquivo, em vez de confiar somente no nome informado pelo navegador. + +## 7. Variaveis de ambiente + +Exemplo de `.env`: + +```env +DATABASE_URL="postgresql://meu_gpt_user:SENHA_FORTE@127.0.0.1:5432/meu_gpt" + +AUTH_SECRET="GERE_UMA_CHAVE_LONGA_E_ALEATORIA" +AUTH_URL="https://gpt.seudominio.com" + +OPENAI_API_KEY="SUA_CHAVE_DA_API" +OPENAI_MODEL="MODELO_PERMITIDO_PELA_SUA_CONTA" + +UPLOAD_DIR="/var/lib/meu-gpt/uploads" +MAX_UPLOAD_BYTES="10485760" + +DEFAULT_MONTHLY_LIMIT_USD="5.00" +``` + +Gere o segredo da autenticacao com: + +```bash +openssl rand -base64 32 +``` + +Regras: + +- nao envie `.env` para Git; +- nunca use variavel iniciada por `NEXT_PUBLIC_` para a chave da OpenAI; +- deixe o arquivo legivel apenas pelo usuario que executa a aplicacao; +- troque imediatamente qualquer segredo que tenha sido exposto. + +## 8. Cadastro e login + +### Cadastro + +O endpoint de cadastro deve: + +1. validar nome, e-mail e senha com `zod`; +2. normalizar o e-mail para letras minusculas; +3. exigir uma senha com tamanho minimo; +4. verificar se o e-mail ja existe; +5. gerar o hash da senha; +6. criar o usuario com limite mensal padrao; +7. nunca devolver `passwordHash` na resposta. + +Exemplo do hash: + +```ts +import bcrypt from "bcryptjs"; + +const passwordHash = await bcrypt.hash(password, 12); +``` + +### Login + +No login: + +1. procure o usuario pelo e-mail; +2. verifique se ele esta ativo; +3. compare a senha informada com o hash; +4. crie uma sessao contendo somente os identificadores necessarios; +5. redirecione para a tela de chat. + +```ts +const validPassword = await bcrypt.compare(password, user.passwordHash); +``` + +Proteja todas as rotas de chat, upload, historico e consumo. O backend deve obter o `userId` da sessao; nunca aceite um `userId` enviado pelo navegador como prova de identidade. + +### Cadastro publico ou controlado + +Para uma aplicacao pessoal ou empresarial, e mais seguro escolher uma destas opcoes: + +- somente o administrador cria usuarios; +- cadastro exige um codigo de convite; +- cadastro publico exige verificacao de e-mail. + +Nao deixe cadastro publico ilimitado em uma aplicacao que usa sua chave da API. + +## 9. Historico de conversas + +### Fluxo + +1. O usuario cria uma conversa. +2. A aplicacao cria um registro `Conversation`. +3. A mensagem do usuario e salva em `Message`. +4. O backend carrega as mensagens anteriores daquela conversa. +5. O backend chama a OpenAI. +6. A resposta e salva como outra `Message`. +7. O registro de consumo e salvo. +8. A tela atualiza a lista e o horario da conversa. + +### Regra de propriedade + +Toda consulta deve combinar o identificador da conversa com o usuario autenticado: + +```ts +const conversation = await prisma.conversation.findFirst({ + where: { + id: conversationId, + userId: session.user.id, + }, +}); +``` + +Buscar somente pelo `conversationId` criaria uma falha de seguranca: um usuario poderia tentar abrir a conversa de outro usuario alterando a URL. + +### Contexto enviado ao modelo + +Nao envie para a API todas as mensagens de uma conversa sem limite. Conversas grandes: + +- aumentam o custo; +- ficam mais lentas; +- podem ultrapassar o limite de contexto do modelo. + +Uma estrategia inicial e enviar as mensagens mais recentes. Depois, implemente resumo automatico das mensagens antigas e armazene esse resumo na conversa. + +## 10. Upload de arquivos + +### Fluxo seguro + +1. exigir usuario autenticado; +2. limitar o tamanho; +3. permitir somente extensoes e tipos necessarios; +4. conferir o tipo real do arquivo; +5. gerar nome aleatorio para armazenamento; +6. calcular SHA-256; +7. salvar fora da pasta publica; +8. registrar os metadados no banco; +9. enviar para a OpenAI apenas quando for usado em uma mensagem; +10. apagar arquivos temporarios e arquivos remotos quando nao forem mais necessarios. + +Exemplo de nome fisico: + +```text +/var/lib/meu-gpt/uploads/usuario-id/550e8400-e29b-41d4-a716-446655440000.pdf +``` + +O nome original fica no banco para ser exibido na interface, mas nao deve ser usado diretamente como caminho no disco. + +### Tipos iniciais recomendados + +Comece com poucos formatos: + +- PDF; +- TXT; +- CSV; +- DOCX, se o fluxo escolhido oferecer suporte adequado; +- imagens PNG e JPEG, se o modelo selecionado aceitar imagens. + +Defina um limite menor na propria aplicacao, por exemplo 10 MB, mesmo que a API aceite arquivos maiores. Isso protege o disco, a memoria e o custo. + +### Dois usos diferentes de arquivos + +**Arquivo anexado a uma pergunta:** o documento e enviado como entrada daquela mensagem. E a opcao mais simples para a primeira versao. + +**Biblioteca permanente de documentos:** exige busca nos documentos, controle de permissoes, indexacao e normalmente uma estrategia de RAG ou busca em arquivos. Deve ser uma segunda fase. + +## 11. Controle de custo por usuario + +### Como medir + +A resposta da OpenAI informa dados de uso, incluindo tokens de entrada, saida e total. O backend deve salvar esses valores em `UsageRecord`. + +Exemplo conceitual: + +```ts +const usage = response.usage; + +await prisma.usageRecord.create({ + data: { + userId, + conversationId, + model: response.model, + inputTokens: usage?.input_tokens ?? 0, + cachedInputTokens: usage?.input_tokens_details?.cached_tokens ?? 0, + outputTokens: usage?.output_tokens ?? 0, + reasoningTokens: usage?.output_tokens_details?.reasoning_tokens ?? 0, + totalTokens: usage?.total_tokens ?? 0, + costUsd: calculatedCost, + status: "SUCCESS", + requestId: response.id, + }, +}); +``` + +Os nomes exatos dos campos devem ser conferidos na versao do SDK instalada. + +### Como calcular + +Mantenha no backend uma tabela de precos por modelo: + +```ts +type ModelPrice = { + inputUsdPerMillion: number; + cachedInputUsdPerMillion?: number; + outputUsdPerMillion: number; +}; +``` + +Formula geral: + +```text +custo de entrada = + tokens de entrada cobraveis / 1.000.000 x preco de entrada + +custo de entrada em cache = + tokens em cache / 1.000.000 x preco de cache + +custo de saida = + tokens de saida / 1.000.000 x preco de saida + +custo total = + entrada + cache + saida +``` + +Nao grave valores monetarios usando `float`. Use `Decimal` no banco para evitar erros de arredondamento. + +Os precos mudam. Por isso: + +- nao espalhe precos pelo codigo; +- mantenha uma unica tabela de configuracao; +- registre o modelo usado em cada chamada; +- revise os precos na pagina oficial antes de atualizar; +- trate o valor mostrado como estimativa interna e reconcilie-o periodicamente com o painel da OpenAI. + +### Verificacao do limite + +Antes de chamar a API: + +```ts +const startOfMonth = new Date( + new Date().getFullYear(), + new Date().getMonth(), + 1, +); + +const usage = await prisma.usageRecord.aggregate({ + where: { + userId, + status: "SUCCESS", + createdAt: { gte: startOfMonth }, + }, + _sum: { costUsd: true }, +}); +``` + +Se o total for maior ou igual ao limite, a API deve responder: + +```json +{ + "error": "Limite mensal atingido" +} +``` + +Use o status HTTP `429` para indicar que o limite de uso foi atingido. + +### Evitar que chamadas simultaneas ultrapassem o limite + +Uma simples verificacao antes da chamada nao e suficiente quando o mesmo usuario envia varias requisicoes ao mesmo tempo. + +Para um limite mais rigido: + +- permita somente uma geracao ativa por usuario; ou +- reserve um valor estimado antes da chamada em uma transacao; +- ao terminar, substitua a reserva pelo custo real; +- libere a reserva se a chamada falhar. + +Tambem defina `max_output_tokens` para limitar o tamanho e o custo maximo da resposta. + +### O painel de consumo + +Mostre ao usuario: + +- consumo do mes; +- limite mensal; +- percentual utilizado; +- tokens de entrada e saida; +- consumo por conversa; +- modelo utilizado; +- data de renovacao do limite. + +O administrador deve visualizar os mesmos dados para todos os usuarios. + +## 12. Fluxo da rota de chat + +Uma rota segura segue esta ordem: + +```text +1. Validar a sessao +2. Validar os dados recebidos +3. Confirmar que a conversa pertence ao usuario +4. Confirmar que o usuario esta ativo +5. Conferir o limite mensal +6. Salvar a mensagem do usuario +7. Preparar contexto e anexos +8. Chamar a OpenAI +9. Salvar a resposta +10. Salvar tokens e custo +11. Devolver a resposta ao navegador +``` + +Pseudoimplementacao: + +```ts +export async function POST(request: Request) { + const session = await requireSession(); + const input = chatSchema.parse(await request.json()); + + const conversation = await findOwnedConversation( + input.conversationId, + session.user.id, + ); + + await assertUserCanSpend(session.user.id); + + const userMessage = await saveUserMessage(conversation.id, input); + + try { + const response = await createOpenAIResponse({ + conversation, + userMessage, + }); + + const calculatedCost = calculateCost(response.model, response.usage); + + await saveAssistantMessageAndUsage({ + userId: session.user.id, + conversationId: conversation.id, + response, + calculatedCost, + }); + + return Response.json({ text: response.output_text }); + } catch (error) { + await saveFailedUsage(session.user.id, conversation.id); + throw error; + } +} +``` + +No codigo real, salve a mensagem do assistente e o consumo na mesma transacao do banco. + +## 13. Painel administrativo + +Crie uma area acessivel somente quando: + +```ts +session.user.role === "ADMIN" +``` + +Funcoes iniciais: + +- listar usuarios; +- bloquear e desbloquear; +- alterar limite mensal; +- promover um usuario a administrador; +- consultar consumo por periodo; +- consultar erros; +- excluir ou anonimizar um usuario; +- apagar anexos e conversas conforme a politica definida. + +Toda alteracao administrativa importante deve gerar um registro de auditoria em uma futura tabela `AuditLog`. + +## 14. Seguranca essencial + +Antes de publicar: + +- use HTTPS; +- mantenha a chave da OpenAI somente no servidor; +- use hash forte de senha; +- aplique limite de tentativas no login; +- aplique limite de requisicoes no chat e upload; +- valide todos os dados com `zod`; +- confira a propriedade de cada conversa e arquivo; +- limite tamanho e tipo dos uploads; +- use nomes aleatorios no disco; +- nao renderize HTML recebido do modelo sem sanitizacao; +- configure cookies como `HttpOnly`, `Secure` e `SameSite`; +- bloqueie usuarios desativados em todas as APIs; +- mantenha dependencias atualizadas; +- faca backup criptografado; +- nunca inclua segredos nos logs; +- defina politica de retencao e exclusao de dados. + +Se a aplicacao ficar acessivel somente por VPN, a superficie de ataque diminui, mas login e autorizacao continuam necessarios. + +## 15. Preparar armazenamento no LXC + +Exemplo: + +```bash +mkdir -p /var/lib/meu-gpt/uploads +chown -R meu-gpt:meu-gpt /var/lib/meu-gpt +chmod 750 /var/lib/meu-gpt +chmod 750 /var/lib/meu-gpt/uploads +``` + +O usuario Linux `meu-gpt` deve ser o mesmo que executa o processo da aplicacao. + +Evite executar a aplicacao como `root`. + +## 16. Migrations e primeira conta administrativa + +Depois de configurar o Prisma: + +```bash +npx prisma generate +npx prisma migrate dev --name auth_history_upload_usage +``` + +Em producao, aplique migrations ja criadas: + +```bash +npx prisma migrate deploy +``` + +Crie um script de seed para a primeira conta administrativa. A senha deve vir de uma variavel de ambiente temporaria, ser transformada em hash e nunca aparecer no repositorio. + +## 17. Build e execucao + +```bash +npm run build +pm2 start npm --name meu-gpt -- start +pm2 save +pm2 startup +``` + +Use o comando exibido pelo `pm2 startup` para ativar o inicio automatico. + +Consulte logs: + +```bash +pm2 logs meu-gpt +``` + +Os logs devem conter IDs de requisicao e mensagens de erro, mas nao senhas, tokens de sessao, chave da API ou conteudo confidencial dos arquivos. + +## 18. Nginx + +Exemplo basico: + +```nginx +server { + listen 80; + server_name gpt.seudominio.com; + + client_max_body_size 10M; + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +O limite do Nginx deve ser igual ou ligeiramente maior que o limite configurado na aplicacao. + +Depois: + +```bash +nginx -t +systemctl reload nginx +certbot --nginx -d gpt.seudominio.com +``` + +## 19. Backup + +O backup precisa incluir: + +- banco PostgreSQL; +- pasta de uploads; +- arquivos de configuracao; +- migrations do Prisma. + +Exemplo de backup do banco: + +```bash +sudo -u postgres pg_dump -Fc meu_gpt > /var/backups/meu-gpt-db.dump +``` + +Nao basta criar o backup. Teste periodicamente a restauracao em outro banco ou container. + +Considere snapshots do LXC como protecao adicional, mas mantenha tambem backups independentes do Proxmox. + +## 20. Ordem recomendada de implementacao + +### Fase 1: banco e login + +- instalar PostgreSQL; +- adicionar Prisma; +- criar `User`; +- criar cadastro controlado; +- implementar login e logout; +- proteger as rotas. + +### Fase 2: historico + +- criar `Conversation` e `Message`; +- criar lista lateral; +- abrir, renomear, arquivar e excluir conversa; +- validar propriedade em todas as rotas. + +### Fase 3: consumo + +- criar `UsageRecord`; +- registrar tokens retornados pela OpenAI; +- centralizar precos; +- exibir consumo mensal; +- bloquear chamadas acima do limite; +- tratar requisicoes simultaneas. + +### Fase 4: arquivos + +- criar `Attachment`; +- adicionar upload privado; +- validar arquivo; +- anexar arquivo a uma mensagem; +- configurar exclusao e retencao. + +### Fase 5: administracao e operacao + +- criar painel administrativo; +- adicionar auditoria; +- configurar backups; +- configurar rate limit; +- revisar logs e alertas; +- testar restauracao. + +## 21. Testes necessarios + +### Autenticacao + +- cadastro com e-mail duplicado; +- senha incorreta; +- usuario bloqueado; +- rota privada sem sessao; +- usuario comum tentando abrir o painel administrativo. + +### Autorizacao + +- usuario A tentando abrir conversa do usuario B; +- usuario A tentando baixar anexo do usuario B; +- alteracao manual de IDs na URL e no corpo da requisicao. + +### Consumo + +- chamada registra tokens; +- custo usa o modelo correto; +- limite bloqueia nova chamada; +- mudanca de mes reinicia a soma; +- duas chamadas simultaneas nao ultrapassam o limite rigido; +- erro da OpenAI nao e cobrado incorretamente pelo sistema. + +### Upload + +- arquivo acima do limite; +- extensao permitida com conteudo de outro tipo; +- nome contendo `../`; +- arquivo vazio; +- arquivo de outro usuario; +- exclusao do arquivo local e do registro correspondente. + +## 22. Melhorias futuras + +- verificacao de e-mail; +- recuperacao de senha; +- autenticacao em dois fatores; +- login corporativo; +- streaming da resposta; +- busca nas conversas; +- exportacao de conversa; +- RAG para biblioteca de documentos; +- MinIO para armazenamento; +- Redis para rate limit e controle de concorrencia; +- antivirus para uploads; +- alertas de consumo; +- observabilidade e auditoria; +- separacao do PostgreSQL em outro LXC. + +## 23. O que muda em relacao ao projeto original + +| Parte | Projeto original | Projeto v2 | +|---|---|---| +| Acesso | Uma senha compartilhada | Conta individual e sessao | +| Usuarios | Nao possui | Salvos no PostgreSQL | +| Conversas | Somente na tela | Salvas no banco | +| Arquivos | Nao possui | Upload privado e metadados | +| Custos | Sem controle individual | Tokens e custo por usuario | +| Administracao | Nao possui | Usuarios, limites e consumo | +| Seguranca | Basica | Autenticacao, autorizacao e rate limit | +| Backup | Nao detalhado | Banco, arquivos e restauracao | + +## 24. Referencias para estudo + +- [OpenAI: inicio rapido da API](https://platform.openai.com/docs/quickstart) +- [OpenAI: referencia da Responses API](https://platform.openai.com/docs/api-reference/responses) +- [OpenAI: arquivos](https://platform.openai.com/docs/api-reference/files) +- [OpenAI: uso da API](https://platform.openai.com/docs/api-reference/usage) +- [OpenAI: precos da API](https://openai.com/api/pricing/) +- [OpenAI: controles e retencao de dados](https://platform.openai.com/docs/models/default-usage-policies-by-endpoint) +- [Next.js: Route Handlers](https://nextjs.org/docs/app/getting-started/route-handlers) +- [Prisma: integracao com Next.js](https://www.prisma.io/docs/guides/frameworks/nextjs) +- [Auth.js: documentacao](https://authjs.dev/) +- [PostgreSQL: documentacao](https://www.postgresql.org/docs/) + +## 25. Resumo + +A evolucao principal e transformar uma pagina de chat protegida por senha em um sistema multiusuario. + +O Next.js continua cuidando das telas e do backend. O PostgreSQL passa a guardar usuarios, conversas, mensagens, anexos e consumo. O Prisma facilita o acesso ao banco. O Auth.js cuida do login e da sessao. Os arquivos ficam em uma pasta privada, e cada resposta da OpenAI gera um registro de tokens e custo. + +A melhor ordem de aprendizado e: + +```text +login -> historico -> consumo -> upload -> painel administrativo +``` + +Essa ordem permite testar cada parte antes de adicionar a proxima e reduz a dificuldade de encontrar erros.