# City10 — Cidade 3D Virtual com Agentes de IA **City10** é uma plataforma full-stack de simulação urbana 3D com agentes de inteligência artificial, construída sobre **Laravel 13** e **Three.js**. O visualizador3D é jogável no navegador: trânsito semafórico, pedestres, agentes (Prefeito, lojistas), conversas de rua com IA, praças com academia e uma praia com lazer. O raciocínio dos NPCs acontece através da API [OpenRouter.ai](https://openrouter.ai), restrito a uma lista de modelos gratuitos. > Plataforma operada pela **Syspanel** — Santa Rita do Sapucaí/MG, Brasil. > Contato: [contato@syspanel.com.br](mailto:contato@syspanel.com.br) · > WhatsApp: (35) 99226-1684 · [www.syspanel.com.br](https://syspanel.com.br) --- ## Visão Geral da Arquitetura | Camada | Tecnologia | Responsabilidade | |---|---|---| | Backend / Painel Admin | Laravel 13 (PHP ≥ 8.3) | Autenticação, API REST, regras de negócio, consentimento LGPD | | Banco de Dados | MariaDB (MySQL) | Persistência de usuários, lojas, agentes, conversas e consentimentos | | Cache / Fila | Database (sessões/cache/jobs) | Sessões, cache, agendamentos e throttle | | Frontend 3D | Three.js | Mundo jogável no navegador (cidade, trânsito, praia, clima) | | Tempo Real | Polling HTTP + SSE | Presence (~2,5 s), chat (~2,5 s) e stream de resposta de NPC (SSE) | | Cérebro dos Agentes | OpenRouter.ai | Raciocínio dos NPCs e conversas com modelos gratuitos | --- ## Fase 1 — Plataforma (Entregue) - Estrutura Laravel 13 com autenticação diferenciada (**Admin** / **Usuário Comum**). - **Migrations**: usuários com `role`, lojas com coordenadas 3D (`pos_x`, `pos_y`, `pos_z`), agentes de IA e trilha de consentimento legal (LGPD). - **API REST** (Sanctum) para usuários, lojas, agentes, cidade e documentos legais. - **CAPTCHA matemático** próprio (soma), sem dependências externas, nos formulários públicos. - **Multi-idioma**: Português (Brasil), Inglês e Espanhol — selecionável pelo usuário. - **Termos de Uso, Política de Privacidade e Política de Cookies** (LGPD), versionados e com aceite auditável (data, hora, versão, IP). - **Banner de cookies** com link para os Termos de Uso e Privacidade. - **Página inicial** responsiva (desktop e smartphone). --- ## Fase 2 — Mundo 3D Jogável (Entregue) O visualizador `/city` carrega o mundo completo em tempo real: - **Cidade de 72 quarteirões** (grade 9 × 8 de blocos de 40 m; bounds `−120..160 × −120..120`), com rio e ponte a oeste, extensão rodoviária ao sul, casas de jogadores e um conjunto de lugares públicos com letreiros luminosos: **hospital, escola, prefeitura, universidade, corpo de bombeiros** (prédios cívicos) e **supermercado, drogaria, restaurante, cabeleireiro, banco, hotel e shopping** (11 lojas no total, todas com placa frontal + letreiro vertical blade). - **Trânsito**: carros, motos, bikes e ônibus com tráfego à direita, loop por quarteirão e **semáforos por cruzamento** (fases NS/EW com amarelos e all-red; veículos param na linha de parada **antes** das faixas). - **Faixas zebradas reais** (barras longitudinais paralelas ao fluxo, design MUTCD) com calçadas e meio-fios interrompidos nas travessias — 323 faixas no layout atual. - **Pedestres** com travessia sincronizada ao semáforo; bloqueio de travessia do jogador no vermelho. - **Praças** (1 a cada 4 células) com academia externa: exercícios com pose, efeito em saúde/energia e missão “Shape em dia”. - **Praia a leste** (`/city` + `App\Support\Beach`): areia, mar com ondas animadas (deslocamento de vértices), espuma na orla, **banhistas, nadadores, surfistas, salva-vidas (torre + patrulha), quadra de basquete com jogadores e bola em arremesso, barracas de comidas, cadeiras e guarda-sóis**. O jogador pode **relaxar na areia** (tecla `E` → `POST /city/actions/beach`), recuperando energia/saúde por tick até o máximo. - **Dois aeroportos** derivados dos bounds (pavimento + sinalização de pista com designadores, taxiways com eixo amarelo, pátio de embarque com posições de estacionamento de aeronaves, terminal com pontes articuladas, hangars, torre de controle e helipista): **7 aeronaves de 7 companhias** (jato comercial, jato regional, monomotor e helicóptero) executam o ciclo completo *taxi → decolagem → cruíse sobre a cidade → aproximação → pouso → taxi → gate*, com contagem de decolagens/pousos em `stats().flights`. - **Torre de controle com IA**: o agente `atc` "Torre de Controle City10" (modelo `AI_ATC_MODEL`, `poolside/laguna-xs-2.1:free`) gera clearances de decolagem a cada decolagem (`POST /city/airport/dispatch`, cooldown de 30 s) numa **cadeia de modelos** `AI_ATC_MODEL` → default → `AI_FALLBACK_MODEL` (`xiaomi/mimo-v2.6-flash`), com texto determinístico quando tudo falha; o clearance mais recente aparece como aviso "✈ ...". - **Agentes vivos**: prefeito itinerante, lojistas nas lojas, pedestres com rotas, mais trens (passagem de nível com barreiras), ônibus/trem embarcáveis, avião e barcos no rio. - **Dia/noite e clima** com ciclo de horas, névoa, chuva e sombras que seguem o jogador. - **Conversas de rua** com outros jogadores e NPCs (ver próxima seção). - **Performance**: *batching* estático por material, sombra seguindo o jogador (janela ±120), lâmpadas/rodas com LOD por distância e fachadas a 256 px — medições ~30–60 fps numa GTX 770. ### Controles | Controle | Ação | |---|---| | `W A S D` | Andar (A/D = lateral) | | Mouse (pointer lock) | Olhar; **arrastar na cena** quando sem lock | | `←` `→` | **Viram a câmera** (não andam de lado) | | Joystick virtual (mobile) | Vertical = andar, horizontal = **virar a câmera** | | `E` | Contexto: exercício na praça / relaxar na praia / parar | | `Espaço` | Pular | | Clique num NPC | Abrir chat | | Chegar perto de alguém | Chat abre sozinho; sai de perto ele fecha | --- ## Conversas de Rua (`/talk/person`) e IA por Personagem - **Registro por dia**: cada fala gravada em `person_talks` (`from/to` de character ou agent + `talked_on` + `is_fallback`), consultável via `GET /talk/person?kind=agent|character&peer=ID`. - **Fio da meada**: o histórico completo (dias anteriores + hoje) é enviado como contexto nas respostas de IA — placeholders de erro (`is_fallback`) ficam visíveis na UI mas **nunca** entram no contexto do modelo. - **Quem responde**: - Par com **humano vivo** (sessão tocada nos últimos 5 min) → relay puro, nunca é substituído por IA; - Par **sem humano** (cidadãos demo, NPCs) → persona anônima de morador responde via OpenRouter, sem dados cadastrais no payload. - **Resposta de IA** é gerada *after-response* (não depende de worker de fila), com espaçamento por par, allow-list de modelos, fallback localizado em falha e auditoria em `last_decision`. - **Identidade por personagem**: colunas em `characters` — `ai_model`, `ai_age`, `ai_gender`, `ai_personality`, `ai_bio` (persona injetada no prompt; recém-criados já nascem com personalidade/idade). - **Modelo por personagem** (ordem de resolução, sempre validado em `allowed_models`): coluna `ai_model` → mapa `AI_CHARACTER_MODELS` (id ou nome) → slot determinístico do pool `AI_MODELS` → `AI_DEFAULT_MODEL`. --- ## Requisitos - PHP **≥ 8.3** (com `pdo_mysql`, `mbstring`, `curl`, `zip`, `gd`, `bcmath`) - Composer 2 - MariaDB ≥ 10.6 (ou MySQL ≥ 8.0) - Node.js ≥ 18 (apenas para assets Vite/Tailwind, opcional na Fase 1) - Docker (opcional, para o ambiente `dockercity10`) --- ## Instalação ### 1. Dependências PHP ```bash composer install ``` ### 2. Configuração do ambiente ```bash cp .env.example .env php artisan key:generate ``` Edite o `.env` e configure o banco de dados: ```env DB_CONNECTION=mariadb DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD= ``` ### 3. Chave do OpenRouter.ai e modelos A chave **não** é versionada. Insira-a apenas no `.env` local: ```env OPENROUTER_API_KEY= AI_DEFAULT_MODEL=deepseek/deepseek-v4-flash-0731 # Pool de modelos gratuitos distribuídos deterministicamente entre os # personagens (cada um mantém o próprio modelo estável). AI_MODELS=deepseek/deepseek-v4-flash-0731,nvidia/nemotron-3.5-lightning:free,liquid/lfm-2.5-2.6b:free,openrouter/free,nvidia/nemotron-3-ultra-550b-a55b:free # Override por personagem: "nome ou id=modelo" separado por vírgula. AI_CHARACTER_MODELS= # AI_ATC_MODEL: default model of the control-tower agent (airport # clearances: takeoff authorizations). Must be allow-listed. AI_ATC_MODEL=poolside/laguna-xs-2.1:free # AI_FALLBACK_MODEL: tried when the preferred model of a call fails # (owner-approved paid model with near-zero cost). AI_FALLBACK_MODEL=xiaomi/mimo-v2.6-flash ``` ### 4. Banco de dados ```bash php artisan migrate --seed ``` ### 5. Servidor de desenvolvimento ```bash php artisan serve --port=16980 ``` A aplicação ficará disponível em `http://localhost:16980`. ### Ambiente Docker (dockercity10) O container `dockercity10` já expõe a aplicação na porta do host **16980** (container `:80`, Apache + PHP-FPM) e o MariaDB na porta **16981**. Após clonar o projeto em `/app` (bind-mount), rode as migrations dentro do container: ```bash docker exec -it dockercity10 bash -c "cd /app && php artisan migrate --seed" ``` --- ## Contas de Teste (ambiente de desenvolvimento) | Papel | E-mail | Senha | |---|---|---| | Administrador | `marcocosta@gmx.com` | `Mega886ax` | | Usuário Comum | `user@sistema.net` | `User123` | > ⚠️ Estas credenciais são exclusivas para desenvolvimento. Altere-as ou > remova-as (`php artisan db:seed --class=UserSeeder` após ajustar) antes de > qualquer implantação em produção. --- ## Testes ```bash php artisan test # suíte completa (PHPUnit) ./vendor/bin/pint # formatação de código ``` Destaques da suíte (testes de recurso): autenticação/LGPD, ações da cidade (exercício, posição com clamp até a orla da praia), social, mercado, missões, **conversas de rua** (`PersonTalkTest` — histórico multidiário, resolução de modelo, ausência de PII no payload) e **lazer na praia** (`BeachLeisureTest` — geometria no payload, efeitos e zona). --- ## Estrutura de Endpoints da API Base URL: `http://localhost:16980/api` (Bearer Sanctum) ### Públicos | Método | Rota | Descrição | |---|---|---| | GET | `/auth/captcha` | Gera desafio matemático (necessário para login/registro) | | POST | `/auth/login` | Autentica e emite token Sanctum | | POST | `/auth/register` | Cria conta de usuário comum | | GET | `/legal/documents` | Lista a versão atual dos documentos legais | ### Autenticados (Bearer token) | Método | Rota | Descrição | |---|---|---| | GET | `/auth/me` | Perfil + status de consentimento | | PATCH | `/auth/profile` | Atualiza nome, idioma ou senha | | POST | `/auth/logout` | Revoga o token atual | | GET | `/city/world` | Snapshot da cidade (lojas + agentes com coordenadas 3D) | | GET/POST | `/stores` | Lista/cria lojas | | GET/PUT/DELETE | `/stores/{id}` | Gerencia uma loja (dono ou admin) | | GET | `/stores-world/seed` | Mundo de lojas (seed 3D) | | GET | `/legal/status` | Status de aceite dos documentos | | POST | `/legal/accept` | Registra o aceite (auditoria LGPD) | | GET | `/legal/history` | Histórico de consentimentos do usuário | ### Somente Administrador | Método | Rota | Descrição | |---|---|---| | CRUD | `/api/users` | Gestão de usuários | | CRUD | `/api/agents` | Gestão de agentes de IA | | GET | `/api/agents-meta/models` | Lista os modelos gratuitos permitidos | | GET | `/api/agents-world/seed` | Mundo de agentes (seed 3D) | | GET/POST | `/stores`, `/citizens`, `/cities`, `/world` | Admin web (aprovação de cidadãos, cidades, mundo) | --- ## Rotas Web da Cidade (sessão de navegador) Todas exigem login + termos aceitos. | Método | Rota | Descrição | |---|---|---| | GET | `/city` | Visualizador 3D (HTML + bundle Three.js) | | GET | `/city/data` | Payload do mundo: layout, lojas, agentes, praças, prédios, `beach` | | GET | `/city/presence` | Cidadãos online (posições, `is_me`) — throttle 60/min | | GET/POST | `/talk/person` | Conversas de rua: histórico/contexto e envio (throttle 120 e 30/min) | | POST | `/city/actions/position` | Sincroniza posição (clamp até a orla da praia) | | POST | `/city/actions/{action}` | Ações: `eat`, `drink`, `sleep`, `wake`, `work`, `study`, `buy`, `sell`, `build`, `apply-job`, `exercise`, `stop-exercise`, `beach`, `ride`, `accident`… | | POST/GET | `/city/chat/{agent}` (+`/stream`) | Conversa com NPC (envio + SSE de resposta) | | POST/GET | `/city/messages/{character}` | Mensagens assíncronas entre personagens | | POST | `/city/social/{verb}` · GET `/city/social/inbox` | Amizade, casamento, filho, inbox | | GET | `/city/airport` | Sites dos aeroportos, torre (ATC) e clearance atual | | POST | `/city/airport/dispatch` | Pede um clearance de decolagem à torre (cooldown 30 s) | | GET/POST | `/city/market` (`/buy`, `/sell`) | Mercado | | GET/PUT | `/city/customize` | Personalização do personagem | --- ## Modelos de IA Permitidos Somente os modelos abaixo podem ser usados (validado no backend em `config/ai.php`; os quatro últimos foram verificados ao vivo no catálogo do OpenRouter). Exceção aprovada pelo responsável: `xiaomi/mimo-v2.6-flash` (pago, custo mínimo ~1,4e-7/token, verificado ao vivo) — usado como **fallback** de todas as cadeias de chamada: ``` poolside/laguna-m.1:free cohere/north-mini-code:free deepseek/deepseek-v4-flash-0731:free qwen/qwen3.8-27b:free nvidia/nemotron-3-ultra-550b-a55b:free nvidia/nemotron-3-super-120b-a12b:free google/gemma-4-31b-it:free google/gemma-4-26b-a4b-it:free openai/gpt-oss-20b:free nvidia/nemotron-nano-12b-v2-vl:free nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free nvidia/nemotron-3-nano-30b-a3b:free nvidia/nemotron-nano-9b-v2:free poolside/laguna-xs-2.1:free inclusionai/ling-3.0-flash-vl:free qwen/qwen3.7-flash:free deepseek/deepseek-v4-flash-0731 nvidia/nemotron-3.5-lightning:free liquid/lfm-2.5-2.6b:free openrouter/free xiaomi/mimo-v2.6-flash (fallback — ver nota acima) ``` --- ## Segurança e Conformidade (LGPD) - **Senhas** armazenadas com bcrypt (cast `hashed`). - **Tokens de API** (Sanctum) revogáveis por usuário. - **RBAC**: papéis `admin` / `user` com middleware dedicado. - **CAPTCHA matemático** nos formulários públicos (login/registro). - **Consentimento auditável**: data, hora, versão do documento, IP e user-agent gravados em `user_consents` (imutáveis). - **Banner de cookies** com opção de aceitar/recusar cookies não essenciais. - **Direitos do titular** (art. 18 LGPD): histórico de consentimentos disponível ao usuário; contato para exercer direitos: `contato@syspanel.com.br`. - **IA sem PII**: ao chamar o OpenRouter envia-se apenas contexto simulado da cidade e o diálogo/identidade in-world — nunca e-mail, senha ou dados de conta (regras em [`RULES.md`](RULES.md), seção 2). --- ## Licença Software **Proprietário** — © 2026 Syspanel. Todos os direitos reservados. Veja o arquivo [`LICENSE`](LICENSE) para os termos completos de uso. Bibliotecas de terceiros utilizadas são compatíveis com uso comercial (por exemplo: Laravel — MIT; Three.js — MIT). O crédito aos autores originais está registrado em [`RULES.md`](RULES.md). --- ## Contato - **E-mail**: [contato@syspanel.com.br](mailto:contato@syspanel.com.br) - **WhatsApp**: (35) 99226-1684 - **Site**: [www.syspanel.com.br](https://syspanel.com.br) - **Localização**: Santa Rita do Sapucaí — Minas Gerais — Brasil --- © 2026 — Todos os direitos reservados — Powered by [Syspanel](https://syspanel.com.br) — www.syspanel.com.br