Files
City10/README.md
T
marcocosta10000 e7498e1566 feat(city): add airports, ATC agent, luminous signs, and AI model fallback chain
- Add two airports (north/south) with full geometry: runways, taxiways,
  aprons, terminals, hangars, stands, and helipads; walkable airport
  grounds extend beyond city bounds.
- Introduce ATC AI agent ("Torre de Controle City10") using AI_ATC_MODEL
  to generate takeoff clearances; includes dispatch endpoint with
  30-second cooldown and deterministic fallback on failure.
- Implement AI model fallback chain: preferred model → AI_FALLBACK_MODEL
  before failing, applied in ChatController and PersonTalkController.
- Add luminous sign labels (letreiros) for plazas, beach, food, hospital,
  school, city hall, and airports with day/night glow.
- Fix city presence cache: compute is_me per viewer instead of baking
  into shared per-second cache to prevent cross-user flag leakage.
- Add tests: AirportTest, CityPresenceTest, SignLabelsTest, and
  PersonTalkTest fallback model retry scenario.
2026-10-31 22:06:18 -03:00

369 lines
15 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, hospital, escola, prefeitura e casas de jogadores.
- **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=<sua_senha>
```
### 3. Chave do OpenRouter.ai e modelos
A chave **não** é versionada. Insira-a apenas no `.env` local:
```env
OPENROUTER_API_KEY=<sua_chave>
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